Add enterprise escape hatch for updated GREASE

This change will likely be removed once the new algorithm is
confirmed to be safe.

Bug: 1261908
Change-Id: Idb1ffafe0730b6460a8328ce61c70166569d20d8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251184
Commit-Queue: Matt Reichhoff <[email protected]>
Reviewed-by: Josh Horwich <[email protected]>
Reviewed-by: Colin Blundell <[email protected]>
Reviewed-by: Robbie McElrath <[email protected]>
Reviewed-by: Julian Pastarmov <[email protected]>
Cr-Commit-Position: refs/heads/main@{#937500}
diff --git a/chrome/browser/ash/arc/arc_util.cc b/chrome/browser/ash/arc/arc_util.cc
index d61d41ebd..082acd41 100644
--- a/chrome/browser/ash/arc/arc_util.cc
+++ b/chrome/browser/ash/arc/arc_util.cc
@@ -643,7 +643,8 @@
   ua_override.ua_string_override = content::BuildUserAgentFromOSAndProduct(
       kOsOverrideForTabletSite, product);
 
-  ua_override.ua_metadata_override = embedder_support::GetUserAgentMetadata();
+  ua_override.ua_metadata_override =
+      embedder_support::GetUserAgentMetadata(g_browser_process->local_state());
   ua_override.ua_metadata_override->platform = "Android";
   ua_override.ua_metadata_override->platform_version = "9";
   ua_override.ua_metadata_override->model = "Chrome tablet";
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index fe390f8..a6920f0 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -5799,7 +5799,8 @@
 }
 
 blink::UserAgentMetadata ChromeContentBrowserClient::GetUserAgentMetadata() {
-  return embedder_support::GetUserAgentMetadata();
+  return embedder_support::GetUserAgentMetadata(
+      g_browser_process->local_state());
 }
 
 absl::optional<gfx::ImageSkia> ChromeContentBrowserClient::GetProductLogo() {
diff --git a/chrome/browser/client_hints/client_hints_browsertest.cc b/chrome/browser/client_hints/client_hints_browsertest.cc
index be992379..6c193f0 100644
--- a/chrome/browser/client_hints/client_hints_browsertest.cc
+++ b/chrome/browser/client_hints/client_hints_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/command_line.h"
 #include "base/containers/contains.h"
 #include "base/metrics/field_trial_param_associator.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
@@ -23,6 +24,7 @@
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h"
+#include "chrome/browser/policy/policy_test_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
@@ -39,6 +41,9 @@
 #include "components/embedder_support/user_agent_utils.h"
 #include "components/metrics/content/subprocess_metrics_provider.h"
 #include "components/page_load_metrics/browser/page_load_metrics_test_waiter.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_pref_names.h"
+#include "components/policy/policy_constants.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/client_hints.h"
@@ -182,7 +187,7 @@
 
 }  // namespace
 
-class ClientHintsBrowserTest : public InProcessBrowserTest,
+class ClientHintsBrowserTest : public policy::PolicyTest,
                                public testing::WithParamInterface<bool> {
  public:
   ClientHintsBrowserTest()
@@ -3775,3 +3780,64 @@
   ASSERT_TRUE(ui_test_utils::NavigateToURL(
       otr_browser, without_accept_ch_without_lifetime_url()));
 }
+
+class UpdatedGreaseFeatureParamTest : public ClientHintsBrowserTest {
+  std::unique_ptr<base::FeatureList> EnabledFeatures() override {
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->InitializeFromCommandLine("GreaseUACH:updated_algorithm/true",
+                                            "");
+    return feature_list;
+  }
+};
+
+// Checks that the updated GREASE algorithm is used when explicitly enabled.
+IN_PROC_BROWSER_TEST_F(UpdatedGreaseFeatureParamTest,
+                       UpdatedGreaseFeatureParamTest) {
+  const GURL gurl = accept_ch_without_lifetime_url();
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
+  std::string ua_ch_result = main_frame_ua_observed();
+  // The updated GREASE algorithm should contain at least one of these
+  // characters. The equal sign, space, and semicolon are not present as they
+  // exist in the old algorithm.
+  std::vector<char> updated_grease_chars = {'(', ':', '-', '.',
+                                            '/', ')', '?', '_'};
+  bool saw_updated_grease = false;
+  for (auto i : updated_grease_chars) {
+    if (ua_ch_result.find(i) != std::string::npos) {
+      saw_updated_grease = true;
+    }
+  }
+  ASSERT_TRUE(saw_updated_grease);
+}
+
+class GreaseEnterprisePolicyTest : public ClientHintsBrowserTest {
+  void SetUpInProcessBrowserTestFixture() override {
+    policy::PolicyTest::SetUpInProcessBrowserTestFixture();
+    policy::PolicyMap policies;
+    SetPolicy(&policies, policy::key::kUserAgentClientHintsGREASEUpdateEnabled,
+              absl::optional<base::Value>(false));
+    provider_.UpdateChromePolicy(policies);
+  }
+
+  std::unique_ptr<base::FeatureList> EnabledFeatures() override {
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->InitializeFromCommandLine("GreaseUACH:updated_algorithm/true",
+                                            "");
+    return feature_list;
+  }
+};
+
+// Makes sure that the enterprise policy is able to prevent updated GREASE.
+IN_PROC_BROWSER_TEST_F(GreaseEnterprisePolicyTest, GreaseEnterprisePolicyTest) {
+  const GURL gurl = accept_ch_without_lifetime_url();
+  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), gurl));
+  std::string ua_ch_result = main_frame_ua_observed();
+  // The updated GREASE algorithm would contain at least one of these
+  // characters. The equal sign, space, and semicolon are not present as they
+  // exist in the old algorithm.
+  std::vector<char> updated_grease_chars = {'(', ':', '-', '.',
+                                            '/', ')', '?', '_'};
+  for (auto i : updated_grease_chars) {
+    ASSERT_TRUE(ua_ch_result.find(i) == std::string::npos);
+  }
+}
diff --git a/chrome/browser/client_hints/client_hints_factory.cc b/chrome/browser/client_hints/client_hints_factory.cc
index ad9ff4a..c9133e3 100644
--- a/chrome/browser/client_hints/client_hints_factory.cc
+++ b/chrome/browser/client_hints/client_hints_factory.cc
@@ -50,7 +50,7 @@
       HostContentSettingsMapFactory::GetForProfile(context),
       CookieSettingsFactory::GetForProfile(
           Profile::FromBrowserContext(context)),
-      embedder_support::GetUserAgentMetadata());
+      embedder_support::GetUserAgentMetadata(g_browser_process->local_state()));
 }
 
 content::BrowserContext* ClientHintsFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index c65a6912..17f882c 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1537,6 +1537,9 @@
   { key::kCORSNonWildcardRequestHeadersSupport,
     prefs::kCorsNonWildcardRequestHeadersSupport,
     base::Value::Type::BOOLEAN },
+  { key::kUserAgentClientHintsGREASEUpdateEnabled,
+    policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled,
+    base::Value::Type::BOOLEAN},
 };
 // clang-format on
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 05341cd..0873f31a 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -958,6 +958,8 @@
       policy::policy_prefs::kTargetBlankImpliesNoOpener, true);
   registry->RegisterBooleanPref(
       policy::policy_prefs::kWebSQLInThirdPartyContextEnabled, false);
+  registry->RegisterBooleanPref(
+      policy::policy_prefs::kUserAgentClientHintsGREASEUpdateEnabled, true);
 #if defined(OS_ANDROID)
   registry->RegisterBooleanPref(policy::policy_prefs::kBackForwardCacheEnabled,
                                 true);
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index db0063c..e3e3789d 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -1655,7 +1655,8 @@
     blink::UserAgentOverride ua_override;
     ua_override.ua_string_override = content::BuildUserAgentFromOSAndProduct(
         kOsOverrideForTabletSite, product);
-    ua_override.ua_metadata_override = embedder_support::GetUserAgentMetadata();
+    ua_override.ua_metadata_override = embedder_support::GetUserAgentMetadata(
+        g_browser_process->local_state());
     ua_override.ua_metadata_override->mobile = true;
     ua_override.ua_metadata_override->platform =
         kChPlatformOverrideForTabletSite;