diff --git a/browser/brave_content_browser_client.cc b/browser/brave_content_browser_client.cc index 5d92e0a9558f..af81c926ca25 100644 --- a/browser/brave_content_browser_client.cc +++ b/browser/brave_content_browser_client.cc @@ -17,7 +17,6 @@ #include "brave/browser/brave_browser_main_extra_parts.h" #include "brave/browser/brave_browser_process.h" #include "brave/browser/brave_shields/brave_shields_web_contents_observer.h" -#include "brave/browser/brave_shields/reduce_language_navigation_throttle.h" #include "brave/browser/brave_wallet/brave_wallet_context_utils.h" #include "brave/browser/brave_wallet/brave_wallet_provider_delegate_impl.h" #include "brave/browser/brave_wallet/brave_wallet_service_factory.h" @@ -973,13 +972,6 @@ BraveContentBrowserClient::CreateThrottlesForNavigation( g_browser_process->GetApplicationLocale())) throttles.push_back(std::move(domain_block_navigation_throttle)); - if (std::unique_ptr - reduce_language_navigation_throttle = brave_shields:: - ReduceLanguageNavigationThrottle::MaybeCreateThrottleFor( - handle, HostContentSettingsMapFactory::GetForProfile( - Profile::FromBrowserContext(context)))) - throttles.push_back(std::move(reduce_language_navigation_throttle)); - // Debounce if (auto debounce_throttle = debounce::DebounceNavigationThrottle::MaybeCreateThrottleFor( diff --git a/browser/brave_shields/reduce_language_navigation_throttle.cc b/browser/brave_shields/reduce_language_navigation_throttle.cc deleted file mode 100644 index 1d21094a9d6e..000000000000 --- a/browser/brave_shields/reduce_language_navigation_throttle.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* 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 http://mozilla.org/MPL/2.0/. */ - -#include "brave/browser/brave_shields/reduce_language_navigation_throttle.h" - -#include -#include - -#include "base/feature_list.h" -#include "base/threading/thread_task_runner_handle.h" -#include "brave/browser/brave_browser_process.h" -#include "brave/components/brave_shields/browser/brave_farbling_service.h" -#include "brave/components/brave_shields/browser/brave_shields_util.h" -#include "brave/components/brave_shields/common/features.h" -#include "chrome/browser/profiles/profile.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" -#include "components/language/core/browser/language_prefs.h" -#include "components/language/core/browser/pref_names.h" -#include "components/prefs/pref_service.h" -#include "components/user_prefs/user_prefs.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/browser/navigation_handle.h" -#include "content/public/browser/web_contents.h" -#include "net/http/http_request_headers.h" -#include "net/http/http_util.h" - -namespace brave_shields { - -// static -std::unique_ptr -ReduceLanguageNavigationThrottle::MaybeCreateThrottleFor( - content::NavigationHandle* navigation_handle, - HostContentSettingsMap* content_settings) { - content::BrowserContext* context = - navigation_handle->GetWebContents()->GetBrowserContext(); - PrefService* pref_service = user_prefs::UserPrefs::Get(context); - if (!IsReduceLanguageEnabledForProfile(pref_service)) - return nullptr; - return std::make_unique(navigation_handle, - content_settings); -} - -ReduceLanguageNavigationThrottle::ReduceLanguageNavigationThrottle( - content::NavigationHandle* navigation_handle, - HostContentSettingsMap* content_settings) - : content::NavigationThrottle(navigation_handle), - content_settings_(content_settings) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); -} - -ReduceLanguageNavigationThrottle::~ReduceLanguageNavigationThrottle() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); -} - -content::NavigationThrottle::ThrottleCheckResult -ReduceLanguageNavigationThrottle::WillStartRequest() { - UpdateHeaders(); - return content::NavigationThrottle::PROCEED; -} - -content::NavigationThrottle::ThrottleCheckResult -ReduceLanguageNavigationThrottle::WillRedirectRequest() { - UpdateHeaders(); - return content::NavigationThrottle::PROCEED; -} - -void ReduceLanguageNavigationThrottle::UpdateHeaders() { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - content::NavigationHandle* handle = navigation_handle(); - GURL url = handle->GetURL(); - content::BrowserContext* context = - handle->GetWebContents()->GetBrowserContext(); - PrefService* pref_service = user_prefs::UserPrefs::Get(context); - - if (!brave_shields::ShouldDoReduceLanguage(content_settings_, url, - pref_service)) - return; - - ControlType fingerprinting_control_type = - brave_shields::GetFingerprintingControlType(content_settings_, url); - - // If fingerprint blocking is maximum, set Accept-Language header to - // static value regardless of other preferences. - if (fingerprinting_control_type == ControlType::BLOCK) { - handle->SetRequestHeader(net::HttpRequestHeaders::kAcceptLanguage, - "en-US,en;q=0.9"); - return; - } - - // If fingerprint blocking is default, compute Accept-Language header - // based on user preferences. - std::string languages = - pref_service->Get(language::prefs::kAcceptLanguages)->GetString(); - std::string first_language = language::GetFirstLanguage(languages); - // Add a fake q value after the language code. - std::vector q_values = {";q=0.5", ";q=0.6", ";q=0.7", ";q=0.8", - ";q=0.9"}; - brave::FarblingPRNG prng; - auto* profile = Profile::FromBrowserContext(context); - if (g_brave_browser_process->brave_farbling_service() - ->MakePseudoRandomGeneratorForURL( - url, profile && !profile->IsOffTheRecord(), &prng)) { - first_language += q_values[prng() % q_values.size()]; - } - handle->SetRequestHeader(net::HttpRequestHeaders::kAcceptLanguage, - first_language); -} - -const char* ReduceLanguageNavigationThrottle::GetNameForLogging() { - return "ReduceLanguageNavigationThrottle"; -} - -} // namespace brave_shields diff --git a/browser/brave_shields/reduce_language_navigation_throttle.h b/browser/brave_shields/reduce_language_navigation_throttle.h deleted file mode 100644 index 29ad25737271..000000000000 --- a/browser/brave_shields/reduce_language_navigation_throttle.h +++ /dev/null @@ -1,60 +0,0 @@ -/* 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 http://mozilla.org/MPL/2.0/. */ - -#ifndef BRAVE_BROWSER_BRAVE_SHIELDS_REDUCE_LANGUAGE_NAVIGATION_THROTTLE_H_ -#define BRAVE_BROWSER_BRAVE_SHIELDS_REDUCE_LANGUAGE_NAVIGATION_THROTTLE_H_ - -#include -#include -#include - -#include "base/memory/weak_ptr.h" -#include "brave/components/brave_shields/browser/brave_shields_util.h" -#include "content/public/browser/navigation_throttle.h" -#include "url/gurl.h" - -class HostContentSettingsMap; - -namespace content { -class NavigationHandle; -class WebContents; -} // namespace content - -namespace brave_shields { - -class ReduceLanguageNavigationThrottle : public content::NavigationThrottle { - public: - explicit ReduceLanguageNavigationThrottle( - content::NavigationHandle* navigation_handle, - HostContentSettingsMap* content_settings); - ~ReduceLanguageNavigationThrottle() override; - - ReduceLanguageNavigationThrottle(const ReduceLanguageNavigationThrottle&) = - delete; - ReduceLanguageNavigationThrottle& operator=( - const ReduceLanguageNavigationThrottle&) = delete; - - static std::unique_ptr - MaybeCreateThrottleFor(content::NavigationHandle* navigation_handle, - HostContentSettingsMap* content_settings); - - // content::NavigationThrottle implementation: - content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override; - content::NavigationThrottle::ThrottleCheckResult WillRedirectRequest() - override; - const char* GetNameForLogging() override; - - private: - HostContentSettingsMap* content_settings_ = nullptr; - - void UpdateHeaders(); - - base::WeakPtrFactory weak_ptr_factory_{ - this}; -}; - -} // namespace brave_shields - -#endif // BRAVE_BROWSER_BRAVE_SHIELDS_REDUCE_LANGUAGE_NAVIGATION_THROTTLE_H_ diff --git a/browser/brave_shields/sources.gni b/browser/brave_shields/sources.gni index fd65a1b5205e..d8e68aea1173 100644 --- a/browser/brave_shields/sources.gni +++ b/browser/brave_shields/sources.gni @@ -12,8 +12,6 @@ brave_browser_brave_shields_sources = [ "//brave/browser/brave_shields/brave_shields_web_contents_observer.h", "//brave/browser/brave_shields/https_everywhere_component_installer.cc", "//brave/browser/brave_shields/https_everywhere_component_installer.h", - "//brave/browser/brave_shields/reduce_language_navigation_throttle.cc", - "//brave/browser/brave_shields/reduce_language_navigation_throttle.h", ] brave_browser_brave_shields_deps = [ diff --git a/browser/farbling/brave_navigator_languages_farbling_browsertest.cc b/browser/farbling/brave_navigator_languages_farbling_browsertest.cc index c3741dfb4a9b..f3c839e245c3 100644 --- a/browser/farbling/brave_navigator_languages_farbling_browsertest.cc +++ b/browser/farbling/brave_navigator_languages_farbling_browsertest.cc @@ -131,7 +131,7 @@ class BraveNavigatorLanguagesFarblingBrowserTest : public InProcessBrowserTest { } void MonitorHTTPRequest(const net::test_server::HttpRequest& request) { - if (request.relative_url != "/simple.html") + if (request.relative_url.find("/reduce-language/") == std::string::npos) return; if (expected_http_accept_language_.empty()) return; @@ -232,13 +232,15 @@ IN_PROC_BROWSER_TEST_F(BraveNavigatorLanguagesFarblingBrowserTest, EXPECT_EQ(expected_title, watcher2.WaitAndGetTitle()); } -// Tests results of farbling user agent +// Tests results of farbling HTTP Accept-Language header IN_PROC_BROWSER_TEST_F(BraveNavigatorLanguagesFarblingBrowserTest, FarbleHTTPAcceptLanguage) { std::string domain_b = "b.test"; std::string domain_d = "d.test"; - GURL url_b = https_server_.GetURL(domain_b, "/simple.html"); - GURL url_d = https_server_.GetURL(domain_d, "/simple.html"); + GURL url_b = https_server_.GetURL( + domain_b, "/reduce-language/page-with-subresources.html"); + GURL url_d = https_server_.GetURL( + domain_d, "/reduce-language/page-with-subresources.html"); SetAcceptLanguages("la,es,en"); // Farbling level: off @@ -265,4 +267,32 @@ IN_PROC_BROWSER_TEST_F(BraveNavigatorLanguagesFarblingBrowserTest, NavigateToURLUntilLoadStop(url_b); BlockFingerprinting(domain_d); NavigateToURLUntilLoadStop(url_d); + + // Test with subdivided language code as the primary language. + SetAcceptLanguages("zh-HK,zh,la"); + + // Farbling level: off + // HTTP Accept-Language header should not be farbled. + AllowFingerprinting(domain_b); + SetExpectedHTTPAcceptLanguage("zh-HK,zh;q=0.9,la;q=0.8"); + NavigateToURLUntilLoadStop(url_b); + AllowFingerprinting(domain_d); + NavigateToURLUntilLoadStop(url_d); + + // Farbling level: default + // HTTP Accept-Language header should be farbled by domain. + SetFingerprintingDefault(domain_b); + SetExpectedHTTPAcceptLanguage("zh-HK,zh;q=0.7"); + NavigateToURLUntilLoadStop(url_b); + SetExpectedHTTPAcceptLanguage("zh-HK,zh;q=0.8"); + SetFingerprintingDefault(domain_d); + NavigateToURLUntilLoadStop(url_d); + + // Farbling level: maximum + // HTTP Accept-Language header should be farbled but the same across domains. + BlockFingerprinting(domain_b); + SetExpectedHTTPAcceptLanguage("en-US,en;q=0.9"); + NavigateToURLUntilLoadStop(url_b); + BlockFingerprinting(domain_d); + NavigateToURLUntilLoadStop(url_d); } diff --git a/browser/net/BUILD.gn b/browser/net/BUILD.gn index 1e5c55f12c8f..00e5d28b7e63 100644 --- a/browser/net/BUILD.gn +++ b/browser/net/BUILD.gn @@ -35,6 +35,8 @@ source_set("net") { "brave_proxying_url_loader_factory.h", "brave_proxying_web_socket.cc", "brave_proxying_web_socket.h", + "brave_reduce_language_network_delegate_helper.cc", + "brave_reduce_language_network_delegate_helper.h", "brave_request_handler.cc", "brave_request_handler.h", "brave_service_key_network_delegate_helper.cc", diff --git a/browser/net/brave_reduce_language_network_delegate_helper.cc b/browser/net/brave_reduce_language_network_delegate_helper.cc new file mode 100644 index 000000000000..468a831703d8 --- /dev/null +++ b/browser/net/brave_reduce_language_network_delegate_helper.cc @@ -0,0 +1,102 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +#include "brave/browser/net/brave_reduce_language_network_delegate_helper.h" + +#include +#include +#include + +#include "base/strings/string_split.h" +#include "brave/browser/brave_browser_process.h" +#include "brave/components/brave_shields/browser/brave_farbling_service.h" +#include "brave/components/brave_shields/browser/brave_shields_util.h" +#include "chrome/browser/content_settings/host_content_settings_map_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/language/core/browser/language_prefs.h" +#include "components/language/core/browser/pref_names.h" +#include "components/prefs/pref_service.h" +#include "content/public/browser/browser_context.h" +#include "net/base/net_errors.h" + +using brave_shields::ControlType; + +namespace brave { + +namespace { +constexpr char kAcceptLanguageMax[] = "en-US,en;q=0.9"; +const std::array kFakeQValues = {";q=0.5", ";q=0.6", ";q=0.7", + ";q=0.8", ";q=0.9"}; +} // namespace + +std::string FarbleAcceptLanguageHeader( + const GURL& tab_origin, + Profile* profile, + HostContentSettingsMap* content_settings) { + std::string languages = + profile->GetPrefs()->Get(language::prefs::kAcceptLanguages)->GetString(); + std::string accept_language_string = language::GetFirstLanguage(languages); + // If the first language is a multi-part code like "en-US" or "zh-HK", + // extract and append the base language code to |accept_language_string|. + const std::vector tokens = base::SplitString( + accept_language_string, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); + if (!tokens.empty() && tokens[0] != accept_language_string) { + accept_language_string += "," + tokens[0]; + } + // Add a fake q value after the language code. + brave::FarblingPRNG prng; + if (g_brave_browser_process->brave_farbling_service() + ->MakePseudoRandomGeneratorForURL( + tab_origin, profile && profile->IsOffTheRecord(), &prng)) { + accept_language_string += kFakeQValues[prng() % kFakeQValues.size()]; + } + return accept_language_string; +} + +int OnBeforeStartTransaction_ReduceLanguageWork( + net::HttpRequestHeaders* headers, + const ResponseCallback& next_callback, + std::shared_ptr ctx) { + Profile* profile = Profile::FromBrowserContext(ctx->browser_context); + DCHECK(profile); + HostContentSettingsMap* content_settings = + HostContentSettingsMapFactory::GetForProfile(profile); + DCHECK(content_settings); + if (!brave_shields::ShouldDoReduceLanguage(content_settings, ctx->tab_origin, + profile->GetPrefs())) { + return net::OK; + } + + std::string accept_language_string; + switch (brave_shields::GetFingerprintingControlType(content_settings, + ctx->tab_origin)) { + case ControlType::BLOCK: { + // If fingerprint blocking is maximum, set Accept-Language header to + // static value regardless of other preferences. + accept_language_string = kAcceptLanguageMax; + break; + } + case ControlType::DEFAULT: { + // If fingerprint blocking is default, compute Accept-Language header + // based on user preferences and some randomization. + accept_language_string = FarbleAcceptLanguageHeader( + ctx->tab_origin, profile, content_settings); + break; + } + default: + // Other cases are handled within ShouldDoReduceLanguage, so we should + // never reach here. + NOTREACHED(); + } + + headers->SetHeader(net::HttpRequestHeaders::kAcceptLanguage, + accept_language_string); + ctx->set_headers.insert(net::HttpRequestHeaders::kAcceptLanguage); + + return net::OK; +} + +} // namespace brave diff --git a/browser/net/brave_reduce_language_network_delegate_helper.h b/browser/net/brave_reduce_language_network_delegate_helper.h new file mode 100644 index 000000000000..c4fc3ff38382 --- /dev/null +++ b/browser/net/brave_reduce_language_network_delegate_helper.h @@ -0,0 +1,39 @@ +/* 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 http://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_BROWSER_NET_BRAVE_REDUCE_LANGUAGE_NETWORK_DELEGATE_HELPER_H_ +#define BRAVE_BROWSER_NET_BRAVE_REDUCE_LANGUAGE_NETWORK_DELEGATE_HELPER_H_ + +#include +#include + +#include "brave/browser/net/url_context.h" +#include "url/gurl.h" + +class HostContentSettingsMap; +class PrefService; +class Profile; +struct BraveRequestInfo; + +namespace net { +class HttpRequestHeaders; +class URLRequest; +} // namespace net + +namespace brave { + +std::string FarbleAcceptLanguageHeader( + const GURL& tab_origin, + Profile* profile, + HostContentSettingsMap* content_settings); + +int OnBeforeStartTransaction_ReduceLanguageWork( + net::HttpRequestHeaders* headers, + const ResponseCallback& next_callback, + std::shared_ptr ctx); + +} // namespace brave + +#endif // BRAVE_BROWSER_NET_BRAVE_REDUCE_LANGUAGE_NETWORK_DELEGATE_HELPER_H_ diff --git a/browser/net/brave_request_handler.cc b/browser/net/brave_request_handler.cc index de4714047535..5cb68e931044 100644 --- a/browser/net/brave_request_handler.cc +++ b/browser/net/brave_request_handler.cc @@ -14,6 +14,7 @@ #include "brave/browser/net/brave_ad_block_tp_network_delegate_helper.h" #include "brave/browser/net/brave_common_static_redirect_network_delegate_helper.h" #include "brave/browser/net/brave_httpse_network_delegate_helper.h" +#include "brave/browser/net/brave_reduce_language_network_delegate_helper.h" #include "brave/browser/net/brave_service_key_network_delegate_helper.h" #include "brave/browser/net/brave_site_hacks_network_delegate_helper.h" #include "brave/browser/net/brave_stp_util.h" @@ -112,6 +113,13 @@ void BraveRequestHandler::SetupCallbacks() { before_start_transaction_callbacks_.push_back(start_transaction_callback); #endif + if (base::FeatureList::IsEnabled( + brave_shields::features::kBraveReduceLanguage)) { + start_transaction_callback = + base::BindRepeating(brave::OnBeforeStartTransaction_ReduceLanguageWork); + before_start_transaction_callbacks_.push_back(start_transaction_callback); + } + #if BUILDFLAG(ENABLE_BRAVE_WEBTORRENT) brave::OnHeadersReceivedCallback headers_received_callback = base::BindRepeating(webtorrent::OnHeadersReceived_TorrentRedirectWork); diff --git a/test/data/reduce-language/image.png b/test/data/reduce-language/image.png new file mode 100644 index 000000000000..44ddb41fe95a Binary files /dev/null and b/test/data/reduce-language/image.png differ diff --git a/test/data/reduce-language/page-with-subresources.html b/test/data/reduce-language/page-with-subresources.html new file mode 100644 index 000000000000..d613e67553de --- /dev/null +++ b/test/data/reduce-language/page-with-subresources.html @@ -0,0 +1,11 @@ + + + + OK + +