forked from mirrors/gecko-dev
Per spec, the informational description about data collection under the main Firefox Suggest checkbox should be hidden except for the "online" scenario, since only the online scenario sends data to Mozilla. We're also changing the two checkbox labels and adding another description under the sponsored checkbox. Depends on D125024 Differential Revision: https://phabricator.services.mozilla.com/D125031
2715 lines
86 KiB
JavaScript
2715 lines
86 KiB
JavaScript
/* 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 */
|
|
|
|
var { AppConstants } = ChromeUtils.import(
|
|
"resource://gre/modules/AppConstants.jsm"
|
|
);
|
|
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"DownloadUtils",
|
|
"resource://gre/modules/DownloadUtils.jsm"
|
|
);
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"LoginHelper",
|
|
"resource://gre/modules/LoginHelper.jsm"
|
|
);
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"OSKeyStore",
|
|
"resource://gre/modules/OSKeyStore.jsm"
|
|
);
|
|
ChromeUtils.defineModuleGetter(
|
|
this,
|
|
"SiteDataManager",
|
|
"resource:///modules/SiteDataManager.jsm"
|
|
);
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
NimbusFeatures: "resource://nimbus/ExperimentAPI.jsm",
|
|
UrlbarProviderQuickSuggest:
|
|
"resource:///modules/UrlbarProviderQuickSuggest.jsm",
|
|
});
|
|
XPCOMUtils.defineLazyGetter(this, "L10n", () => {
|
|
return new Localization([
|
|
"branding/brand.ftl",
|
|
"browser/preferences/preferences.ftl",
|
|
]);
|
|
});
|
|
|
|
var { PrivateBrowsingUtils } = ChromeUtils.import(
|
|
"resource://gre/modules/PrivateBrowsingUtils.jsm"
|
|
);
|
|
|
|
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",
|
|
];
|
|
|
|
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_PASSWORD_GENERATION_AVAILABLE = "signon.generation.available";
|
|
const { BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN } = Ci.nsICookieService;
|
|
|
|
const PASSWORD_MANAGER_PREF_ID = "services.passwordSavingEnabled";
|
|
const PREF_PASSWORD_MANAGER_ENABLED = "signon.rememberSignons";
|
|
|
|
XPCOMUtils.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;
|
|
}
|
|
});
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(
|
|
this,
|
|
"listManager",
|
|
"@mozilla.org/url-classifier/listmanager;1",
|
|
"nsIUrlListManager"
|
|
);
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"OS_AUTH_ENABLED",
|
|
"signon.management.page.os-auth.enabled",
|
|
true
|
|
);
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"gIsFirstPartyIsolated",
|
|
"privacy.firstparty.isolate",
|
|
false
|
|
);
|
|
|
|
XPCOMUtils.defineLazyPreferenceGetter(
|
|
this,
|
|
"gStatePartitioningMVPEnabled",
|
|
"browser.contentblocking.state-partitioning.mvp.ui.enabled",
|
|
false
|
|
);
|
|
|
|
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" },
|
|
|
|
// 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.view_cookies", type: "bool" },
|
|
{ id: "pref.privacy.disable_button.change_blocklist", 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.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", type: "bool" },
|
|
{ id: "browser.urlbar.suggest.quicksuggest.sponsored", 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.lifetimePolicy", 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" },
|
|
// Do not track
|
|
{ id: "privacy.donottrackheader.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" },
|
|
|
|
// 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" },
|
|
|
|
// 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" },
|
|
|
|
// Windows SSO
|
|
{ id: "network.http.windows-sso.enabled", 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" },
|
|
]);
|
|
}
|
|
|
|
// 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() {
|
|
if (gStatePartitioningMVPEnabled) {
|
|
let warnings = document.querySelectorAll(
|
|
".content-blocking-warning-description"
|
|
);
|
|
for (let warning of warnings) {
|
|
document.l10n.setAttributes(
|
|
warning,
|
|
"content-blocking-and-isolating-etp-warning-description-2"
|
|
);
|
|
}
|
|
document.getElementById(
|
|
"fpiIncompatibilityWarning"
|
|
).hidden = !gIsFirstPartyIsolated;
|
|
}
|
|
|
|
let links = document.querySelectorAll(".contentBlockWarningLink");
|
|
let contentBlockingWarningUrl =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"turn-off-etp-desktop";
|
|
for (let link of links) {
|
|
link.setAttribute("href", contentBlockingWarningUrl);
|
|
}
|
|
}
|
|
|
|
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(subject, topic, data) {
|
|
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);
|
|
}
|
|
});
|
|
},
|
|
|
|
syncFromHttpsOnlyPref() {
|
|
let httpsOnlyOnPref = Services.prefs.getBoolPref(
|
|
"dom.security.https_only_mode"
|
|
);
|
|
let httpsOnlyOnPBMPref = Services.prefs.getBoolPref(
|
|
"dom.security.https_only_mode_pbm"
|
|
);
|
|
let httpsOnlyRadioGroup = document.getElementById("httpsOnlyRadioGroup");
|
|
let httpsOnlyExceptionButton = document.getElementById(
|
|
"httpsOnlyExceptionButton"
|
|
);
|
|
|
|
if (httpsOnlyOnPref) {
|
|
httpsOnlyRadioGroup.value = "enabled";
|
|
httpsOnlyExceptionButton.disabled = false;
|
|
} else if (httpsOnlyOnPBMPref) {
|
|
httpsOnlyRadioGroup.value = "privateOnly";
|
|
httpsOnlyExceptionButton.disabled = true;
|
|
} else {
|
|
httpsOnlyRadioGroup.value = "disabled";
|
|
httpsOnlyExceptionButton.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() {
|
|
let link = document.getElementById("httpsOnlyLearnMore");
|
|
let httpsOnlyURL =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"https-only-prefs";
|
|
link.setAttribute("href", httpsOnlyURL);
|
|
|
|
// 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",
|
|
"command",
|
|
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()
|
|
);
|
|
},
|
|
|
|
/**
|
|
* 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.initializeHistoryMode();
|
|
this.updateHistoryModePane();
|
|
this.updatePrivacyMicroControls();
|
|
this.initAutoStartPrivateBrowsingReverter();
|
|
|
|
/* Initialize Content Blocking */
|
|
this.initContentBlocking();
|
|
|
|
this._showCustomBlockList();
|
|
this.trackingProtectionReadPrefs();
|
|
this.networkCookieBehaviorReadPrefs();
|
|
this._initTrackingProtectionExtensionControl();
|
|
|
|
Services.telemetry.setEventRecordingEnabled("pwmgr", true);
|
|
|
|
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("network.cookie.lifetimePolicy").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)
|
|
);
|
|
|
|
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("openSearchEnginePreferences", "click", function(event) {
|
|
if (event.button == 0) {
|
|
gotoPref("search");
|
|
}
|
|
return false;
|
|
});
|
|
setEventListener(
|
|
"privateBrowsingAutoStart",
|
|
"command",
|
|
gPrivacyPane.updateAutostart
|
|
);
|
|
setEventListener(
|
|
"cookieExceptions",
|
|
"command",
|
|
gPrivacyPane.showCookieExceptions
|
|
);
|
|
setEventListener(
|
|
"httpsOnlyExceptionButton",
|
|
"command",
|
|
gPrivacyPane.showHttpsOnlyModeExceptions
|
|
);
|
|
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._initPasswordGenerationUI();
|
|
this._initMasterPasswordUI();
|
|
|
|
this.initListenersForExtensionControllingPasswordManager();
|
|
// set up the breach alerts Learn More link with the correct URL
|
|
const breachAlertsLearnMoreLink = document.getElementById(
|
|
"breachAlertsLearnMoreLink"
|
|
);
|
|
const breachAlertsLearnMoreUrl =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"lockwise-alerts";
|
|
breachAlertsLearnMoreLink.setAttribute("href", breachAlertsLearnMoreUrl);
|
|
|
|
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
|
|
);
|
|
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("deleteOnClose", () => this.readDeleteOnClose());
|
|
setSyncToPrefListener("deleteOnClose", () => this.writeDeleteOnClose());
|
|
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);
|
|
}
|
|
}
|
|
|
|
this._initAddressBar();
|
|
|
|
this.initSiteDataControls();
|
|
setEventListener(
|
|
"clearSiteDataButton",
|
|
"command",
|
|
gPrivacyPane.clearSiteData
|
|
);
|
|
setEventListener(
|
|
"siteDataSettings",
|
|
"command",
|
|
gPrivacyPane.showSiteDataSettings
|
|
);
|
|
let url =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"storage-permissions";
|
|
document.getElementById("siteDataLearnMoreLink").setAttribute("href", url);
|
|
|
|
let notificationInfoURL =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
|
|
document
|
|
.getElementById("notificationPermissionsLearnMore")
|
|
.setAttribute("href", notificationInfoURL);
|
|
|
|
if (AppConstants.platform == "win") {
|
|
let windowsSSOURL =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"windows-sso";
|
|
document
|
|
.getElementById("windowsSSOLearnMoreLink")
|
|
.setAttribute("href", windowsSSOURL);
|
|
}
|
|
|
|
if (AppConstants.MOZ_DATA_REPORTING) {
|
|
this.initDataCollection();
|
|
if (AppConstants.MOZ_CRASHREPORTER) {
|
|
this.initSubmitCrashes();
|
|
}
|
|
this.initSubmitHealthReport();
|
|
setEventListener(
|
|
"submitHealthReportBox",
|
|
"command",
|
|
gPrivacyPane.updateSubmitHealthReport
|
|
);
|
|
setEventListener(
|
|
"telemetryDataDeletionLearnMore",
|
|
"command",
|
|
gPrivacyPane.showDataDeletion
|
|
);
|
|
if (AppConstants.MOZ_NORMANDY) {
|
|
this.initOptOutStudyCheckbox();
|
|
}
|
|
this.initAddonRecommendationsCheckbox();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* init HTTPS-Only mode */
|
|
this.initHttpsOnly();
|
|
|
|
// 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("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();
|
|
|
|
let link = document.getElementById("contentBlockingLearnMore");
|
|
let contentBlockingUrl =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"enhanced-tracking-protection";
|
|
link.setAttribute("href", contentBlockingUrl);
|
|
|
|
// 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"
|
|
);
|
|
let l10nID = gStatePartitioningMVPEnabled
|
|
? "sitedata-option-block-cross-site-tracking-cookies-including-social-media"
|
|
: "sitedata-option-block-cross-site-and-social-media-trackers";
|
|
document.l10n.setAttributes(contentBlockOptionSocialMedia, l10nID);
|
|
}
|
|
if (gStatePartitioningMVPEnabled) {
|
|
let contentBlockOptionIsolate = document.getElementById(
|
|
"isolateCookiesSocialMedia"
|
|
);
|
|
document.l10n.setAttributes(
|
|
contentBlockOptionIsolate,
|
|
"sitedata-option-block-cross-site-cookies-including-social-media"
|
|
);
|
|
}
|
|
|
|
setUpContentBlockingWarnings();
|
|
},
|
|
|
|
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 + " .third-party-tracking-cookies-plus-isolate-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":
|
|
let cookieSelector = gStatePartitioningMVPEnabled
|
|
? " .cross-site-cookies-option"
|
|
: " .third-party-tracking-cookies-plus-isolate-option";
|
|
document.querySelector(selector + cookieSelector).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 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;
|
|
let cookieExpirationLocked = Services.prefs.prefIsLocked(
|
|
"network.cookie.lifetimePolicy"
|
|
);
|
|
deleteOnCloseCheckbox.disabled =
|
|
privateBrowsing || completelyBlockCookies || cookieExpirationLocked;
|
|
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"
|
|
);
|
|
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;
|
|
if (stpCookiePref.value) {
|
|
stpPref.value = true;
|
|
}
|
|
break;
|
|
case "private":
|
|
enabledPref.value = false;
|
|
pbmPref.value = true;
|
|
if (stpCookiePref.value) {
|
|
stpPref.value = false;
|
|
}
|
|
break;
|
|
case "never":
|
|
enabledPref.value = false;
|
|
pbmPref.value = false;
|
|
if (stpCookiePref.value) {
|
|
stpPref.value = false;
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
|
|
toggleExpansion(e) {
|
|
let carat = e.target;
|
|
carat.classList.toggle("up");
|
|
carat.closest(".content-blocking-category").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.
|
|
*/
|
|
dependentControls: [
|
|
"rememberHistory",
|
|
"rememberForms",
|
|
"alwaysClear",
|
|
"clearDataSettings",
|
|
],
|
|
|
|
/**
|
|
* Check whether preferences values are set to keep history
|
|
*
|
|
* @param aPrefs an array of pref names to check for
|
|
* @returns boolean true if all of the prefs are set to keep history,
|
|
* false otherwise
|
|
*/
|
|
_checkHistoryValues(aPrefs) {
|
|
for (let pref of Object.keys(aPrefs)) {
|
|
if (Preferences.get(pref).value != aPrefs[pref]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
|
|
/**
|
|
* Initialize the history mode menulist based on the privacy preferences
|
|
*/
|
|
initializeHistoryMode() {
|
|
let mode;
|
|
let getVal = aPref => Preferences.get(aPref).value;
|
|
|
|
if (getVal("privacy.history.custom")) {
|
|
mode = "custom";
|
|
} else if (this._checkHistoryValues(this.prefsForKeepingHistory)) {
|
|
if (getVal("browser.privatebrowsing.autostart")) {
|
|
mode = "dontremember";
|
|
} else {
|
|
mode = "remember";
|
|
}
|
|
} else {
|
|
mode = "custom";
|
|
}
|
|
|
|
document.getElementById("historyMode").value = mode;
|
|
},
|
|
|
|
/**
|
|
* Update the selected pane based on the history mode menulist
|
|
*/
|
|
updateHistoryModePane() {
|
|
let selectedIndex = -1;
|
|
switch (document.getElementById("historyMode").value) {
|
|
case "remember":
|
|
selectedIndex = 0;
|
|
break;
|
|
case "dontremember":
|
|
selectedIndex = 1;
|
|
break;
|
|
case "custom":
|
|
selectedIndex = 2;
|
|
break;
|
|
}
|
|
document.getElementById("historyPane").selectedIndex = selectedIndex;
|
|
Preferences.get("privacy.history.custom").value = selectedIndex == 2;
|
|
},
|
|
|
|
/**
|
|
* Update the private browsing auto-start pref and the history mode
|
|
* micro-management prefs based on the history mode menulist
|
|
*/
|
|
updateHistoryModePrefs() {
|
|
let pref = Preferences.get("browser.privatebrowsing.autostart");
|
|
switch (document.getElementById("historyMode").value) {
|
|
case "remember":
|
|
if (pref.value) {
|
|
pref.value = false;
|
|
}
|
|
|
|
// select the remember history option if needed
|
|
Preferences.get("places.history.enabled").value = true;
|
|
|
|
// select the remember forms history option
|
|
Preferences.get("browser.formfill.enable").value = true;
|
|
|
|
// select the clear on close option
|
|
Preferences.get("privacy.sanitize.sanitizeOnShutdown").value = false;
|
|
break;
|
|
case "dontremember":
|
|
if (!pref.value) {
|
|
pref.value = true;
|
|
}
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Update the privacy micro-management controls based on the
|
|
* value of the private browsing auto-start preference.
|
|
*/
|
|
updatePrivacyMicroControls() {
|
|
// Check the "Delete cookies when Firefox is closed" checkbox and disable the setting
|
|
// when we're in auto private mode (or reset it back otherwise).
|
|
document.getElementById("deleteOnClose").checked = this.readDeleteOnClose();
|
|
|
|
let clearDataSettings = document.getElementById("clearDataSettings");
|
|
|
|
if (document.getElementById("historyMode").value == "custom") {
|
|
let disabled = Preferences.get("browser.privatebrowsing.autostart").value;
|
|
this.dependentControls.forEach(aElement => {
|
|
let control = document.getElementById(aElement);
|
|
let preferenceId = control.getAttribute("preference");
|
|
if (!preferenceId) {
|
|
let dependentControlId = control.getAttribute("control");
|
|
if (dependentControlId) {
|
|
let dependentControl = document.getElementById(dependentControlId);
|
|
preferenceId = dependentControl.getAttribute("preference");
|
|
}
|
|
}
|
|
|
|
let preference = preferenceId ? Preferences.get(preferenceId) : {};
|
|
control.disabled = disabled || preference.locked;
|
|
if (control != clearDataSettings) {
|
|
this.ensurePrivacyMicroControlUncheckedWhenDisabled(control);
|
|
}
|
|
});
|
|
|
|
clearDataSettings.removeAttribute("hidden");
|
|
|
|
if (!disabled) {
|
|
// adjust the Settings button for sanitizeOnShutdown
|
|
this._updateSanitizeSettingsButton();
|
|
}
|
|
} else {
|
|
clearDataSettings.hidden = true;
|
|
}
|
|
},
|
|
|
|
ensurePrivacyMicroControlUncheckedWhenDisabled(el) {
|
|
if (Preferences.get("browser.privatebrowsing.autostart").value) {
|
|
// Set checked to false when called from updatePrivacyMicroControls
|
|
el.checked = false;
|
|
// return false for the onsyncfrompreference case:
|
|
return false;
|
|
}
|
|
return undefined; // tell preferencesBindings to assign the 'right' value.
|
|
},
|
|
|
|
// CLEAR PRIVATE DATA
|
|
|
|
/*
|
|
* Preferences:
|
|
*
|
|
* privacy.sanitize.sanitizeOnShutdown
|
|
* - true if the user's private data is cleared on startup according to the
|
|
* Clear Private Data settings, false otherwise
|
|
*/
|
|
|
|
/**
|
|
* Displays the Clear Private Data settings dialog.
|
|
*/
|
|
showClearPrivateDataSettings() {
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/sanitize.xhtml",
|
|
{ features: "resizable=no" }
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Displays a dialog from which individual parts of private data may be
|
|
* cleared.
|
|
*/
|
|
clearPrivateDataNow(aClearEverything) {
|
|
var ts = Preferences.get("privacy.sanitize.timeSpan");
|
|
var timeSpanOrig = ts.value;
|
|
|
|
if (aClearEverything) {
|
|
ts.value = 0;
|
|
}
|
|
|
|
gSubDialog.open("chrome://browser/content/sanitize.xhtml", {
|
|
features: "resizable=no",
|
|
closingCallback: () => {
|
|
// reset the timeSpan pref
|
|
if (aClearEverything) {
|
|
ts.value = timeSpanOrig;
|
|
}
|
|
|
|
Services.obs.notifyObservers(null, "clear-private-data");
|
|
},
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Enables or disables the "Settings..." button depending
|
|
* on the privacy.sanitize.sanitizeOnShutdown preference value
|
|
*/
|
|
_updateSanitizeSettingsButton() {
|
|
var settingsButton = document.getElementById("clearDataSettings");
|
|
var sanitizeOnShutdownPref = Preferences.get(
|
|
"privacy.sanitize.sanitizeOnShutdown"
|
|
);
|
|
|
|
settingsButton.disabled = !sanitizeOnShutdownPref.value;
|
|
},
|
|
|
|
toggleDoNotDisturbNotifications(event) {
|
|
AlertsServiceDND.manualDoNotDisturb = event.target.checked;
|
|
},
|
|
|
|
// PRIVATE BROWSING
|
|
|
|
/**
|
|
* Initialize the starting state for the auto-start private browsing mode pref reverter.
|
|
*/
|
|
initAutoStartPrivateBrowsingReverter() {
|
|
// We determine the mode in initializeHistoryMode, which is guaranteed to have been
|
|
// called before now, so this is up-to-date.
|
|
let mode = document.getElementById("historyMode");
|
|
this._lastMode = mode.selectedIndex;
|
|
// The value of the autostart pref, on the other hand, is gotten from Preferences,
|
|
// which updates the DOM asynchronously, so we can't rely on the DOM. Get it directly
|
|
// from the prefs.
|
|
this._lastCheckState = Preferences.get(
|
|
"browser.privatebrowsing.autostart"
|
|
).value;
|
|
},
|
|
|
|
_lastMode: null,
|
|
_lastCheckState: null,
|
|
async updateAutostart() {
|
|
let mode = document.getElementById("historyMode");
|
|
let autoStart = document.getElementById("privateBrowsingAutoStart");
|
|
let pref = Preferences.get("browser.privatebrowsing.autostart");
|
|
if (
|
|
(mode.value == "custom" && this._lastCheckState == autoStart.checked) ||
|
|
(mode.value == "remember" && !this._lastCheckState) ||
|
|
(mode.value == "dontremember" && this._lastCheckState)
|
|
) {
|
|
// These are all no-op changes, so we don't need to prompt.
|
|
this._lastMode = mode.selectedIndex;
|
|
this._lastCheckState = autoStart.hasAttribute("checked");
|
|
return;
|
|
}
|
|
|
|
if (!this._shouldPromptForRestart) {
|
|
// We're performing a revert. Just let it happen.
|
|
return;
|
|
}
|
|
|
|
let buttonIndex = await confirmRestartPrompt(
|
|
autoStart.checked,
|
|
1,
|
|
true,
|
|
false
|
|
);
|
|
if (buttonIndex == CONFIRM_RESTART_PROMPT_RESTART_NOW) {
|
|
pref.value = autoStart.hasAttribute("checked");
|
|
Services.startup.quit(
|
|
Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart
|
|
);
|
|
return;
|
|
}
|
|
|
|
this._shouldPromptForRestart = false;
|
|
|
|
if (this._lastCheckState) {
|
|
autoStart.checked = "checked";
|
|
} else {
|
|
autoStart.removeAttribute("checked");
|
|
}
|
|
pref.value = autoStart.hasAttribute("checked");
|
|
mode.selectedIndex = this._lastMode;
|
|
mode.doCommand();
|
|
|
|
this._shouldPromptForRestart = true;
|
|
},
|
|
|
|
/**
|
|
* Displays fine-grained, per-site preferences for tracking protection.
|
|
*/
|
|
showTrackingProtectionExceptions() {
|
|
let params = {
|
|
permissionType: "trackingprotection",
|
|
hideStatusColumn: true,
|
|
};
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/permissions.xhtml",
|
|
undefined,
|
|
params
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Displays the available block lists for tracking protection.
|
|
*/
|
|
showBlockLists() {
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/blocklists.xhtml"
|
|
);
|
|
},
|
|
|
|
// COOKIES AND SITE DATA
|
|
|
|
/*
|
|
* Preferences:
|
|
*
|
|
* network.cookie.cookieBehavior
|
|
* - determines how the browser should handle cookies:
|
|
* 0 means enable all cookies
|
|
* 1 means reject all third party cookies
|
|
* 2 means disable all cookies
|
|
* 3 means reject third party cookies unless at least one is already set for the eTLD
|
|
* 4 means reject all trackers
|
|
* 5 means reject all trackers and partition third-party cookies
|
|
* see netwerk/cookie/src/CookieService.cpp for details
|
|
* network.cookie.lifetimePolicy
|
|
* - determines how long cookies are stored:
|
|
* 0 means keep cookies until they expire
|
|
* 2 means keep cookies until the browser is closed
|
|
*/
|
|
|
|
readDeleteOnClose() {
|
|
let privateBrowsing = Preferences.get("browser.privatebrowsing.autostart")
|
|
.value;
|
|
if (privateBrowsing) {
|
|
return true;
|
|
}
|
|
|
|
let lifetimePolicy = Preferences.get("network.cookie.lifetimePolicy").value;
|
|
return lifetimePolicy == Ci.nsICookieService.ACCEPT_SESSION;
|
|
},
|
|
|
|
writeDeleteOnClose() {
|
|
let checkbox = document.getElementById("deleteOnClose");
|
|
return checkbox.checked
|
|
? Ci.nsICookieService.ACCEPT_SESSION
|
|
: Ci.nsICookieService.ACCEPT_NORMALLY;
|
|
},
|
|
|
|
/**
|
|
* Reads the network.cookie.cookieBehavior preference value and
|
|
* enables/disables the "blockCookiesMenu" menulist accordingly.
|
|
*/
|
|
readBlockCookies() {
|
|
let bcControl = document.getElementById("blockCookiesMenu");
|
|
bcControl.disabled =
|
|
Services.cookies.getCookieBehavior(false) ==
|
|
Ci.nsICookieService.BEHAVIOR_ACCEPT;
|
|
},
|
|
|
|
/**
|
|
* Updates the "accept third party cookies" menu based on whether the
|
|
* "contentBlockingBlockCookiesCheckbox" checkbox is checked.
|
|
*/
|
|
writeBlockCookies() {
|
|
let block = document.getElementById("contentBlockingBlockCookiesCheckbox");
|
|
let blockCookiesMenu = document.getElementById("blockCookiesMenu");
|
|
|
|
if (block.checked) {
|
|
// Automatically select 'third-party trackers' as the default.
|
|
blockCookiesMenu.selectedIndex = 0;
|
|
return this.writeBlockCookiesFrom();
|
|
}
|
|
return Ci.nsICookieService.BEHAVIOR_ACCEPT;
|
|
},
|
|
|
|
readBlockCookiesFrom() {
|
|
switch (Services.cookies.getCookieBehavior(false)) {
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN:
|
|
return "all-third-parties";
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT:
|
|
return "always";
|
|
case Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN:
|
|
return "unvisited";
|
|
case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER:
|
|
return "trackers";
|
|
case BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN:
|
|
return "trackers-plus-isolate";
|
|
default:
|
|
return undefined;
|
|
}
|
|
},
|
|
|
|
writeBlockCookiesFrom() {
|
|
let block = document.getElementById("blockCookiesMenu").selectedItem;
|
|
switch (block.value) {
|
|
case "trackers":
|
|
return Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER;
|
|
case "unvisited":
|
|
return Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN;
|
|
case "always":
|
|
return Ci.nsICookieService.BEHAVIOR_REJECT;
|
|
case "all-third-parties":
|
|
return Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN;
|
|
case "trackers-plus-isolate":
|
|
return Ci.nsICookieService
|
|
.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN;
|
|
default:
|
|
return undefined;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Discard the browsers of all tabs in all windows. Pinned tabs, as
|
|
* well as tabs for which discarding doesn't succeed (e.g. selected
|
|
* tabs, tabs with beforeunload listeners), are reloaded.
|
|
*/
|
|
reloadAllOtherTabs() {
|
|
let ourTab = BrowserWindowTracker.getTopWindow().gBrowser.selectedTab;
|
|
BrowserWindowTracker.orderedWindows.forEach(win => {
|
|
let otherGBrowser = win.gBrowser;
|
|
for (let tab of otherGBrowser.tabs) {
|
|
if (tab == ourTab) {
|
|
// Don't reload our preferences tab.
|
|
continue;
|
|
}
|
|
|
|
if (tab.pinned || tab.selected) {
|
|
otherGBrowser.reloadTab(tab);
|
|
} else {
|
|
otherGBrowser.discardBrowser(tab);
|
|
}
|
|
}
|
|
});
|
|
|
|
for (let notification of document.querySelectorAll(".reload-tabs")) {
|
|
notification.hidden = true;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* If there are more tabs than just the preferences tab, show a warning to the user that
|
|
* they need to reload their tabs to apply the setting.
|
|
*/
|
|
maybeNotifyUserToReload() {
|
|
let shouldShow = false;
|
|
if (window.BrowserWindowTracker.orderedWindows.length > 1) {
|
|
shouldShow = true;
|
|
} else {
|
|
let tabbrowser = window.BrowserWindowTracker.getTopWindow().gBrowser;
|
|
if (tabbrowser.tabs.length > 1) {
|
|
shouldShow = true;
|
|
}
|
|
}
|
|
if (shouldShow) {
|
|
for (let notification of document.querySelectorAll(".reload-tabs")) {
|
|
notification.hidden = false;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Displays fine-grained, per-site preferences for cookies.
|
|
*/
|
|
showCookieExceptions() {
|
|
var params = {
|
|
blockVisible: true,
|
|
sessionVisible: true,
|
|
allowVisible: true,
|
|
prefilledHost: "",
|
|
permissionType: "cookie",
|
|
};
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/permissions.xhtml",
|
|
undefined,
|
|
params
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Displays per-site preferences for HTTPS-Only Mode exceptions.
|
|
*/
|
|
showHttpsOnlyModeExceptions() {
|
|
var params = {
|
|
blockVisible: false,
|
|
sessionVisible: true,
|
|
allowVisible: false,
|
|
prefilledHost: "",
|
|
permissionType: "https-only-load-insecure",
|
|
};
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/permissions.xhtml",
|
|
undefined,
|
|
params
|
|
);
|
|
},
|
|
|
|
showSiteDataSettings() {
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/siteDataSettings.xhtml"
|
|
);
|
|
},
|
|
|
|
toggleSiteData(shouldShow) {
|
|
let clearButton = document.getElementById("clearSiteDataButton");
|
|
let settingsButton = document.getElementById("siteDataSettings");
|
|
clearButton.disabled = !shouldShow;
|
|
settingsButton.disabled = !shouldShow;
|
|
},
|
|
|
|
showSiteDataLoading() {
|
|
let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
|
|
document.l10n.setAttributes(
|
|
totalSiteDataSizeLabel,
|
|
"sitedata-total-size-calculating"
|
|
);
|
|
},
|
|
|
|
updateTotalDataSizeLabel(siteDataUsage) {
|
|
SiteDataManager.getCacheSize().then(function(cacheUsage) {
|
|
let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
|
|
let totalUsage = siteDataUsage + cacheUsage;
|
|
let [value, unit] = DownloadUtils.convertByteUnits(totalUsage);
|
|
document.l10n.setAttributes(
|
|
totalSiteDataSizeLabel,
|
|
"sitedata-total-size",
|
|
{
|
|
value,
|
|
unit,
|
|
}
|
|
);
|
|
});
|
|
},
|
|
|
|
clearSiteData() {
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/clearSiteData.xhtml"
|
|
);
|
|
},
|
|
|
|
// ADDRESS BAR
|
|
|
|
/**
|
|
* Initializes the address bar section.
|
|
*/
|
|
_initAddressBar() {
|
|
// Update the Firefox Suggest section on Nimbus changes. Note that
|
|
// `onUpdate` passes the Nimbus feature name as its first arg but that is
|
|
// not the arg that `_updateFirefoxSuggestSection` expects, so we do not
|
|
// want to pass it on.
|
|
this._firefoxSuggestNimbusUpdate = () =>
|
|
this._updateFirefoxSuggestSection();
|
|
NimbusFeatures.urlbar.onUpdate(this._firefoxSuggestNimbusUpdate);
|
|
window.addEventListener("unload", () =>
|
|
NimbusFeatures.urlbar.off(this._firefoxSuggestNimbusUpdate)
|
|
);
|
|
|
|
// Set up the sponsored checkbox. When the main checkbox is checked, the
|
|
// sponsored checkbox should be enabled and its checked status should
|
|
// reflect the sponsored pref. When the main checkbox is unchecked, the
|
|
// sponsored checkbox should be disabled and unchecked, but the sponsored
|
|
// pref should retain its value. Due to this complexity, we manage the
|
|
// sponsored checkbox manually.
|
|
Preferences.get("browser.urlbar.suggest.quicksuggest").on("change", () =>
|
|
// Update the enabled and checked status of the sponsored checkbox when
|
|
// the main pref changes.
|
|
this._updateFirefoxSuggestSponsoredCheckbox()
|
|
);
|
|
setEventListener("firefoxSuggestSponsoredSuggestion", "command", () => {
|
|
// Update the sponsored pref value when the sponsored checkbox is
|
|
// toggled.
|
|
Preferences.get(
|
|
"browser.urlbar.suggest.quicksuggest.sponsored"
|
|
).value = document.getElementById(
|
|
"firefoxSuggestSponsoredSuggestion"
|
|
).checked;
|
|
});
|
|
|
|
// Set the Firefox Suggest learn-more link URL.
|
|
document
|
|
.getElementById("firefoxSuggestSuggestionLearnMore")
|
|
.setAttribute("href", UrlbarProviderQuickSuggest.helpUrl);
|
|
|
|
this._updateFirefoxSuggestSection(true);
|
|
},
|
|
|
|
/**
|
|
* Updates the Firefox Suggest section (in the address bar section) depending
|
|
* on whether the user is enrolled in a Firefox Suggest rollout.
|
|
*
|
|
* @param {boolean} [onInit]
|
|
* Pass true when calling this when initializing the pane.
|
|
*/
|
|
_updateFirefoxSuggestSection(onInit = false) {
|
|
let container = document.getElementById("firefoxSuggestContainer");
|
|
|
|
if (UrlbarPrefs.get("quickSuggestEnabled")) {
|
|
// Update the l10n IDs of text elements.
|
|
let l10nIdByElementId = {
|
|
locationBarGroupHeader: "addressbar-header-firefox-suggest",
|
|
locationBarSuggestionLabel: "addressbar-suggest-firefox-suggest",
|
|
};
|
|
for (let [elementId, l10nId] of Object.entries(l10nIdByElementId)) {
|
|
let element = document.getElementById(elementId);
|
|
element.dataset.l10nIdOriginal = element.dataset.l10nId;
|
|
element.dataset.l10nId = l10nId;
|
|
}
|
|
// The main checkbox description discusses data collection, which we
|
|
// perform only in the "online" scenario. Hide it otherwise.
|
|
document.getElementById("firefoxSuggestSuggestionDescription").hidden =
|
|
UrlbarPrefs.get("quickSuggestScenario") != "online";
|
|
// Show the container.
|
|
this._updateFirefoxSuggestSponsoredCheckbox();
|
|
container.removeAttribute("hidden");
|
|
} else if (!onInit) {
|
|
// Firefox Suggest is not enabled. This is the default, so to avoid
|
|
// accidentally messing anything up, only modify the doc if we're being
|
|
// called due to a change in the rollout-enabled status (!onInit).
|
|
container.setAttribute("hidden", "true");
|
|
let elementIds = ["locationBarGroupHeader", "locationBarSuggestionLabel"];
|
|
for (let id of elementIds) {
|
|
let element = document.getElementById(id);
|
|
element.dataset.l10nId = element.dataset.l10nIdOriginal;
|
|
delete element.dataset.l10nIdOriginal;
|
|
document.l10n.translateElements([element]);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Updates the sponsored Firefox Suggest checkbox (in the address bar section)
|
|
* depending on the status of the main Firefox Suggest checkbox.
|
|
*/
|
|
_updateFirefoxSuggestSponsoredCheckbox() {
|
|
let sponsoredCheckbox = document.getElementById(
|
|
"firefoxSuggestSponsoredSuggestion"
|
|
);
|
|
sponsoredCheckbox.disabled = !Preferences.get(
|
|
"browser.urlbar.suggest.quicksuggest"
|
|
).value;
|
|
sponsoredCheckbox.checked =
|
|
!sponsoredCheckbox.disabled &&
|
|
Preferences.get("browser.urlbar.suggest.quicksuggest.sponsored").value;
|
|
},
|
|
|
|
// GEOLOCATION
|
|
|
|
/**
|
|
* Displays the location exceptions dialog where specific site location
|
|
* preferences can be set.
|
|
*/
|
|
showLocationExceptions() {
|
|
let params = { permissionType: "geo" };
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/sitePermissions.xhtml",
|
|
{ features: "resizable=yes" },
|
|
params
|
|
);
|
|
},
|
|
|
|
// XR
|
|
|
|
/**
|
|
* Displays the XR exceptions dialog where specific site XR
|
|
* preferences can be set.
|
|
*/
|
|
showXRExceptions() {
|
|
let params = { permissionType: "xr" };
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/sitePermissions.xhtml",
|
|
{ features: "resizable=yes" },
|
|
params
|
|
);
|
|
},
|
|
|
|
// CAMERA
|
|
|
|
/**
|
|
* Displays the camera exceptions dialog where specific site camera
|
|
* preferences can be set.
|
|
*/
|
|
showCameraExceptions() {
|
|
let params = { permissionType: "camera" };
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/sitePermissions.xhtml",
|
|
{ features: "resizable=yes" },
|
|
params
|
|
);
|
|
},
|
|
|
|
// MICROPHONE
|
|
|
|
/**
|
|
* Displays the microphone exceptions dialog where specific site microphone
|
|
* preferences can be set.
|
|
*/
|
|
showMicrophoneExceptions() {
|
|
let params = { permissionType: "microphone" };
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/sitePermissions.xhtml",
|
|
{ features: "resizable=yes" },
|
|
params
|
|
);
|
|
},
|
|
|
|
// NOTIFICATIONS
|
|
|
|
/**
|
|
* Displays the notifications exceptions dialog where specific site notification
|
|
* preferences can be set.
|
|
*/
|
|
showNotificationExceptions() {
|
|
let params = { permissionType: "desktop-notification" };
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/sitePermissions.xhtml",
|
|
{ features: "resizable=yes" },
|
|
params
|
|
);
|
|
},
|
|
|
|
// MEDIA
|
|
|
|
showAutoplayMediaExceptions() {
|
|
var params = { permissionType: "autoplay-media" };
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/sitePermissions.xhtml",
|
|
{ features: "resizable=yes" },
|
|
params
|
|
);
|
|
},
|
|
|
|
// POP-UPS
|
|
|
|
/**
|
|
* Displays the popup exceptions dialog where specific site popup preferences
|
|
* can be set.
|
|
*/
|
|
showPopupExceptions() {
|
|
var params = {
|
|
blockVisible: false,
|
|
sessionVisible: false,
|
|
allowVisible: true,
|
|
prefilledHost: "",
|
|
permissionType: "popup",
|
|
};
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/permissions.xhtml",
|
|
{ features: "resizable=yes" },
|
|
params
|
|
);
|
|
},
|
|
|
|
// UTILITY FUNCTIONS
|
|
|
|
/**
|
|
* Utility function to enable/disable the button specified by aButtonID based
|
|
* on the value of the Boolean preference specified by aPreferenceID.
|
|
*/
|
|
updateButtons(aButtonID, aPreferenceID) {
|
|
var button = document.getElementById(aButtonID);
|
|
var preference = Preferences.get(aPreferenceID);
|
|
button.disabled = !preference.value || preference.locked;
|
|
return undefined;
|
|
},
|
|
|
|
// BEGIN UI CODE
|
|
|
|
/*
|
|
* Preferences:
|
|
*
|
|
* dom.disable_open_during_load
|
|
* - true if popups are blocked by default, false otherwise
|
|
*/
|
|
|
|
// POP-UPS
|
|
|
|
/**
|
|
* Displays a dialog in which the user can view and modify the list of sites
|
|
* where passwords are never saved.
|
|
*/
|
|
showPasswordExceptions() {
|
|
var params = {
|
|
blockVisible: true,
|
|
sessionVisible: false,
|
|
allowVisible: false,
|
|
hideStatusColumn: true,
|
|
prefilledHost: "",
|
|
permissionType: "login-saving",
|
|
};
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/permissions.xhtml",
|
|
undefined,
|
|
params
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Initializes master password UI: the "use master password" checkbox, selects
|
|
* the master password button to show, and enables/disables it as necessary.
|
|
* The master password is controlled by various bits of NSS functionality, so
|
|
* the UI for it can't be controlled by the normal preference bindings.
|
|
*/
|
|
_initMasterPasswordUI() {
|
|
var noMP = !LoginHelper.isMasterPasswordSet();
|
|
|
|
var button = document.getElementById("changeMasterPassword");
|
|
button.disabled = noMP;
|
|
|
|
var checkbox = document.getElementById("useMasterPassword");
|
|
checkbox.checked = !noMP;
|
|
checkbox.disabled =
|
|
(noMP && !Services.policies.isAllowed("createMasterPassword")) ||
|
|
(!noMP && !Services.policies.isAllowed("removeMasterPassword"));
|
|
|
|
let learnMoreLink = document.getElementById("primaryPasswordLearnMoreLink");
|
|
let learnMoreURL =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"primary-password-stored-logins";
|
|
learnMoreLink.setAttribute("href", learnMoreURL);
|
|
},
|
|
|
|
/**
|
|
* Enables/disables the master password button depending on the state of the
|
|
* "use master password" checkbox, and prompts for master password removal if
|
|
* one is set.
|
|
*/
|
|
async updateMasterPasswordButton() {
|
|
var checkbox = document.getElementById("useMasterPassword");
|
|
var button = document.getElementById("changeMasterPassword");
|
|
button.disabled = !checkbox.checked;
|
|
|
|
// unchecking the checkbox should try to immediately remove the master
|
|
// password, because it's impossible to non-destructively remove the master
|
|
// password used to encrypt all the passwords without providing it (by
|
|
// design), and it would be extremely odd to pop up that dialog when the
|
|
// user closes the prefwindow and saves his settings
|
|
if (!checkbox.checked) {
|
|
await this._removeMasterPassword();
|
|
} else {
|
|
await this.changeMasterPassword();
|
|
}
|
|
|
|
this._initMasterPasswordUI();
|
|
},
|
|
|
|
/**
|
|
* Displays the "remove master password" dialog to allow the user to remove
|
|
* the current master password. When the dialog is dismissed, master password
|
|
* UI is automatically updated.
|
|
*/
|
|
async _removeMasterPassword() {
|
|
var secmodDB = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService(
|
|
Ci.nsIPKCS11ModuleDB
|
|
);
|
|
if (secmodDB.isFIPSEnabled) {
|
|
let title = document.getElementById("fips-title").textContent;
|
|
let desc = document.getElementById("fips-desc").textContent;
|
|
Services.prompt.alert(window, title, desc);
|
|
this._initMasterPasswordUI();
|
|
} else {
|
|
gSubDialog.open("chrome://mozapps/content/preferences/removemp.xhtml", {
|
|
closingCallback: this._initMasterPasswordUI.bind(this),
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Displays a dialog in which the master password may be changed.
|
|
*/
|
|
async changeMasterPassword() {
|
|
// Require OS authentication before the user can set a Master Password.
|
|
// OS reauthenticate functionality is not available on Linux yet (bug 1527745)
|
|
if (
|
|
!LoginHelper.isMasterPasswordSet() &&
|
|
OS_AUTH_ENABLED &&
|
|
OSKeyStore.canReauth()
|
|
) {
|
|
let messageId =
|
|
"primary-password-os-auth-dialog-message-" + AppConstants.platform;
|
|
let [messageText, captionText] = await L10n.formatMessages([
|
|
{
|
|
id: messageId,
|
|
},
|
|
{
|
|
id: "master-password-os-auth-dialog-caption",
|
|
},
|
|
]);
|
|
let win = Services.wm.getMostRecentBrowserWindow();
|
|
let loggedIn = await OSKeyStore.ensureLoggedIn(
|
|
messageText.value,
|
|
captionText.value,
|
|
win,
|
|
false
|
|
);
|
|
if (!loggedIn.authenticated) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
gSubDialog.open("chrome://mozapps/content/preferences/changemp.xhtml", {
|
|
features: "resizable=no",
|
|
closingCallback: this._initMasterPasswordUI.bind(this),
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Set up the initial state for the password generation UI.
|
|
* It will be hidden unless the .available pref is true
|
|
*/
|
|
_initPasswordGenerationUI() {
|
|
// we don't watch the .available pref for runtime changes
|
|
let prefValue = Services.prefs.getBoolPref(
|
|
PREF_PASSWORD_GENERATION_AVAILABLE,
|
|
false
|
|
);
|
|
document.getElementById("generatePasswordsBox").hidden = !prefValue;
|
|
},
|
|
|
|
/**
|
|
* Shows the sites where the user has saved passwords and the associated login
|
|
* information.
|
|
*/
|
|
showPasswords() {
|
|
let loginManager = window.windowGlobalChild.getActor("LoginManager");
|
|
loginManager.sendAsyncMessage("PasswordManager:OpenPreferences", {
|
|
entryPoint: "preferences",
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Enables/disables dependent controls related to password saving
|
|
* When password saving is not enabled, we need to also disable the password generation checkbox
|
|
* The Exceptions button is used to configure sites where passwords are never saved.
|
|
*/
|
|
readSavePasswords() {
|
|
var prefValue = Preferences.get("signon.rememberSignons").value;
|
|
document.getElementById("passwordExceptions").disabled = !prefValue;
|
|
document.getElementById("generatePasswords").disabled = !prefValue;
|
|
document.getElementById("passwordAutofillCheckbox").disabled = !prefValue;
|
|
|
|
// don't override pref value in UI
|
|
return undefined;
|
|
},
|
|
|
|
/**
|
|
* Initalizes pref listeners for the password manager.
|
|
*
|
|
* This ensures that the user is always notified if an extension is controlling the password manager.
|
|
*/
|
|
initListenersForExtensionControllingPasswordManager() {
|
|
this._passwordManagerCheckbox = document.getElementById("savePasswords");
|
|
this._disableExtensionButton = document.getElementById(
|
|
"disablePasswordManagerExtension"
|
|
);
|
|
|
|
this._disableExtensionButton.addEventListener(
|
|
"command",
|
|
makeDisableControllingExtension(
|
|
PREF_SETTING_TYPE,
|
|
PASSWORD_MANAGER_PREF_ID
|
|
)
|
|
);
|
|
|
|
initListenersForPrefChange(
|
|
PREF_SETTING_TYPE,
|
|
PASSWORD_MANAGER_PREF_ID,
|
|
this._passwordManagerCheckbox
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Enables/disables the add-ons Exceptions button depending on whether
|
|
* or not add-on installation warnings are displayed.
|
|
*/
|
|
readWarnAddonInstall() {
|
|
var warn = Preferences.get("xpinstall.whitelist.required");
|
|
var exceptions = document.getElementById("addonExceptions");
|
|
|
|
exceptions.disabled = !warn.value;
|
|
|
|
// don't override the preference value
|
|
return undefined;
|
|
},
|
|
|
|
_initSafeBrowsing() {
|
|
let enableSafeBrowsing = document.getElementById("enableSafeBrowsing");
|
|
let blockDownloads = document.getElementById("blockDownloads");
|
|
let blockUncommonUnwanted = document.getElementById(
|
|
"blockUncommonUnwanted"
|
|
);
|
|
|
|
let safeBrowsingPhishingPref = Preferences.get(
|
|
"browser.safebrowsing.phishing.enabled"
|
|
);
|
|
let safeBrowsingMalwarePref = Preferences.get(
|
|
"browser.safebrowsing.malware.enabled"
|
|
);
|
|
|
|
let blockDownloadsPref = Preferences.get(
|
|
"browser.safebrowsing.downloads.enabled"
|
|
);
|
|
let malwareTable = Preferences.get("urlclassifier.malwareTable");
|
|
|
|
let blockUnwantedPref = Preferences.get(
|
|
"browser.safebrowsing.downloads.remote.block_potentially_unwanted"
|
|
);
|
|
let blockUncommonPref = Preferences.get(
|
|
"browser.safebrowsing.downloads.remote.block_uncommon"
|
|
);
|
|
|
|
let learnMoreLink = document.getElementById("enableSafeBrowsingLearnMore");
|
|
let phishingUrl =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"phishing-malware";
|
|
learnMoreLink.setAttribute("href", phishingUrl);
|
|
|
|
enableSafeBrowsing.addEventListener("command", function() {
|
|
safeBrowsingPhishingPref.value = enableSafeBrowsing.checked;
|
|
safeBrowsingMalwarePref.value = enableSafeBrowsing.checked;
|
|
|
|
if (enableSafeBrowsing.checked) {
|
|
blockDownloads.removeAttribute("disabled");
|
|
if (blockDownloads.checked) {
|
|
blockUncommonUnwanted.removeAttribute("disabled");
|
|
}
|
|
} else {
|
|
blockDownloads.setAttribute("disabled", "true");
|
|
blockUncommonUnwanted.setAttribute("disabled", "true");
|
|
}
|
|
});
|
|
|
|
blockDownloads.addEventListener("command", function() {
|
|
blockDownloadsPref.value = blockDownloads.checked;
|
|
if (blockDownloads.checked) {
|
|
blockUncommonUnwanted.removeAttribute("disabled");
|
|
} else {
|
|
blockUncommonUnwanted.setAttribute("disabled", "true");
|
|
}
|
|
});
|
|
|
|
blockUncommonUnwanted.addEventListener("command", function() {
|
|
blockUnwantedPref.value = blockUncommonUnwanted.checked;
|
|
blockUncommonPref.value = blockUncommonUnwanted.checked;
|
|
|
|
let malware = malwareTable.value
|
|
.split(",")
|
|
.filter(
|
|
x =>
|
|
x !== "goog-unwanted-proto" &&
|
|
x !== "goog-unwanted-shavar" &&
|
|
x !== "moztest-unwanted-simple"
|
|
);
|
|
|
|
if (blockUncommonUnwanted.checked) {
|
|
if (malware.includes("goog-malware-shavar")) {
|
|
malware.push("goog-unwanted-shavar");
|
|
} else {
|
|
malware.push("goog-unwanted-proto");
|
|
}
|
|
|
|
malware.push("moztest-unwanted-simple");
|
|
}
|
|
|
|
// sort alphabetically to keep the pref consistent
|
|
malware.sort();
|
|
|
|
malwareTable.value = malware.join(",");
|
|
|
|
// Force an update after changing the malware table.
|
|
listManager.forceUpdates(malwareTable.value);
|
|
});
|
|
|
|
// set initial values
|
|
|
|
enableSafeBrowsing.checked =
|
|
safeBrowsingPhishingPref.value && safeBrowsingMalwarePref.value;
|
|
if (!enableSafeBrowsing.checked) {
|
|
blockDownloads.setAttribute("disabled", "true");
|
|
blockUncommonUnwanted.setAttribute("disabled", "true");
|
|
}
|
|
|
|
blockDownloads.checked = blockDownloadsPref.value;
|
|
if (!blockDownloadsPref.value) {
|
|
blockUncommonUnwanted.setAttribute("disabled", "true");
|
|
}
|
|
blockUncommonUnwanted.checked =
|
|
blockUnwantedPref.value && blockUncommonPref.value;
|
|
},
|
|
|
|
/**
|
|
* Displays the exceptions lists for add-on installation warnings.
|
|
*/
|
|
showAddonExceptions() {
|
|
var params = this._addonParams;
|
|
|
|
gSubDialog.open(
|
|
"chrome://browser/content/preferences/dialogs/permissions.xhtml",
|
|
undefined,
|
|
params
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Parameters for the add-on install permissions dialog.
|
|
*/
|
|
_addonParams: {
|
|
blockVisible: false,
|
|
sessionVisible: false,
|
|
allowVisible: true,
|
|
prefilledHost: "",
|
|
permissionType: "install",
|
|
},
|
|
|
|
/**
|
|
* readEnableOCSP is used by the preferences UI to determine whether or not
|
|
* the checkbox for OCSP fetching should be checked (it returns true if it
|
|
* should be checked and false otherwise). The about:config preference
|
|
* "security.OCSP.enabled" is an integer rather than a boolean, so it can't be
|
|
* directly mapped from {true,false} to {checked,unchecked}. The possible
|
|
* values for "security.OCSP.enabled" are:
|
|
* 0: fetching is disabled
|
|
* 1: fetch for all certificates
|
|
* 2: fetch only for EV certificates
|
|
* Hence, if "security.OCSP.enabled" is non-zero, the checkbox should be
|
|
* checked. Otherwise, it should be unchecked.
|
|
*/
|
|
readEnableOCSP() {
|
|
var preference = Preferences.get("security.OCSP.enabled");
|
|
// This is the case if the preference is the default value.
|
|
if (preference.value === undefined) {
|
|
return true;
|
|
}
|
|
return preference.value != 0;
|
|
},
|
|
|
|
/**
|
|
* writeEnableOCSP is used by the preferences UI to map the checked/unchecked
|
|
* state of the OCSP fetching checkbox to the value that the preference
|
|
* "security.OCSP.enabled" should be set to (it returns that value). See the
|
|
* readEnableOCSP documentation for more background. We unfortunately don't
|
|
* have enough information to map from {true,false} to all possible values for
|
|
* "security.OCSP.enabled", but a reasonable alternative is to map from
|
|
* {true,false} to {<the default value>,0}. That is, if the box is checked,
|
|
* "security.OCSP.enabled" will be set to whatever default it should be, given
|
|
* the platform and channel. If the box is unchecked, the preference will be
|
|
* set to 0. Obviously this won't work if the default is 0, so we will have to
|
|
* revisit this if we ever set it to 0.
|
|
*/
|
|
writeEnableOCSP() {
|
|
var checkbox = document.getElementById("enableOCSP");
|
|
var defaults = Services.prefs.getDefaultBranch(null);
|
|
var defaultValue = defaults.getIntPref("security.OCSP.enabled");
|
|
return checkbox.checked ? defaultValue : 0;
|
|
},
|
|
|
|
/**
|
|
* Displays the user's certificates and associated options.
|
|
*/
|
|
showCertificates() {
|
|
gSubDialog.open("chrome://pippki/content/certManager.xhtml");
|
|
},
|
|
|
|
/**
|
|
* Displays a dialog from which the user can manage his security devices.
|
|
*/
|
|
showSecurityDevices() {
|
|
gSubDialog.open("chrome://pippki/content/device_manager.xhtml");
|
|
},
|
|
|
|
/**
|
|
* Displays the learn more health report page when a user opts out of data collection.
|
|
*/
|
|
showDataDeletion() {
|
|
let url =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"telemetry-clientid";
|
|
window.open(url, "_blank");
|
|
},
|
|
|
|
initDataCollection() {
|
|
this._setupLearnMoreLink(
|
|
"toolkit.datacollection.infoURL",
|
|
"dataCollectionPrivacyNotice"
|
|
);
|
|
},
|
|
|
|
initSubmitCrashes() {
|
|
this._setupLearnMoreLink(
|
|
"toolkit.crashreporter.infoURL",
|
|
"crashReporterLearnMore"
|
|
);
|
|
setEventListener("crashReporterLabel", "click", function(event) {
|
|
if (event.target.localName == "a") {
|
|
return;
|
|
}
|
|
const checkboxId = event.target.getAttribute("for");
|
|
document.getElementById(checkboxId).click();
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Set up or hide the Learn More links for various data collection options
|
|
*/
|
|
_setupLearnMoreLink(pref, element) {
|
|
// set up the Learn More link with the correct URL
|
|
let url = Services.urlFormatter.formatURLPref(pref);
|
|
let el = document.getElementById(element);
|
|
|
|
if (url) {
|
|
el.setAttribute("href", url);
|
|
} else {
|
|
el.hidden = true;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Initialize the health report service reference and checkbox.
|
|
*/
|
|
initSubmitHealthReport() {
|
|
this._setupLearnMoreLink(
|
|
"datareporting.healthreport.infoURL",
|
|
"FHRLearnMore"
|
|
);
|
|
|
|
let checkbox = document.getElementById("submitHealthReportBox");
|
|
|
|
// Telemetry is only sending data if MOZ_TELEMETRY_REPORTING is defined.
|
|
// We still want to display the preferences panel if that's not the case, but
|
|
// we want it to be disabled and unchecked.
|
|
if (
|
|
Services.prefs.prefIsLocked(PREF_UPLOAD_ENABLED) ||
|
|
!AppConstants.MOZ_TELEMETRY_REPORTING
|
|
) {
|
|
checkbox.setAttribute("disabled", "true");
|
|
return;
|
|
}
|
|
|
|
checkbox.checked =
|
|
Services.prefs.getBoolPref(PREF_UPLOAD_ENABLED) &&
|
|
AppConstants.MOZ_TELEMETRY_REPORTING;
|
|
},
|
|
|
|
/**
|
|
* Update the health report preference with state from checkbox.
|
|
*/
|
|
updateSubmitHealthReport() {
|
|
let checkbox = document.getElementById("submitHealthReportBox");
|
|
let telemetryContainer = document.getElementById("telemetry-container");
|
|
|
|
Services.prefs.setBoolPref(PREF_UPLOAD_ENABLED, checkbox.checked);
|
|
telemetryContainer.hidden = checkbox.checked;
|
|
},
|
|
|
|
/**
|
|
* Initialize the opt-out-study preference checkbox into about:preferences and
|
|
* handles events coming from the UI for it.
|
|
*/
|
|
initOptOutStudyCheckbox(doc) {
|
|
// The checkbox should be disabled if any of the below are true. This
|
|
// prevents the user from changing the value in the box.
|
|
//
|
|
// * the policy forbids shield
|
|
// * Normandy is disabled
|
|
//
|
|
// The checkbox should match the value of the preference only if all of
|
|
// these are true. Otherwise, the checkbox should remain unchecked. This
|
|
// is because in these situations, Shield studies are always disabled, and
|
|
// so showing a checkbox would be confusing.
|
|
//
|
|
// * the policy allows Shield
|
|
// * Normandy is enabled
|
|
|
|
const allowedByPolicy = Services.policies.isAllowed("Shield");
|
|
const checkbox = document.getElementById("optOutStudiesEnabled");
|
|
|
|
if (
|
|
allowedByPolicy &&
|
|
Services.prefs.getBoolPref(PREF_NORMANDY_ENABLED, false)
|
|
) {
|
|
if (Services.prefs.getBoolPref(PREF_OPT_OUT_STUDIES_ENABLED, false)) {
|
|
checkbox.setAttribute("checked", "true");
|
|
} else {
|
|
checkbox.removeAttribute("checked");
|
|
}
|
|
checkbox.setAttribute("preference", PREF_OPT_OUT_STUDIES_ENABLED);
|
|
checkbox.removeAttribute("disabled");
|
|
} else {
|
|
checkbox.removeAttribute("preference");
|
|
checkbox.removeAttribute("checked");
|
|
checkbox.setAttribute("disabled", "true");
|
|
}
|
|
},
|
|
|
|
initAddonRecommendationsCheckbox() {
|
|
// Setup the learn more link.
|
|
const url =
|
|
Services.urlFormatter.formatURLPref("app.support.baseURL") +
|
|
"personalized-addons";
|
|
document
|
|
.getElementById("addonRecommendationLearnMore")
|
|
.setAttribute("href", url);
|
|
|
|
// Setup the checkbox.
|
|
dataCollectionCheckboxHandler({
|
|
checkbox: document.getElementById("addonRecommendationEnabled"),
|
|
pref: PREF_ADDON_RECOMMENDATIONS_ENABLED,
|
|
});
|
|
},
|
|
|
|
observe(aSubject, aTopic, aData) {
|
|
switch (aTopic) {
|
|
case "sitedatamanager:updating-sites":
|
|
// While updating, we want to disable this section and display loading message until updated
|
|
this.toggleSiteData(false);
|
|
this.showSiteDataLoading();
|
|
break;
|
|
|
|
case "sitedatamanager:sites-updated":
|
|
this.toggleSiteData(true);
|
|
SiteDataManager.getTotalUsage().then(
|
|
this.updateTotalDataSizeLabel.bind(this)
|
|
);
|
|
break;
|
|
}
|
|
},
|
|
};
|