summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/preferences/privacy.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/preferences/privacy.js')
-rw-r--r--comm/mail/components/preferences/privacy.js562
1 files changed, 562 insertions, 0 deletions
diff --git a/comm/mail/components/preferences/privacy.js b/comm/mail/components/preferences/privacy.js
new file mode 100644
index 0000000000..2bb8cba6ad
--- /dev/null
+++ b/comm/mail/components/preferences/privacy.js
@@ -0,0 +1,562 @@
+/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+"use strict";
+
+/* import-globals-from preferences.js */
+
+var { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
+ OSKeyStore: "resource://gre/modules/OSKeyStore.sys.mjs",
+});
+
+const PREF_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
+
+Preferences.addAll([
+ { id: "mail.spam.manualMark", type: "bool" },
+ { id: "mail.spam.manualMarkMode", type: "int" },
+ { id: "mail.spam.markAsReadOnSpam", type: "bool" },
+ { id: "mail.spam.logging.enabled", type: "bool" },
+ { id: "mail.phishing.detection.enabled", type: "bool" },
+ { id: "browser.safebrowsing.enabled", type: "bool" },
+ { id: "mailnews.downloadToTempFile", type: "bool" },
+ { id: "pref.privacy.disable_button.view_passwords", type: "bool" },
+ { id: "pref.privacy.disable_button.cookie_exceptions", type: "bool" },
+ { id: "pref.privacy.disable_button.view_cookies", type: "bool" },
+ {
+ id: "mailnews.message_display.disable_remote_image",
+ type: "bool",
+ inverted: "true",
+ },
+ { id: "places.history.enabled", type: "bool" },
+ { id: "network.cookie.cookieBehavior", type: "int" },
+ { id: "network.cookie.blockFutureCookies", type: "bool" },
+ { id: "privacy.donottrackheader.enabled", type: "bool" },
+ { 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: "mail.e2ee.auto_enable", type: "bool" },
+ { id: "mail.e2ee.auto_disable", type: "bool" },
+ { id: "mail.e2ee.notify_on_auto_disable", type: "bool" },
+]);
+
+if (AppConstants.MOZ_DATA_REPORTING) {
+ Preferences.addAll([
+ // Preference instances for prefs that we need to monitor while the page is open.
+ { id: PREF_UPLOAD_ENABLED, type: "bool" },
+ ]);
+}
+
+// Data Choices tab
+if (AppConstants.MOZ_CRASHREPORTER) {
+ Preferences.add({
+ id: "browser.crashReports.unsubmittedCheck.autoSubmit2",
+ type: "bool",
+ });
+}
+
+function setEventListener(aId, aEventType, aCallback) {
+ document
+ .getElementById(aId)
+ .addEventListener(aEventType, aCallback.bind(gPrivacyPane));
+}
+
+var gPrivacyPane = {
+ init() {
+ this.updateManualMarkMode(Preferences.get("mail.spam.manualMark").value);
+ this.updateJunkLogButton(
+ Preferences.get("mail.spam.logging.enabled").value
+ );
+
+ this._initMasterPasswordUI();
+
+ if (AppConstants.MOZ_DATA_REPORTING) {
+ this.initDataCollection();
+ if (AppConstants.MOZ_CRASHREPORTER) {
+ this.initSubmitCrashes();
+ }
+ this.initSubmitHealthReport();
+ setEventListener(
+ "submitHealthReportBox",
+ "command",
+ gPrivacyPane.updateSubmitHealthReport
+ );
+ setEventListener(
+ "telemetryDataDeletionLearnMore",
+ "command",
+ gPrivacyPane.showDataDeletion
+ );
+ }
+
+ this.readAcceptCookies();
+ let element = document.getElementById("acceptCookies");
+ Preferences.addSyncFromPrefListener(element, () =>
+ this.readAcceptCookies()
+ );
+ Preferences.addSyncToPrefListener(element, () => this.writeAcceptCookies());
+
+ element = document.getElementById("acceptThirdPartyMenu");
+ Preferences.addSyncFromPrefListener(element, () =>
+ this.readAcceptThirdPartyCookies()
+ );
+ Preferences.addSyncToPrefListener(element, () =>
+ this.writeAcceptThirdPartyCookies()
+ );
+
+ element = document.getElementById("enableOCSP");
+ Preferences.addSyncFromPrefListener(element, () => this.readEnableOCSP());
+ Preferences.addSyncToPrefListener(element, () => this.writeEnableOCSP());
+
+ this.initE2eeCheckboxes();
+ },
+
+ /**
+ * Reload the current message after a preference affecting the view
+ * has been changed.
+ */
+ reloadMessageInOpener() {
+ if (window.opener && typeof window.opener.ReloadMessage == "function") {
+ window.opener.ReloadMessage();
+ }
+ },
+
+ /**
+ * Reads the network.cookie.cookieBehavior preference value and
+ * enables/disables the rest of the cookie UI accordingly, returning true
+ * if cookies are enabled.
+ */
+ readAcceptCookies() {
+ let pref = Preferences.get("network.cookie.cookieBehavior");
+ let exceptionsButton = document.getElementById("cookieExceptions");
+ let acceptThirdPartyLabel = document.getElementById(
+ "acceptThirdPartyLabel"
+ );
+ let acceptThirdPartyMenu = document.getElementById("acceptThirdPartyMenu");
+ let showCookiesButton = document.getElementById("showCookiesButton");
+
+ // enable the rest of the UI for anything other than "disable all cookies"
+ let acceptCookies = pref.value != 2;
+ let cookieBehaviorLocked = Services.prefs.prefIsLocked(
+ "network.cookie.cookieBehavior"
+ );
+
+ exceptionsButton.disabled = cookieBehaviorLocked;
+ acceptThirdPartyLabel.disabled = acceptThirdPartyMenu.disabled =
+ !acceptCookies || cookieBehaviorLocked;
+ showCookiesButton.disabled = cookieBehaviorLocked;
+
+ return acceptCookies;
+ },
+
+ /**
+ * Enables/disables the "keep until" label and menulist in response to the
+ * "accept cookies" checkbox being checked or unchecked.
+ *
+ * @returns 0 if cookies are accepted, 2 if they are not;
+ * the value network.cookie.cookieBehavior should get
+ */
+ writeAcceptCookies() {
+ let accept = document.getElementById("acceptCookies");
+ let acceptThirdPartyMenu = document.getElementById("acceptThirdPartyMenu");
+ // if we're enabling cookies, automatically select 'accept third party always'
+ if (accept.checked) {
+ acceptThirdPartyMenu.selectedIndex = 0;
+ }
+
+ return accept.checked ? 0 : 2;
+ },
+
+ /**
+ * Displays fine-grained, per-site preferences for cookies.
+ */
+ showCookieExceptions() {
+ let bundle = document.getElementById("bundlePreferences");
+ let params = {
+ blockVisible: true,
+ sessionVisible: true,
+ allowVisible: true,
+ prefilledHost: "",
+ permissionType: "cookie",
+ windowTitle: bundle.getString("cookiepermissionstitle"),
+ introText: bundle.getString("cookiepermissionstext"),
+ };
+ gSubDialog.open(
+ "chrome://messenger/content/preferences/permissions.xhtml",
+ undefined,
+ params
+ );
+ },
+
+ /**
+ * Displays all the user's cookies in a dialog.
+ */
+ showCookies(aCategory) {
+ gSubDialog.open("chrome://messenger/content/preferences/cookies.xhtml");
+ },
+
+ /**
+ * Converts between network.cookie.cookieBehavior and the third-party cookie UI
+ */
+ readAcceptThirdPartyCookies() {
+ let pref = Preferences.get("network.cookie.cookieBehavior");
+ switch (pref.value) {
+ case 0:
+ return "always";
+ case 1:
+ return "never";
+ case 2:
+ return "never";
+ case 3:
+ return "visited";
+ default:
+ return undefined;
+ }
+ },
+
+ writeAcceptThirdPartyCookies() {
+ let accept = document.getElementById("acceptThirdPartyMenu").selectedItem;
+ switch (accept.value) {
+ case "always":
+ return 0;
+ case "visited":
+ return 3;
+ case "never":
+ return 1;
+ default:
+ return undefined;
+ }
+ },
+
+ /**
+ * Displays fine-grained, per-site preferences for remote content.
+ * We use the "image" type for that, but it can also be stylesheets or
+ * iframes.
+ */
+ showRemoteContentExceptions() {
+ let bundle = document.getElementById("bundlePreferences");
+ let params = {
+ blockVisible: true,
+ sessionVisible: false,
+ allowVisible: true,
+ prefilledHost: "",
+ permissionType: "image",
+ windowTitle: bundle.getString("imagepermissionstitle"),
+ introText: bundle.getString("imagepermissionstext"),
+ };
+ gSubDialog.open(
+ "chrome://messenger/content/preferences/permissions.xhtml",
+ undefined,
+ params
+ );
+ },
+ updateManualMarkMode(aEnableRadioGroup) {
+ document.getElementById("manualMarkMode").disabled = !aEnableRadioGroup;
+ },
+
+ updateJunkLogButton(aEnableButton) {
+ document.getElementById("openJunkLogButton").disabled = !aEnableButton;
+ },
+
+ openJunkLog() {
+ // The junk log dialog can't work as a sub-dialog, because that means
+ // loading it in a browser, and we can't load a chrome: page containing a
+ // file: page in a browser. Open it as a real dialog instead.
+ window.browsingContext.topChromeWindow.openDialog(
+ "chrome://messenger/content/junkLog.xhtml"
+ );
+ },
+
+ resetTrainingData() {
+ // make sure the user really wants to do this
+ var bundle = document.getElementById("bundlePreferences");
+ var title = bundle.getString("confirmResetJunkTrainingTitle");
+ var text = bundle.getString("confirmResetJunkTrainingText");
+
+ // if the user says no, then just fall out
+ if (!Services.prompt.confirm(window, title, text)) {
+ return;
+ }
+
+ // otherwise go ahead and remove the training data
+ MailServices.junk.resetTrainingData();
+ },
+
+ /**
+ * Initializes primary password UI: the "use primary password" checkbox, selects
+ * the primary password button to show, and enables/disables it as necessary.
+ * The primary 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 primary password button depending on the state of the
+ * "use primary password" checkbox, and prompts for primary 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 primary password" dialog to allow the user to remove
+ * the current primary password. When the dialog is dismissed, primary 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),
+ });
+ }
+ this._initMasterPasswordUI();
+ },
+
+ /**
+ * Displays a dialog in which the primary password may be changed.
+ */
+ async changeMasterPassword() {
+ // OS reauthenticate functionality is not available on Linux yet (bug 1527745)
+ if (
+ !LoginHelper.isPrimaryPasswordSet() &&
+ Services.prefs.getBoolPref("signon.management.page.os-auth.enabled") &&
+ AppConstants.platform != "linux"
+ ) {
+ 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.getMostRecentWindow("");
+ let loggedIn = await OSKeyStore.ensureLoggedIn(
+ messageText.value,
+ captionText.value,
+ win,
+ false
+ );
+ if (!loggedIn.authenticated) {
+ return;
+ }
+ }
+
+ gSubDialog.open("chrome://mozapps/content/preferences/changemp.xhtml", {
+ closingCallback: this._initMasterPasswordUI.bind(this),
+ });
+ },
+
+ /**
+ * Shows the sites where the user has saved passwords and the associated
+ * login information.
+ */
+ showPasswords() {
+ gSubDialog.open(
+ "chrome://messenger/content/preferences/passwordManager.xhtml"
+ );
+ },
+
+ updateDownloadedPhishingListState() {
+ document.getElementById("useDownloadedList").disabled =
+ !document.getElementById("enablePhishingDetector").checked;
+ },
+
+ /**
+ * Display the user's certificates and associated options.
+ */
+ showCertificates() {
+ gSubDialog.open("chrome://pippki/content/certManager.xhtml");
+ },
+
+ /**
+ * security.OCSP.enabled is an integer value for legacy reasons.
+ * A value of 1 means OCSP is enabled. Any other value means it is disabled.
+ */
+ 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 == 1;
+ },
+
+ /**
+ * See documentation for readEnableOCSP.
+ */
+ writeEnableOCSP() {
+ var checkbox = document.getElementById("enableOCSP");
+ return checkbox.checked ? 1 : 0;
+ },
+
+ /**
+ * Display a dialog from which the user can manage his security devices.
+ */
+ showSecurityDevices() {
+ gSubDialog.open("chrome://pippki/content/device_manager.xhtml");
+ },
+
+ /**
+ * Displays the learn more health report page when a user opts out of data collection.
+ */
+ showDataDeletion() {
+ let url =
+ Services.urlFormatter.formatURLPref("app.support.baseURL") +
+ "telemetry-clientid";
+ window.open(url, "_blank");
+ },
+
+ initDataCollection() {
+ this._setupLearnMoreLink(
+ "toolkit.datacollection.infoURL",
+ "dataCollectionPrivacyNotice"
+ );
+ },
+
+ initSubmitCrashes() {
+ this._setupLearnMoreLink(
+ "toolkit.crashreporter.infoURL",
+ "crashReporterLearnMore"
+ );
+ },
+
+ /**
+ * 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.setAttribute("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");
+
+ Services.prefs.setBoolPref(PREF_UPLOAD_ENABLED, checkbox.checked);
+
+ // If allow telemetry is checked, hide the box saying you're no longer
+ // allowing it.
+ document.getElementById("telemetry-container").hidden = checkbox.checked;
+ },
+
+ initE2eeCheckboxes() {
+ let on = document.getElementById("emailE2eeAutoEnable");
+ let off = document.getElementById("emailE2eeAutoDisable");
+ let notify = document.getElementById("emailE2eeAutoDisableNotify");
+
+ on.checked = Preferences.get("mail.e2ee.auto_enable").value;
+ off.checked = Preferences.get("mail.e2ee.auto_disable").value;
+ notify.checked = Preferences.get("mail.e2ee.notify_on_auto_disable").value;
+
+ if (!on.checked) {
+ off.disabled = true;
+ notify.disabled = true;
+ } else {
+ off.disabled = false;
+ notify.disabled = !off.checked;
+ }
+ },
+
+ updateE2eeCheckboxes() {
+ let on = document.getElementById("emailE2eeAutoEnable");
+ let off = document.getElementById("emailE2eeAutoDisable");
+ let notify = document.getElementById("emailE2eeAutoDisableNotify");
+
+ if (!on.checked) {
+ off.disabled = true;
+ notify.disabled = true;
+ } else {
+ off.disabled = false;
+ notify.disabled = !off.checked;
+ }
+ },
+};
+
+Preferences.get("mailnews.message_display.disable_remote_image").on(
+ "change",
+ gPrivacyPane.reloadMessageInOpener
+);
+Preferences.get("mail.phishing.detection.enabled").on(
+ "change",
+ gPrivacyPane.reloadMessageInOpener
+);