From 604800b04edc4e3a39dc019a0ddbc5c29c7b1fc5 Mon Sep 17 00:00:00 2001 From: Cepera Date: Tue, 13 Dec 2022 18:14:30 +0300 Subject: [PATCH] Restore the DNS over HTTPS work-around on Windows (#15989) Re-introduces logic from https://github.com/brave/brave-core/pull/13434 This reverts commit b9f88f6d1b8e56eafea625196089fefefff08992. Fixes https://github.com/brave/brave-browser/issues/26787 Co-authored-by: Brian Clifton --- browser/about_flags.cc | 19 +- browser/brave_features_internal_names.h | 10 +- browser/brave_local_state_prefs.cc | 4 + .../brave_vpn/brave_vpn_service_factory.cc | 24 +- browser/brave_vpn/dns/BUILD.gn | 22 + .../dns/brave_vpn_dns_observer_factory.cc | 61 +++ .../dns/brave_vpn_dns_observer_factory.h | 49 +++ .../dns/brave_vpn_dns_observer_service.cc | 131 ++++++ .../dns/brave_vpn_dns_observer_service.h | 68 +++ ...brave_vpn_dns_observer_service_unittest.cc | 392 ++++++++++++++++++ browser/brave_vpn/sources.gni | 14 + browser/ui/BUILD.gn | 11 +- ..._dns_settings_notificiation_dialog_view.cc | 147 +++++++ ...n_dns_settings_notificiation_dialog_view.h | 54 +++ .../brave_settings_secure_dns_handler.cc | 37 ++ .../brave_settings_secure_dns_handler.h | 28 ++ .../net/stub_resolver_config_reader.cc | 140 +++++++ .../browser/ui/webui/settings/settings_ui.cc | 7 + ...red_settings_localized_strings_provider.cc | 52 +++ chromium_src/chrome/common/pref_names.cc | 12 + chromium_src/chrome/common/pref_names.h | 21 + components/brave_vpn/brave_vpn_utils.cc | 6 +- components/brave_vpn/features.cc | 5 + components/brave_vpn/features.h | 5 +- components/brave_vpn/pref_names.h | 7 +- components/resources/brave_vpn_strings.grdp | 22 + test/BUILD.gn | 1 + 27 files changed, 1338 insertions(+), 11 deletions(-) create mode 100644 browser/brave_vpn/dns/BUILD.gn create mode 100644 browser/brave_vpn/dns/brave_vpn_dns_observer_factory.cc create mode 100644 browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h create mode 100644 browser/brave_vpn/dns/brave_vpn_dns_observer_service.cc create mode 100644 browser/brave_vpn/dns/brave_vpn_dns_observer_service.h create mode 100644 browser/brave_vpn/dns/brave_vpn_dns_observer_service_unittest.cc create mode 100644 browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.cc create mode 100644 browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.h create mode 100644 browser/ui/webui/settings/brave_settings_secure_dns_handler.cc create mode 100644 browser/ui/webui/settings/brave_settings_secure_dns_handler.h create mode 100644 chromium_src/chrome/browser/net/stub_resolver_config_reader.cc create mode 100644 chromium_src/chrome/common/pref_names.cc create mode 100644 chromium_src/chrome/common/pref_names.h diff --git a/browser/about_flags.cc b/browser/about_flags.cc index 968a2c708b3..9902017e83d 100644 --- a/browser/about_flags.cc +++ b/browser/about_flags.cc @@ -229,7 +229,12 @@ constexpr char kBraveSyncDescription[] = constexpr char kBraveVPNName[] = "Enable experimental Brave VPN"; constexpr char kBraveVPNDescription[] = "Experimental native VPN support"; - +#if BUILDFLAG(IS_WIN) +constexpr char kBraveVPNDnsProtectionName[] = "Enable DoH for Brave VPN"; +constexpr char kBraveVPNDnsProtectionDescription[] = + "Override DoH settings with Cloudflare dns if necessary to avoid leaking " + "requests due to Smart Multi-Home Named Resolution"; +#endif constexpr char kBraveSkusSdkName[] = "Enable experimental SKU SDK"; constexpr char kBraveSkusSdkDescription[] = "Experimental SKU SDK support"; @@ -422,8 +427,19 @@ constexpr char kBraveAndroidSafeBrowsingDescription[] = flag_descriptions::kBraveVPNDescription, \ kOsMac | kOsWin, \ FEATURE_VALUE_TYPE(brave_vpn::features::kBraveVPN)}, +#if BUILDFLAG(IS_WIN) +#define BRAVE_VPN_DNS_FEATURE_ENTRIES \ + {kBraveVPNDnsFeatureInternalName, \ + flag_descriptions::kBraveVPNDnsProtectionName, \ + flag_descriptions::kBraveVPNDnsProtectionDescription, \ + kOsWin, \ + FEATURE_VALUE_TYPE(brave_vpn::features::kBraveVPNDnsProtection)}, +#else +#define BRAVE_VPN_DNS_FEATURE_ENTRIES +#endif #else #define BRAVE_VPN_FEATURE_ENTRIES +#define BRAVE_VPN_DNS_FEATURE_ENTRIES #endif #define BRAVE_SKU_SDK_FEATURE_ENTRIES \ @@ -734,6 +750,7 @@ constexpr char kBraveAndroidSafeBrowsingDescription[] = CRYPTO_WALLETS_FEATURE_ENTRIES \ BRAVE_REWARDS_GEMINI_FEATURE_ENTRIES \ BRAVE_VPN_FEATURE_ENTRIES \ + BRAVE_VPN_DNS_FEATURE_ENTRIES \ BRAVE_SKU_SDK_FEATURE_ENTRIES \ SPEEDREADER_FEATURE_ENTRIES \ BRAVE_TRANSLATE_GO_FEATURE_ENTRIES \ diff --git a/browser/brave_features_internal_names.h b/browser/brave_features_internal_names.h index f55e0a65695..bbc71f8f389 100644 --- a/browser/brave_features_internal_names.h +++ b/browser/brave_features_internal_names.h @@ -6,7 +6,15 @@ #ifndef BRAVE_BROWSER_BRAVE_FEATURES_INTERNAL_NAMES_H_ #define BRAVE_BROWSER_BRAVE_FEATURES_INTERNAL_NAMES_H_ -constexpr char kBraveVPNFeatureInternalName[] = "brave-vpn"; +#include "brave/components/brave_vpn/buildflags/buildflags.h" +#include "build/build_config.h" + constexpr char kPlaylistFeatureInternalName[] = "playlist"; +#if BUILDFLAG(ENABLE_BRAVE_VPN) +constexpr char kBraveVPNFeatureInternalName[] = "brave-vpn"; +#if BUILDFLAG(IS_WIN) +constexpr char kBraveVPNDnsFeatureInternalName[] = "brave-vpn-dns"; +#endif +#endif #endif // BRAVE_BROWSER_BRAVE_FEATURES_INTERNAL_NAMES_H_ diff --git a/browser/brave_local_state_prefs.cc b/browser/brave_local_state_prefs.cc index 0fb291995ce..1363bc3b8d6 100644 --- a/browser/brave_local_state_prefs.cc +++ b/browser/brave_local_state_prefs.cc @@ -5,6 +5,8 @@ #include "brave/browser/brave_local_state_prefs.h" +#include + #include "base/values.h" #include "brave/browser/brave_stats/brave_stats_updater.h" #include "brave/browser/metrics/buildflags/buildflags.h" @@ -128,6 +130,8 @@ void RegisterLocalStatePrefs(PrefRegistrySimple* registry) { skus::RegisterLocalStatePrefs(registry); #endif + registry->RegisterStringPref(::prefs::kBraveVpnDnsConfig, std::string()); + ntp_background_images::NTPP3AHelperImpl::RegisterLocalStatePrefs(registry); core_metrics::CoreMetricsService::RegisterPrefs(registry); diff --git a/browser/brave_vpn/brave_vpn_service_factory.cc b/browser/brave_vpn/brave_vpn_service_factory.cc index a0c99380c41..bc50bd66ec4 100644 --- a/browser/brave_vpn/brave_vpn_service_factory.cc +++ b/browser/brave_vpn/brave_vpn_service_factory.cc @@ -11,6 +11,7 @@ #include "brave/components/brave_vpn/brave_vpn_os_connection_api.h" #include "brave/components/brave_vpn/brave_vpn_service.h" #include "brave/components/brave_vpn/brave_vpn_utils.h" +#include "brave/components/brave_vpn/features.h" #include "brave/components/skus/common/features.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" @@ -21,6 +22,11 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/storage_partition.h" +#if BUILDFLAG(IS_WIN) +#include "brave/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h" +#include "brave/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h" +#endif + namespace brave_vpn { // static @@ -50,6 +56,11 @@ BraveVpnServiceFactory::BraveVpnServiceFactory() "BraveVpnService", BrowserContextDependencyManager::GetInstance()) { DependsOn(skus::SkusServiceFactory::GetInstance()); + +#if BUILDFLAG(IS_WIN) + DependsOn(brave_vpn::BraveVpnDnsObserverFactory::GetInstance()); +#endif + #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) auto* connection_api = BraveVPNOSConnectionAPI::GetInstance(); connection_api->set_shared_url_loader_factory( @@ -77,8 +88,17 @@ KeyedService* BraveVpnServiceFactory::BuildServiceInstanceFor( }, context); - return new BraveVpnService(shared_url_loader_factory, local_state, - user_prefs::UserPrefs::Get(context), callback); + auto* vpn_service = + new BraveVpnService(shared_url_loader_factory, local_state, + user_prefs::UserPrefs::Get(context), callback); +#if BUILDFLAG(IS_WIN) + auto* dns_observer_service = + brave_vpn::BraveVpnDnsObserverFactory::GetInstance() + ->GetServiceForContext(context); + if (dns_observer_service) + dns_observer_service->Observe(vpn_service); +#endif + return vpn_service; } void BraveVpnServiceFactory::RegisterProfilePrefs( diff --git a/browser/brave_vpn/dns/BUILD.gn b/browser/brave_vpn/dns/BUILD.gn new file mode 100644 index 00000000000..bb93f5c575e --- /dev/null +++ b/browser/brave_vpn/dns/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2022 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +import("//brave/components/brave_vpn/buildflags/buildflags.gni") +import("//testing/test.gni") + +source_set("unit_tests") { + testonly = true + if (enable_brave_vpn && is_win) { + sources = [ "brave_vpn_dns_observer_service_unittest.cc" ] + deps = [ + "//brave/components/brave_vpn", + "//chrome/common:constants", + "//chrome/test:test_support", + "//net", + "//testing/gtest", + "//third_party/abseil-cpp:absl", + ] + } +} diff --git a/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.cc b/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.cc new file mode 100644 index 00000000000..b3349f768bd --- /dev/null +++ b/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.cc @@ -0,0 +1,61 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h" + +#include +#include +#include + +#include "base/feature_list.h" +#include "brave/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h" +#include "brave/components/brave_vpn/brave_vpn_utils.h" +#include "brave/components/brave_vpn/features.h" +#include "brave/components/brave_vpn/pref_names.h" +#include "chrome/browser/browser_process.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/user_prefs/user_prefs.h" +#include "content/public/browser/browser_context.h" + +namespace brave_vpn { + +// static +BraveVpnDnsObserverFactory* BraveVpnDnsObserverFactory::GetInstance() { + return base::Singleton::get(); +} + +BraveVpnDnsObserverFactory::~BraveVpnDnsObserverFactory() = default; + +BraveVpnDnsObserverFactory::BraveVpnDnsObserverFactory() + : BrowserContextKeyedServiceFactory( + "BraveVpnDNSObserverService", + BrowserContextDependencyManager::GetInstance()) {} + +KeyedService* BraveVpnDnsObserverFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return new BraveVpnDnsObserverService(g_browser_process->local_state(), + user_prefs::UserPrefs::Get(context)); +} + +// static +BraveVpnDnsObserverService* BraveVpnDnsObserverFactory::GetServiceForContext( + content::BrowserContext* context) { + if (!base::FeatureList::IsEnabled( + brave_vpn::features::kBraveVPNDnsProtection)) { + return nullptr; + } + DCHECK(IsBraveVPNEnabled()); + return static_cast( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +void BraveVpnDnsObserverFactory::RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) { + registry->RegisterBooleanPref(prefs::kBraveVpnShowDNSPolicyWarningDialog, + true); +} + +} // namespace brave_vpn diff --git a/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h b/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h new file mode 100644 index 00000000000..f17558c42cb --- /dev/null +++ b/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h @@ -0,0 +1,49 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_BRAVE_VPN_DNS_BRAVE_VPN_DNS_OBSERVER_FACTORY_H_ +#define BRAVE_BROWSER_BRAVE_VPN_DNS_BRAVE_VPN_DNS_OBSERVER_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +namespace content { +class BrowserContext; +} // namespace content + +namespace user_prefs { +class PrefRegistrySyncable; +} // namespace user_prefs + +namespace brave_vpn { + +class BraveVpnDnsObserverService; + +class BraveVpnDnsObserverFactory : public BrowserContextKeyedServiceFactory { + public: + BraveVpnDnsObserverFactory(const BraveVpnDnsObserverFactory&) = delete; + BraveVpnDnsObserverFactory& operator=(const BraveVpnDnsObserverFactory&) = + delete; + + static BraveVpnDnsObserverFactory* GetInstance(); + static BraveVpnDnsObserverService* GetServiceForContext( + content::BrowserContext* context); + void RegisterProfilePrefs( + user_prefs::PrefRegistrySyncable* registry) override; + + private: + friend struct base::DefaultSingletonTraits; + + BraveVpnDnsObserverFactory(); + ~BraveVpnDnsObserverFactory() override; + + // BrowserContextKeyedServiceFactory overrides: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; +}; + +} // namespace brave_vpn + +#endif // BRAVE_BROWSER_BRAVE_VPN_DNS_BRAVE_VPN_DNS_OBSERVER_FACTORY_H_ diff --git a/browser/brave_vpn/dns/brave_vpn_dns_observer_service.cc b/browser/brave_vpn/dns/brave_vpn_dns_observer_service.cc new file mode 100644 index 00000000000..e2060e0bbad --- /dev/null +++ b/browser/brave_vpn/dns/brave_vpn_dns_observer_service.cc @@ -0,0 +1,131 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h" + +#include + +#include "base/strings/string_util.h" +#include "brave/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.h" +#include "brave/components/brave_vpn/brave_vpn_utils.h" +#include "brave/components/brave_vpn/pref_names.h" +#include "chrome/browser/net/secure_dns_config.h" +#include "chrome/browser/net/stub_resolver_config_reader.h" +#include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/simple_message_box.h" +#include "chrome/common/pref_names.h" +#include "chrome/grit/chromium_strings.h" +#include "components/grit/brave_components_strings.h" +#include "components/prefs/pref_service.h" +#include "ui/base/l10n/l10n_util.h" + +namespace brave_vpn { + +namespace { +const char kCloudflareDnsProviderURL[] = + "https://chrome.cloudflare-dns.com/dns-query"; + +void SkipDNSDialog(PrefService* prefs, bool checked) { + if (!prefs) + return; + prefs->SetBoolean(prefs::kBraveVpnShowDNSPolicyWarningDialog, !checked); +} + +gfx::NativeWindow GetAnchorBrowserWindow() { + auto* browser = chrome::FindLastActive(); + return browser ? browser->window()->GetNativeWindow() + : gfx::kNullNativeWindow; +} + +bool AreConfigsEqual(SecureDnsConfig& one, SecureDnsConfig& two) { + return one.mode() == two.mode() && + one.management_mode() == two.management_mode() && + one.doh_servers() == two.doh_servers(); +} + +} // namespace + +BraveVpnDnsObserverService::BraveVpnDnsObserverService( + PrefService* local_state, + PrefService* profile_prefs) + : local_state_(local_state), profile_prefs_(profile_prefs) { + DCHECK(profile_prefs_); + DCHECK(local_state_); + local_state_->ClearPref(::prefs::kBraveVpnDnsConfig); +} + +BraveVpnDnsObserverService::~BraveVpnDnsObserverService() = default; + +void BraveVpnDnsObserverService::ShowPolicyWarningMessage() { + if (!profile_prefs_->GetBoolean(prefs::kBraveVpnShowDNSPolicyWarningDialog)) { + return; + } + + if (policy_callback_) { + std::move(policy_callback_).Run(); + return; + } + + chrome::ShowWarningMessageBoxWithCheckbox( + GetAnchorBrowserWindow(), l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), + l10n_util::GetStringUTF16(IDS_BRAVE_VPN_DNS_POLICY_ALERT), + l10n_util::GetStringUTF16(IDS_BRAVE_VPN_DNS_POLICY_CHECKBOX), + base::BindOnce(&SkipDNSDialog, profile_prefs_)); +} + +void BraveVpnDnsObserverService::ShowVpnDnsSettingsNotificationDialog() { + if (dialog_callback_) { + dialog_callback_.Run(); + return; + } + BraveVpnDnsSettingsNotificiationDialogView::Show(chrome::FindLastActive()); +} + +void BraveVpnDnsObserverService::UnlockDNS() { + local_state_->ClearPref(::prefs::kBraveVpnDnsConfig); + // Read DNS config to initiate update of actual state. + SystemNetworkContextManager::GetStubResolverConfigReader() + ->UpdateNetworkService(false); +} + +void BraveVpnDnsObserverService::LockDNS() { + auto old_dns_config = + SystemNetworkContextManager::GetStubResolverConfigReader() + ->GetSecureDnsConfiguration(false); + + local_state_->SetString(::prefs::kBraveVpnDnsConfig, + kCloudflareDnsProviderURL); + + // Trigger StubResolverConfigReader to see if it should override the settings + // with kBraveVpnDnsConfig + SystemNetworkContextManager::GetStubResolverConfigReader() + ->UpdateNetworkService(false); + auto new_dns_config = + SystemNetworkContextManager::GetStubResolverConfigReader() + ->GetSecureDnsConfiguration(false); + + if (old_dns_config.mode() != net::SecureDnsMode::kSecure) { + if (AreConfigsEqual(old_dns_config, new_dns_config)) { + ShowPolicyWarningMessage(); + } else { + ShowVpnDnsSettingsNotificationDialog(); + } + } +} + +void BraveVpnDnsObserverService::OnConnectionStateChanged( + brave_vpn::mojom::ConnectionState state) { + if (state == brave_vpn::mojom::ConnectionState::CONNECTED) { + LockDNS(); + } else if (state == brave_vpn::mojom::ConnectionState::DISCONNECTED) { + UnlockDNS(); + } +} + +} // namespace brave_vpn diff --git a/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h b/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h new file mode 100644 index 00000000000..d3399fcf965 --- /dev/null +++ b/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h @@ -0,0 +1,68 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_BRAVE_VPN_DNS_BRAVE_VPN_DNS_OBSERVER_SERVICE_H_ +#define BRAVE_BROWSER_BRAVE_VPN_DNS_BRAVE_VPN_DNS_OBSERVER_SERVICE_H_ + +#include +#include +#include + +#include "base/memory/weak_ptr.h" +#include "brave/components/brave_vpn/brave_vpn_service_observer.h" +#include "components/keyed_service/core/keyed_service.h" +#include "components/prefs/pref_change_registrar.h" +#include "net/dns/dns_config.h" +#include "net/dns/dns_config_service.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +class PrefService; + +namespace brave_vpn { + +class BraveVpnDnsObserverService : public brave_vpn::BraveVPNServiceObserver, + public KeyedService { + public: + explicit BraveVpnDnsObserverService(PrefService* local_state, + PrefService* profile_prefs); + ~BraveVpnDnsObserverService() override; + BraveVpnDnsObserverService(const BraveVpnDnsObserverService&) = delete; + BraveVpnDnsObserverService operator=(const BraveVpnDnsObserverService&) = + delete; + + // brave_vpn::BraveVPNServiceObserver + void OnConnectionStateChanged( + brave_vpn::mojom::ConnectionState state) override; + + void SetPolicyNotificationCallbackForTesting(base::OnceClosure callback) { + policy_callback_ = std::move(callback); + } + + void SetVPNNotificationCallbackForTesting(base::RepeatingClosure callback) { + dialog_callback_ = std::move(callback); + } + + private: + friend class BraveVpnDnsObserverServiceUnitTest; + + void OnPrefChanged(); + void LockDNS(); + void UnlockDNS(); + void ShowPolicyWarningMessage(); + void ShowVpnDnsSettingsNotificationDialog(); + void OnDnsModePrefChanged(); + + base::OnceClosure policy_callback_; + base::RepeatingClosure dialog_callback_; + bool skip_notification_dialog_for_testing_ = false; + raw_ptr local_state_; + raw_ptr profile_prefs_; + + base::WeakPtrFactory weak_ptr_factory_{this}; +}; + +} // namespace brave_vpn + +#endif // BRAVE_BROWSER_BRAVE_VPN_DNS_BRAVE_VPN_DNS_OBSERVER_SERVICE_H_ diff --git a/browser/brave_vpn/dns/brave_vpn_dns_observer_service_unittest.cc b/browser/brave_vpn/dns/brave_vpn_dns_observer_service_unittest.cc new file mode 100644 index 00000000000..931f803c070 --- /dev/null +++ b/browser/brave_vpn/dns/brave_vpn_dns_observer_service_unittest.cc @@ -0,0 +1,392 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h" + +#include + +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/test/scoped_feature_list.h" +#include "brave/browser/brave_profile_prefs.h" +#include "brave/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h" +#include "brave/components/brave_vpn/brave_vpn_utils.h" +#include "brave/components/brave_vpn/features.h" +#include "brave/components/brave_vpn/pref_names.h" +#include "chrome/browser/net/secure_dns_config.h" +#include "chrome/browser/net/secure_dns_util.h" +#include "chrome/browser/net/stub_resolver_config_reader.h" +#include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/browser/prefs/browser_prefs.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/scoped_testing_local_state.h" +#include "chrome/test/base/testing_browser_process.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "content/public/test/browser_task_environment.h" +#include "net/dns/public/secure_dns_mode.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace brave_vpn { +namespace { +const char kCustomServersURLs[] = + "https://server1.com\nhttps://server2.com/{?dns}"; +const char kCloudflareDnsProviderURL[] = + "https://chrome.cloudflare-dns.com/dns-query"; +} // namespace + +class BraveVpnDnsObserverServiceUnitTest : public testing::Test { + public: + BraveVpnDnsObserverServiceUnitTest() {} + + void SetUp() override { + RegisterLocalState(local_state_.registry()); + BraveVpnDnsObserverFactory::GetInstance()->RegisterProfilePrefs( + profile_pref_service_.registry()); + stub_resolver_config_reader_ = + std::make_unique(&local_state_); + SystemNetworkContextManager::set_stub_resolver_config_reader_for_testing( + stub_resolver_config_reader_.get()); + CreateDnsObserverService(); + } + + void CreateDnsObserverService() { + dns_observer_service_.reset( + new BraveVpnDnsObserverService(local_state(), pref_service())); + dns_observer_service_->SetVPNNotificationCallbackForTesting( + base::DoNothing()); + } + + void ResetDnsObserverService() { dns_observer_service_.reset(); } + + void TearDown() override { + // BraveVpnDnsObserverService destructor must be called before the task + // runner is destroyed. + ResetDnsObserverService(); + } + void EnableParentalControl(bool value) { + StubResolverConfigReader* config_reader = + SystemNetworkContextManager::GetStubResolverConfigReader(); + config_reader->OverrideParentalControlsForTesting(value); + } + PrefService* local_state() { return &local_state_; } + PrefService* pref_service() { return &profile_pref_service_; } + + void FireBraveVPNStateChange(mojom::ConnectionState state) { + dns_observer_service_->OnConnectionStateChanged(state); + } + + bool WasVpnNotificationShownForState(mojom::ConnectionState state) { + bool callback_called = false; + dns_observer_service_->SetVPNNotificationCallbackForTesting( + base::BindLambdaForTesting([&]() { callback_called = true; })); + FireBraveVPNStateChange(state); + return callback_called; + } + + void CheckUserNotifiedAndDnsOverridenOnLaunch( + const std::string& user_dns_mode, + const std::string& user_servers, + const std::string& expected_servers, + bool expected_dialog_shown) { + ResetDnsObserverService(); + // DNS mode was set to off by user. + SetDNSMode(user_dns_mode, user_servers); + // Set vpn config to indicate vpn was enabled when browser closed + local_state()->SetString(::prefs::kBraveVpnDnsConfig, + kCloudflareDnsProviderURL); + CreateDnsObserverService(); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + // After launch BraveVPNService will notify observers with actual state. + // and we expect the dns notification dialog will not be shown as vpn is + // enabled. + EXPECT_EQ( + WasVpnNotificationShownForState(mojom::ConnectionState::CONNECTED), + expected_dialog_shown); + + // the dns config was overriden. + ExpectDNSMode(SecureDnsConfig::kModeSecure, expected_servers); + } + + void SetDNSMode(const std::string& mode, const std::string& doh_providers) { + local_state()->SetString(::prefs::kDnsOverHttpsTemplates, doh_providers); + local_state()->SetString(::prefs::kDnsOverHttpsMode, mode); + SystemNetworkContextManager::GetStubResolverConfigReader() + ->UpdateNetworkService(false); + } + + bool WasPolicyNotificationShownForState(mojom::ConnectionState state) { + bool callback_called = false; + dns_observer_service_->SetPolicyNotificationCallbackForTesting( + base::BindLambdaForTesting([&]() { callback_called = true; })); + FireBraveVPNStateChange(state); + return callback_called; + } + + void ExpectDNSMode(const std::string& mode, + const std::string& doh_providers) { + auto dns_config = SystemNetworkContextManager::GetStubResolverConfigReader() + ->GetSecureDnsConfiguration(false); + auto* current_mode = SecureDnsConfig::ModeToString(dns_config.mode()); + auto current_servers = dns_config.doh_servers().ToString(); + EXPECT_EQ(current_mode, mode); + EXPECT_EQ(current_servers, doh_providers); + } + + void SetManagedMode(const std::string& value) { + local_state_.SetManagedPref(::prefs::kDnsOverHttpsMode, + std::make_unique(value)); + } + + private: + std::unordered_map policy_map_; + content::BrowserTaskEnvironment task_environment_; + std::unique_ptr dns_observer_service_; + sync_preferences::TestingPrefServiceSyncable profile_pref_service_; + TestingPrefServiceSimple local_state_; + std::unique_ptr stub_resolver_config_reader_; +}; + +TEST_F(BraveVpnDnsObserverServiceUnitTest, OverrideDohConfigForOffMode) { + // Browser DoH mode off -> override browser config and enable vpn + local_state()->ClearPref(::prefs::kBraveVpnDnsConfig); + SetDNSMode(SecureDnsConfig::kModeOff, ""); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + EXPECT_FALSE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, OverrideDohConfigForAutomaticMode) { + // Browser DoH mode automatic -> override browser config and enable vpn + SetDNSMode(SecureDnsConfig::kModeAutomatic, ""); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, ""); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + EXPECT_FALSE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, ""); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, OverrideDohConfigForSecureMode) { + // Browser DoH mode secure -> override browser config and enable vpn + SetDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + EXPECT_FALSE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + OverrideDohConfigForAutomaticModeWithValidCustomServers) { + // Browser DoH mode automatic with custom servers + // -> we override browser config and enable vpn + SetDNSMode(SecureDnsConfig::kModeAutomatic, kCustomServersURLs); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, kCustomServersURLs); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + EXPECT_FALSE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, kCustomServersURLs); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + OverrideDohConfigForAutomaticModeWithBrokenCustomServers) { + // Browser DoH mode automatic with broken custom servers + // -> override browser config and enable vpn + SetDNSMode(SecureDnsConfig::kModeAutomatic, std::string()); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, std::string()); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + EXPECT_FALSE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, std::string()); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + OverrideDohConfigForSecureModeWithCustomServers) { + // Browser DoH mode secure with custom servers + // -> override browser config and enable vpn + SetDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + EXPECT_FALSE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTING); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + DoNotOverrideDoHConfigWithPolicyOff) { + SetManagedMode(SecureDnsConfig::kModeOff); + + SetDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_TRUE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_FALSE(WasPolicyNotificationShownForState( + mojom::ConnectionState::DISCONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::DISCONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + DoNotOverrideDoHConfigWithPolicyAutomatic) { + SetManagedMode(SecureDnsConfig::kModeAutomatic); + + SetDNSMode(SecureDnsConfig::kModeAutomatic, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, ""); + EXPECT_TRUE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, ""); + EXPECT_FALSE(WasPolicyNotificationShownForState( + mojom::ConnectionState::DISCONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::DISCONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeAutomatic, ""); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + DoNotOverrideDoHConfigWithPolicySecure) { + SetManagedMode(SecureDnsConfig::kModeSecure); + SetDNSMode(SecureDnsConfig::kModeSecure, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, ""); + EXPECT_FALSE(WasPolicyNotificationShownForState( + mojom::ConnectionState::DISCONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::DISCONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, ""); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + DoNotOverrideDoHConfigWithPolicySecureAndCustomServers) { + SetDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + SetManagedMode(SecureDnsConfig::kModeSecure); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + EXPECT_FALSE(WasPolicyNotificationShownForState( + mojom::ConnectionState::DISCONNECTING)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::DISCONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCustomServersURLs); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + DoNotOverrideDoHConfigWithParentalControlEnabled) { + SetDNSMode(SecureDnsConfig::kModeSecure, ""); + EnableParentalControl(true); + EXPECT_TRUE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::DISCONNECTED)); + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + + EnableParentalControl(false); + ExpectDNSMode(SecureDnsConfig::kModeSecure, ""); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, DoNotShowPolicyDialogIfUserSkipped) { + // Do not show dialog option enabled + SetManagedMode(SecureDnsConfig::kModeOff); + pref_service()->SetBoolean(prefs::kBraveVpnShowDNSPolicyWarningDialog, false); + SetDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_FALSE( + WasPolicyNotificationShownForState(mojom::ConnectionState::CONNECTED)); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, DnsOverridenOnLaunchIfVPNEnabled) { + CheckUserNotifiedAndDnsOverridenOnLaunch(SecureDnsConfig::kModeOff, + std::string(), + kCloudflareDnsProviderURL, true); + CheckUserNotifiedAndDnsOverridenOnLaunch(SecureDnsConfig::kModeAutomatic, + std::string(), + kCloudflareDnsProviderURL, true); + CheckUserNotifiedAndDnsOverridenOnLaunch(SecureDnsConfig::kModeSecure, "", "", + false); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, + VPNConnectedOnBrowserShutDownAndDisconnectedOnStart) { + ResetDnsObserverService(); + // DNS mode was set to off by user. + SetDNSMode(SecureDnsConfig::kModeOff, ""); + // Set vpn config to indicate vpn was enabled when browser closed. + local_state()->SetString(::prefs::kBraveVpnDnsConfig, + kCloudflareDnsProviderURL); + CreateDnsObserverService(); + // Before VPN service initialization we have vpn overriden. + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); + // On launch vpn service notifies it is disconnected. + FireBraveVPNStateChange(mojom::ConnectionState::DISCONNECTED); + // Do not override anymore as vpn is disconnected. + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_TRUE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +TEST_F(BraveVpnDnsObserverServiceUnitTest, FeatureDisabledWhenVPNConnected) { + // DNS mode was set to off by user and the vpn dns observer feature + // is enabled by default. + SetDNSMode(SecureDnsConfig::kModeOff, ""); + FireBraveVPNStateChange(mojom::ConnectionState::CONNECTED); + ExpectDNSMode(SecureDnsConfig::kModeSecure, kCloudflareDnsProviderURL); + + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + brave_vpn::features::kBraveVPNDnsProtection); + // Do not override anymore because the feature is disabled. + ExpectDNSMode(SecureDnsConfig::kModeOff, ""); + EXPECT_FALSE(local_state()->GetString(::prefs::kBraveVpnDnsConfig).empty()); +} + +} // namespace brave_vpn diff --git a/browser/brave_vpn/sources.gni b/browser/brave_vpn/sources.gni index 12de53cebcc..475e91468db 100644 --- a/browser/brave_vpn/sources.gni +++ b/browser/brave_vpn/sources.gni @@ -15,6 +15,20 @@ if (enable_brave_vpn) { "//brave/browser/brave_vpn/vpn_utils.cc", "//brave/browser/brave_vpn/vpn_utils.h", ] + if (is_win) { + brave_browser_brave_vpn_sources += [ + "//brave/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.cc", + "//brave/browser/brave_vpn/dns/brave_vpn_dns_observer_factory.h", + "//brave/browser/brave_vpn/dns/brave_vpn_dns_observer_service.cc", + "//brave/browser/brave_vpn/dns/brave_vpn_dns_observer_service.h", + ] + brave_browser_brave_vpn_deps += [ + "//brave/app:brave_generated_resources_grit", + "//brave/browser:browser_process", + "//chrome/common:constants", + "//net", + ] + } brave_browser_brave_vpn_deps += [ "//base", "//brave/components/brave_vpn", diff --git a/browser/ui/BUILD.gn b/browser/ui/BUILD.gn index 26d7e117b4a..4c377dc2b0b 100644 --- a/browser/ui/BUILD.gn +++ b/browser/ui/BUILD.gn @@ -291,7 +291,16 @@ source_set("ui") { "views/window_closing_confirm_dialog_view.cc", "views/window_closing_confirm_dialog_view.h", ] - + if (enable_brave_vpn) { + if (is_win) { + sources += [ + "views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.cc", + "views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.h", + "webui/settings/brave_settings_secure_dns_handler.cc", + "webui/settings/brave_settings_secure_dns_handler.h", + ] + } + } if (use_aura) { sources += [ "views/renderer_context_menu/brave_render_view_context_menu_views.cc", diff --git a/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.cc b/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.cc new file mode 100644 index 00000000000..6cc21a570ad --- /dev/null +++ b/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.cc @@ -0,0 +1,147 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.h" + +#include +#include + +#include "brave/components/brave_vpn/pref_names.h" +#include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/views/frame/browser_view.h" +#include "components/constrained_window/constrained_window_views.h" +#include "components/grit/brave_components_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/views/controls/button/checkbox.h" +#include "ui/views/controls/link.h" +#include "ui/views/controls/styled_label.h" +#include "ui/views/layout/box_layout.h" + +namespace brave_vpn { + +namespace { + +constexpr char kBraveVPNLearnMoreURL[] = + "https://support.brave.com/hc/en-us/articles/10864482160141"; + +constexpr int kChildSpacing = 16; +constexpr int kPadding = 24; +constexpr int kTopPadding = 32; +constexpr int kBottomPadding = 26; +constexpr int kDialogWidth = 400; + +} // namespace + +// static +void BraveVpnDnsSettingsNotificiationDialogView::Show(Browser* browser) { + auto* prefs = browser->profile()->GetPrefs(); + if (!prefs->GetBoolean(prefs::kBraveVPNShowNotificationDialog)) + return; + // The dialog eats mouse events which results in the close button + // getting stuck in the hover state. Reset the window controls to + // prevent this. + BrowserView::GetBrowserViewForBrowser(browser) + ->GetWidget() + ->non_client_view() + ->ResetWindowControls(); + + constrained_window::CreateBrowserModalDialogViews( + new BraveVpnDnsSettingsNotificiationDialogView(browser), + browser->window()->GetNativeWindow()) + ->Show(); +} + +BraveVpnDnsSettingsNotificiationDialogView:: + BraveVpnDnsSettingsNotificiationDialogView(Browser* browser) + : browser_(browser), prefs_(browser->profile()->GetPrefs()) { + SetLayoutManager(std::make_unique( + views::BoxLayout::Orientation::kVertical, + gfx::Insets::TLBR(kTopPadding, kPadding, kBottomPadding, kPadding), + kChildSpacing)); + SetButtons(ui::DIALOG_BUTTON_OK); + SetButtonLabel(ui::DIALOG_BUTTON_OK, + l10n_util::GetStringUTF16( + IDS_BRAVE_VPN_DNS_SETTINGS_NOTIFICATION_DIALOG_OK_TEXT)); + + RegisterWindowClosingCallback( + base::BindOnce(&BraveVpnDnsSettingsNotificiationDialogView::OnClosing, + base::Unretained(this))); + SetAcceptCallback( + base::BindOnce(&BraveVpnDnsSettingsNotificiationDialogView::OnAccept, + base::Unretained(this))); + auto* header_label = + AddChildView(std::make_unique(l10n_util::GetStringUTF16( + IDS_BRAVE_VPN_DNS_SETTINGS_NOTIFICATION_DIALOG_TITLE))); + header_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + + const std::u16string contents_text = l10n_util::GetStringUTF16( + IDS_BRAVE_VPN_DNS_SETTINGS_NOTIFICATION_DIALOG_TEXT); + + std::u16string learn_more_link_text = l10n_util::GetStringUTF16( + IDS_BRAVE_VPN_DNS_SETTINGS_NOTIFICATION_DIALOG_LEARN_MORE_TEXT); + std::u16string full_text = l10n_util::GetStringFUTF16( + IDS_BRAVE_VPN_DNS_SETTINGS_NOTIFICATION_DIALOG_TEXT, + learn_more_link_text); + const int main_message_length = + full_text.size() - learn_more_link_text.size(); + + auto* contents_label = AddChildView(std::make_unique()); + contents_label->SetTextContext(views::style::CONTEXT_DIALOG_BODY_TEXT); + views::StyledLabel::RangeStyleInfo message_style; + contents_label->SetText(full_text); + contents_label->AddStyleRange(gfx::Range(0, main_message_length), + message_style); + contents_label->SizeToFit(kDialogWidth); + + // Add "Learn more" link. + views::StyledLabel::RangeStyleInfo link_style = + views::StyledLabel::RangeStyleInfo::CreateForLink(base::BindRepeating( + &BraveVpnDnsSettingsNotificiationDialogView::OnLearnMoreLinkClicked, + base::Unretained(this))); + contents_label->AddStyleRange( + gfx::Range(main_message_length, full_text.size()), link_style); + contents_label->SetHorizontalAlignment(gfx::HorizontalAlignment::ALIGN_LEFT); + + dont_ask_again_checkbox_ = + AddChildView(std::make_unique(l10n_util::GetStringUTF16( + IDS_BRAVE_VPN_DNS_SETTINGS_NOTIFICATION_DIALOG_CHECKBOX_TEXT))); +} + +BraveVpnDnsSettingsNotificiationDialogView:: + ~BraveVpnDnsSettingsNotificiationDialogView() = default; + +void BraveVpnDnsSettingsNotificiationDialogView::OnLearnMoreLinkClicked() { + chrome::AddSelectedTabWithURL(browser_, GURL(kBraveVPNLearnMoreURL), + ui::PAGE_TRANSITION_AUTO_TOPLEVEL); + AcceptDialog(); +} + +ui::ModalType BraveVpnDnsSettingsNotificiationDialogView::GetModalType() const { + return ui::MODAL_TYPE_WINDOW; +} + +bool BraveVpnDnsSettingsNotificiationDialogView::ShouldShowCloseButton() const { + return false; +} + +bool BraveVpnDnsSettingsNotificiationDialogView::ShouldShowWindowTitle() const { + return false; +} + +void BraveVpnDnsSettingsNotificiationDialogView::OnAccept() { + close_window_ = true; +} + +void BraveVpnDnsSettingsNotificiationDialogView::OnClosing() { + prefs_->SetBoolean(prefs::kBraveVPNShowNotificationDialog, + !dont_ask_again_checkbox_->GetChecked()); +} + +BEGIN_METADATA(BraveVpnDnsSettingsNotificiationDialogView, + views::DialogDelegateView) +END_METADATA + +} // namespace brave_vpn diff --git a/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.h b/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.h new file mode 100644 index 00000000000..434c228d9be --- /dev/null +++ b/browser/ui/views/brave_vpn/brave_vpn_dns_settings_notificiation_dialog_view.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_UI_VIEWS_BRAVE_VPN_BRAVE_VPN_DNS_SETTINGS_NOTIFICIATION_DIALOG_VIEW_H_ +#define BRAVE_BROWSER_UI_VIEWS_BRAVE_VPN_BRAVE_VPN_DNS_SETTINGS_NOTIFICIATION_DIALOG_VIEW_H_ + +#include "ui/views/window/dialog_delegate.h" + +class Browser; +class PrefService; + +namespace views { +class Checkbox; +} + +namespace brave_vpn { + +class BraveVpnDnsSettingsNotificiationDialogView + : public views::DialogDelegateView { + public: + METADATA_HEADER(BraveVpnDnsSettingsNotificiationDialogView); + + static void Show(Browser* browser); + + BraveVpnDnsSettingsNotificiationDialogView( + const BraveVpnDnsSettingsNotificiationDialogView&) = delete; + BraveVpnDnsSettingsNotificiationDialogView& operator=( + const BraveVpnDnsSettingsNotificiationDialogView&) = delete; + + private: + explicit BraveVpnDnsSettingsNotificiationDialogView(Browser* browser); + ~BraveVpnDnsSettingsNotificiationDialogView() override; + + void OnAccept(); + void OnClosing(); + + void OnLearnMoreLinkClicked(); + + // views::DialogDelegate overrides: + ui::ModalType GetModalType() const override; + bool ShouldShowCloseButton() const override; + bool ShouldShowWindowTitle() const override; + + bool close_window_ = true; + raw_ptr browser_ = nullptr; + raw_ptr prefs_ = nullptr; + raw_ptr dont_ask_again_checkbox_ = nullptr; +}; + +} // namespace brave_vpn + +#endif // BRAVE_BROWSER_UI_VIEWS_BRAVE_VPN_BRAVE_VPN_DNS_SETTINGS_NOTIFICIATION_DIALOG_VIEW_H_ diff --git a/browser/ui/webui/settings/brave_settings_secure_dns_handler.cc b/browser/ui/webui/settings/brave_settings_secure_dns_handler.cc new file mode 100644 index 00000000000..3ea4c131e67 --- /dev/null +++ b/browser/ui/webui/settings/brave_settings_secure_dns_handler.cc @@ -0,0 +1,37 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/ui/webui/settings/brave_settings_secure_dns_handler.h" + +#include "base/feature_list.h" +#include "brave/components/brave_vpn/features.h" +#include "chrome/browser/browser_process.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" + +namespace settings { + +BraveSecureDnsHandler::BraveSecureDnsHandler() = default; +BraveSecureDnsHandler::~BraveSecureDnsHandler() = default; + +void BraveSecureDnsHandler::OnJavascriptAllowed() { + SecureDnsHandler::OnJavascriptAllowed(); + pref_registrar_.Init(g_browser_process->local_state()); + if (base::FeatureList::IsEnabled( + brave_vpn::features::kBraveVPNDnsProtection)) { + pref_registrar_.Add( + prefs::kBraveVpnDnsConfig, + base::BindRepeating( + &BraveSecureDnsHandler::SendSecureDnsSettingUpdatesToJavascript, + base::Unretained(this))); + } +} + +void BraveSecureDnsHandler::OnJavascriptDisallowed() { + SecureDnsHandler::OnJavascriptDisallowed(); + pref_registrar_.RemoveAll(); +} + +} // namespace settings diff --git a/browser/ui/webui/settings/brave_settings_secure_dns_handler.h b/browser/ui/webui/settings/brave_settings_secure_dns_handler.h new file mode 100644 index 00000000000..336c46b761b --- /dev/null +++ b/browser/ui/webui/settings/brave_settings_secure_dns_handler.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_SETTINGS_SECURE_DNS_HANDLER_H_ +#define BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_SETTINGS_SECURE_DNS_HANDLER_H_ + +#include "chrome/browser/ui/webui/settings/settings_secure_dns_handler.h" +#include "components/prefs/pref_change_registrar.h" + +namespace settings { + +class BraveSecureDnsHandler : public SecureDnsHandler { + public: + BraveSecureDnsHandler(); + ~BraveSecureDnsHandler() override; + + void OnJavascriptAllowed() override; + void OnJavascriptDisallowed() override; + + private: + PrefChangeRegistrar pref_registrar_; +}; + +} // namespace settings + +#endif // BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_SETTINGS_SECURE_DNS_HANDLER_H_ diff --git a/chromium_src/chrome/browser/net/stub_resolver_config_reader.cc b/chromium_src/chrome/browser/net/stub_resolver_config_reader.cc new file mode 100644 index 00000000000..aee961cad64 --- /dev/null +++ b/chromium_src/chrome/browser/net/stub_resolver_config_reader.cc @@ -0,0 +1,140 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "chrome/browser/net/stub_resolver_config_reader.h" +#include "base/feature_list.h" +#include "brave/components/brave_vpn/buildflags/buildflags.h" +#include "build/buildflag.h" +#include "chrome/browser/net/secure_dns_config.h" +#include "chrome/common/pref_names.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/network_service_instance.h" +#include "net/dns/public/dns_over_https_config.h" +#include "services/network/public/mojom/network_service.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +#if BUILDFLAG(ENABLE_BRAVE_VPN) +#include "brave/components/brave_vpn/features.h" +#endif + +#if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BRAVE_VPN) +namespace { + +bool IsBraveVPNConnected(PrefService* local_state) { + if (!base::FeatureList::IsEnabled( + brave_vpn::features::kBraveVPNDnsProtection)) { + return false; + } + return !local_state->GetString(prefs::kBraveVpnDnsConfig).empty(); +} + +bool ShouldOverride(net::SecureDnsMode secure_dns_mode, + PrefService* local_state, + SecureDnsConfig::ManagementMode management_mode, + bool is_managed) { + if (!IsBraveVPNConnected(local_state)) + return false; + if (secure_dns_mode == net::SecureDnsMode::kSecure) + return false; + if (management_mode != SecureDnsConfig::ManagementMode::kNoOverride || + is_managed) { + // there is already a managed policy or parental control in place + return false; + } + + return true; +} + +bool MaybeOverrideDnsClientEnabled( + net::SecureDnsMode secure_dns_mode, + bool insecure_dns_client_enabled, + PrefService* local_state, + SecureDnsConfig::ManagementMode management_mode, + bool is_managed) { + if (ShouldOverride(secure_dns_mode, local_state, management_mode, + is_managed)) { + // disable the insecure client for doh + return false; + } + + return insecure_dns_client_enabled; +} + +net::SecureDnsMode MaybeOverrideDnsMode( + net::SecureDnsMode secure_dns_mode, + PrefService* local_state, + SecureDnsConfig::ManagementMode management_mode, + bool is_managed) { + if (ShouldOverride(secure_dns_mode, local_state, management_mode, + is_managed)) { + return net::SecureDnsMode::kSecure; + } + return secure_dns_mode; +} + +net::DnsOverHttpsConfig MaybeOverrideDnsConfig( + net::SecureDnsMode secure_dns_mode, + net::DnsOverHttpsConfig doh_config, + PrefService* local_state, + SecureDnsConfig::ManagementMode management_mode, + bool is_managed) { + if (ShouldOverride(secure_dns_mode, local_state, management_mode, + is_managed)) { + return net::DnsOverHttpsConfig::FromStringLax( + local_state->GetString(prefs::kBraveVpnDnsConfig)); + } + return doh_config; +} + +SecureDnsConfig::ManagementMode MaybeOverrideForcedManagementMode( + net::SecureDnsMode secure_dns_mode, + PrefService* local_state, + SecureDnsConfig::ManagementMode management_mode, + bool is_managed) { + // Don't change management mode if the doh settings are + // managed by policy or by parental controls + if (is_managed || + management_mode != SecureDnsConfig::ManagementMode::kNoOverride) + return management_mode; + + // Otherwise always block changes to the doh config while the VPN + // is connected + if (IsBraveVPNConnected(local_state)) + return SecureDnsConfig::ManagementMode::kDisabledManaged; + + return management_mode; +} + +} // namespace + +#define SecureDnsConfig(SECURE_DNS_MODE, SECURE_DOH_CONFIG, \ + FORCED_MANAGEMENT_MODE) \ + SecureDnsConfig( \ + MaybeOverrideDnsMode(SECURE_DNS_MODE, local_state_, \ + FORCED_MANAGEMENT_MODE, is_managed), \ + MaybeOverrideDnsConfig(SECURE_DNS_MODE, SECURE_DOH_CONFIG, local_state_, \ + FORCED_MANAGEMENT_MODE, is_managed), \ + MaybeOverrideForcedManagementMode(SECURE_DNS_MODE, local_state_, \ + FORCED_MANAGEMENT_MODE, is_managed)) + +#define ConfigureStubHostResolver(INSECURE_DNS_CLIENT_ENABLED, \ + SECURE_DNS_MODE, DNS_OVER_HTTPS_CONFIG, \ + ADDITIONAL_DNS_TYPES_ENABLED) \ + ConfigureStubHostResolver( \ + MaybeOverrideDnsClientEnabled(SECURE_DNS_MODE, \ + INSECURE_DNS_CLIENT_ENABLED, local_state_, \ + forced_management_mode, is_managed), \ + MaybeOverrideDnsMode(SECURE_DNS_MODE, local_state_, \ + forced_management_mode, is_managed), \ + MaybeOverrideDnsConfig(SECURE_DNS_MODE, DNS_OVER_HTTPS_CONFIG, \ + local_state_, forced_management_mode, \ + is_managed), \ + ADDITIONAL_DNS_TYPES_ENABLED) +#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BRAVE_VPN) +#include "src/chrome/browser/net/stub_resolver_config_reader.cc" +#if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BRAVE_VPN) +#undef ConfigureStubHostResolver +#undef SecureDnsConfig +#endif // BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BRAVE_VPN) diff --git a/chromium_src/chrome/browser/ui/webui/settings/settings_ui.cc b/chromium_src/chrome/browser/ui/webui/settings/settings_ui.cc index 604faa62f36..342bb12574a 100644 --- a/chromium_src/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chromium_src/chrome/browser/ui/webui/settings/settings_ui.cc @@ -6,8 +6,15 @@ #include "brave/browser/ui/webui/settings/brave_import_data_handler.h" #include "brave/browser/ui/webui/settings/brave_search_engines_handler.h" #include "brave/browser/ui/webui/settings/brave_site_settings_handler.h" +#include "brave/components/brave_vpn/buildflags/buildflags.h" +#include "chrome/browser/ui/webui/settings/settings_secure_dns_handler.h" #include "chrome/browser/ui/webui/settings/site_settings_handler.h" +#if BUILDFLAG(IS_WIN) && BUILDFLAG(ENABLE_BRAVE_VPN) +#include "brave/browser/ui/webui/settings/brave_settings_secure_dns_handler.h" + +#define SecureDnsHandler BraveSecureDnsHandler +#endif #define SiteSettingsHandler BraveSiteSettingsHandler #define ImportDataHandler BraveImportDataHandler #define SearchEnginesHandler BraveSearchEnginesHandler diff --git a/chromium_src/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chromium_src/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc index 67a698e8db7..1f6118e156a 100644 --- a/chromium_src/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc +++ b/chromium_src/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc @@ -3,7 +3,40 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "brave/components/brave_vpn/buildflags/buildflags.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/net/secure_dns_config.h" +#include "chrome/browser/net/stub_resolver_config_reader.h" +#include "chrome/browser/net/system_network_context_manager.h" +#include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" +#include "components/grit/brave_components_strings.h" +#include "components/prefs/pref_service.h" +#include "net/dns/public/secure_dns_mode.h" + +#if BUILDFLAG(ENABLE_BRAVE_VPN) && BUILDFLAG(IS_WIN) +#include "brave/components/brave_vpn/features.h" + +namespace { + +bool ShouldReplaceSecureDNSDisabledDescription() { + if (!base::FeatureList::IsEnabled( + brave_vpn::features::kBraveVPNDnsProtection)) + return false; + auto dns_config = SystemNetworkContextManager::GetStubResolverConfigReader() + ->GetSecureDnsConfiguration(false); + return !g_browser_process->local_state() + ->GetString(prefs::kBraveVpnDnsConfig) + .empty() || + dns_config.mode() == net::SecureDnsMode::kSecure; +} + +} // namespace + +#define AddSecureDnsStrings AddSecureDnsStrings_ChromiumImpl + +#endif // BUILDFLAG(ENABLE_BRAVE_VPN) && BUILDFLAG(IS_WIN) // Use custom strings for diagnostic (crashes, hangs) reporting settings. #undef IDS_SETTINGS_ENABLE_LOGGING_PREF @@ -13,3 +46,22 @@ IDS_BRAVE_DIAGNOSTIC_REPORTS_PREF_DESC #include "src/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc" + +#if BUILDFLAG(ENABLE_BRAVE_VPN) && BUILDFLAG(IS_WIN) +#undef AddSecureDnsStrings +namespace settings { + +void AddSecureDnsStrings(content::WebUIDataSource* html_source) { + AddSecureDnsStrings_ChromiumImpl(html_source); + if (!ShouldReplaceSecureDNSDisabledDescription()) + return; + static constexpr webui::LocalizedString kLocalizedStrings[] = { + {"secureDnsDisabledForManagedEnvironment", + IDS_SETTINGS_SECURE_DNS_DISABLED_BY_BRAVE_VPN}}; + + html_source->AddLocalizedStrings(kLocalizedStrings); +} + +} // namespace settings + +#endif // BUILDFLAG(ENABLE_BRAVE_VPN) && BUILDFLAG(IS_WIN) diff --git a/chromium_src/chrome/common/pref_names.cc b/chromium_src/chrome/common/pref_names.cc new file mode 100644 index 00000000000..8a141230223 --- /dev/null +++ b/chromium_src/chrome/common/pref_names.cc @@ -0,0 +1,12 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "chrome/common/pref_names.h" + +namespace prefs { +const char kBraveVpnDnsConfig[] = "brave.brave_vpn.dns_config"; +} // namespace prefs + +#include "src/chrome/common/pref_names.cc" diff --git a/chromium_src/chrome/common/pref_names.h b/chromium_src/chrome/common/pref_names.h new file mode 100644 index 00000000000..3e48f94d1d3 --- /dev/null +++ b/chromium_src/chrome/common/pref_names.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2022 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_CHROMIUM_SRC_CHROME_COMMON_PREF_NAMES_H_ +#define BRAVE_CHROMIUM_SRC_CHROME_COMMON_PREF_NAMES_H_ + +#include "build/build_config.h" + +namespace prefs { +// Used by BraveVpnDnsObserverService to set cloudflare server url when +// BraveVPN is connected, otherwise this pref is empty. Final decision +// about whether or not to override actual DNS state will be made in +// stub_resolver_config_reader. +extern const char kBraveVpnDnsConfig[]; +} // namespace prefs + +#include "src/chrome/common/pref_names.h" + +#endif // BRAVE_CHROMIUM_SRC_CHROME_COMMON_PREF_NAMES_H_ diff --git a/components/brave_vpn/brave_vpn_utils.cc b/components/brave_vpn/brave_vpn_utils.cc index 49c2ca72ad8..116010d78da 100644 --- a/components/brave_vpn/brave_vpn_utils.cc +++ b/components/brave_vpn/brave_vpn_utils.cc @@ -25,14 +25,11 @@ namespace brave_vpn { namespace { - void RegisterVPNLocalStatePrefs(PrefRegistrySimple* registry) { #if !BUILDFLAG(IS_ANDROID) registry->RegisterListPref(prefs::kBraveVPNRegionList); registry->RegisterStringPref(prefs::kBraveVPNDeviceRegion, ""); registry->RegisterStringPref(prefs::kBraveVPNSelectedRegion, ""); - registry->RegisterBooleanPref(prefs::kBraveVPNShowDNSPolicyWarningDialog, - true); #endif registry->RegisterStringPref(prefs::kBraveVPNEnvironment, skus::GetDefaultEnvironment()); @@ -101,6 +98,9 @@ std::string GetManageUrl(const std::string& env) { void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { registry->RegisterDictionaryPref(prefs::kBraveVPNRootPref); registry->RegisterBooleanPref(prefs::kBraveVPNShowButton, true); +#if BUILDFLAG(IS_WIN) + registry->RegisterBooleanPref(prefs::kBraveVPNShowNotificationDialog, true); +#endif #if BUILDFLAG(IS_ANDROID) registry->RegisterStringPref(prefs::kBraveVPNPurchaseTokenAndroid, ""); registry->RegisterStringPref(prefs::kBraveVPNPackageAndroid, ""); diff --git a/components/brave_vpn/features.cc b/components/brave_vpn/features.cc index 93b31579ea2..7e24cccaaf5 100644 --- a/components/brave_vpn/features.cc +++ b/components/brave_vpn/features.cc @@ -25,6 +25,11 @@ BASE_FEATURE(kBraveVPNLinkSubscriptionAndroidUI, "BraveVPNLinkSubscriptionAndroidUI", base::FEATURE_DISABLED_BY_DEFAULT); +#if BUILDFLAG(IS_WIN) +BASE_FEATURE(kBraveVPNDnsProtection, + "BraveVPNDnsProtection", + base::FEATURE_ENABLED_BY_DEFAULT); +#endif } // namespace features } // namespace brave_vpn diff --git a/components/brave_vpn/features.h b/components/brave_vpn/features.h index 50aa93ddb38..ae807ce9d89 100644 --- a/components/brave_vpn/features.h +++ b/components/brave_vpn/features.h @@ -7,13 +7,16 @@ #define BRAVE_COMPONENTS_BRAVE_VPN_FEATURES_H_ #include "base/feature_list.h" +#include "build/build_config.h" namespace brave_vpn { namespace features { BASE_DECLARE_FEATURE(kBraveVPN); BASE_DECLARE_FEATURE(kBraveVPNLinkSubscriptionAndroidUI); - +#if BUILDFLAG(IS_WIN) +BASE_DECLARE_FEATURE(kBraveVPNDnsProtection); +#endif } // namespace features } // namespace brave_vpn diff --git a/components/brave_vpn/pref_names.h b/components/brave_vpn/pref_names.h index 39bf2c15a9e..d66ba61cc42 100644 --- a/components/brave_vpn/pref_names.h +++ b/components/brave_vpn/pref_names.h @@ -18,8 +18,12 @@ constexpr char kBraveVPNRegionList[] = "brave.brave_vpn.region_list"; constexpr char kBraveVPNDeviceRegion[] = "brave.brave_vpn.device_region_name"; constexpr char kBraveVPNSelectedRegion[] = "brave.brave_vpn.selected_region_name"; -constexpr char kBraveVPNShowDNSPolicyWarningDialog[] = +#if BUILDFLAG(IS_WIN) +constexpr char kBraveVpnShowDNSPolicyWarningDialog[] = "brave.brave_vpn.show_dns_policy_warning_dialog"; +constexpr char kBraveVPNShowNotificationDialog[] = + "brave.brave_vpn.show_notification_dialog"; +#endif // BUILDFLAG(IS_WIN) constexpr char kBraveVPNEnvironment[] = "brave.brave_vpn.env"; // Dict that has subscriber credential its expiration date. constexpr char kBraveVPNSubscriberCredential[] = @@ -36,7 +40,6 @@ constexpr char kBraveVPNLastUseTime[] = "brave.brave_vpn.last_use_time"; constexpr char kBraveVPNUsedSecondDay[] = "brave.brave_vpn.used_second_day"; constexpr char kBraveVPNDaysInMonthUsed[] = "brave.brave_vpn.days_in_month_used"; - } // namespace prefs } // namespace brave_vpn diff --git a/components/resources/brave_vpn_strings.grdp b/components/resources/brave_vpn_strings.grdp index 628e321f1e5..f67d63e8002 100644 --- a/components/resources/brave_vpn_strings.grdp +++ b/components/resources/brave_vpn_strings.grdp @@ -219,7 +219,29 @@ Secure DNS is disabled by your organization's policies. Using Brave VPN without Secure DNS may reveal the names of the sites you visit to your Internet service provider or organization. + + + Brave VPN on Windows + + + + Learn more. + + + The setting is locked by BraveVPN while it is connected + + + + Windows has a feature called Smart Multi-Homed Name Resolution, which can expose information about your location and the sites you visit. Now that you’ve enabled Brave VPN, we’ve changed the DNS settings in the browser to protect against this exposure. The settings will remain in effect and locked while VPN is connected. $1Learn more. + + + + Do not warn me about this anymore. + + + Ok + Do not warn me about this anymore. diff --git a/test/BUILD.gn b/test/BUILD.gn index 6637583705e..e19ee8dac91 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -166,6 +166,7 @@ test("brave_unit_tests") { "//brave/browser", "//brave/browser:unit_tests", "//brave/browser/brave_rewards/rewards_panel:unit_tests", + "//brave/browser/brave_vpn/dns:unit_tests", "//brave/browser/brave_wallet", "//brave/browser/brave_wallet:unit_tests", "//brave/browser/content_settings:unit_tests",