Skip to content

Commit

Permalink
[M111][Privacy Sandbox] Support compatibility privacySandboxEnabled API
Browse files Browse the repository at this point in the history
The existing privacySandboxEnabled Chrome Extension API is being
depreciated in favour of three new k-APIs - topicsEnabled, fledgeEnabled
and adMeasurementEnabled in M111.

This CL enables the existing privacySandboxEnabled API to be respected
and compatible with the new k-APIs during the migration period.
If an extension has disabled the privacySandboxEnabled API, then the
new k-APIs must also be disabled.
If an extension clears the privacySandboxEnabled API, then the new
k-APIs are also cleared.

See a screen recording of an extension disabling the privacySandbox API:
http://dr/file/d/1MoLhOVmmh4bqW18lkdDctQRmsTo-Hjdy/view
Test extension for Privacy Sandbox Extension APIs used:
http://dr/file/d/1Wlk3TzECpU7j_23H9UUZxUdSY2UDTMQc/view
Experiment #privacy-sandbox-settings-4 was enabled.

(cherry picked from commit 5fc51e7)

Bug: 1378703, b/254414152
Change-Id: Id5e711149e85ceb84217e2b59d6b2ebaffef8997
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4133664
Commit-Queue: Filipa Senra <fsenra@google.com>
Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1097899}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4202368
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/5563@{#44}
Cr-Branched-From: 3ac59a6-refs/heads/main@{#1097615}
  • Loading branch information
Filipa Senra authored and Chromium LUCI CQ committed Jan 31, 2023
1 parent e8eea85 commit cfa336a
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 9 deletions.
40 changes: 40 additions & 0 deletions chrome/browser/extensions/api/preference/preference_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,33 @@ ExtensionFunction::ResponseAction SetPreferenceFunction::Run() {
BuildPrivacySandboxDeprecationInspectorIssueInfo(source_url()));
}

// Clear the new Privacy Sandbox APIs if an extension sets to true the
// deprecated pref |kPrivacySandboxApisEnabled| and set to false the new
// Privacy Sandbox APIs if an extension sets to false the deprecated pref
// |kPrivacySandboxApisEnabled| in order to maintain backward compatibility
// during the migration period.
// TODO(b/263568309): Remove this once the deprecated API is retired.
if (prefs::kPrivacySandboxApisEnabled == browser_pref) {
if (browser_pref_value->GetBool()) {
prefs_helper->RemoveExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1TopicsEnabled, scope);
prefs_helper->RemoveExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1FledgeEnabled, scope);
prefs_helper->RemoveExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1AdMeasurementEnabled, scope);
} else {
prefs_helper->SetExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1TopicsEnabled, scope,
base::Value(false));
prefs_helper->SetExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1FledgeEnabled, scope,
base::Value(false));
prefs_helper->SetExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1AdMeasurementEnabled, scope,
base::Value(false));
}
}

prefs_helper->SetExtensionControlledPref(extension_id(), browser_pref, scope,
browser_pref_value->Clone());
#if BUILDFLAG(IS_CHROMEOS_LACROS)
Expand Down Expand Up @@ -961,6 +988,19 @@ ExtensionFunction::ResponseAction ClearPreferenceFunction::Run() {
BuildPrivacySandboxDeprecationInspectorIssueInfo(source_url()));
}

// Clear the new Privacy Sandbox APIs if an extension clears the deprecated
// pref |kPrivacySandboxApisEnabled| in order to maintain backward
// compatibility during the migration period.
// TODO(b/263568309): Remove this once the deprecated API is retired.
if (prefs::kPrivacySandboxApisEnabled == browser_pref) {
prefs_helper->RemoveExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1TopicsEnabled, scope);
prefs_helper->RemoveExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1FledgeEnabled, scope);
prefs_helper->RemoveExtensionControlledPref(
extension_id(), prefs::kPrivacySandboxM1AdMeasurementEnabled, scope);
}

// Whenever an extension clears the |kSafeBrowsingEnabled| preference,
// it must also clear |kSafeBrowsingEnhanced|. See crbug.com/1064722 for
// more background.
Expand Down
160 changes: 160 additions & 0 deletions chrome/browser/extensions/api/preference/preference_apitest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,51 @@ class ExtensionPreferenceApiTest
/* expected_controlled */ false);
}

void CheckPrivacySandboxPreferencesDisabled() {
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxApisEnabled,
base::Value(false),
/* expected_controlled */ true);
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxM1TopicsEnabled,
base::Value(false),
/* expected_controlled */ true);
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxM1FledgeEnabled,
base::Value(false),
/* expected_controlled */ true);
VerifyPrefValueAndControlledState(
prefs::kPrivacySandboxM1AdMeasurementEnabled, base::Value(false),
/* expected_controlled */ true);
}

void CheckPrivacySandboxPreferencesEnabled() {
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxApisEnabled,
base::Value(true),
/* expected_controlled */ true);
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxM1TopicsEnabled,
base::Value(true),
/* expected_controlled */ false);
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxM1FledgeEnabled,
base::Value(true),
/* expected_controlled */ false);
VerifyPrefValueAndControlledState(
prefs::kPrivacySandboxM1AdMeasurementEnabled, base::Value(true),
/* expected_controlled */ false);
}

void CheckPrivacySandboxPreferencesCleared() {
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxApisEnabled,
base::Value(true),
/* expected_controlled */ false);
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxM1TopicsEnabled,
base::Value(true),
/* expected_controlled */ false);
VerifyPrefValueAndControlledState(prefs::kPrivacySandboxM1FledgeEnabled,
base::Value(true),
/* expected_controlled */ false);
VerifyPrefValueAndControlledState(
prefs::kPrivacySandboxM1AdMeasurementEnabled, base::Value(true),
/* expected_controlled */ false);
}

// Verifies whether the boolean |preference| has the |expected_value| and is
// |expected_controlled| by an extension.

Expand Down Expand Up @@ -630,6 +675,121 @@ IN_PROC_BROWSER_TEST_P(ExtensionPreferenceApiTest, ThirdPartyCookiesAllowed) {
/* expected_controlled */ false);
}

// Tests the behavior of the PrivacySandboxEnabled API during the migration
// period.
// The preferences |kPrivacySandboxM1Topics|, |kPrivacySandboxM1Fledge| and
// |kPrivacySandboxM1AdMeasurement| should be enforced to kOff if
// |kPrivacySandboxApisEnabled| is set to false by an extension.
// They should also be cleared if |kPrivacySandboxApisEnabled| is cleared.
// This check is not done in the Standard test so we can test if the granular
// Privacy Sandbox APIs are turned off, when |kPrivacySandboxApisEnabled| is
// turned off, in isolation of controlling them directly.
// Disabled due to flakes on multiple platforms; see https://crbug.com/1410736.
IN_PROC_BROWSER_TEST_F(ExtensionPreferenceApiTest,
DISABLED_PrivacySandboxMigration) {
PrefService* prefs = profile_->GetPrefs();
prefs->SetBoolean(prefs::kPrivacySandboxM1TopicsEnabled, true);
prefs->SetBoolean(prefs::kPrivacySandboxM1FledgeEnabled, true);
prefs->SetBoolean(prefs::kPrivacySandboxM1AdMeasurementEnabled, true);

base::FilePath extension_path =
test_data_dir_.AppendASCII("preference/privacy_sandbox_migration");

// STEP 1. Install extension and set the pref |kPrivacySandboxApisEnabled| to
// false.
// The preferences for PrivacySandbox, Topics, Fledge and AdMeasurement should
// all be disabled.
{
extensions::ResultCatcher catcher;
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
EXPECT_TRUE(LoadExtension(extension_path)) << message_;
EXPECT_TRUE(listener.WaitUntilSatisfied());
// Run the tests.
listener.Reply("run set to false test");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
CheckPrivacySandboxPreferencesDisabled();

// STEP 2. Reload extension.
// The preferences should not be reset when the extension is reloaded.
{
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
ReloadExtension(last_loaded_extension_id());
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply("");
}
CheckPrivacySandboxPreferencesDisabled();

// STEP 4. Enable the pref |kPrivacySandboxApisEnabled|.
// The preference PrivacySandbox should be enabled but the preferences Topics,
// Fledge and AdMeasurement should all be cleared and on their default values.
{
extensions::ResultCatcher catcher;
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
ReloadExtension(last_loaded_extension_id());
EXPECT_TRUE(listener.WaitUntilSatisfied());
// Run the tests.
listener.Reply("run set to true test");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
CheckPrivacySandboxPreferencesEnabled();

// STEP 5. Redo Step 1.
// So we can see a meaningful change on Step 6.
{
extensions::ResultCatcher catcher;
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
ReloadExtension(last_loaded_extension_id());
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply("run set to false test");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
CheckPrivacySandboxPreferencesDisabled();

// STEP 6. Clear the pref |kPrivacySandboxApisEnabled|.
// The preferences for PrivacySandbox, Topics, Fledge and AdMeasurement should
// all be cleared and on their default values.
{
extensions::ResultCatcher catcher;
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
ReloadExtension(last_loaded_extension_id());
EXPECT_TRUE(listener.WaitUntilSatisfied());
// Run the tests.
listener.Reply("run clear test");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
CheckPrivacySandboxPreferencesCleared();

// STEP 7. Redo Step 1.
// So we can see a meaningful change on Step 8.
{
extensions::ResultCatcher catcher;
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
ReloadExtension(last_loaded_extension_id());
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply("run set to false test");
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
CheckPrivacySandboxPreferencesDisabled();

// STEP 8. Uninstall and install the extension (without running the test
// that calls the extension API)
// Uninstalling and installing should clear the preferences.
extensions::TestExtensionRegistryObserver observer(
extensions::ExtensionRegistry::Get(profile_), last_loaded_extension_id());
UninstallExtension(last_loaded_extension_id());
observer.WaitForExtensionUninstalled();
CheckPrivacySandboxPreferencesCleared();

{
ExtensionTestMessageListener listener("ready", ReplyBehavior::kWillReply);
EXPECT_TRUE(LoadExtension(extension_path));
EXPECT_TRUE(listener.WaitUntilSatisfied());
listener.Reply("");
}
CheckPrivacySandboxPreferencesCleared();
}

namespace extensions {

class ExtensionPrefDevToolsIssueTest
Expand Down
2 changes: 1 addition & 1 deletion chrome/common/extensions/api/privacy.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
"$ref": "types.ChromeSetting",
"value": ["privacySandboxEnabled", {"type": "boolean"}],
"deprecated": "We’re deprecating the API <code><a href='#property-websites-privacySandboxEnabled'>chrome.privacy.websites.privacySandboxEnabled</a></code>, though it will remain active for backward compatibility until release M113. Instead, please use <code><a href='#property-websites-topicsEnabled'>chrome.privacy.websites.topicsEnabled</a></code>, <code><a href='#property-websites-fledgeEnabled'>chrome.privacy.websites.fledgeEnabled</a></code> and <code><a href='#property-websites-adMeasurementEnabled'>chrome.privacy.websites.adMeasurementEnabled</a></code>.",
"description": "If enabled, the experimental <a href=https://www.chromium.org/Home/chromium-privacy/privacy-sandbox>Privacy Sandbox</a> features are active. The value of this preference is of type boolean, and the default value is <code>true</code>. PLEASE NOTE: The schema of this API may change in the future as the Privacy Sandbox features crystallize. In that case, we will provide prior notice."
"description": "If enabled, the experimental <a href='https://www.chromium.org/Home/chromium-privacy/privacy-sandbox'>Privacy Sandbox</a> features are active. The value of this preference is of type boolean, and the default value is <code>true</code>."
},
"topicsEnabled": {
"$ref": "types.ChromeSetting",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name" : "Preferences API Test Extension for Privacy Sandbox Migration",
"version" : "0.1",
"manifest_version": 2,
"description" : "Preferences API Test Extension for Privacy Sandbox Migration",
"permissions": [ "privacy" ],
"background": {
"scripts": ["test.js"],
"persistent": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Privacy Sandbox Migration API test
// Run with browser_tests
// --gtest_filter=ExtensionPreferenceApiTest.PrivacySandboxMigration

var privacyWebsitesNamespace = chrome.privacy.websites;

function expect(expected, message) {
return chrome.test.callbackPass(function(value) {
chrome.test.assertEq(expected, value, message);
});
}

// Verifies that the preference has the expected default value.
function expectDefault(prefName, defaultValue) {
return expect(
{value: defaultValue, levelOfControl: 'controllable_by_this_extension'},
'`' + prefName + '` is expected to be the default, which is ' +
defaultValue);
}

// Verifies that the preference is properly controlled by the extension.
function expectControlled(prefName, newValue) {
return expect(
{
value: newValue,
levelOfControl: 'controlled_by_this_extension',
},
'`' + prefName + '` is expected to be controlled by this extension');
}

function setToFalsePref() {
chrome.test.getConfig(function(config) {
chrome.test.runTests([
// Setting the deprecated pref to false |kPrivacySandboxApisEnabled|
// should also set to false the new Privacy Sandbox APIs in order to
// maintain backward compatibility during the migration period.
function testSetToFalsePrivacyGuideEnabled() {
privacyWebsitesNamespace.privacySandboxEnabled.set(
{value: false}, function() {
privacyWebsitesNamespace.topicsEnabled.get(
{}, expectControlled('topicsEnabled', false));
privacyWebsitesNamespace.fledgeEnabled.get(
{}, expectControlled('fledgeEnabled', false));
privacyWebsitesNamespace.adMeasurementEnabled.get(
{}, expectControlled('adMeasurementEnabled', false));
});
},
])
})
}

function setToTruePref() {
chrome.test.getConfig(function(config) {
chrome.test.runTests([
// Setting the deprecated pref to true |kPrivacySandboxApisEnabled|
// should clear the new Privacy Sandbox APIs in order to
// maintain backward compatibility during the migration period.
function testSetToTruePrivacyGuideEnabled() {
privacyWebsitesNamespace.privacySandboxEnabled.set(
{value: true}, function() {
privacyWebsitesNamespace.topicsEnabled.get(
{}, expectDefault('topicsEnabled', true));
privacyWebsitesNamespace.fledgeEnabled.get(
{}, expectDefault('fledgeEnabled', true));
privacyWebsitesNamespace.adMeasurementEnabled.get(
{}, expectDefault('adMeasurementEnabled', true));
});
},
])
})
}

function clearPref() {
chrome.test.getConfig(function(config) {
chrome.test.runTests([
// Clearing the deprecated pref|kPrivacySandboxApisEnabled|
// should also clear the new k-APIs in order to maintain backward
// compatibility during the migration period.
function testClearPrivacyGuideEnabled() {
privacyWebsitesNamespace.privacySandboxEnabled.clear({}, function() {
privacyWebsitesNamespace.topicsEnabled.get(
{}, expectDefault('topicsEnabled', true));
privacyWebsitesNamespace.fledgeEnabled.get(
{}, expectDefault('fledgeEnabled', true));
privacyWebsitesNamespace.adMeasurementEnabled.get(
{}, expectDefault('adMeasurementEnabled', true));
});
},
])
})
}

chrome.test.sendMessage('ready', function(message) {
if (message == 'run set to false test') {
setToFalsePref();
} else if (message == 'run set to true test') {
setToTruePref();
} else if (message == 'run clear test') {
clearPref();
}
});
21 changes: 13 additions & 8 deletions chrome/test/data/extensions/api_test/preference/standard/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,6 @@ chrome.test.sendMessage('ready', function(message) {
}
}
},
function setGlobals() {
for (let preferenceSet of preferences_to_test) {
for (let key in preferenceSet.preferences) {
prefSetterOppositeOfDefault.call(
preferenceSet.root, key, preferenceSet.preferences[key]);
}
}
},
// For Privacy Sandbox APIs unable to enable a pref.
function setToEnableExpectErrorDefault() {
for (let preferenceSet of
Expand Down Expand Up @@ -196,6 +188,19 @@ chrome.test.sendMessage('ready', function(message) {
}
}
},
// setGlobals() after setToEnableExpectErrorAndControlled(), so disabling
// privacySandboxEnabled doesn't trigger topicsEnabled, fledgeEnabled and
// adsMeasurementEnabled to false
// TODO(b/263568309): Move this method after getPreferences() after the
// deprecated API privacySandboxEnabled is retired.
function setGlobals() {
for (let preferenceSet of preferences_to_test) {
for (let key in preferenceSet.preferences) {
prefSetterOppositeOfDefault.call(
preferenceSet.root, key, preferenceSet.preferences[key]);
}
}
},
// Set the WebRTCIPHhandlingPolicy and verify it in the get function.
function testWebRTCIPHandlingPolicy() {
if (pn.webRTCIPHandlingPolicy == undefined) {
Expand Down

0 comments on commit cfa336a

Please sign in to comment.