Bug 1800675 - Add about:preferences entry for cookie banner handling. r=fluent-reviewers,flod,mconley

Differential Revision: https://phabricator.services.mozilla.com/D164632
This commit is contained in:
Jared Hirsch 2023-01-11 15:54:01 +00:00
Родитель e65ec6d643
Коммит 128ed3a6e6
10 изменённых файлов: 328 добавлений и 4 удалений

Просмотреть файл

@ -0,0 +1,11 @@
# 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/.
## Privacy Section - Cookie Banner Handling
cookie-banner-handling-header = Cookie Banner Reduction
cookie-banner-reject-accept = { -brand-short-name } automatically tries to reject cookie requests on cookie banners. If a reject option isnt available, { -brand-short-name } may accept all cookies to dismiss the banner.
cookie-banner-learn-more = Learn More
forms-handle-cookie-banners =
.label = Reduce Cookie Banners

Просмотреть файл

@ -55,6 +55,7 @@
<link rel="localization" href="security/certificates/deviceManager.ftl"/>
<link rel="localization" href="security/certificates/certManager.ftl"/>
<link rel="localization" href="preview/firefoxSuggest.ftl"/>
<link rel="localization" href="preview/cookieBannerPreferences.ftl"/>
<link rel="shortcut icon" href="chrome://global/skin/icons/settings.svg"/>

Просмотреть файл

@ -383,6 +383,25 @@
</hbox>
</groupbox>
<!-- Cookie Banner Handling -->
<groupbox id="cookieBannerHandlingGroup" data-category="panePrivacy" data-subcategory="cookiebanner" hidden="true">
<label><html:h2 data-l10n-id="cookie-banner-handling-header" /></label>
<vbox flex="1">
<hbox>
<description>
<html:span id="cookieBannerReductionExplanation" class="tail-with-learn-more" data-l10n-id="cookie-banner-reject-accept" ></html:span>
<label id="cookieBannerHandlingLearnMore" class="learnMore" is="text-link" data-l10n-id="cookie-banner-learn-more"></label>
</description>
</hbox>
<hbox>
<checkbox id="handleCookieBanners"
preference="cookiebanners.service.mode"
data-l10n-id="forms-handle-cookie-banners"
flex="1" />
</hbox>
</vbox>
</groupbox>
<!-- Passwords -->
<groupbox id="passwordsGroup" orient="vertical" data-category="panePrivacy" data-subcategory="logins" hidden="true">
<label><html:h2 data-l10n-id="pane-privacy-logins-and-passwords-header" data-l10n-attrs="searchkeywords"/></label>

Просмотреть файл

@ -193,6 +193,10 @@ Preferences.addAll([
// Quick Actions
{ id: "browser.urlbar.quickactions.showPrefs", type: "bool" },
{ id: "browser.urlbar.suggest.quickactions", type: "bool" },
// Cookie Banner Handling
{ id: "cookiebanners.ui.desktop.enabled", type: "bool" },
{ id: "cookiebanners.service.mode", type: "int" },
]);
// Study opt out
@ -754,6 +758,8 @@ var gPrivacyPane = {
"storage-permissions";
document.getElementById("siteDataLearnMoreLink").setAttribute("href", url);
this.initCookieBannerHandling();
let notificationInfoURL =
Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
document
@ -1982,6 +1988,92 @@ var gPrivacyPane = {
);
},
/**
* Initializes the cookie banner handling subgroup on the privacy pane.
*
* This UI is shown if the "cookiebanners.ui.desktop.enabled" pref is true.
*
* The cookie banner handling checkbox tracks the state of the integer-valued
* "cookiebanners.service.mode" pref: unchecked if the value is either
* nsICookieBannerService.MODE_DISABLED, meaning the feature is turned off, or
* nsICookieBannerService.MODE_DETECT_ONLY, which is used to allow us to
* advertise the feature to the user via an onboarding doorhanger.
*
* If the user checks the checkbox, the pref value is set to
* nsICookieBannerService.MODE_REJECT_OR_ACCEPT.
*
* If the user unchecks the checkbox, the mode pref value is set to
* nsICookieBannerService.MODE_DISABLED.
*
* Advanced users can choose other int-valued modes via about:config.
*/
initCookieBannerHandling() {
this._initCookieBannerHandlingLearnMore();
setSyncFromPrefListener("handleCookieBanners", () =>
this.readCookieBannerMode()
);
setSyncToPrefListener("handleCookieBanners", () =>
this.writeCookieBannerMode()
);
let preference = Preferences.get("cookiebanners.ui.desktop.enabled");
preference.on("change", () => this.updateCookieBannerHandlingVisibility());
this.updateCookieBannerHandlingVisibility();
},
_initCookieBannerHandlingLearnMore() {
let url =
Services.urlFormatter.formatURLPref("app.support.baseURL") +
"cookie-banner-reduction";
let learnMore = document.getElementById("cookieBannerHandlingLearnMore");
learnMore.setAttribute("href", url);
},
/**
* Reads the cookiebanners.service.mode preference value and updates
* the cookie banner handling checkbox accordingly.
*/
readCookieBannerMode() {
let mode = Preferences.get("cookiebanners.service.mode").value;
let disabledModes = [
Ci.nsICookieBannerService.MODE_DISABLED,
Ci.nsICookieBannerService.MODE_DETECT_ONLY,
];
let isEnabled = !disabledModes.includes(mode);
return isEnabled;
},
/**
* Translates user clicks on the cookie banner handling checkbox to the
* corresponding integer-valued cookie banner mode preference.
*/
writeCookieBannerMode() {
let checkbox = document.getElementById("handleCookieBanners");
let mode = checkbox.checked
? Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT
: Ci.nsICookieBannerService.MODE_DISABLED;
return mode;
},
/**
* Shows or hides the cookie banner handling section based on the value of
* the "cookiebanners.ui.desktop.enabled" pref.
*/
updateCookieBannerHandlingVisibility() {
let groupbox = document.getElementById("cookieBannerHandlingGroup");
let isEnabled = Preferences.get("cookiebanners.ui.desktop.enabled").value;
// Because the top-level pane showing code unsets the hidden attribute, we
// manually hide the section when cookie banner handling is preffed off.
if (isEnabled) {
groupbox.removeAttribute("style");
} else {
groupbox.setAttribute("style", "display: none !important");
}
},
// ADDRESS BAR
/**

Просмотреть файл

@ -101,6 +101,7 @@ skip-if = true
[browser_proxy_backup.js]
[browser_privacypane_2.js]
[browser_privacypane_3.js]
[browser_privacy_cookieBannerHandling.js]
[browser_privacy_firefoxSuggest.js]
[browser_privacy_passwordGenerationAndAutofill.js]
[browser_privacy_relayIntegration.js]

Просмотреть файл

@ -36,6 +36,15 @@ function checkElements(expectedPane) {
continue;
}
// Cookie Banner Handling is currently disabled by default (bug 1800679)
if (element.id == "cookieBannerHandlingGroup") {
is_element_hidden(
element,
"Disabled cookieBannerHandlingGroup should be hidden"
);
continue;
}
// Update prefs are hidden when running an MSIX build
if (
updatePrefContainers.includes(element.id) &&

Просмотреть файл

@ -33,6 +33,13 @@ async function runTest(win) {
await win.gotoPref("panePrivacy");
for (let element of elements) {
let attributeValue = element.getAttribute("data-category");
// Ignore the cookie banner handling section, as it is currently preffed
// off by default (bug 1800679).
if (element.id === "cookieBannerHandlingGroup") {
continue;
}
if (attributeValue == "panePrivacy") {
is_element_visible(element, "HTTPSOnly should be visible");

Просмотреть файл

@ -0,0 +1,181 @@
/* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/ */
// This file tests the Privacy pane's Cookie Banner Handling UI.
"use strict";
const FEATURE_PREF = "cookiebanners.ui.desktop.enabled";
const MODE_PREF = "cookiebanners.service.mode";
const GROUPBOX_ID = "cookieBannerHandlingGroup";
const CHECKBOX_ID = "handleCookieBanners";
// Test the section is hidden on page load if the feature pref is disabled.
add_task(async function test_section_hidden_when_feature_flag_disabled() {
await SpecialPowers.pushPrefEnv({
set: [
[FEATURE_PREF, false],
[MODE_PREF, Ci.nsICookieBannerService.MODE_DISABLED],
],
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
async function(browser) {
let groupbox = browser.contentDocument.getElementById(GROUPBOX_ID);
is_element_hidden(groupbox, "#cookieBannerHandlingGroup is hidden");
}
);
await SpecialPowers.popPrefEnv();
});
// Test the section is shown on page load if the feature pref is enabled.
add_task(async function test_section_shown_when_feature_flag_enabled() {
await SpecialPowers.pushPrefEnv({
set: [
[FEATURE_PREF, true],
[MODE_PREF, Ci.nsICookieBannerService.MODE_DISABLED],
],
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
async function(browser) {
let groupbox = browser.contentDocument.getElementById(GROUPBOX_ID);
is_element_visible(groupbox, "#cookieBannerHandlingGroup is visible");
}
);
await SpecialPowers.popPrefEnv();
});
// Test the checkbox is unchecked in DISABLED mode.
add_task(async function test_checkbox_unchecked_disabled_mode() {
await SpecialPowers.pushPrefEnv({
set: [
[FEATURE_PREF, true],
[MODE_PREF, Ci.nsICookieBannerService.MODE_DISABLED],
],
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
async function(browser) {
let checkbox = browser.contentDocument.getElementById(CHECKBOX_ID);
ok(!checkbox.checked, "checkbox is not checked in DISABLED mode");
}
);
await SpecialPowers.popPrefEnv();
});
// Test the checkbox is unchecked in DETECT_ONLY mode.
add_task(async function test_checkbox_unchecked_detect_only_mode() {
await SpecialPowers.pushPrefEnv({
set: [
[FEATURE_PREF, true],
[MODE_PREF, Ci.nsICookieBannerService.MODE_DETECT_ONLY],
],
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
async function(browser) {
let checkbox = browser.contentDocument.getElementById(CHECKBOX_ID);
ok(!checkbox.checked, "checkbox is not checked in DETECT_ONLY mode");
}
);
await SpecialPowers.popPrefEnv();
});
// Test the checkbox is checked in REJECT_OR_ACCEPT mode.
add_task(async function test_checkbox_checked_reject_or_accept_mode() {
await SpecialPowers.pushPrefEnv({
set: [
[FEATURE_PREF, true],
[MODE_PREF, Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT],
],
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
async function(browser) {
let checkbox = browser.contentDocument.getElementById(CHECKBOX_ID);
ok(checkbox.checked, "checkbox is checked in REJECT_OR_ACCEPT mode");
}
);
await SpecialPowers.popPrefEnv();
});
// Test the checkbox is checked in REJECT mode.
add_task(async function test_checkbox_checked_reject_mode() {
await SpecialPowers.pushPrefEnv({
set: [
[FEATURE_PREF, true],
[MODE_PREF, Ci.nsICookieBannerService.MODE_REJECT],
],
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
async function(browser) {
let checkbox = browser.contentDocument.getElementById(CHECKBOX_ID);
ok(checkbox.checked, "checkbox is checked in REJECT mode");
}
);
await SpecialPowers.popPrefEnv();
});
// Test that toggling the checkbox toggles the mode pref value as expected.
add_task(async function test_checkbox_modifies_mode_pref() {
await SpecialPowers.pushPrefEnv({
set: [
[FEATURE_PREF, true],
[MODE_PREF, Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT],
],
});
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
async function(browser) {
let checkboxSelector = "#" + CHECKBOX_ID;
let checkbox = browser.contentDocument.querySelector(checkboxSelector);
let section = browser.contentDocument.getElementById(GROUPBOX_ID);
section.scrollIntoView();
Assert.ok(checkbox.checked, "initially, the checkbox should be checked");
await BrowserTestUtils.synthesizeMouseAtCenter(
checkboxSelector,
{},
browser
);
Assert.ok(!checkbox.checked, "checkbox should be unchecked");
Assert.equal(
Ci.nsICookieBannerService.MODE_DISABLED,
Services.prefs.getIntPref(MODE_PREF),
"cookie banner handling mode should be set to DISABLED mode after unchecking the checkbox"
);
await BrowserTestUtils.synthesizeMouseAtCenter(
checkboxSelector,
{},
browser
);
Assert.ok(checkbox.checked, "checkbox should be checked");
Assert.equal(
Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
Services.prefs.getIntPref(MODE_PREF),
"cookie banner handling mode should be set to REJECT_OR_ACCEPT mode after checking the checkbox"
);
}
);
await SpecialPowers.popPrefEnv();
});

Просмотреть файл

@ -131,11 +131,13 @@ async function runSearchInput(input) {
async function evaluateSearchResults(
keyword,
searchReults,
searchResults,
includeExperiments = false
) {
searchReults = Array.isArray(searchReults) ? searchReults : [searchReults];
searchReults.push("header-searchResults");
searchResults = Array.isArray(searchResults)
? searchResults
: [searchResults];
searchResults.push("header-searchResults");
await runSearchInput(keyword);
@ -145,7 +147,7 @@ async function evaluateSearchResults(
if (!includeExperiments && child.id?.startsWith("pane-experimental")) {
continue;
}
if (searchReults.includes(child.id)) {
if (searchResults.includes(child.id)) {
is_element_visible(child, `${child.id} should be in search results`);
} else if (child.id) {
is_element_hidden(child, `${child.id} should not be in search results`);

Просмотреть файл

@ -14,6 +14,7 @@
preview/firefoxSuggest.ftl (../components/urlbar/content/firefoxSuggest.ftl)
preview/identityCredentialNotification.ftl (../components/credentialmanager/identityCredentialNotification.ftl)
preview/protectionsPanel.ftl (../base/content/protectionsPanel.ftl)
preview/cookieBannerPreferences.ftl (../components/preferences/cookieBannerPreferences.ftl)
locales-preview/migrationWizard.ftl (../locales-preview/migrationWizard.ftl)
browser (%browser/**/*.ftl)