|
10 | 10 | #include "CheckFailure.h" |
11 | 11 | #include "TextInputDialog.h" |
12 | 12 | #include "Util.h" |
| 13 | + |
| 14 | +#include "ScenarioOriginConfigurationAPI.h" |
| 15 | + |
| 16 | +using namespace Microsoft::WRL; |
| 17 | + |
| 18 | +static constexpr int kEnhancedSecurityModeValue = 1; |
| 19 | +static constexpr int kSmartScreenValue = 2; |
| 20 | + |
| 21 | +ScenarioOriginConfigurationAPI::ScenarioOriginConfigurationAPI(AppWindow* appWindow) |
| 22 | + : m_appWindow(appWindow) |
| 23 | +{ |
| 24 | + CHECK_FAILURE(m_appWindow ? S_OK : E_POINTER); |
| 25 | + wil::com_ptr<ICoreWebView2> webView = m_appWindow->GetWebView(); |
| 26 | + CHECK_FAILURE(webView ? S_OK : E_POINTER); |
| 27 | + auto webView2_13 = webView.try_query<ICoreWebView2_13>(); |
| 28 | + CHECK_FAILURE(webView2_13 ? S_OK : E_POINTER); |
| 29 | + CHECK_FAILURE(webView2_13->get_Profile(&m_webviewProfile)); |
| 30 | +} |
| 31 | + |
| 32 | +ScenarioOriginConfigurationAPI::~ScenarioOriginConfigurationAPI() = default; |
| 33 | + |
| 34 | +std::wstring ScenarioOriginConfigurationAPI::FeatureToString( |
| 35 | + COREWEBVIEW2_ORIGIN_FEATURE feature) |
| 36 | +{ |
| 37 | + switch (feature) |
| 38 | + { |
| 39 | + case COREWEBVIEW2_ORIGIN_FEATURE_ENHANCED_SECURITY_MODE: |
| 40 | + return L"EnhancedSecurityMode"; |
| 41 | + case COREWEBVIEW2_ORIGIN_FEATURE_REPUTATION_CHECKING: |
| 42 | + return L"ReputationChecking"; |
| 43 | + default: |
| 44 | + return L"Unknown"; |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +void ScenarioOriginConfigurationAPI::SetFeatureForOrigins( |
| 49 | + const std::vector<std::wstring>& originPatterns, |
| 50 | + const std::vector< |
| 51 | + std::pair<COREWEBVIEW2_ORIGIN_FEATURE, COREWEBVIEW2_ORIGIN_FEATURE_STATE>>& features) |
| 52 | +{ |
| 53 | + auto experimentalProfile16 = |
| 54 | + m_webviewProfile.try_query<ICoreWebView2ExperimentalProfile16>(); |
| 55 | + CHECK_FEATURE_RETURN_EMPTY(experimentalProfile16); |
| 56 | + |
| 57 | + // featureSettings holds wil::com_ptr for COM lifetime management (keeps refcount > 0). |
| 58 | + // featureSettingsRaw holds raw pointers extracted from featureSettings to pass to the API. |
| 59 | + // Both are needed because the API requires a pointer array, but we need smart pointers to |
| 60 | + // prevent premature COM object destruction. |
| 61 | + std::vector<wil::com_ptr<ICoreWebView2ExperimentalOriginFeatureSetting>> featureSettings; |
| 62 | + std::vector<ICoreWebView2ExperimentalOriginFeatureSetting*> featureSettingsRaw; |
| 63 | + |
| 64 | + for (const auto& [featureKind, featureState] : features) |
| 65 | + { |
| 66 | + wil::com_ptr<ICoreWebView2ExperimentalOriginFeatureSetting> setting; |
| 67 | + CHECK_FAILURE(experimentalProfile16->CreateOriginFeatureSetting( |
| 68 | + featureKind, featureState, &setting)); |
| 69 | + featureSettings.push_back(setting); |
| 70 | + featureSettingsRaw.push_back(setting.get()); |
| 71 | + } |
| 72 | + |
| 73 | + std::vector<LPCWSTR> origins; |
| 74 | + for (const auto& pattern : originPatterns) |
| 75 | + { |
| 76 | + origins.push_back(pattern.c_str()); |
| 77 | + } |
| 78 | + |
| 79 | + CHECK_FAILURE(experimentalProfile16->SetOriginFeatures( |
| 80 | + static_cast<UINT32>(origins.size()), origins.data(), |
| 81 | + static_cast<UINT32>(featureSettingsRaw.size()), featureSettingsRaw.data())); |
| 82 | +} |
| 83 | + |
| 84 | +void ScenarioOriginConfigurationAPI::GetOriginFeatures() |
| 85 | +{ |
| 86 | + auto experimentalProfile16 = |
| 87 | + m_webviewProfile.try_query<ICoreWebView2ExperimentalProfile16>(); |
| 88 | + CHECK_FEATURE_RETURN_EMPTY(experimentalProfile16); |
| 89 | + |
| 90 | + TextInputDialog inputDialog( |
| 91 | + m_appWindow->GetMainWindow(), L"Get Trusted Origin Features", |
| 92 | + L"Enter the origin to retrieve feature settings for:", L"Origin:", |
| 93 | + std::wstring(L"https://www.microsoft.com"), |
| 94 | + false); // not read-only |
| 95 | + |
| 96 | + if (inputDialog.confirmed) |
| 97 | + { |
| 98 | + std::wstring origin = inputDialog.input; |
| 99 | + |
| 100 | + CHECK_FAILURE(experimentalProfile16->GetEffectiveFeaturesForOrigin( |
| 101 | + origin.c_str(), |
| 102 | + Callback<ICoreWebView2ExperimentalGetEffectiveFeaturesForOriginCompletedHandler>( |
| 103 | + [appWindow = m_appWindow, origin]( |
| 104 | + HRESULT errorCode, |
| 105 | + ICoreWebView2ExperimentalOriginFeatureSettingCollectionView* result) |
| 106 | + -> HRESULT |
| 107 | + { |
| 108 | + if (SUCCEEDED(errorCode)) |
| 109 | + { |
| 110 | + UINT32 count = 0; |
| 111 | + CHECK_FAILURE(result->get_Count(&count)); |
| 112 | + |
| 113 | + std::wstring message = L"Features for origin: " + origin + L"\n"; |
| 114 | + for (UINT32 i = 0; i < count; i++) |
| 115 | + { |
| 116 | + wil::com_ptr<ICoreWebView2ExperimentalOriginFeatureSetting> setting; |
| 117 | + CHECK_FAILURE(result->GetValueAtIndex(i, &setting)); |
| 118 | + |
| 119 | + COREWEBVIEW2_ORIGIN_FEATURE feature; |
| 120 | + COREWEBVIEW2_ORIGIN_FEATURE_STATE featureState; |
| 121 | + CHECK_FAILURE(setting->get_Feature(&feature)); |
| 122 | + CHECK_FAILURE(setting->get_State(&featureState)); |
| 123 | + |
| 124 | + message += |
| 125 | + L"Feature: " + FeatureToString(feature) + L", Enabled: " + |
| 126 | + (featureState == COREWEBVIEW2_ORIGIN_FEATURE_STATE_ENABLED |
| 127 | + ? L"True" |
| 128 | + : L"False") + |
| 129 | + L"\n"; |
| 130 | + } |
| 131 | + |
| 132 | + MessageBoxW( |
| 133 | + appWindow->GetMainWindow(), message.c_str(), |
| 134 | + L"Trusted Origin Features", MB_OK); |
| 135 | + } |
| 136 | + else |
| 137 | + { |
| 138 | + ShowFailure( |
| 139 | + errorCode, |
| 140 | + L"Failed to get effective features for origin: " + origin); |
| 141 | + } |
| 142 | + return S_OK; |
| 143 | + }) |
| 144 | + .Get())); |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +void ScenarioOriginConfigurationAPI::SetOriginFeatures() |
| 149 | +{ |
| 150 | + static constexpr wchar_t kOriginPatternsLabel[] = L"Enter origin patterns separated with ;"; |
| 151 | + static constexpr wchar_t kFeaturesGroupLabel[] = L"Select features to enable:"; |
| 152 | + |
| 153 | + // Builder with text area for origin input and checkbox for feature selection. |
| 154 | + auto enhancedDialog = |
| 155 | + TextInputDialog::Builder( |
| 156 | + m_appWindow->GetMainWindow(), L"Configure Trusted Origin", |
| 157 | + L"Trusted Origin Configuration:") |
| 158 | + .AddTextArea(kOriginPatternsLabel, L"https://www.microsoft.com") |
| 159 | + .AddCheckBoxGroup( |
| 160 | + kFeaturesGroupLabel, |
| 161 | + {{L"Enable Enhanced Security Mode", kEnhancedSecurityModeValue, true}, |
| 162 | + {L"Disable Reputation Checking", kSmartScreenValue, false}}) |
| 163 | + .Build(); |
| 164 | + |
| 165 | + if (enhancedDialog.confirmed) |
| 166 | + { |
| 167 | + // Retrieve the origin text area. Skip if the control is missing. |
| 168 | + auto textAreaIt = enhancedDialog.results.find(kOriginPatternsLabel); |
| 169 | + if (textAreaIt == enhancedDialog.results.end()) |
| 170 | + return; |
| 171 | + auto& textArea = std::get<TextArea>(textAreaIt->second); |
| 172 | + std::wstring input = textArea.input; |
| 173 | + |
| 174 | + // Retrieve the feature checkbox group. Skip if the control is missing. |
| 175 | + std::vector<std::pair<COREWEBVIEW2_ORIGIN_FEATURE, COREWEBVIEW2_ORIGIN_FEATURE_STATE>> |
| 176 | + features; |
| 177 | + auto groupIt = enhancedDialog.results.find(kFeaturesGroupLabel); |
| 178 | + if (groupIt == enhancedDialog.results.end()) |
| 179 | + return; |
| 180 | + auto& group = std::get<CheckBoxGroup>(groupIt->second); |
| 181 | + for (const auto& option : group.options) |
| 182 | + { |
| 183 | + if (option.isSelected && option.value == kEnhancedSecurityModeValue) |
| 184 | + { |
| 185 | + features.push_back( |
| 186 | + {COREWEBVIEW2_ORIGIN_FEATURE_ENHANCED_SECURITY_MODE, |
| 187 | + COREWEBVIEW2_ORIGIN_FEATURE_STATE_ENABLED}); |
| 188 | + } |
| 189 | + if (option.isSelected && option.value == kSmartScreenValue) |
| 190 | + { |
| 191 | + // Disabling SmartScreen for the origin = allow-listing it. |
| 192 | + features.push_back( |
| 193 | + {COREWEBVIEW2_ORIGIN_FEATURE_REPUTATION_CHECKING, |
| 194 | + COREWEBVIEW2_ORIGIN_FEATURE_STATE_DISABLED}); |
| 195 | + } |
| 196 | + } |
| 197 | + |
| 198 | + std::vector<std::wstring> origins = Util::SplitString(input, L';'); |
| 199 | + |
| 200 | + // Set features for all origins in a single call. |
| 201 | + if (!features.empty()) |
| 202 | + { |
| 203 | + SetFeatureForOrigins(origins, features); |
| 204 | + } |
| 205 | + } |
| 206 | +} |
0 commit comments