tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 60cb4824d57267f5b7f18543ab356ae56a672aae
parent 443bc3032282afa636188c99bbe39c1827983c66
Author: Emma Zuehlcke <emz@mozilla.com>
Date:   Thu, 18 Dec 2025 17:00:38 +0000

Bug 1971445 - Create ETP > Custom > Customize settings in config-based prefs. r=fluent-reviewers,hjones,bvandersloot,bolsson,desktop-theme-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D274317

Diffstat:
Mbrowser/components/preferences/main.js | 144++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mbrowser/components/preferences/preferences.js | 5+++++
Mbrowser/components/preferences/privacy.inc.xhtml | 2+-
Mbrowser/components/preferences/privacy.js | 264++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mbrowser/locales-preview/privacyPreferences.ftl | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/themes/shared/preferences/preferences.css | 5+++++
6 files changed, 459 insertions(+), 9 deletions(-)

diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js @@ -3516,7 +3516,7 @@ SettingGroupManager.registerGroups({ supportPage: "enhanced-tracking-protection", items: [ { - id: "contentBlockingCategory", + id: "contentBlockingCategoryRadioGroup", control: "moz-radio-group", options: [ { @@ -3581,6 +3581,148 @@ SettingGroupManager.registerGroups({ }, ], }, + etpReset: { + inProgress: true, + headingLevel: 2, + l10nId: "preferences-etp-reset", + items: [ + { + id: "etpResetButtonGroup", + control: "div", + items: [ + { + id: "etpResetStandardButton", + control: "moz-button", + l10nId: "preferences-etp-reset-standard-button", + }, + { + id: "etpResetStrictButton", + control: "moz-button", + l10nId: "preferences-etp-reset-strict-button", + }, + ], + }, + ], + }, + etpCustomize: { + inProgress: true, + headingLevel: 2, + l10nId: "preferences-etp-custom-control-group", + items: [ + { + id: "etpAllowListBaselineEnabledCustom", + l10nId: "content-blocking-baseline-exceptions-3", + supportPage: "manage-enhanced-tracking-protection-exceptions", + control: "moz-checkbox", + items: [ + { + id: "etpAllowListConvenienceEnabledCustom", + l10nId: "content-blocking-convenience-exceptions-3", + control: "moz-checkbox", + }, + ], + }, + { + id: "etpCustomCookiesEnabled", + l10nId: "preferences-etp-custom-cookies-enabled", + control: "moz-toggle", + items: [ + { + id: "cookieBehavior", + l10nId: "preferences-etp-custom-cookie-behavior", + control: "moz-select", + options: [ + { + value: Ci.nsICookieService.BEHAVIOR_ACCEPT.toString(), + l10nId: "preferences-etpc-custom-cookie-behavior-accept-all", + }, + { + value: Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER.toString(), + l10nId: "sitedata-option-block-cross-site-trackers", + }, + { + value: + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN.toString(), + l10nId: "sitedata-option-block-cross-site-cookies2", + }, + { + value: Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN.toString(), + l10nId: "sitedata-option-block-unvisited", + }, + { + value: Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN.toString(), + l10nId: "sitedata-option-block-all-cross-site-cookies", + }, + { + value: Ci.nsICookieService.BEHAVIOR_REJECT.toString(), + l10nId: "sitedata-option-block-all", + }, + ], + }, + ], + }, + { + id: "etpCustomTrackingProtectionEnabled", + l10nId: "preferences-etp-custom-tracking-protection-enabled", + control: "moz-toggle", + items: [ + { + id: "etpCustomTrackingProtectionEnabledContext", + l10nId: + "preferences-etp-custom-tracking-protection-enabled-context", + control: "moz-select", + options: [ + { + value: "all", + l10nId: + "content-blocking-tracking-protection-option-all-windows", + }, + { + value: "pbmOnly", + l10nId: "content-blocking-option-private", + }, + ], + }, + ], + }, + { + id: "etpCustomCryptominingProtectionEnabled", + l10nId: "preferences-etp-custom-crypto-mining-protection-enabled", + control: "moz-toggle", + }, + { + id: "etpCustomKnownFingerprintingProtectionEnabled", + l10nId: + "preferences-etp-custom-known-fingerprinting-protection-enabled", + control: "moz-toggle", + }, + { + id: "etpCustomSuspectFingerprintingProtectionEnabled", + l10nId: + "preferences-etp-custom-suspect-fingerprinting-protection-enabled", + control: "moz-toggle", + items: [ + { + id: "etpCustomSuspectFingerprintingProtectionEnabledContext", + l10nId: + "preferences-etp-custom-suspect-fingerprinting-protection-enabled-context", + control: "moz-select", + options: [ + { + value: "all", + l10nId: + "content-blocking-tracking-protection-option-all-windows", + }, + { + value: "pbmOnly", + l10nId: "content-blocking-option-private", + }, + ], + }, + ], + }, + ], + }, manageAddresses: { items: [ { diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js @@ -290,6 +290,11 @@ const CONFIG_PANES = Object.freeze({ l10nId: "preferences-etp-header", groupIds: ["etpBanner", "etpAdvanced"], }, + etpCustomize: { + parent: "etp", + l10nId: "preferences-etp-customize-header", + groupIds: ["etpReset", "etpCustomize"], + }, manageAddresses: { parent: "privacy", l10nId: "autofill-addresses-manage-addresses-title", diff --git a/browser/components/preferences/privacy.inc.xhtml b/browser/components/preferences/privacy.inc.xhtml @@ -18,7 +18,7 @@ <html:setting-group groupid="etpStatus" data-category="panePrivacy" data-subcategory="etpStatus" hidden="true"></html:setting-group> <!-- Tracking / Content Blocking --> -<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true" aria-describedby="contentBlockingDescription" class="highlighting-group"> +<groupbox id="trackingGroup" data-category="panePrivacy" data-srd-groupid="etpBanner" hidden="true" aria-describedby="contentBlockingDescription" class="highlighting-group"> <label id="contentBlockingHeader"><html:h2 data-l10n-id="content-blocking-enhanced-tracking-protection"/></label> <html:setting-group groupid="securityPrivacyStatus"/> <vbox data-subcategory="trackingprotection"> diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js @@ -2787,11 +2787,44 @@ Preferences.addSetting({ }, }); +function shouldDisableETPCategoryControls() { + let policy = Services.policies.getActivePolicies(); + return policy?.EnableTrackingProtection?.Locked || policy?.Cookies?.Locked; +} + Preferences.addSetting({ id: "contentBlockingCategory", pref: "browser.contentblocking.category", }); +// We need a separate setting for the radio group for custom disable behavior. +// Setter and getter simply write to the pref. +Preferences.addSetting({ + id: "contentBlockingCategoryRadioGroup", + deps: ["contentBlockingCategory"], + get(_, { contentBlockingCategory }) { + return contentBlockingCategory.value; + }, + set(value, { contentBlockingCategory }) { + contentBlockingCategory.value = value; + }, + getControlConfig(config, _, setting) { + if (!shouldDisableETPCategoryControls()) { + return config; + } + + let { options } = config; + + // If ETP level is set to custom keep the radio button enabled so the "customize" button works even when the category selection itself is locked. + for (let option of options) { + option.disabled = + option.id != "etpLevelCustom" || setting.value != "custom"; + } + + return config; + }, +}); + Preferences.addSetting({ id: "etpStatusBoxGroup", }); @@ -2897,6 +2930,227 @@ Preferences.addSetting({ }, }); +Preferences.addSetting({ + id: "etpResetButtonGroup", +}); + +Preferences.addSetting({ + id: "etpResetStandardButton", + deps: ["contentBlockingCategory"], + onUserClick(_, { contentBlockingCategory }) { + contentBlockingCategory.value = "standard"; + }, + disabled({ contentBlockingCategory }) { + return ( + contentBlockingCategory.value == "standard" || + shouldDisableETPCategoryControls() + ); + }, +}); + +Preferences.addSetting({ + id: "etpResetStrictButton", + deps: ["contentBlockingCategory"], + onUserClick(_, { contentBlockingCategory }) { + contentBlockingCategory.value = "strict"; + }, + disabled({ contentBlockingCategory }) { + return ( + contentBlockingCategory.value == "strict" || + shouldDisableETPCategoryControls() + ); + }, +}); + +Preferences.addSetting({ + id: "etpAllowListBaselineEnabledCustom", + pref: "privacy.trackingprotection.allow_list.baseline.enabled", +}); + +Preferences.addSetting({ + id: "etpAllowListConvenienceEnabledCustom", + pref: "privacy.trackingprotection.allow_list.convenience.enabled", +}); + +Preferences.addSetting({ + id: "etpCustomCookiesEnabled", + deps: ["cookieBehavior"], + disabled: ({ cookieBehavior }) => { + return cookieBehavior.locked; + }, + get(_, { cookieBehavior }) { + return cookieBehavior.value != Ci.nsICookieService.BEHAVIOR_ACCEPT; + }, + set(value, { cookieBehavior }) { + if (!value) { + cookieBehavior.value = Ci.nsICookieService.BEHAVIOR_ACCEPT; + } else { + // When the user enabled cookie blocking, set the cookie behavior to the default. + cookieBehavior.value = cookieBehavior.pref.defaultValue; + } + }, +}); + +Preferences.addSetting({ + id: "trackingProtectionEnabled", + pref: "privacy.trackingprotection.enabled", +}); + +Preferences.addSetting({ + id: "trackingProtectionEnabledPBM", + pref: "privacy.trackingprotection.pbmode.enabled", +}); + +Preferences.addSetting({ + id: "etpCustomTrackingProtectionEnabledContext", + deps: ["trackingProtectionEnabled", "trackingProtectionEnabledPBM"], + get(_, { trackingProtectionEnabled, trackingProtectionEnabledPBM }) { + if (trackingProtectionEnabled.value && trackingProtectionEnabledPBM.value) { + return "all"; + } else if (trackingProtectionEnabledPBM) { + return "pbmOnly"; + } + return null; + }, + set(value, { trackingProtectionEnabled, trackingProtectionEnabledPBM }) { + if (value == "all") { + trackingProtectionEnabled.value = true; + trackingProtectionEnabledPBM.value = true; + } else if (value == "pbmOnly") { + trackingProtectionEnabled.value = false; + trackingProtectionEnabledPBM.value = true; + } + }, +}); + +Preferences.addSetting({ + id: "etpCustomTrackingProtectionEnabled", + deps: ["trackingProtectionEnabled", "trackingProtectionEnabledPBM"], + disabled: ({ trackingProtectionEnabled, trackingProtectionEnabledPBM }) => { + return ( + trackingProtectionEnabled.locked || trackingProtectionEnabledPBM.locked + ); + }, + get(_, { trackingProtectionEnabled, trackingProtectionEnabledPBM }) { + return ( + trackingProtectionEnabled.value || trackingProtectionEnabledPBM.value + ); + }, + set(value, { trackingProtectionEnabled, trackingProtectionEnabledPBM }) { + if (value) { + trackingProtectionEnabled.value = false; + trackingProtectionEnabledPBM.value = true; + } else { + trackingProtectionEnabled.value = false; + trackingProtectionEnabledPBM.value = false; + } + }, +}); + +Preferences.addSetting({ + id: "etpCustomCryptominingProtectionEnabled", + pref: "privacy.trackingprotection.cryptomining.enabled", +}); + +Preferences.addSetting({ + id: "etpCustomKnownFingerprintingProtectionEnabled", + pref: "privacy.trackingprotection.fingerprinting.enabled", +}); + +Preferences.addSetting({ + id: "etpCustomFingerprintingProtectionEnabled", + pref: "privacy.fingerprintingProtection", +}); + +Preferences.addSetting({ + id: "etpCustomFingerprintingProtectionEnabledPBM", + pref: "privacy.fingerprintingProtection.pbmode", +}); + +Preferences.addSetting({ + id: "etpCustomSuspectFingerprintingProtectionEnabled", + deps: [ + "etpCustomFingerprintingProtectionEnabled", + "etpCustomFingerprintingProtectionEnabledPBM", + ], + disabled({ + etpCustomFingerprintingProtectionEnabled, + etpCustomFingerprintingProtectionEnabledPBM, + }) { + return ( + etpCustomFingerprintingProtectionEnabled.locked || + etpCustomFingerprintingProtectionEnabledPBM.locked + ); + }, + get( + _, + { + etpCustomFingerprintingProtectionEnabled, + etpCustomFingerprintingProtectionEnabledPBM, + } + ) { + return ( + etpCustomFingerprintingProtectionEnabled.value || + etpCustomFingerprintingProtectionEnabledPBM.value + ); + }, + set( + value, + { + etpCustomFingerprintingProtectionEnabled, + etpCustomFingerprintingProtectionEnabledPBM, + } + ) { + if (value) { + etpCustomFingerprintingProtectionEnabled.value = false; + etpCustomFingerprintingProtectionEnabledPBM.value = true; + } else { + etpCustomFingerprintingProtectionEnabled.value = false; + etpCustomFingerprintingProtectionEnabledPBM.value = false; + } + }, +}); + +Preferences.addSetting({ + id: "etpCustomSuspectFingerprintingProtectionEnabledContext", + deps: [ + "etpCustomFingerprintingProtectionEnabled", + "etpCustomFingerprintingProtectionEnabledPBM", + ], + get( + _, + { + etpCustomFingerprintingProtectionEnabled, + etpCustomFingerprintingProtectionEnabledPBM, + } + ) { + if ( + etpCustomFingerprintingProtectionEnabled.value && + etpCustomFingerprintingProtectionEnabledPBM.value + ) { + return "all"; + } else if (etpCustomFingerprintingProtectionEnabledPBM) { + return "pbmOnly"; + } + return null; + }, + set( + value, + { + etpCustomFingerprintingProtectionEnabled, + etpCustomFingerprintingProtectionEnabledPBM, + } + ) { + if (value == "all") { + etpCustomFingerprintingProtectionEnabled.value = true; + etpCustomFingerprintingProtectionEnabledPBM.value = true; + } else if (value == "pbmOnly") { + etpCustomFingerprintingProtectionEnabled.value = false; + etpCustomFingerprintingProtectionEnabledPBM.value = true; + } + }, +}); + function setEventListener(aId, aEventType, aCallback) { document .getElementById(aId) @@ -3015,13 +3269,7 @@ var gPrivacyPane = { Services.obs.notifyObservers(window, "privacy-pane-tp-ui-updated"); } - let policy = Services.policies.getActivePolicies(); - if ( - policy && - ((policy.EnableTrackingProtection && - policy.EnableTrackingProtection.Locked) || - (policy.Cookies && policy.Cookies.Locked)) - ) { + if (shouldDisableETPCategoryControls()) { setInputsDisabledState(true); } if (tPPrefisLocked) { @@ -3461,6 +3709,8 @@ var gPrivacyPane = { initSettingGroup("etpStatus"); initSettingGroup("etpBanner"); initSettingGroup("etpAdvanced"); + initSettingGroup("etpReset"); + initSettingGroup("etpCustomize"); /* Initialize Content Blocking */ this.initContentBlocking(); diff --git a/browser/locales-preview/privacyPreferences.ftl b/browser/locales-preview/privacyPreferences.ftl @@ -255,3 +255,51 @@ preferences-etp-level-warning-message = preferences-etp-manage-exceptions-button = .label = Manage exceptions .description = Manage websites where Enhanced Tracking Protection is disabled. + +preferences-etp-customize-header = + .heading = Customize privacy protection + .description = Aut voluptates deleniti ut. Aut et praesentium voluptas dolore nostrum occaecati. + +preferences-etp-reset = + .label = Reset + .description = Aut voluptates deleniti ut. Aut et praesentium voluptas dolore nostrum occaecati. Fugit soluta dolor aut soluta sapiente ut vel. + + +preferences-etp-reset-standard-button = + .label = Reset to standard + +preferences-etp-reset-strict-button = + .label = Reset to strict + +preferences-etp-custom-control-group = + .label = Tracking protection + +preferences-etp-custom-cookies-enabled = + .label = Cookies + .description = Description + +preferences-etp-custom-cookie-behavior = + .aria-label = { preferences-etp-custom-cookies-enabled.label } + +preferences-etpc-custom-cookie-behavior-accept-all = + .label = Allow all cookies + +preferences-etp-custom-tracking-protection-enabled = + .label = Tracking content + .description = Description + +preferences-etp-custom-tracking-protection-enabled-context = + .aria-label = { preferences-etp-custom-tracking-protection-enabled.label } + +preferences-etp-custom-crypto-mining-protection-enabled = + .label = Cryptominers + +preferences-etp-custom-known-fingerprinting-protection-enabled = + .label = Known fingerprinters + +preferences-etp-custom-suspect-fingerprinting-protection-enabled = + .label = Suspected fingerprinters + .description = Description + +preferences-etp-custom-suspect-fingerprinting-protection-enabled-context = + .aria-label = { preferences-etp-custom-suspect-fingerprinting-protection-enabled.label } diff --git a/browser/themes/shared/preferences/preferences.css b/browser/themes/shared/preferences/preferences.css @@ -1551,6 +1551,11 @@ setting-group[groupid="home"] { --promo-image-position: top; } +#etpResetButtonGroup { + display: flex; + gap: var(--space-small); +} + #addresses-list-header, #payments-list-header { --box-label-font-weight: var(--heading-font-weight);