/* 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/. */
/* import-globals-from extensionControlled.js */
/* import-globals-from preferences.js */
const PREF_UPLOAD_ENABLED =
"datareporting.healthreport.uploadEnabled";
const TRACKING_PROTECTION_KEY =
"websites.trackingProtectionMode";
const TRACKING_PROTECTION_PREFS = [
"privacy.trackingprotection.enabled",
"privacy.trackingprotection.pbmode.enabled",
];
const CONTENT_BLOCKING_PREFS = [
"privacy.trackingprotection.enabled",
"privacy.trackingprotection.pbmode.enabled",
"network.cookie.cookieBehavior",
"privacy.trackingprotection.fingerprinting.enabled",
"privacy.trackingprotection.cryptomining.enabled",
"privacy.firstparty.isolate",
"privacy.trackingprotection.emailtracking.enabled",
"privacy.trackingprotection.emailtracking.pbmode.enabled",
"privacy.fingerprintingProtection",
"privacy.fingerprintingProtection.pbmode",
];
const PREF_OPT_OUT_STUDIES_ENABLED =
"app.shield.optoutstudies.enabled";
const PREF_NORMANDY_ENABLED =
"app.normandy.enabled";
const PREF_ADDON_RECOMMENDATIONS_ENABLED =
"browser.discovery.enabled";
const PREF_PRIVATE_ATTRIBUTION_ENABLED =
"dom.private-attribution.submission.enabled";
const PREF_PASSWORD_GENERATION_AVAILABLE =
"signon.generation.available";
const { BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN } = Ci.nsICookieService;
const PASSWORD_MANAGER_PREF_ID =
"services.passwordSavingEnabled";
ChromeUtils.defineLazyGetter(
this,
"AlertsServiceDND",
function () {
try {
let alertsService = Cc[
"@mozilla.org/alerts-service;1"]
.getService(Ci.nsIAlertsService)
.QueryInterface(Ci.nsIAlertsDoNotDisturb);
// This will throw if manualDoNotDisturb isn't implemented.
alertsService.manualDoNotDisturb;
return alertsService;
}
catch (ex) {
return undefined;
}
});
ChromeUtils.defineLazyGetter(lazy,
"AboutLoginsL10n", () => {
return new Localization([
"branding/brand.ftl",
"browser/aboutLogins.ftl"]);
});
XPCOMUtils.defineLazyServiceGetter(
lazy,
"gParentalControlsService",
"@mozilla.org/parental-controls-service;1",
"nsIParentalControlsService"
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gIsFirstPartyIsolated",
"privacy.firstparty.isolate",
false
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"useOldClearHistoryDialog",
"privacy.sanitize.useOldClearHistoryDialog",
false
);
ChromeUtils.defineESModuleGetters(
this, {
DoHConfigController:
"resource:///modules/DoHConfig.sys.mjs",
Sanitizer:
"resource:///modules/Sanitizer.sys.mjs",
});
const SANITIZE_ON_SHUTDOWN_MAPPINGS = {
history:
"privacy.clearOnShutdown.history",
downloads:
"privacy.clearOnShutdown.downloads",
formdata:
"privacy.clearOnShutdown.formdata",
sessions:
"privacy.clearOnShutdown.sessions",
siteSettings:
"privacy.clearOnShutdown.siteSettings",
cookies:
"privacy.clearOnShutdown.cookies",
cache:
"privacy.clearOnShutdown.cache",
offlineApps:
"privacy.clearOnShutdown.offlineApps",
};
/*
* Prefs that are unique to sanitizeOnShutdown and are not shared
* with the deleteOnClose mechanism like privacy.clearOnShutdown.cookies, -cache and -offlineApps
*/
const SANITIZE_ON_SHUTDOWN_PREFS_ONLY = [
"privacy.clearOnShutdown.history",
"privacy.clearOnShutdown.downloads",
"privacy.clearOnShutdown.sessions",
"privacy.clearOnShutdown.formdata",
"privacy.clearOnShutdown.siteSettings",
];
const SANITIZE_ON_SHUTDOWN_PREFS_ONLY_V2 = [
"privacy.clearOnShutdown_v2.browsingHistoryAndDownloads",
"privacy.clearOnShutdown_v2.siteSettings",
];
Preferences.addAll([
// Content blocking / Tracking Protection
{ id:
"privacy.trackingprotection.enabled", type:
"bool" },
{ id:
"privacy.trackingprotection.pbmode.enabled", type:
"bool" },
{ id:
"privacy.trackingprotection.fingerprinting.enabled", type:
"bool" },
{ id:
"privacy.trackingprotection.cryptomining.enabled", type:
"bool" },
{ id:
"privacy.trackingprotection.emailtracking.enabled", type:
"bool" },
{
id:
"privacy.trackingprotection.emailtracking.pbmode.enabled",
type:
"bool",
},
// Fingerprinting Protection
{ id:
"privacy.fingerprintingProtection", type:
"bool" },
{ id:
"privacy.fingerprintingProtection.pbmode", type:
"bool" },
// Resist Fingerprinting
{ id:
"privacy.resistFingerprinting", type:
"bool" },
{ id:
"privacy.resistFingerprinting.pbmode", type:
"bool" },
// Social tracking
{ id:
"privacy.trackingprotection.socialtracking.enabled", type:
"bool" },
{ id:
"privacy.socialtracking.block_cookies.enabled", type:
"bool" },
// Tracker list
{ id:
"urlclassifier.trackingTable", type:
"string" },
// Button prefs
{ id:
"pref.privacy.disable_button.cookie_exceptions", type:
"bool" },
{
id:
"pref.privacy.disable_button.tracking_protection_exceptions",
type:
"bool",
},
// Location Bar
{ id:
"browser.urlbar.suggest.bookmark", type:
"bool" },
{ id:
"browser.urlbar.suggest.clipboard", type:
"bool" },
{ id:
"browser.urlbar.suggest.history", type:
"bool" },
{ id:
"browser.urlbar.suggest.openpage", type:
"bool" },
{ id:
"browser.urlbar.suggest.topsites", type:
"bool" },
{ id:
"browser.urlbar.suggest.engines", type:
"bool" },
{ id:
"browser.urlbar.suggest.quicksuggest.nonsponsored", type:
"bool" },
{ id:
"browser.urlbar.suggest.quicksuggest.sponsored", type:
"bool" },
{ id:
"browser.urlbar.quicksuggest.dataCollection.enabled", type:
"bool" },
{ id: PREF_URLBAR_QUICKSUGGEST_BLOCKLIST, type:
"string" },
{ id: PREF_URLBAR_WEATHER_USER_ENABLED, type:
"bool" },
// History
{ id:
"places.history.enabled", type:
"bool" },
{ id:
"browser.formfill.enable", type:
"bool" },
{ id:
"privacy.history.custom", type:
"bool" },
// Cookies
{ id:
"network.cookie.cookieBehavior", type:
"int" },
{ id:
"network.cookie.blockFutureCookies", type:
"bool" },
// Content blocking category
{ id:
"browser.contentblocking.category", type:
"string" },
{ id:
"browser.contentblocking.features.strict", type:
"string" },
// Clear Private Data
{ id:
"privacy.sanitize.sanitizeOnShutdown", type:
"bool" },
{ id:
"privacy.sanitize.timeSpan", type:
"int" },
{ id:
"privacy.clearOnShutdown.cookies", type:
"bool" },
{ id:
"privacy.clearOnShutdown_v2.cookiesAndStorage", type:
"bool" },
{ id:
"privacy.clearOnShutdown.cache", type:
"bool" },
{ id:
"privacy.clearOnShutdown_v2.cache", type:
"bool" },
{ id:
"privacy.clearOnShutdown.offlineApps", type:
"bool" },
{ id:
"privacy.clearOnShutdown.history", type:
"bool" },
{
id:
"privacy.clearOnShutdown_v2.browsingHistoryAndDownloads",
type:
"bool",
},
{ id:
"privacy.clearOnShutdown.downloads", type:
"bool" },
{ id:
"privacy.clearOnShutdown.sessions", type:
"bool" },
{ id:
"privacy.clearOnShutdown.formdata", type:
"bool" },
{ id:
"privacy.clearOnShutdown.siteSettings", type:
"bool" },
{ id:
"privacy.clearOnShutdown_v2.siteSettings", type:
"bool" },
// Do not track
{ id:
"privacy.donottrackheader.enabled", type:
"bool" },
// Global Privacy Control
{ id:
"privacy.globalprivacycontrol.enabled", type:
"bool" },
// Media
{ id:
"media.autoplay.default", type:
"int" },
// Popups
{ id:
"dom.disable_open_during_load", type:
"bool" },
// Passwords
{ id:
"signon.rememberSignons", type:
"bool" },
{ id:
"signon.generation.enabled", type:
"bool" },
{ id:
"signon.autofillForms", type:
"bool" },
{ id:
"signon.management.page.breach-alerts.enabled", type:
"bool" },
{ id:
"signon.firefoxRelay.feature", type:
"string" },
// Buttons
{ id:
"pref.privacy.disable_button.view_passwords", type:
"bool" },
{ id:
"pref.privacy.disable_button.view_passwords_exceptions", type:
"bool" },
/* Certificates tab
* security.default_personal_cert
* - a string:
* "Select Automatically" select a certificate automatically when a site
* requests one
* "Ask Every Time" present a dialog to the user so he can select
* the certificate to use on a site which
* requests one
*/
{ id:
"security.default_personal_cert", type:
"string" },
{ id:
"security.disable_button.openCertManager", type:
"bool" },
{ id:
"security.disable_button.openDeviceManager", type:
"bool" },
{ id:
"security.OCSP.enabled", type:
"int" },
{ id:
"security.enterprise_roots.enabled", type:
"bool" },
// Add-ons, malware, phishing
{ id:
"xpinstall.whitelist.required", type:
"bool" },
{ id:
"browser.safebrowsing.malware.enabled", type:
"bool" },
{ id:
"browser.safebrowsing.phishing.enabled", type:
"bool" },
{ id:
"browser.safebrowsing.downloads.enabled", type:
"bool" },
{ id:
"urlclassifier.malwareTable", type:
"string" },
{
id:
"browser.safebrowsing.downloads.remote.block_potentially_unwanted",
type:
"bool",
},
{ id:
"browser.safebrowsing.downloads.remote.block_uncommon", type:
"bool" },
// First-Party Isolation
{ id:
"privacy.firstparty.isolate", type:
"bool" },
// HTTPS-Only
{ id:
"dom.security.https_only_mode", type:
"bool" },
{ id:
"dom.security.https_only_mode_pbm", type:
"bool" },
{ id:
"dom.security.https_first", type:
"bool" },
{ id:
"dom.security.https_first_pbm", type:
"bool" },
// Windows SSO
{ id:
"network.http.windows-sso.enabled", type:
"bool" },
// 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.privateBrowsing", type:
"int" },
// DoH
{ id:
"network.trr.mode", type:
"int" },
{ id:
"network.trr.uri", type:
"string" },
{ id:
"network.trr.default_provider_uri", type:
"string" },
{ id:
"network.trr.custom_uri", type:
"string" },
{ id:
"network.trr_ui.show_fallback_warning_option", type:
"bool" },
{ id:
"network.trr.display_fallback_warning", type:
"bool" },
{ id:
"doh-rollout.disable-heuristics", type:
"bool" },
]);
// Study opt out
if (AppConstants.MOZ_DATA_REPORTING) {
Preferences.addAll([
// Preference instances for prefs that we need to monitor while the page is open.
{ id: PREF_OPT_OUT_STUDIES_ENABLED, type:
"bool" },
{ id: PREF_ADDON_RECOMMENDATIONS_ENABLED, type:
"bool" },
{ id: PREF_UPLOAD_ENABLED, type:
"bool" },
{ id:
"datareporting.usage.uploadEnabled", type:
"bool" },
{ id:
"dom.private-attribution.submission.enabled", type:
"bool" },
]);
}
// Privacy segmentation section
Preferences.add({
id:
"browser.dataFeatureRecommendations.enabled",
type:
"bool",
});
// Data Choices tab
if (AppConstants.MOZ_CRASHREPORTER) {
Preferences.add({
id:
"browser.crashReports.unsubmittedCheck.autoSubmit2",
type:
"bool",
});
}
function setEventListener(aId, aEventType, aCallback) {
document
.getElementById(aId)
.addEventListener(aEventType, aCallback.bind(gPrivacyPane));
}
function setSyncFromPrefListener(aId, aCallback) {
Preferences.addSyncFromPrefListener(document.getElementById(aId), aCallback);
}
function setSyncToPrefListener(aId, aCallback) {
Preferences.addSyncToPrefListener(document.getElementById(aId), aCallback);
}
function dataCollectionCheckboxHandler({
checkbox,
pref,
matchPref = () =>
true,
isDisabled = () =>
false,
}) {
function updateCheckbox() {
let collectionEnabled = Services.prefs.getBoolPref(
PREF_UPLOAD_ENABLED,
false
);
if (collectionEnabled && matchPref()) {
if (Services.prefs.getBoolPref(pref,
false)) {
checkbox.setAttribute(
"checked",
"true");
}
else {
checkbox.removeAttribute(
"checked");
}
checkbox.setAttribute(
"preference", pref);
}
else {
checkbox.removeAttribute(
"preference");
checkbox.removeAttribute(
"checked");
}
checkbox.disabled =
!collectionEnabled || Services.prefs.prefIsLocked(pref) || isDisabled();
}
Preferences.get(PREF_UPLOAD_ENABLED).on(
"change", updateCheckbox);
updateCheckbox();
}
// Sets the "Learn how" SUMO link in the Strict/Custom options of Content Blocking.
function setUpContentBlockingWarnings() {
document.getElementById(
"fpiIncompatibilityWarning").hidden =
!gIsFirstPartyIsolated;
document.getElementById(
"rfpIncompatibilityWarning").hidden =
!Preferences.get(
"privacy.resistFingerprinting").value &&
!Preferences.get(
"privacy.resistFingerprinting.pbmode").value;
}
function initTCPStandardSection() {
let cookieBehaviorPref = Preferences.get(
"network.cookie.cookieBehavior");
let updateTCPSectionVisibilityState = () => {
document.getElementById(
"etpStandardTCPBox").hidden =
cookieBehaviorPref.value !=
Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
};
cookieBehaviorPref.on(
"change", updateTCPSectionVisibilityState);
updateTCPSectionVisibilityState();
}
var gPrivacyPane = {
_pane:
null,
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
_shouldPromptForRestart:
true,
/**
* Update the tracking protection UI to deal with extension control.
*/
_updateTrackingProtectionUI() {
let cBPrefisLocked = CONTENT_BLOCKING_PREFS.some(pref =>
Services.prefs.prefIsLocked(pref)
);
let tPPrefisLocked = TRACKING_PROTECTION_PREFS.some(pref =>
Services.prefs.prefIsLocked(pref)
);
function setInputsDisabledState(isControlled) {
let tpDisabled = tPPrefisLocked || isControlled;
let disabled = cBPrefisLocked || isControlled;
let tpCheckbox = document.getElementById(
"contentBlockingTrackingProtectionCheckbox"
);
// Only enable the TP menu if Detect All Trackers is enabled.
document.getElementById(
"trackingProtectionMenu").disabled =
tpDisabled || !tpCheckbox.checked;
tpCheckbox.disabled = tpDisabled;
document.getElementById(
"standardRadio").disabled = disabled;
document.getElementById(
"strictRadio").disabled = disabled;
document
.getElementById(
"contentBlockingOptionStrict")
.classList.toggle(
"disabled", disabled);
document
.getElementById(
"contentBlockingOptionStandard")
.classList.toggle(
"disabled", disabled);
let arrowButtons = document.querySelectorAll(
"button.arrowhead");
for (let button of arrowButtons) {
button.disabled = disabled;
}
// Notify observers that the TP UI has been updated.
// This is needed since our tests need to be notified about the
// trackingProtectionMenu element getting disabled/enabled at the right time.
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))
) {
setInputsDisabledState(
true);
}
if (tPPrefisLocked) {
// An extension can't control this setting if either pref is locked.
hideControllingExtension(TRACKING_PROTECTION_KEY);
setInputsDisabledState(
false);
}
else {
handleControllingExtension(
PREF_SETTING_TYPE,
TRACKING_PROTECTION_KEY
).then(setInputsDisabledState);
}
},
/**
* Hide the "Change Block List" link for trackers/tracking content in the
* custom Content Blocking/ETP panel. By default, it will not be visible.
*/
_showCustomBlockList() {
let prefValue = Services.prefs.getBoolPref(
"browser.contentblocking.customBlockList.preferences.ui.enabled"
);
if (!prefValue) {
document.getElementById(
"changeBlockListLink").style.display =
"none";
}
else {
setEventListener(
"changeBlockListLink",
"click",
this.showBlockLists);
}
},
/**
* Set up handlers for showing and hiding controlling extension info
* for tracking protection.
*/
_initTrackingProtectionExtensionControl() {
setEventListener(
"contentBlockingDisableTrackingProtectionExtension",
"command",
makeDisableControllingExtension(
PREF_SETTING_TYPE,
TRACKING_PROTECTION_KEY
)
);
let trackingProtectionObserver = {
observe() {
gPrivacyPane._updateTrackingProtectionUI();
},
};
for (let pref of TRACKING_PROTECTION_PREFS) {
Services.prefs.addObserver(pref, trackingProtectionObserver);
}
window.addEventListener(
"unload", () => {
for (let pref of TRACKING_PROTECTION_PREFS) {
Services.prefs.removeObserver(pref, trackingProtectionObserver);
}
});
},
_initThirdPartyCertsToggle() {
// Third-party certificate import is only implemented for Windows and Mac,
// and we should not expose this as a user-configurable setting if there's
// an enterprise policy controlling it (either to enable _or_ disable it).
let canConfigureThirdPartyCerts =
(AppConstants.platform ==
"win" || AppConstants.platform ==
"macosx") &&
typeof Services.policies.getActivePolicies()?.Certificates
?.ImportEnterpriseRoots ==
"undefined";
document.getElementById(
"certEnableThirdPartyToggleBox").hidden =
!canConfigureThirdPartyCerts;
},
syncFromHttpsOnlyPref() {
let httpsOnlyOnPref = Services.prefs.getBoolPref(
"dom.security.https_only_mode"
);
let httpsOnlyOnPBMPref = Services.prefs.getBoolPref(
"dom.security.https_only_mode_pbm"
);
let httpsFirstOnPref = Services.prefs.getBoolPref(
"dom.security.https_first"
);
let httpsFirstOnPBMPref = Services.prefs.getBoolPref(
"dom.security.https_first_pbm"
);
let httpsOnlyRadioGroup = document.getElementById(
"httpsOnlyRadioGroup");
let httpsOnlyExceptionButton = document.getElementById(
"httpsOnlyExceptionButton"
);
if (httpsOnlyOnPref) {
httpsOnlyRadioGroup.value =
"enabled";
}
else if (httpsOnlyOnPBMPref) {
httpsOnlyRadioGroup.value =
"privateOnly";
}
else {
httpsOnlyRadioGroup.value =
"disabled";
}
httpsOnlyExceptionButton.disabled =
!httpsOnlyOnPref &&
!httpsFirstOnPref &&
!httpsOnlyOnPBMPref &&
!httpsFirstOnPBMPref;
if (
Services.prefs.prefIsLocked(
"dom.security.https_only_mode") ||
Services.prefs.prefIsLocked(
"dom.security.https_only_mode_pbm")
) {
httpsOnlyRadioGroup.disabled =
true;
}
},
syncToHttpsOnlyPref() {
let value = document.getElementById(
"httpsOnlyRadioGroup").value;
Services.prefs.setBoolPref(
"dom.security.https_only_mode_pbm",
value ==
"privateOnly"
);
Services.prefs.setBoolPref(
"dom.security.https_only_mode",
value ==
"enabled"
);
},
/**
* Init HTTPS-Only mode and corresponding prefs
*/
initHttpsOnly() {
// Set radio-value based on the pref value
this.syncFromHttpsOnlyPref();
// Create event listener for when the user clicks
// on one of the radio buttons
setEventListener(
"httpsOnlyRadioGroup",
"change",
this.syncToHttpsOnlyPref);
// Update radio-value when the pref changes
Preferences.get(
"dom.security.https_only_mode").on(
"change", () =>
this.syncFromHttpsOnlyPref()
);
Preferences.get(
"dom.security.https_only_mode_pbm").on(
"change", () =>
this.syncFromHttpsOnlyPref()
);
Preferences.get(
"dom.security.https_first").on(
"change", () =>
this.syncFromHttpsOnlyPref()
);
Preferences.get(
"dom.security.https_first_pbm").on(
"change", () =>
this.syncFromHttpsOnlyPref()
);
},
get dnsOverHttpsResolvers() {
let providers = DoHConfigController.currentConfig.providerList;
// if there's no default, we'll hold its position with an empty string
let defaultURI = DoHConfigController.currentConfig.fallbackProviderURI;
let defaultIndex = providers.findIndex(p => p.uri == defaultURI);
if (defaultIndex == -1 && defaultURI) {
// the default value for the pref isn't included in the resolvers list
// so we'll make a stub for it. Without an id, we'll have to use the url as the label
providers.unshift({ uri: defaultURI });
}
return providers;
},
updateDoHResolverList(mode) {
let resolvers =
this.dnsOverHttpsResolvers;
let currentURI = Preferences.get(
"network.trr.uri").value;
if (!currentURI) {
currentURI = Preferences.get(
"network.trr.default_provider_uri").value;
}
let menu = document.getElementById(`${mode}ResolverChoices`);
let selectedIndex = currentURI
? resolvers.findIndex(r => r.uri == currentURI)
: 0;
if (selectedIndex == -1) {
// select the last "Custom" item
selectedIndex = menu.itemCount - 1;
}
menu.selectedIndex = selectedIndex;
let customInput = document.getElementById(`${mode}InputField`);
customInput.hidden = menu.value !=
"custom";
},
populateDoHResolverList(mode) {
let resolvers =
this.dnsOverHttpsResolvers;
let defaultURI = DoHConfigController.currentConfig.fallbackProviderURI;
let menu = document.getElementById(`${mode}ResolverChoices`);
// populate the DNS-Over-HTTPS resolver list
menu.removeAllItems();
for (let resolver of resolvers) {
let item = menu.appendItem(undefined, resolver.uri);
if (resolver.uri == defaultURI) {
document.l10n.setAttributes(
item,
"connection-dns-over-https-url-item-default",
{
name: resolver.UIName || resolver.uri,
}
);
}
else {
item.label = resolver.UIName || resolver.uri;
}
}
let lastItem = menu.appendItem(undefined,
"custom");
document.l10n.setAttributes(
lastItem,
"connection-dns-over-https-url-custom"
);
// set initial selection in the resolver provider picker
this.updateDoHResolverList(mode);
let customInput = document.getElementById(`${mode}InputField`);
function updateURIPref() {
if (customInput.value ==
"") {
// Setting the pref to empty string will make it have the default
// pref value which makes us fallback to using the default TRR
// resolver in network.trr.default_provider_uri.
// If the input is empty we set it to "(space)" which is essentially
// the same.
Services.prefs.setStringPref(
"network.trr.uri",
" ");
}
else {
Services.prefs.setStringPref(
"network.trr.uri", customInput.value);
}
}
menu.addEventListener(
"command", () => {
if (menu.value ==
"custom") {
customInput.hidden =
false;
updateURIPref();
}
else {
customInput.hidden =
true;
Services.prefs.setStringPref(
"network.trr.uri", menu.value);
}
Glean.securityDohSettings.providerChoiceValue.record({
value: menu.value,
});
// Update other menu too.
let otherMode = mode ==
"dohEnabled" ?
"dohStrict" :
"dohEnabled";
let otherMenu = document.getElementById(`${otherMode}ResolverChoices`);
let otherInput = document.getElementById(`${otherMode}InputField`);
otherMenu.value = menu.value;
otherInput.hidden = otherMenu.value !=
"custom";
});
// Change the URL when you press ENTER in the input field it or loses focus
customInput.addEventListener(
"change", () => {
updateURIPref();
});
},
async updateDoHStatus() {
let trrURI = Services.dns.currentTrrURI;
let hostname =
"";
try {
hostname =
new URL(trrURI).hostname;
}
catch (e) {
hostname = await document.l10n.formatValue(
"preferences-doh-bad-url");
}
let steering = document.getElementById(
"dohSteeringStatus");
steering.hidden =
true;
let dohResolver = document.getElementById(
"dohResolver");
dohResolver.hidden =
true;
let status = document.getElementById(
"dohStatus");
async
function setStatus(localizedStringName, options) {
let opts = options || {};
let statusString = await document.l10n.formatValue(
localizedStringName,
opts
);
document.l10n.setAttributes(status,
"preferences-doh-status", {
status: statusString,
});
}
function computeStatus() {
let mode = Services.dns.currentTrrMode;
if (
mode == Ci.nsIDNSService.MODE_TRRFIRST ||
mode == Ci.nsIDNSService.MODE_TRRONLY
) {
if (lazy.gParentalControlsService.parentalControlsEnabled) {
return "preferences-doh-status-not-active";
}
let confirmationState = Services.dns.currentTrrConfirmationState;
switch (confirmationState) {
case Ci.nsIDNSService.CONFIRM_TRYING_OK:
case Ci.nsIDNSService.CONFIRM_OK:
case Ci.nsIDNSService.CONFIRM_DISABLED:
return "preferences-doh-status-active";
default:
return "preferences-doh-status-not-active";
}
}
return "preferences-doh-status-disabled";
}
let errReason =
"";
let confirmationStatus = Services.dns.lastConfirmationStatus;
let mode = Services.dns.currentTrrMode;
if (
(mode == Ci.nsIDNSService.MODE_TRRFIRST ||
mode == Ci.nsIDNSService.MODE_TRRONLY) &&
lazy.gParentalControlsService.parentalControlsEnabled
) {
errReason = Services.dns.getTRRSkipReasonName(
Ci.nsITRRSkipReason.TRR_PARENTAL_CONTROL
);
}
else if (confirmationStatus != Cr.NS_OK) {
errReason = ChromeUtils.getXPCOMErrorName(confirmationStatus);
}
else {
errReason = Services.dns.getTRRSkipReasonName(
Services.dns.lastConfirmationSkipReason
);
}
let statusLabel = computeStatus();
// setStatus will format and set the statusLabel asynchronously.
setStatus(statusLabel, { reason: errReason });
dohResolver.hidden = statusLabel ==
"preferences-doh-status-disabled";
let statusLearnMore = document.getElementById(
"dohStatusLearnMore");
statusLearnMore.hidden = statusLabel !=
"preferences-doh-status-not-active";
// No need to set the resolver name since we're not going to show it.
if (statusLabel ==
"preferences-doh-status-disabled") {
return;
}
function nameOrDomain() {
for (let resolver of DoHConfigController.currentConfig.providerList) {
if (resolver.uri == trrURI) {
return resolver.UIName || hostname || trrURI;
}
}
// Also check if this is a steering provider.
for (let resolver of DoHConfigController.currentConfig.providerSteering
.providerList) {
if (resolver.uri == trrURI) {
steering.hidden =
false;
return resolver.UIName || hostname || trrURI;
}
}
return hostname;
}
let resolverNameOrDomain = nameOrDomain();
document.l10n.setAttributes(dohResolver,
"preferences-doh-resolver", {
name: resolverNameOrDomain,
});
},
highlightDoHCategoryAndUpdateStatus() {
let value = Preferences.get(
"network.trr.mode").value;
let defaultOption = document.getElementById(
"dohOptionDefault");
let enabledOption = document.getElementById(
"dohOptionEnabled");
let strictOption = document.getElementById(
"dohOptionStrict");
let offOption = document.getElementById(
"dohOptionOff");
defaultOption.classList.remove(
"selected");
enabledOption.classList.remove(
"selected");
strictOption.classList.remove(
"selected");
offOption.classList.remove(
"selected");
switch (value) {
case Ci.nsIDNSService.MODE_NATIVEONLY:
defaultOption.classList.add(
"selected");
break;
case Ci.nsIDNSService.MODE_TRRFIRST:
enabledOption.classList.add(
"selected");
break;
case Ci.nsIDNSService.MODE_TRRONLY:
strictOption.classList.add(
"selected");
break;
case Ci.nsIDNSService.MODE_TRROFF:
offOption.classList.add(
"selected");
break;
default:
// The pref is set to a random value.
// This shouldn't happen, but let's make sure off is selected.
offOption.classList.add(
"selected");
document.getElementById(
"dohCategoryRadioGroup").selectedIndex = 3;
break;
}
// When the mode is set to 0 we need to clear the URI so
// doh-rollout can kick in.
if (value == Ci.nsIDNSService.MODE_NATIVEONLY) {
Services.prefs.clearUserPref(
"network.trr.uri");
Services.prefs.clearUserPref(
"doh-rollout.disable-heuristics");
}
// Bug 1861285
// When the mode is set to 2 or 3, we need to check if network.trr.uri is a empty string.
// In this case, we need to update network.trr.uri to default to fallbackProviderURI.
// This occurs when the mode is previously set to 0 (Default Protection).
if (
value == Ci.nsIDNSService.MODE_TRRFIRST ||
value == Ci.nsIDNSService.MODE_TRRONLY
) {
if (!Services.prefs.getStringPref(
"network.trr.uri")) {
Services.prefs.setStringPref(
"network.trr.uri",
DoHConfigController.currentConfig.fallbackProviderURI
);
}
}
// Bug 1900672
// When the mode is set to 5, clear the pref to ensure that
// network.trr.uri is set to fallbackProviderURIwhen the mode is set to 2 or 3 afterwards
if (value == Ci.nsIDNSService.MODE_TRROFF) {
Services.prefs.clearUserPref(
"network.trr.uri");
}
gPrivacyPane.updateDoHStatus();
},
/**
* Init DoH corresponding prefs
*/
initDoH() {
setEventListener(
"dohDefaultArrow",
"command",
this.toggleExpansion);
setEventListener(
"dohEnabledArrow",
"command",
this.toggleExpansion);
setEventListener(
"dohStrictArrow",
"command",
this.toggleExpansion);
function modeButtonPressed(e) {
// Clicking the active mode again should not generate another event
if (
parseInt(e.target.value) == Preferences.get(
"network.trr.mode").value
) {
return;
}
Glean.securityDohSettings.modeChangedButton.record({
value: e.target.id,
});
}
setEventListener(
"dohDefaultRadio",
"command", modeButtonPressed);
setEventListener(
"dohEnabledRadio",
"command", modeButtonPressed);
setEventListener(
"dohStrictRadio",
"command", modeButtonPressed);
setEventListener(
"dohOffRadio",
"command", modeButtonPressed);
function warnCheckboxClicked(e) {
Glean.securityDohSettings.warnCheckboxCheckbox.record({
value: e.target.checked,
});
}
setEventListener(
"dohWarnCheckbox1",
"command", warnCheckboxClicked);
setEventListener(
"dohWarnCheckbox2",
"command", warnCheckboxClicked);
this.populateDoHResolverList(
"dohEnabled");
this.populateDoHResolverList(
"dohStrict");
Preferences.get(
"network.trr.uri").on(
"change", () => {
gPrivacyPane.updateDoHResolverList(
"dohEnabled");
gPrivacyPane.updateDoHResolverList(
"dohStrict");
gPrivacyPane.updateDoHStatus();
});
// Update status box and hightlightling when the pref changes
Preferences.get(
"network.trr.mode").on(
"change",
gPrivacyPane.highlightDoHCategoryAndUpdateStatus
);
this.highlightDoHCategoryAndUpdateStatus();
Services.obs.addObserver(
this,
"network:trr-uri-changed");
Services.obs.addObserver(
this,
"network:trr-mode-changed");
Services.obs.addObserver(
this,
"network:trr-confirmation");
let unload = () => {
Services.obs.removeObserver(
this,
"network:trr-uri-changed");
Services.obs.removeObserver(
this,
"network:trr-mode-changed");
Services.obs.removeObserver(
this,
"network:trr-confirmation");
};
window.addEventListener(
"unload", unload, { once:
true });
if (Preferences.get(
"network.trr_ui.show_fallback_warning_option").value) {
document.getElementById(
"dohWarningBox1").hidden =
false;
document.getElementById(
"dohWarningBox2").hidden =
false;
}
let uriPref = Services.prefs.getStringPref(
"network.trr.uri");
// If the value isn't one of the providers, we need to update the
// custom_uri pref to make sure the input box contains the correct URL.
if (uriPref && !
this.dnsOverHttpsResolvers.some(e => e.uri == uriPref)) {
Services.prefs.setStringPref(
"network.trr.custom_uri",
Services.prefs.getStringPref(
"network.trr.uri")
);
}
if (Services.prefs.prefIsLocked(
"network.trr.mode")) {
document.getElementById(
"dohCategoryRadioGroup").disabled =
true;
Services.prefs.setStringPref(
"network.trr.custom_uri", uriPref);
}
},
initWebAuthn() {
document.getElementById(
"openWindowsPasskeySettings").hidden =
!Services.prefs.getBoolPref(
"security.webauthn.show_ms_settings_link",
true
);
},
/**
* Sets up the UI for the number of days of history to keep, and updates the
* label of the "Clear Now..." button.
*/
init() {
this._updateSanitizeSettingsButton();
this.initDeleteOnCloseBox();
this.syncSanitizationPrefsWithDeleteOnClose();
this.initializeHistoryMode();
this.updateHistoryModePane();
this.updatePrivacyMicroControls();
this.initAutoStartPrivateBrowsingReverter();
/* Initialize Content Blocking */
this.initContentBlocking();
this._showCustomBlockList();
this.trackingProtectionReadPrefs();
this.fingerprintingProtectionReadPrefs();
this.networkCookieBehaviorReadPrefs();
this._initTrackingProtectionExtensionControl();
this._initThirdPartyCertsToggle();
Preferences.get(
"privacy.trackingprotection.enabled").on(
"change",
gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane)
);
Preferences.get(
"privacy.trackingprotection.pbmode.enabled").on(
"change",
gPrivacyPane.trackingProtectionReadPrefs.bind(gPrivacyPane)
);
// Watch all of the prefs that the new Cookies & Site Data UI depends on
Preferences.get(
"network.cookie.cookieBehavior").on(
"change",
gPrivacyPane.networkCookieBehaviorReadPrefs.bind(gPrivacyPane)
);
Preferences.get(
"browser.privatebrowsing.autostart").on(
"change",
gPrivacyPane.networkCookieBehaviorReadPrefs.bind(gPrivacyPane)
);
Preferences.get(
"privacy.firstparty.isolate").on(
"change",
gPrivacyPane.networkCookieBehaviorReadPrefs.bind(gPrivacyPane)
);
Preferences.get(
"privacy.fingerprintingProtection").on(
"change",
gPrivacyPane.fingerprintingProtectionReadPrefs.bind(gPrivacyPane)
);
Preferences.get(
"privacy.fingerprintingProtection.pbmode").on(
"change",
gPrivacyPane.fingerprintingProtectionReadPrefs.bind(gPrivacyPane)
);
setEventListener(
"trackingProtectionExceptions",
"command",
gPrivacyPane.showTrackingProtectionExceptions
);
Preferences.get(
"privacy.sanitize.sanitizeOnShutdown").on(
"change",
gPrivacyPane._updateSanitizeSettingsButton.bind(gPrivacyPane)
);
Preferences.get(
"browser.privatebrowsing.autostart").on(
"change",
gPrivacyPane.updatePrivacyMicroControls.bind(gPrivacyPane)
);
setEventListener(
"historyMode",
"command",
function () {
gPrivacyPane.updateHistoryModePane();
gPrivacyPane.updateHistoryModePrefs();
gPrivacyPane.updatePrivacyMicroControls();
gPrivacyPane.updateAutostart();
});
setEventListener(
"clearHistoryButton",
"command",
function () {
let historyMode = document.getElementById(
"historyMode");
// Select "everything" in the clear history dialog if the
// user has set their history mode to never remember history.
gPrivacyPane.clearPrivateDataNow(historyMode.value ==
"dontremember");
});
setEventListener(
"privateBrowsingAutoStart",
"command",
gPrivacyPane.updateAutostart
);
setEventListener(
"cookieExceptions",
"command",
gPrivacyPane.showCookieExceptions
);
setEventListener(
"httpsOnlyExceptionButton",
"command",
gPrivacyPane.showHttpsOnlyModeExceptions
);
setEventListener(
"dohExceptionsButton",
"command",
gPrivacyPane.showDoHExceptions
);
setEventListener(
"clearDataSettings",
"command",
gPrivacyPane.showClearPrivateDataSettings
);
setEventListener(
"passwordExceptions",
"command",
gPrivacyPane.showPasswordExceptions
);
setEventListener(
"useMasterPassword",
"command",
gPrivacyPane.updateMasterPasswordButton
);
setEventListener(
"changeMasterPassword",
"command",
gPrivacyPane.changeMasterPassword
);
setEventListener(
"showPasswords",
"command", gPrivacyPane.showPasswords);
setEventListener(
"addonExceptions",
"command",
gPrivacyPane.showAddonExceptions
);
setEventListener(
"viewCertificatesButton",
"command",
gPrivacyPane.showCertificates
);
setEventListener(
"viewSecurityDevicesButton",
"command",
gPrivacyPane.showSecurityDevices
);
this._pane = document.getElementById(
"panePrivacy");
this._initGlobalPrivacyControlUI();
this._initPasswordGenerationUI();
this._initRelayIntegrationUI();
this._initMasterPasswordUI();
this._initOSAuthentication();
this.initListenersForExtensionControllingPasswordManager();
this._initSafeBrowsing();
setEventListener(
"autoplaySettingsButton",
"command",
gPrivacyPane.showAutoplayMediaExceptions
);
setEventListener(
"notificationSettingsButton",
"command",
gPrivacyPane.showNotificationExceptions
);
setEventListener(
"locationSettingsButton",
"command",
gPrivacyPane.showLocationExceptions
);
setEventListener(
"xrSettingsButton",
"command",
gPrivacyPane.showXRExceptions
);
setEventListener(
"cameraSettingsButton",
"command",
gPrivacyPane.showCameraExceptions
);
setEventListener(
"microphoneSettingsButton",
"command",
gPrivacyPane.showMicrophoneExceptions
);
document.getElementById(
"speakerSettingsRow").hidden =
!Services.prefs.getBoolPref(
"media.setsinkid.enabled",
false);
setEventListener(
"speakerSettingsButton",
"command",
gPrivacyPane.showSpeakerExceptions
);
setEventListener(
"popupPolicyButton",
"command",
gPrivacyPane.showPopupExceptions
);
setEventListener(
"notificationsDoNotDisturb",
"command",
gPrivacyPane.toggleDoNotDisturbNotifications
);
setSyncFromPrefListener(
"contentBlockingBlockCookiesCheckbox", () =>
this.readBlockCookies()
);
setSyncToPrefListener(
"contentBlockingBlockCookiesCheckbox", () =>
this.writeBlockCookies()
);
setSyncFromPrefListener(
"blockCookiesMenu", () =>
this.readBlockCookiesFrom()
);
setSyncToPrefListener(
"blockCookiesMenu", () =>
this.writeBlockCookiesFrom()
);
setSyncFromPrefListener(
"savePasswords", () =>
this.readSavePasswords());
let microControlHandler = el =>
this.ensurePrivacyMicroControlUncheckedWhenDisabled(el);
setSyncFromPrefListener(
"rememberHistory", microControlHandler);
setSyncFromPrefListener(
"rememberForms", microControlHandler);
setSyncFromPrefListener(
"alwaysClear", microControlHandler);
setSyncFromPrefListener(
"popupPolicy", () =>
this.updateButtons(
"popupPolicyButton",
"dom.disable_open_during_load")
);
setSyncFromPrefListener(
"warnAddonInstall", () =>
this.readWarnAddonInstall()
);
setSyncFromPrefListener(
"enableOCSP", () =>
this.readEnableOCSP());
setSyncToPrefListener(
"enableOCSP", () =>
this.writeEnableOCSP());
if (AlertsServiceDND) {
let notificationsDoNotDisturbBox = document.getElementById(
"notificationsDoNotDisturbBox"
);
notificationsDoNotDisturbBox.removeAttribute(
"hidden");
let checkbox = document.getElementById(
"notificationsDoNotDisturb");
document.l10n.setAttributes(checkbox,
"permissions-notification-pause");
if (AlertsServiceDND.manualDoNotDisturb) {
let notificationsDoNotDisturb = document.getElementById(
"notificationsDoNotDisturb"
);
notificationsDoNotDisturb.setAttribute(
"checked",
true);
}
}
let onNimbus = () =>
this._updateFirefoxSuggestToggle();
NimbusFeatures.urlbar.onUpdate(onNimbus);
this._updateFirefoxSuggestToggle(
true);
window.addEventListener(
"unload", () => {
NimbusFeatures.urlbar.offUpdate(onNimbus);
});
this.initSiteDataControls();
setEventListener(
"clearSiteDataButton",
"command",
gPrivacyPane.clearSiteData
);
setEventListener(
"siteDataSettings",
"command",
gPrivacyPane.showSiteDataSettings
);
this.initCookieBannerHandling();
this.initDataCollection();
if (AppConstants.MOZ_DATA_REPORTING) {
if (AppConstants.MOZ_CRASHREPORTER) {
this.initSubmitCrashes();
}
this.initSubmitHealthReport();
setEventListener(
"submitHealthReportBox",
"command",
gPrivacyPane.updateSubmitHealthReport
);
if (AppConstants.MOZ_NORMANDY) {
this.initOptOutStudyCheckbox();
}
this.initAddonRecommendationsCheckbox();
this.initPrivateAttributionCheckbox();
}
let signonBundle = document.getElementById(
"signonBundle");
let pkiBundle = document.getElementById(
"pkiBundle");
appendSearchKeywords(
"showPasswords", [
signonBundle.getString(
"loginsDescriptionAll2"),
]);
appendSearchKeywords(
"viewSecurityDevicesButton", [
pkiBundle.getString(
"enable_fips"),
]);
if (!PrivateBrowsingUtils.enabled) {
document.getElementById(
"privateBrowsingAutoStart").hidden =
true;
document.querySelector(
"menuitem[value='dontremember']").hidden =
true;
}
let privateBrowsingPref = Preferences.get(
"browser.privatebrowsing.autostart"
);
if (privateBrowsingPref.locked) {
// If permanent private browsing mode is locked to off,
// disable the "Never Remember History" option
document.querySelector(
"menuitem[value='dontremember']").disabled =
!privateBrowsingPref.value;
// If we're locked in permanent private browsing mode,
// disable the dropdown menu completely
document.getElementById(
"historyMode").disabled =
privateBrowsingPref.value;
}
/* init HTTPS-Only mode */
this.initHttpsOnly();
this.initDoH();
this.initWebAuthn();
// Notify observers that the UI is now ready
Services.obs.notifyObservers(window,
"privacy-pane-loaded");
},
initSiteDataControls() {
Services.obs.addObserver(
this,
"sitedatamanager:sites-updated");
Services.obs.addObserver(
this,
"sitedatamanager:updating-sites");
let unload = () => {
window.removeEventListener(
"unload", unload);
Services.obs.removeObserver(
this,
"sitedatamanager:sites-updated");
Services.obs.removeObserver(
this,
"sitedatamanager:updating-sites");
};
window.addEventListener(
"unload", unload);
SiteDataManager.updateSites();
},
// CONTENT BLOCKING
/**
* Initializes the content blocking section.
*/
initContentBlocking() {
setEventListener(
"contentBlockingTrackingProtectionCheckbox",
"command",
this.trackingProtectionWritePrefs
);
setEventListener(
"contentBlockingTrackingProtectionCheckbox",
"command",
this._updateTrackingProtectionUI
);
setEventListener(
"contentBlockingCryptominersCheckbox",
"command",
this.updateCryptominingLists
);
setEventListener(
"contentBlockingFingerprintersCheckbox",
"command",
this.updateFingerprintingLists
);
setEventListener(
"trackingProtectionMenu",
"command",
this.trackingProtectionWritePrefs
);
setEventListener(
"contentBlockingFingerprintingProtectionCheckbox",
"command",
e => {
const extra = { checked: e.target.checked };
Glean.privacyUiFppClick.checkbox.record(extra);
this.fingerprintingProtectionWritePrefs();
}
);
setEventListener(
"fingerprintingProtectionMenu",
"command", e => {
const extra = { value: e.target.value };
Glean.privacyUiFppClick.menu.record(extra);
this.fingerprintingProtectionWritePrefs();
});
setEventListener(
"standardArrow",
"command",
this.toggleExpansion);
setEventListener(
"strictArrow",
"command",
this.toggleExpansion);
setEventListener(
"customArrow",
"command",
this.toggleExpansion);
Preferences.get(
"network.cookie.cookieBehavior").on(
"change",
gPrivacyPane.readBlockCookies.bind(gPrivacyPane)
);
Preferences.get(
"browser.contentblocking.category").on(
"change",
gPrivacyPane.highlightCBCategory
);
// If any relevant content blocking pref changes, show a warning that the changes will
// not be implemented until they refresh their tabs.
for (let pref of CONTENT_BLOCKING_PREFS) {
Preferences.get(pref).on(
"change", gPrivacyPane.maybeNotifyUserToReload);
// If the value changes, run populateCategoryContents, since that change might have been
// triggered by a default value changing in the standard category.
Preferences.get(pref).on(
"change", gPrivacyPane.populateCategoryContents);
}
Preferences.get(
"urlclassifier.trackingTable").on(
"change",
gPrivacyPane.maybeNotifyUserToReload
);
for (let button of document.querySelectorAll(
".reload-tabs-button")) {
button.addEventListener(
"command", gPrivacyPane.reloadAllOtherTabs);
}
let cryptoMinersOption = document.getElementById(
"contentBlockingCryptominersOption"
);
let fingerprintersOption = document.getElementById(
"contentBlockingFingerprintersOption"
);
let trackingAndIsolateOption = document.querySelector(
"#blockCookiesMenu menuitem[value='trackers-plus-isolate']"
);
cryptoMinersOption.hidden = !Services.prefs.getBoolPref(
"browser.contentblocking.cryptomining.preferences.ui.enabled"
);
fingerprintersOption.hidden = !Services.prefs.getBoolPref(
"browser.contentblocking.fingerprinting.preferences.ui.enabled"
);
let updateTrackingAndIsolateOption = () => {
trackingAndIsolateOption.hidden =
!Services.prefs.getBoolPref(
"browser.contentblocking.reject-and-isolate-cookies.preferences.ui.enabled",
false
) || gIsFirstPartyIsolated;
};
Preferences.get(
"privacy.firstparty.isolate").on(
"change",
updateTrackingAndIsolateOption
);
updateTrackingAndIsolateOption();
Preferences.get(
"browser.contentblocking.features.strict").on(
"change",
this.populateCategoryContents
);
this.populateCategoryContents();
this.highlightCBCategory();
this.readBlockCookies();
// Toggles the text "Cross-site and social media trackers" based on the
// social tracking pref. If the pref is false, the text reads
// "Cross-site trackers".
const STP_COOKIES_PREF =
"privacy.socialtracking.block_cookies.enabled";
if (Services.prefs.getBoolPref(STP_COOKIES_PREF)) {
let contentBlockOptionSocialMedia = document.getElementById(
"blockCookiesSocialMedia"
);
document.l10n.setAttributes(
contentBlockOptionSocialMedia,
"sitedata-option-block-cross-site-tracking-cookies"
);
}
Preferences.get(
"privacy.resistFingerprinting").on(
"change",
setUpContentBlockingWarnings
);
Preferences.get(
"privacy.resistFingerprinting.pbmode").on(
"change",
setUpContentBlockingWarnings
);
setUpContentBlockingWarnings();
initTCPStandardSection();
},
populateCategoryContents() {
for (let type of [
"strict",
"standard"]) {
let rulesArray = [];
let selector;
if (type ==
"strict") {
selector =
"#contentBlockingOptionStrict";
rulesArray = Services.prefs
.getStringPref(
"browser.contentblocking.features.strict")
.split(
",");
if (gIsFirstPartyIsolated) {
let idx = rulesArray.indexOf(
"cookieBehavior5");
if (idx != -1) {
rulesArray[idx] =
"cookieBehavior4";
}
}
}
else {
selector =
"#contentBlockingOptionStandard";
// In standard show/hide UI items based on the default values of the relevant prefs.
let defaults = Services.prefs.getDefaultBranch(
"");
let cookieBehavior = defaults.getIntPref(
"network.cookie.cookieBehavior"
);
switch (cookieBehavior) {
case Ci.nsICookieService.BEHAVIOR_ACCEPT:
rulesArray.push(
"cookieBehavior0");
break;
case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
rulesArray.push(
"cookieBehavior1");
break;
case Ci.nsICookieService.BEHAVIOR_REJECT:
rulesArray.push(
"cookieBehavior2");
break;
case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
rulesArray.push(
"cookieBehavior3");
break;
case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
rulesArray.push(
"cookieBehavior4");
break;
case BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN:
rulesArray.push(
gIsFirstPartyIsolated ?
"cookieBehavior4" :
"cookieBehavior5"
);
break;
}
let cookieBehaviorPBM = defaults.getIntPref(
"network.cookie.cookieBehavior.pbmode"
);
switch (cookieBehaviorPBM) {
case Ci.nsICookieService.BEHAVIOR_ACCEPT:
rulesArray.push(
"cookieBehaviorPBM0");
break;
case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
rulesArray.push(
"cookieBehaviorPBM1");
break;
case Ci.nsICookieService.BEHAVIOR_REJECT:
rulesArray.push(
"cookieBehaviorPBM2");
break;
case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
rulesArray.push(
"cookieBehaviorPBM3");
break;
case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
rulesArray.push(
"cookieBehaviorPBM4");
break;
case BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN:
rulesArray.push(
gIsFirstPartyIsolated
?
"cookieBehaviorPBM4"
:
"cookieBehaviorPBM5"
);
break;
}
rulesArray.push(
defaults.getBoolPref(
"privacy.trackingprotection.cryptomining.enabled"
)
?
"cm"
:
"-cm"
);
rulesArray.push(
defaults.getBoolPref(
"privacy.trackingprotection.fingerprinting.enabled"
)
?
"fp"
:
"-fp"
);
rulesArray.push(
Services.prefs.getBoolPref(
"privacy.socialtracking.block_cookies.enabled"
)
?
"stp"
:
"-stp"
);
rulesArray.push(
defaults.getBoolPref(
"privacy.trackingprotection.enabled")
?
"tp"
:
"-tp"
);
rulesArray.push(
defaults.getBoolPref(
"privacy.trackingprotection.pbmode.enabled")
?
"tpPrivate"
:
"-tpPrivate"
);
}
// Hide all cookie options first, until we learn which one should be showing.
document.querySelector(selector +
" .all-cookies-option").hidden =
true;
document.querySelector(selector +
" .unvisited-cookies-option").hidden =
true;
document.querySelector(selector +
" .cross-site-cookies-option").hidden =
true;
document.querySelector(
selector +
" .third-party-tracking-cookies-option"
).hidden =
true;
document.querySelector(
selector +
" .all-third-party-cookies-private-windows-option"
).hidden =
true;
document.querySelector(
selector +
" .all-third-party-cookies-option"
).hidden =
true;
document.querySelector(selector +
" .social-media-option").hidden =
true;
for (let item of rulesArray) {
// Note "cookieBehavior0", will result in no UI changes, so is not listed here.
switch (item) {
case "tp":
document.querySelector(selector +
" .trackers-option").hidden =
false;
break;
case "-tp":
document.querySelector(selector +
" .trackers-option").hidden =
true;
break;
case "tpPrivate":
document.querySelector(selector +
" .pb-trackers-option").hidden =
false;
break;
case "-tpPrivate":
document.querySelector(selector +
" .pb-trackers-option").hidden =
true;
break;
case "fp":
document.querySelector(
selector +
" .fingerprinters-option"
).hidden =
false;
break;
case "-fp":
document.querySelector(
selector +
" .fingerprinters-option"
).hidden =
true;
break;
case "cm":
document.querySelector(selector +
" .cryptominers-option").hidden =
false;
break;
case "-cm":
document.querySelector(selector +
" .cryptominers-option").hidden =
true;
break;
case "stp": {
// Store social tracking cookies pref
const STP_COOKIES_PREF =
"privacy.socialtracking.block_cookies.enabled";
if (Services.prefs.getBoolPref(STP_COOKIES_PREF)) {
document.querySelector(
selector +
" .social-media-option"
).hidden =
false;
}
break;
}
case "-stp":
// Store social tracking cookies pref
document.querySelector(selector +
" .social-media-option").hidden =
true;
break;
case "cookieBehavior1":
document.querySelector(
selector +
" .all-third-party-cookies-option"
).hidden =
false;
break;
case "cookieBehavior2":
document.querySelector(selector +
" .all-cookies-option").hidden =
false;
break;
case "cookieBehavior3":
document.querySelector(
selector +
" .unvisited-cookies-option"
).hidden =
false;
break;
case "cookieBehavior4":
document.querySelector(
selector +
" .third-party-tracking-cookies-option"
).hidden =
false;
break;
case "cookieBehavior5":
document.querySelector(
selector +
" .cross-site-cookies-option"
).hidden =
false;
break;
case "cookieBehaviorPBM5":
// We only need to show the cookie option for private windows if the
// cookieBehaviors are different between regular windows and private
// windows.
if (!rulesArray.includes(
"cookieBehavior5")) {
document.querySelector(
selector +
" .all-third-party-cookies-private-windows-option"
).hidden =
false;
}
break;
}
}
// Hide the "tracking protection in private browsing" list item
// if the "tracking protection enabled in all windows" list item is showing.
if (!document.querySelector(selector +
" .trackers-option").hidden) {
document.querySelector(selector +
" .pb-trackers-option").hidden =
true;
}
}
},
highlightCBCategory() {
let value = Preferences.get(
"browser.contentblocking.category").value;
let standardEl = document.getElementById(
"contentBlockingOptionStandard");
let strictEl = document.getElementById(
"contentBlockingOptionStrict");
let customEl = document.getElementById(
"contentBlockingOptionCustom");
standardEl.classList.remove(
"selected");
strictEl.classList.remove(
"selected");
customEl.classList.remove(
"selected");
switch (value) {
case "strict":
strictEl.classList.add(
"selected");
break;
case "custom":
customEl.classList.add(
"selected");
break;
case "standard":
/* fall through */
default:
standardEl.classList.add(
"selected");
break;
}
},
updateCryptominingLists() {
let listPrefs = [
"urlclassifier.features.cryptomining.blacklistTables",
"urlclassifier.features.cryptomining.whitelistTables",
];
let listValue = listPrefs
.map(l => Services.prefs.getStringPref(l))
.join(
",");
listManager.forceUpdates(listValue);
},
updateFingerprintingLists() {
let listPrefs = [
"urlclassifier.features.fingerprinting.blacklistTables",
"urlclassifier.features.fingerprinting.whitelistTables",
];
let listValue = listPrefs
.map(l => Services.prefs.getStringPref(l))
.join(
",");
listManager.forceUpdates(listValue);
},
// TRACKING PROTECTION MODE
/**
* Selects the right item of the Tracking Protection menulist and checkbox.
*/
trackingProtectionReadPrefs() {
let enabledPref = Preferences.get(
"privacy.trackingprotection.enabled");
let pbmPref = Preferences.get(
"privacy.trackingprotection.pbmode.enabled");
let tpMenu = document.getElementById(
"trackingProtectionMenu");
let tpCheckbox = document.getElementById(
"contentBlockingTrackingProtectionCheckbox"
);
this._updateTrackingProtectionUI();
// Global enable takes precedence over enabled in Private Browsing.
if (enabledPref.value) {
tpMenu.value =
"always";
tpCheckbox.checked =
true;
}
else if (pbmPref.value) {
tpMenu.value =
"private";
tpCheckbox.checked =
true;
}
else {
tpMenu.value =
"never";
tpCheckbox.checked =
false;
}
},
/**
* Selects the right item of the Fingerprinting Protection menulist and
* checkbox.
*/
fingerprintingProtectionReadPrefs() {
let enabledPref = Preferences.get(
"privacy.fingerprintingProtection");
let pbmPref = Preferences.get(
"privacy.fingerprintingProtection.pbmode");
let fppMenu = document.getElementById(
"fingerprintingProtectionMenu");
let fppCheckbox = document.getElementById(
"contentBlockingFingerprintingProtectionCheckbox"
);
// Global enable takes precedence over enabled in Private Browsing.
if (enabledPref.value) {
fppMenu.value =
"always";
fppCheckbox.checked =
true;
}
else if (pbmPref.value) {
fppMenu.value =
"private";
fppCheckbox.checked =
true;
}
else {
fppMenu.value =
"never";
fppCheckbox.checked =
false;
}
fppMenu.disabled = !fppCheckbox.checked;
},
/**
* Selects the right items of the new Cookies & Site Data UI.
*/
networkCookieBehaviorReadPrefs() {
let behavior = Services.cookies.getCookieBehavior(
false);
let blockCookiesMenu = document.getElementById(
"blockCookiesMenu");
let deleteOnCloseCheckbox = document.getElementById(
"deleteOnClose");
let deleteOnCloseNote = document.getElementById(
"deleteOnCloseNote");
let blockCookies = behavior != Ci.nsICookieService.BEHAVIOR_ACCEPT;
let cookieBehaviorLocked = Services.prefs.prefIsLocked(
"network.cookie.cookieBehavior"
);
let blockCookiesControlsDisabled = !blockCookies || cookieBehaviorLocked;
blockCookiesMenu.disabled = blockCookiesControlsDisabled;
let completelyBlockCookies =
behavior == Ci.nsICookieService.BEHAVIOR_REJECT;
let privateBrowsing = Preferences.get(
"browser.privatebrowsing.autostart"
).value;
deleteOnCloseCheckbox.disabled = privateBrowsing || completelyBlockCookies;
deleteOnCloseNote.hidden = !privateBrowsing;
switch (behavior) {
case Ci.nsICookieService.BEHAVIOR_ACCEPT:
break;
case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
blockCookiesMenu.value =
"all-third-parties";
break;
case Ci.nsICookieService.BEHAVIOR_REJECT:
blockCookiesMenu.value =
"always";
break;
case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
blockCookiesMenu.value =
"unvisited";
break;
case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
blockCookiesMenu.value =
"trackers";
break;
case BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN:
blockCookiesMenu.value =
"trackers-plus-isolate";
break;
}
},
/**
* Sets the pref values based on the selected item of the radiogroup.
*/
trackingProtectionWritePrefs() {
let enabledPref = Preferences.get(
"privacy.trackingprotection.enabled");
let pbmPref = Preferences.get(
"privacy.trackingprotection.pbmode.enabled");
let stpPref = Preferences.get(
"privacy.trackingprotection.socialtracking.enabled"
);
let stpCookiePref = Preferences.get(
"privacy.socialtracking.block_cookies.enabled"
);
// Currently, we don't expose the email tracking protection setting on our
// privacy UI. Instead, we use the existing tracking protection checkbox to
// control the email tracking protection.
let emailTPPref = Preferences.get(
"privacy.trackingprotection.emailtracking.enabled"
);
let emailTPPBMPref = Preferences.get(
"privacy.trackingprotection.emailtracking.pbmode.enabled"
);
let tpMenu = document.getElementById(
"trackingProtectionMenu");
let tpCheckbox = document.getElementById(
"contentBlockingTrackingProtectionCheckbox"
);
let value;
if (tpCheckbox.checked) {
if (tpMenu.value ==
"never") {
tpMenu.value =
"private";
}
value = tpMenu.value;
}
else {
tpMenu.value =
"never";
value =
"never";
}
switch (value) {
case "always":
enabledPref.value =
true;
pbmPref.value =
true;
emailTPPref.value =
true;
emailTPPBMPref.value =
true;
if (stpCookiePref.value) {
stpPref.value =
true;
}
break;
case "private":
enabledPref.value =
false;
pbmPref.value =
true;
emailTPPref.value =
false;
emailTPPBMPref.value =
true;
if (stpCookiePref.value) {
stpPref.value =
false;
}
break;
case "never":
enabledPref.value =
false;
pbmPref.value =
false;
emailTPPref.value =
false;
emailTPPBMPref.value =
false;
if (stpCookiePref.value) {
stpPref.value =
false;
}
break;
}
},
fingerprintingProtectionWritePrefs() {
let enabledPref = Preferences.get(
"privacy.fingerprintingProtection");
let pbmPref = Preferences.get(
"privacy.fingerprintingProtection.pbmode");
let fppMenu = document.getElementById(
"fingerprintingProtectionMenu");
let fppCheckbox = document.getElementById(
"contentBlockingFingerprintingProtectionCheckbox"
);
let value;
if (fppCheckbox.checked) {
if (fppMenu.value ==
"never") {
fppMenu.value =
"private";
}
value = fppMenu.value;
}
else {
fppMenu.value =
"never";
value =
"never";
}
fppMenu.disabled = !fppCheckbox.checked;
switch (value) {
case "always":
enabledPref.value =
true;
pbmPref.value =
true;
break;
case "private":
enabledPref.value =
false;
pbmPref.value =
true;
break;
case "never":
enabledPref.value =
false;
pbmPref.value =
false;
break;
}
},
toggleExpansion(e) {
let carat = e.target;
carat.classList.toggle(
"up");
carat.closest(
".privacy-detailedoption").classList.toggle(
"expanded");
carat.setAttribute(
"aria-expanded",
carat.getAttribute(
"aria-expanded") ===
"false"
);
},
// HISTORY MODE
/**
* The list of preferences which affect the initial history mode settings.
* If the auto start private browsing mode pref is active, the initial
* history mode would be set to "Don't remember anything".
* If ALL of these preferences are set to the values that correspond
* to keeping some part of history, and the auto-start
* private browsing mode is not active, the initial history mode would be
* set to "Remember everything".
* Otherwise, the initial history mode would be set to "Custom".
*
* Extensions adding their own preferences can set values here if needed.
*/
prefsForKeepingHistory: {
"places.history.enabled":
true,
// History is enabled
"browser.formfill.enable":
true,
// Form information is saved
"privacy.sanitize.sanitizeOnShutdown":
false,
// Private date is NOT cleared on shutdown
},
/**
* The list of control IDs which are dependent on the auto-start private
* browsing setting, such that in "Custom" mode they would be disabled if
* the auto-start private browsing checkbox is checked, and enabled otherwise.
*
* Extensions adding their own controls can append their IDs to this array if needed.
*/
--> --------------------
--> maximum size reached
--> --------------------