forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			3519 lines
		
	
	
	
		
			113 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			3519 lines
		
	
	
	
		
			113 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 */
 | 
						|
 | 
						|
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_URLBAR_QUICKSUGGEST_BLOCKLIST =
 | 
						|
  "browser.urlbar.quicksuggest.blockedDigests";
 | 
						|
const PREF_URLBAR_WEATHER_USER_ENABLED = "browser.urlbar.suggest.weather";
 | 
						|
 | 
						|
/*
 | 
						|
 * 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 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";
 | 
						|
 | 
						|
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;
 | 
						|
  }
 | 
						|
});
 | 
						|
 | 
						|
XPCOMUtils.defineLazyPreferenceGetter(
 | 
						|
  this,
 | 
						|
  "OS_AUTH_ENABLED",
 | 
						|
  "signon.management.page.os-auth.enabled",
 | 
						|
  true
 | 
						|
);
 | 
						|
 | 
						|
XPCOMUtils.defineLazyPreferenceGetter(
 | 
						|
  this,
 | 
						|
  "gIsFirstPartyIsolated",
 | 
						|
  "privacy.firstparty.isolate",
 | 
						|
  false
 | 
						|
);
 | 
						|
 | 
						|
ChromeUtils.defineESModuleGetters(this, {
 | 
						|
  DoHConfigController: "resource:///modules/DoHConfig.sys.mjs",
 | 
						|
});
 | 
						|
 | 
						|
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.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.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.cache", type: "bool" },
 | 
						|
  { id: "privacy.clearOnShutdown.offlineApps", type: "bool" },
 | 
						|
  { id: "privacy.clearOnShutdown.history", 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" },
 | 
						|
 | 
						|
  // 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" },
 | 
						|
  ]);
 | 
						|
}
 | 
						|
// 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(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);
 | 
						|
      }
 | 
						|
    });
 | 
						|
  },
 | 
						|
 | 
						|
  _initQuickActionsSection() {
 | 
						|
    let showPref = Preferences.get("browser.urlbar.quickactions.showPrefs");
 | 
						|
    let showQuickActionsGroup = () => {
 | 
						|
      document.getElementById("quickActionsBox").hidden = !showPref.value;
 | 
						|
    };
 | 
						|
    showPref.on("change", showQuickActionsGroup);
 | 
						|
    showQuickActionsGroup();
 | 
						|
  },
 | 
						|
 | 
						|
  _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",
 | 
						|
      "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()
 | 
						|
    );
 | 
						|
    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);
 | 
						|
      }
 | 
						|
      Services.telemetry.recordEvent(
 | 
						|
        "security.doh.settings",
 | 
						|
        "provider_choice",
 | 
						|
        "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;
 | 
						|
      let confirmationState = Services.dns.currentTrrConfirmationState;
 | 
						|
      if (
 | 
						|
        mode == Ci.nsIDNSService.MODE_TRRFIRST ||
 | 
						|
        mode == Ci.nsIDNSService.MODE_TRRONLY
 | 
						|
      ) {
 | 
						|
        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;
 | 
						|
    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");
 | 
						|
    }
 | 
						|
 | 
						|
    gPrivacyPane.updateDoHStatus();
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Init DoH corresponding prefs
 | 
						|
   */
 | 
						|
  initDoH() {
 | 
						|
    Services.telemetry.setEventRecordingEnabled("security.doh.settings", true);
 | 
						|
 | 
						|
    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;
 | 
						|
      }
 | 
						|
      Services.telemetry.recordEvent(
 | 
						|
        "security.doh.settings",
 | 
						|
        "mode_changed",
 | 
						|
        "button",
 | 
						|
        e.target.id
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    setEventListener("dohDefaultRadio", "command", modeButtonPressed);
 | 
						|
    setEventListener("dohEnabledRadio", "command", modeButtonPressed);
 | 
						|
    setEventListener("dohStrictRadio", "command", modeButtonPressed);
 | 
						|
    setEventListener("dohOffRadio", "command", modeButtonPressed);
 | 
						|
 | 
						|
    function warnCheckboxClicked(e) {
 | 
						|
      Services.telemetry.recordEvent(
 | 
						|
        "security.doh.settings",
 | 
						|
        "warn_checkbox",
 | 
						|
        "checkbox",
 | 
						|
        `${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();
 | 
						|
 | 
						|
    Services.telemetry.setEventRecordingEnabled("privacy.ui.fpp", true);
 | 
						|
 | 
						|
    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("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("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(
 | 
						|
      "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.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);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    this._initAddressBar();
 | 
						|
 | 
						|
    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
 | 
						|
      );
 | 
						|
      setEventListener(
 | 
						|
        "telemetryDataDeletionLearnMore",
 | 
						|
        "click",
 | 
						|
        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();
 | 
						|
 | 
						|
    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.
 | 
						|
   */
 | 
						|
  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() {
 | 
						|
    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");
 | 
						|
      },
 | 
						|
    });
 | 
						|
  },
 | 
						|
 | 
						|
  /*
 | 
						|
   * On loading the page, assigns the state to the deleteOnClose checkbox that fits the pref selection
 | 
						|
   */
 | 
						|
  initDeleteOnCloseBox() {
 | 
						|
    let deleteOnCloseBox = document.getElementById("deleteOnClose");
 | 
						|
    deleteOnCloseBox.checked =
 | 
						|
      (Preferences.get("privacy.sanitize.sanitizeOnShutdown").value &&
 | 
						|
        Preferences.get("privacy.clearOnShutdown.cookies").value &&
 | 
						|
        Preferences.get("privacy.clearOnShutdown.cache").value &&
 | 
						|
        Preferences.get("privacy.clearOnShutdown.offlineApps").value) ||
 | 
						|
      Preferences.get("browser.privatebrowsing.autostart").value;
 | 
						|
  },
 | 
						|
 | 
						|
  /*
 | 
						|
   * Keeps the state of the deleteOnClose checkbox in sync with the pref selection
 | 
						|
   */
 | 
						|
  syncSanitizationPrefsWithDeleteOnClose() {
 | 
						|
    let deleteOnCloseBox = document.getElementById("deleteOnClose");
 | 
						|
    let historyMode = Preferences.get("privacy.history.custom");
 | 
						|
    let sanitizeOnShutdownPref = Preferences.get(
 | 
						|
      "privacy.sanitize.sanitizeOnShutdown"
 | 
						|
    );
 | 
						|
    // ClearOnClose cleaning categories
 | 
						|
    let cookiePref = Preferences.get("privacy.clearOnShutdown.cookies");
 | 
						|
    let cachePref = Preferences.get("privacy.clearOnShutdown.cache");
 | 
						|
    let offlineAppsPref = Preferences.get(
 | 
						|
      "privacy.clearOnShutdown.offlineApps"
 | 
						|
    );
 | 
						|
 | 
						|
    // Sync the cleaning prefs with the deleteOnClose box
 | 
						|
    deleteOnCloseBox.addEventListener("command", () => {
 | 
						|
      let { checked } = deleteOnCloseBox;
 | 
						|
      cookiePref.value = checked;
 | 
						|
      cachePref.value = checked;
 | 
						|
      offlineAppsPref.value = checked;
 | 
						|
      // Forget the current pref selection if sanitizeOnShutdown is disabled,
 | 
						|
      // to not over clear when it gets enabled by the sync mechanism
 | 
						|
      if (!sanitizeOnShutdownPref.value) {
 | 
						|
        this._resetCleaningPrefs();
 | 
						|
      }
 | 
						|
      // If no other cleaning category is selected, sanitizeOnShutdown gets synced with deleteOnClose
 | 
						|
      sanitizeOnShutdownPref.value =
 | 
						|
        this._isCustomCleaningPrefPresent() || checked;
 | 
						|
 | 
						|
      // Update the view of the history settings
 | 
						|
      if (checked && !historyMode.value) {
 | 
						|
        historyMode.value = "custom";
 | 
						|
        this.initializeHistoryMode();
 | 
						|
        this.updateHistoryModePane();
 | 
						|
        this.updatePrivacyMicroControls();
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    cookiePref.on("change", this._onSanitizePrefChangeSyncClearOnClose);
 | 
						|
    cachePref.on("change", this._onSanitizePrefChangeSyncClearOnClose);
 | 
						|
    offlineAppsPref.on("change", this._onSanitizePrefChangeSyncClearOnClose);
 | 
						|
    sanitizeOnShutdownPref.on(
 | 
						|
      "change",
 | 
						|
      this._onSanitizePrefChangeSyncClearOnClose
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  /*
 | 
						|
   * Sync the deleteOnClose box to its cleaning prefs
 | 
						|
   */
 | 
						|
  _onSanitizePrefChangeSyncClearOnClose() {
 | 
						|
    let deleteOnCloseBox = document.getElementById("deleteOnClose");
 | 
						|
    deleteOnCloseBox.checked =
 | 
						|
      Preferences.get("privacy.clearOnShutdown.cookies").value &&
 | 
						|
      Preferences.get("privacy.clearOnShutdown.cache").value &&
 | 
						|
      Preferences.get("privacy.clearOnShutdown.offlineApps").value &&
 | 
						|
      Preferences.get("privacy.sanitize.sanitizeOnShutdown").value;
 | 
						|
  },
 | 
						|
 | 
						|
  /*
 | 
						|
   * Unsets cleaning prefs that do not belong to DeleteOnClose
 | 
						|
   */
 | 
						|
  _resetCleaningPrefs() {
 | 
						|
    SANITIZE_ON_SHUTDOWN_PREFS_ONLY.forEach(
 | 
						|
      pref => (Preferences.get(pref).value = false)
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  /*
 | 
						|
   Checks if the user set cleaning prefs that do not belong to DeleteOnClose
 | 
						|
   */
 | 
						|
  _isCustomCleaningPrefPresent() {
 | 
						|
    return SANITIZE_ON_SHUTDOWN_PREFS_ONLY.some(
 | 
						|
      pref => Preferences.get(pref).value
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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",
 | 
						|
      disableETPVisible: true,
 | 
						|
      prefilledHost: "",
 | 
						|
      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
 | 
						|
   */
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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",
 | 
						|
      forcedHTTP: true,
 | 
						|
    };
 | 
						|
    gSubDialog.open(
 | 
						|
      "chrome://browser/content/preferences/dialogs/permissions.xhtml",
 | 
						|
      undefined,
 | 
						|
      params
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  showDoHExceptions() {
 | 
						|
    gSubDialog.open(
 | 
						|
      "chrome://browser/content/preferences/dialogs/dohExceptions.xhtml",
 | 
						|
      undefined
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  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"
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Initializes the cookie banner handling subgroup on the privacy pane.
 | 
						|
   *
 | 
						|
   * This UI is shown if the "cookiebanners.ui.desktop.enabled" pref is true.
 | 
						|
   *
 | 
						|
   * The cookie banner handling checkbox reflects the cookie banner feature
 | 
						|
   * state. It is enabled when the service enabled via the
 | 
						|
   * cookiebanners.service.mode pref. If detection-only mode is enabled the
 | 
						|
   * checkbox is unchecked, since in this mode no banners are handled. It is
 | 
						|
   * only used for detection for banners which means we may prompt the user to
 | 
						|
   * enable the feature via other UI surfaces such as the onboarding doorhanger.
 | 
						|
   *
 | 
						|
   * If the user checks the checkbox, the pref value is set to
 | 
						|
   * nsICookieBannerService.MODE_REJECT_OR_ACCEPT.
 | 
						|
   *
 | 
						|
   * If the user unchecks the checkbox, the mode pref value is set to
 | 
						|
   * nsICookieBannerService.MODE_DISABLED.
 | 
						|
   *
 | 
						|
   * Advanced users can choose other int-valued modes via about:config.
 | 
						|
   */
 | 
						|
  initCookieBannerHandling() {
 | 
						|
    setSyncFromPrefListener("handleCookieBanners", () =>
 | 
						|
      this.readCookieBannerMode()
 | 
						|
    );
 | 
						|
    setSyncToPrefListener("handleCookieBanners", () =>
 | 
						|
      this.writeCookieBannerMode()
 | 
						|
    );
 | 
						|
 | 
						|
    let preference = Preferences.get("cookiebanners.ui.desktop.enabled");
 | 
						|
    preference.on("change", () => this.updateCookieBannerHandlingVisibility());
 | 
						|
 | 
						|
    this.updateCookieBannerHandlingVisibility();
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Reads the cookiebanners.service.mode.privateBrowsing pref,
 | 
						|
   * interpreting the multiple modes as a true/false value
 | 
						|
   */
 | 
						|
  readCookieBannerMode() {
 | 
						|
    return (
 | 
						|
      Preferences.get("cookiebanners.service.mode.privateBrowsing").value !=
 | 
						|
      Ci.nsICookieBannerService.MODE_DISABLED
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Translates user clicks on the cookie banner handling checkbox to the
 | 
						|
   * corresponding integer-valued cookie banner mode preference.
 | 
						|
   */
 | 
						|
  writeCookieBannerMode() {
 | 
						|
    let checkbox = document.getElementById("handleCookieBanners");
 | 
						|
    if (!checkbox.checked) {
 | 
						|
      /* because we removed UI control for the non-PBM pref, disabling it here
 | 
						|
         provides an off-ramp for profiles where it had previously been enabled from the UI */
 | 
						|
      Services.prefs.setIntPref(
 | 
						|
        "cookiebanners.service.mode",
 | 
						|
        Ci.nsICookieBannerService.MODE_DISABLED
 | 
						|
      );
 | 
						|
      return Ci.nsICookieBannerService.MODE_DISABLED;
 | 
						|
    }
 | 
						|
    return Ci.nsICookieBannerService.MODE_REJECT;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Shows or hides the cookie banner handling section based on the value of
 | 
						|
   * the "cookiebanners.ui.desktop.enabled" pref.
 | 
						|
   */
 | 
						|
  updateCookieBannerHandlingVisibility() {
 | 
						|
    let groupbox = document.getElementById("cookieBannerHandlingGroup");
 | 
						|
    let isEnabled = Preferences.get("cookiebanners.ui.desktop.enabled").value;
 | 
						|
 | 
						|
    // Because the top-level pane showing code unsets the hidden attribute, we
 | 
						|
    // manually hide the section when cookie banner handling is preffed off.
 | 
						|
    if (isEnabled) {
 | 
						|
      groupbox.removeAttribute("style");
 | 
						|
    } else {
 | 
						|
      groupbox.setAttribute("style", "display: none !important");
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  // ADDRESS BAR
 | 
						|
 | 
						|
  /**
 | 
						|
   * Initializes the address bar section.
 | 
						|
   */
 | 
						|
  _initAddressBar() {
 | 
						|
    // Update the Firefox Suggest section when its Nimbus config changes.
 | 
						|
    let onNimbus = () => this._updateFirefoxSuggestSection();
 | 
						|
    NimbusFeatures.urlbar.onUpdate(onNimbus);
 | 
						|
    window.addEventListener("unload", () => {
 | 
						|
      NimbusFeatures.urlbar.offUpdate(onNimbus);
 | 
						|
    });
 | 
						|
 | 
						|
    // The Firefox Suggest info box potentially needs updating when any of the
 | 
						|
    // toggles change.
 | 
						|
    let infoBoxPrefs = [
 | 
						|
      "browser.urlbar.suggest.quicksuggest.nonsponsored",
 | 
						|
      "browser.urlbar.suggest.quicksuggest.sponsored",
 | 
						|
      "browser.urlbar.quicksuggest.dataCollection.enabled",
 | 
						|
    ];
 | 
						|
    for (let pref of infoBoxPrefs) {
 | 
						|
      Preferences.get(pref).on("change", () =>
 | 
						|
        this._updateFirefoxSuggestInfoBox()
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    document.getElementById("clipboardSuggestion").hidden = !UrlbarPrefs.get(
 | 
						|
      "clipboard.featureGate"
 | 
						|
    );
 | 
						|
 | 
						|
    this._updateFirefoxSuggestSection(true);
 | 
						|
    this._initQuickActionsSection();
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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;
 | 
						|
      }
 | 
						|
 | 
						|
      // Add the extraMargin class to the engine-prefs link.
 | 
						|
      document
 | 
						|
        .getElementById("openSearchEnginePreferences")
 | 
						|
        .classList.add("extraMargin");
 | 
						|
 | 
						|
      // Show the container.
 | 
						|
      this._updateFirefoxSuggestInfoBox();
 | 
						|
 | 
						|
      this._updateDismissedSuggestionsStatus();
 | 
						|
      Preferences.get(PREF_URLBAR_QUICKSUGGEST_BLOCKLIST).on("change", () =>
 | 
						|
        this._updateDismissedSuggestionsStatus()
 | 
						|
      );
 | 
						|
      Preferences.get(PREF_URLBAR_WEATHER_USER_ENABLED).on("change", () =>
 | 
						|
        this._updateDismissedSuggestionsStatus()
 | 
						|
      );
 | 
						|
      setEventListener("restoreDismissedSuggestions", "command", () =>
 | 
						|
        this.restoreDismissedSuggestions()
 | 
						|
      );
 | 
						|
 | 
						|
      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]);
 | 
						|
      }
 | 
						|
      document
 | 
						|
        .getElementById("openSearchEnginePreferences")
 | 
						|
        .classList.remove("extraMargin");
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Updates the Firefox Suggest info box (in the address bar section) depending
 | 
						|
   * on the states of the Firefox Suggest toggles.
 | 
						|
   */
 | 
						|
  _updateFirefoxSuggestInfoBox() {
 | 
						|
    let nonsponsored = Preferences.get(
 | 
						|
      "browser.urlbar.suggest.quicksuggest.nonsponsored"
 | 
						|
    ).value;
 | 
						|
    let sponsored = Preferences.get(
 | 
						|
      "browser.urlbar.suggest.quicksuggest.sponsored"
 | 
						|
    ).value;
 | 
						|
    let dataCollection = Preferences.get(
 | 
						|
      "browser.urlbar.quicksuggest.dataCollection.enabled"
 | 
						|
    ).value;
 | 
						|
 | 
						|
    // Get the l10n ID of the appropriate text based on the values of the three
 | 
						|
    // prefs.
 | 
						|
    let l10nId;
 | 
						|
    if (nonsponsored && sponsored && dataCollection) {
 | 
						|
      l10nId = "addressbar-firefox-suggest-info-all";
 | 
						|
    } else if (nonsponsored && sponsored && !dataCollection) {
 | 
						|
      l10nId = "addressbar-firefox-suggest-info-nonsponsored-sponsored";
 | 
						|
    } else if (nonsponsored && !sponsored && dataCollection) {
 | 
						|
      l10nId = "addressbar-firefox-suggest-info-nonsponsored-data";
 | 
						|
    } else if (nonsponsored && !sponsored && !dataCollection) {
 | 
						|
      l10nId = "addressbar-firefox-suggest-info-nonsponsored";
 | 
						|
    } else if (!nonsponsored && sponsored && dataCollection) {
 | 
						|
      l10nId = "addressbar-firefox-suggest-info-sponsored-data";
 | 
						|
    } else if (!nonsponsored && sponsored && !dataCollection) {
 | 
						|
      l10nId = "addressbar-firefox-suggest-info-sponsored";
 | 
						|
    } else if (!nonsponsored && !sponsored && dataCollection) {
 | 
						|
      l10nId = "addressbar-firefox-suggest-info-data";
 | 
						|
    }
 | 
						|
 | 
						|
    let instance = (this._firefoxSuggestInfoBoxInstance = {});
 | 
						|
    let infoBox = document.getElementById("firefoxSuggestInfoBox");
 | 
						|
    if (!l10nId) {
 | 
						|
      infoBox.hidden = true;
 | 
						|
    } else {
 | 
						|
      let infoText = document.getElementById("firefoxSuggestInfoText");
 | 
						|
      infoText.dataset.l10nId = l10nId;
 | 
						|
 | 
						|
      // If the info box is currently hidden and we unhide it immediately, it
 | 
						|
      // will show its old text until the new text is asyncly fetched and shown.
 | 
						|
      // That's ugly, so wait for the fetch to finish before unhiding it.
 | 
						|
      document.l10n.translateElements([infoText]).then(() => {
 | 
						|
        if (instance == this._firefoxSuggestInfoBoxInstance) {
 | 
						|
          infoBox.hidden = false;
 | 
						|
        }
 | 
						|
      });
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Enables/disables the "Restore" button for dismissed Firefox Suggest
 | 
						|
   * suggestions.
 | 
						|
   */
 | 
						|
  _updateDismissedSuggestionsStatus() {
 | 
						|
    document.getElementById("restoreDismissedSuggestions").disabled =
 | 
						|
      !Services.prefs.prefHasUserValue(PREF_URLBAR_QUICKSUGGEST_BLOCKLIST) &&
 | 
						|
      !(
 | 
						|
        Services.prefs.prefHasUserValue(PREF_URLBAR_WEATHER_USER_ENABLED) &&
 | 
						|
        !Services.prefs.getBoolPref(PREF_URLBAR_WEATHER_USER_ENABLED)
 | 
						|
      );
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Restores Firefox Suggest suggestions dismissed by the user.
 | 
						|
   */
 | 
						|
  restoreDismissedSuggestions() {
 | 
						|
    Services.prefs.clearUserPref(PREF_URLBAR_QUICKSUGGEST_BLOCKLIST);
 | 
						|
    Services.prefs.clearUserPref(PREF_URLBAR_WEATHER_USER_ENABLED);
 | 
						|
  },
 | 
						|
 | 
						|
  // 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
 | 
						|
    );
 | 
						|
  },
 | 
						|
 | 
						|
  // SPEAKER
 | 
						|
 | 
						|
  /**
 | 
						|
   * Displays the speaker exceptions dialog where specific site speaker
 | 
						|
   * preferences can be set.
 | 
						|
   */
 | 
						|
  showSpeakerExceptions() {
 | 
						|
    let params = { permissionType: "speaker" };
 | 
						|
 | 
						|
    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.isPrimaryPasswordSet();
 | 
						|
 | 
						|
    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"));
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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 primary password may be changed.
 | 
						|
   */
 | 
						|
  async changeMasterPassword() {
 | 
						|
    // Require OS authentication before the user can set a Primary Password.
 | 
						|
    // OS reauthenticate functionality is not available on Linux yet (bug 1527745)
 | 
						|
    if (
 | 
						|
      !LoginHelper.isPrimaryPasswordSet() &&
 | 
						|
      OS_AUTH_ENABLED &&
 | 
						|
      OSKeyStore.canReauth()
 | 
						|
    ) {
 | 
						|
      // Uses primary-password-os-auth-dialog-message-win and
 | 
						|
      // primary-password-os-auth-dialog-message-macosx via concatenation:
 | 
						|
      let messageId =
 | 
						|
        "primary-password-os-auth-dialog-message-" + AppConstants.platform;
 | 
						|
      let [messageText, captionText] = await document.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 GPC/DNT UI.
 | 
						|
   * The GPC part should only appear if the functionality is
 | 
						|
   * enabled.
 | 
						|
   */
 | 
						|
  _initGlobalPrivacyControlUI() {
 | 
						|
    let gpcEnabledPrefValue = Services.prefs.getBoolPref(
 | 
						|
      "privacy.globalprivacycontrol.functionality.enabled",
 | 
						|
      false
 | 
						|
    );
 | 
						|
    document.getElementById("globalPrivacyControlBox").hidden =
 | 
						|
      !gpcEnabledPrefValue;
 | 
						|
    document.getElementById("doNotTrackBox").hidden = !gpcEnabledPrefValue;
 | 
						|
    document.getElementById("legacyDoNotTrackBox").hidden = gpcEnabledPrefValue;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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;
 | 
						|
  },
 | 
						|
 | 
						|
  toggleRelayIntegration() {
 | 
						|
    const checkbox = document.getElementById("relayIntegration");
 | 
						|
    if (checkbox.checked) {
 | 
						|
      FirefoxRelay.markAsAvailable();
 | 
						|
      FirefoxRelayTelemetry.recordRelayPrefEvent("enabled");
 | 
						|
    } else {
 | 
						|
      FirefoxRelay.markAsDisabled();
 | 
						|
      FirefoxRelayTelemetry.recordRelayPrefEvent("disabled");
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  _updateRelayIntegrationUI() {
 | 
						|
    document.getElementById("relayIntegrationBox").hidden =
 | 
						|
      !FirefoxRelay.isAvailable;
 | 
						|
    document.getElementById("relayIntegration").checked =
 | 
						|
      FirefoxRelay.isAvailable && !FirefoxRelay.isDisabled;
 | 
						|
  },
 | 
						|
 | 
						|
  _initRelayIntegrationUI() {
 | 
						|
    document
 | 
						|
      .getElementById("relayIntegrationLearnMoreLink")
 | 
						|
      .setAttribute("href", FirefoxRelay.learnMoreUrl);
 | 
						|
 | 
						|
    setEventListener(
 | 
						|
      "relayIntegration",
 | 
						|
      "command",
 | 
						|
      gPrivacyPane.toggleRelayIntegration.bind(gPrivacyPane)
 | 
						|
    );
 | 
						|
    Preferences.get("signon.firefoxRelay.feature").on(
 | 
						|
      "change",
 | 
						|
      gPrivacyPane._updateRelayIntegrationUI.bind(gPrivacyPane)
 | 
						|
    );
 | 
						|
 | 
						|
    this._updateRelayIntegrationUI();
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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;
 | 
						|
    document.getElementById("relayIntegration").disabled =
 | 
						|
      !prefValue || Services.prefs.prefIsLocked("signon.firefoxRelay.feature");
 | 
						|
    // 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 || warn.locked;
 | 
						|
 | 
						|
    // 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"
 | 
						|
    );
 | 
						|
 | 
						|
    enableSafeBrowsing.addEventListener("command", function () {
 | 
						|
      safeBrowsingPhishingPref.value = enableSafeBrowsing.checked;
 | 
						|
      safeBrowsingMalwarePref.value = enableSafeBrowsing.checked;
 | 
						|
 | 
						|
      blockDownloads.disabled =
 | 
						|
        !enableSafeBrowsing.checked || blockDownloadsPref.locked;
 | 
						|
      blockUncommonUnwanted.disabled =
 | 
						|
        !blockDownloads.checked ||
 | 
						|
        !enableSafeBrowsing.checked ||
 | 
						|
        blockUnwantedPref.locked ||
 | 
						|
        blockUncommonPref.locked;
 | 
						|
    });
 | 
						|
 | 
						|
    blockDownloads.addEventListener("command", function () {
 | 
						|
      blockDownloadsPref.value = blockDownloads.checked;
 | 
						|
      blockUncommonUnwanted.disabled =
 | 
						|
        !blockDownloads.checked ||
 | 
						|
        blockUnwantedPref.locked ||
 | 
						|
        blockUncommonPref.locked;
 | 
						|
    });
 | 
						|
 | 
						|
    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;
 | 
						|
 | 
						|
    if (safeBrowsingPhishingPref.locked || safeBrowsingMalwarePref.locked) {
 | 
						|
      enableSafeBrowsing.disabled = true;
 | 
						|
    }
 | 
						|
    if (blockDownloadsPref.locked) {
 | 
						|
      blockDownloads.disabled = true;
 | 
						|
    }
 | 
						|
    if (blockUnwantedPref.locked || blockUncommonPref.locked) {
 | 
						|
      blockUncommonUnwanted.disabled = true;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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() {
 | 
						|
    if (
 | 
						|
      !AppConstants.MOZ_DATA_REPORTING &&
 | 
						|
      !NimbusFeatures.majorRelease2022.getVariable(
 | 
						|
        "feltPrivacyShowPreferencesSection"
 | 
						|
      )
 | 
						|
    ) {
 | 
						|
      // Nothing to control in the data collection section, remove it.
 | 
						|
      document.getElementById("dataCollectionCategory").remove();
 | 
						|
      document.getElementById("dataCollectionGroup").remove();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    this._setupLearnMoreLink(
 | 
						|
      "toolkit.datacollection.infoURL",
 | 
						|
      "dataCollectionPrivacyNotice"
 | 
						|
    );
 | 
						|
    this.initPrivacySegmentation();
 | 
						|
  },
 | 
						|
 | 
						|
  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();
 | 
						|
    });
 | 
						|
  },
 | 
						|
 | 
						|
  initPrivacySegmentation() {
 | 
						|
    // Section visibility
 | 
						|
    let section = document.getElementById("privacySegmentationSection");
 | 
						|
    let updatePrivacySegmentationSectionVisibilityState = () => {
 | 
						|
      section.hidden = !NimbusFeatures.majorRelease2022.getVariable(
 | 
						|
        "feltPrivacyShowPreferencesSection"
 | 
						|
      );
 | 
						|
    };
 | 
						|
 | 
						|
    NimbusFeatures.majorRelease2022.onUpdate(
 | 
						|
      updatePrivacySegmentationSectionVisibilityState
 | 
						|
    );
 | 
						|
    window.addEventListener("unload", () => {
 | 
						|
      NimbusFeatures.majorRelease2022.offUpdate(
 | 
						|
        updatePrivacySegmentationSectionVisibilityState
 | 
						|
      );
 | 
						|
    });
 | 
						|
 | 
						|
    updatePrivacySegmentationSectionVisibilityState();
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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 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;
 | 
						|
      case "network:trr-uri-changed":
 | 
						|
      case "network:trr-mode-changed":
 | 
						|
      case "network:trr-confirmation":
 | 
						|
        gPrivacyPane.updateDoHStatus();
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  },
 | 
						|
};
 |