[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [tor-browser/tor-browser-60.5.1esr-8.5-1] Bug 25658: Replace security slider with security level UI



commit a7ba005d5398a29d95320a5e8c02bf050e58f08b
Author: Richard Pospesel <richard@xxxxxxxxxxxxxx>
Date:   Mon Mar 4 16:09:51 2019 -0800

    Bug 25658: Replace security slider with security level UI
    
    This patch adds a new 'securitylevel' component to Tor Browser intended
    to replace the torbutton 'Security Slider'.
    
    This component adds a new Security Level toolbar button which visually
    indicates the current global security level via icon (as defined by the
    extensions.torbutton.security_slider pref), a drop-down hanger with a
    short description of the current security level, and a new section in
    the about:preferences#privacy page where users can change their current
    security level. In addition, the hanger and the preferences page will
    show a visual warning when the user has modified prefs associated with
    the security level and provide a one-click 'Restore Defaults' button to
    get the user back on recommended settings.
    
    Strings used by this patch are pulled from the torbutton extension, but
    en-US defaults are provided if there is an error loading from the
    extension. With this patch applied, the usual work-flow of "./mach build
    && ./mach run" work as expected, even if the torbutton extension is
    disabled.
---
 browser/app/profile/000-tor-browser.js             |   2 +-
 browser/base/content/browser.js                    |   7 +
 browser/base/content/browser.xul                   |   5 +
 browser/components/moz.build                       |   1 +
 .../preferences/in-content/preferences.js          |  18 +-
 .../preferences/in-content/preferences.xul         |   1 +
 .../components/preferences/in-content/privacy.js   |  15 +
 .../components/preferences/in-content/privacy.xul  |   2 +
 .../securitylevel/content/securityLevel.js         | 528 +++++++++++++++++++++
 .../securitylevel/content/securityLevelButton.css  |   9 +
 .../content/securityLevelButton.inc.xul            |   5 +
 .../securitylevel/content/securityLevelButton.svg  |  21 +
 .../securitylevel/content/securityLevelPanel.css   |  82 ++++
 .../content/securityLevelPanel.inc.xul             |  33 ++
 .../content/securityLevelPreferences.css           |  26 +
 .../content/securityLevelPreferences.inc.xul       |  66 +++
 browser/components/securitylevel/jar.mn            |   6 +
 browser/components/securitylevel/moz.build         |   1 +
 18 files changed, 823 insertions(+), 5 deletions(-)

diff --git a/browser/app/profile/000-tor-browser.js b/browser/app/profile/000-tor-browser.js
index a0b370c73279..df4d58e1009a 100644
--- a/browser/app/profile/000-tor-browser.js
+++ b/browser/app/profile/000-tor-browser.js
@@ -271,7 +271,7 @@ pref("extensions.legacy.exceptions", "{972ce4c6-7e08-4474-a285-3208198ce6fd},tor
 pref("extensions.webextensions.restrictedDomains", "");
 
 // Toolbar layout
-pref("browser.uiCustomization.state", "{\"placements\":{\"widget-overflow-fixed-list\":[],\"PersonalToolbar\":[\"personal-bookmarks\"],\"nav-bar\":[\"torbutton-button\",\"back-button\",\"forward-button\",\"stop-reload-button\",\"urlbar-container\",\"downloads-button\",\"_73a6fe31-595d-460b-a920-fcc0f8843232_-browser-action\"],\"TabsToolbar\":[\"tabbrowser-tabs\",\"new-tab-button\",\"alltabs-button\"],\"toolbar-menubar\":[\"menubar-items\"],\"PanelUI-contents\":[\"home-button\",\"edit-controls\",\"zoom-controls\",\"new-window-button\",\"save-page-button\",\"print-button\",\"bookmarks-menu-button\",\"history-panelmenu\",\"find-button\",\"preferences-button\",\"add-ons-button\",\"developer-button\",\"https-everywhere-button\"],\"addon-bar\":[\"addonbar-closebutton\",\"status-bar\"]},\"seen\":[\"developer-button\",\"https-everywhere_eff_org-browser-action\",\"_73a6fe31-595d-460b-a920-fcc0f8843232_-browser-action\"],\"dirtyAreaCache\":[\"PersonalToolbar\",\"nav-bar\",\"TabsToolbar\",\"to
 olbar-menubar\"],\"currentVersion\":14,\"newElementCount\":1}");
+pref("browser.uiCustomization.state", "{\"placements\":{\"widget-overflow-fixed-list\":[],\"PersonalToolbar\":[\"personal-bookmarks\"],\"nav-bar\":[\"back-button\",\"forward-button\",\"stop-reload-button\",\"torbutton-button\",\"urlbar-container\",\"downloads-button\",\"security-level-button\"],\"TabsToolbar\":[\"tabbrowser-tabs\",\"new-tab-button\",\"alltabs-button\"],\"toolbar-menubar\":[\"menubar-items\"],\"PanelUI-contents\":[\"home-button\",\"edit-controls\",\"zoom-controls\",\"new-window-button\",\"save-page-button\",\"print-button\",\"bookmarks-menu-button\",\"history-panelmenu\",\"find-button\",\"preferences-button\",\"add-ons-button\",\"developer-button\"],\"addon-bar\":[\"addonbar-closebutton\",\"status-bar\"]},\"seen\":[\"developer-button\",\"https-everywhere-eff_eff_org-browser-action\",\"_73a6fe31-595d-460b-a920-fcc0f8843232_-browser-action\"],\"dirtyAreaCache\":[\"PersonalToolbar\",\"nav-bar\",\"TabsToolbar\",\"toolbar-menubar\"],\"currentVersion\":14,\"newElementCount
 \":1}");
 
 // Putting the search engine prefs into this file to fix #11236.
 // Default search engine
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 4d15249afa97..16e712be0ba3 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -116,6 +116,8 @@ XPCOMUtils.defineLazyScriptGetter(this, ["DownloadsPanel",
 XPCOMUtils.defineLazyScriptGetter(this, ["DownloadsButton",
                                          "DownloadsIndicatorView"],
                                   "chrome://browser/content/downloads/indicator.js");
+XPCOMUtils.defineLazyScriptGetter(this, ["SecurityLevelButton"],
+                                  "chrome://browser/content/securitylevel/securityLevel.js");
 XPCOMUtils.defineLazyScriptGetter(this, "gEditItemOverlay",
                                   "chrome://browser/content/places/editBookmarkOverlay.js");
 if (AppConstants.NIGHTLY_BUILD) {
@@ -1328,6 +1330,9 @@ var gBrowserInit = {
     // doesn't flicker as the window is being shown.
     DownloadsButton.init();
 
+    // Init the SecuritySettingsButton
+    SecurityLevelButton.init();
+
     // Certain kinds of automigration rely on this notification to complete
     // their tasks BEFORE the browser window is shown. SessionStore uses it to
     // restore tabs into windows AFTER important parts like gMultiProcessBrowser
@@ -1899,6 +1904,8 @@ var gBrowserInit = {
 
     DownloadsButton.uninit();
 
+    SecurityLevelButton.uninit();
+
     gAccessibilityServiceIndicator.uninit();
 
     LanguagePrompt.uninit();
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 4d8496bbcf24..dac6fcbddf05 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -8,6 +8,8 @@
 
 <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/downloads/downloads.css"?>
+<?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPanel.css"?>
+<?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelButton.css"?>
 <?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/usercontext/usercontext.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/controlcenter/panel.css" type="text/css"?>
@@ -500,6 +502,7 @@
 #include ../../components/customizableui/content/panelUI.inc.xul
 #include ../../components/controlcenter/content/panel.inc.xul
 #include ../../components/downloads/content/downloadsPanel.inc.xul
+#include ../../components/securitylevel/content/securityLevelPanel.inc.xul
 
     <hbox id="downloads-animation-container" mousethrough="always">
       <vbox id="downloads-notification-anchor" hidden="true">
@@ -954,6 +957,8 @@
             </stack>
           </toolbarbutton>
 
+#include ../../components/securitylevel/content/securityLevelButton.inc.xul
+
         <toolbarbutton id="library-button" class="toolbarbutton-1 chromeclass-toolbar-additional subviewbutton-nav"
                        removable="true"
                        onmousedown="PanelUI.showSubView('appMenu-libraryView', this, event);"
diff --git a/browser/components/moz.build b/browser/components/moz.build
index 587d433eee4d..1ce83d3afb8b 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -49,6 +49,7 @@ DIRS += [
     'privatebrowsing',
     'resistfingerprinting',
     'search',
+    'securitylevel',
     'sessionstore',
     'shell',
     'syncedtabs',
diff --git a/browser/components/preferences/in-content/preferences.js b/browser/components/preferences/in-content/preferences.js
index 3da7d9f26403..e195d30061bc 100644
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -224,10 +224,20 @@ async function spotlight(subcategory) {
   }
   if (subcategory) {
     if (!gSearchResultsPane.categoriesInitialized) {
-      await waitForSystemAddonInjectionsFinished([{
-        isGoingToInject: formAutofillParent.initialized,
-        elementId: "formAutofillGroup",
-      }]);
+      // fix for tor #29554
+      // for some reason this code throws an exception when called and
+      // prevents the scrollAndHighlight code from running so we
+      // swallow the exception here
+      //
+      // This entire block has been removed and/or refactored as part of
+      // mozilla #1520350 (commit d524c53377c22913cac387ad77b803aaf4fb754e)
+      // on 2019/01/28
+      try {
+        await waitForSystemAddonInjectionsFinished([{
+          isGoingToInject: formAutofillParent.initialized,
+          elementId: "formAutofillGroup",
+        }]);
+      } catch (e) { }
     }
     scrollAndHighlight(subcategory);
   }
diff --git a/browser/components/preferences/in-content/preferences.xul b/browser/components/preferences/in-content/preferences.xul
index 91e1cf94ebb4..7a606d76a42a 100644
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -15,6 +15,7 @@
 <?xml-stylesheet href="chrome://browser/skin/preferences/in-content/search.css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/in-content/containers.css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/in-content/privacy.css"?>
+<?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?>
 
 <!DOCTYPE page [
 <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
diff --git a/browser/components/preferences/in-content/privacy.js b/browser/components/preferences/in-content/privacy.js
index e22624c82e0b..d2229d136261 100644
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -21,6 +21,9 @@ ChromeUtils.defineModuleGetter(this, "SiteDataManager",
 XPCOMUtils.defineLazyPreferenceGetter(this, "trackingprotectionUiEnabled",
                                       "privacy.trackingprotection.ui.enabled");
 
+XPCOMUtils.defineLazyScriptGetter(this, ["SecurityLevelPreferences"],
+                                  "chrome://browser/content/securitylevel/securityLevel.js");
+
 ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 const PREF_UPLOAD_ENABLED = "datareporting.healthreport.uploadEnabled";
@@ -150,6 +153,17 @@ var gPrivacyPane = {
   },
 
   /**
+   * Show the Security Level UI
+   */
+  _initSecurityLevel() {
+    SecurityLevelPreferences.init();
+    let unload = () => {
+      window.removeEventListener("unload", unload);
+      SecurityLevelPreferences.uninit();
+    };
+  },
+
+  /**
    * Linkify the Learn More link of the Private Browsing Mode Tracking
    * Protection UI.
    */
@@ -245,6 +259,7 @@ var gPrivacyPane = {
     this.updatePrivacyMicroControls();
     this.initAutoStartPrivateBrowsingReverter();
     this._initTrackingProtection();
+    this._initSecurityLevel();
     this._initTrackingProtectionPBM();
     this._initTrackingProtectionExtensionControl();
     this._initAutocomplete();
diff --git a/browser/components/preferences/in-content/privacy.xul b/browser/components/preferences/in-content/privacy.xul
index a5f3d25193c5..81e5d5b5079c 100644
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -583,6 +583,8 @@
   <label class="header-name" flex="1">&security.label;</label>
 </hbox>
 
+#include ../../securitylevel/content/securityLevelPreferences.inc.xul
+
 <!-- addons, forgery (phishing) UI Security -->
 <groupbox id="browsingProtectionGroup" data-category="panePrivacy" hidden="true">
   <caption><label>&browsingProtection.label;</label></caption>
diff --git a/browser/components/securitylevel/content/securityLevel.js b/browser/components/securitylevel/content/securityLevel.js
new file mode 100644
index 000000000000..405d38839da0
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevel.js
@@ -0,0 +1,528 @@
+"use strict";
+
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+  CustomizableUI: "resource:///modules/CustomizableUI.jsm",
+  PanelMultiView: "resource:///modules/PanelMultiView.jsm",
+});
+
+/*
+ Security Level Strings
+
+ Strings loaded from torbutton, but en-US defaults provided in case torbutton addon not enabled
+*/
+XPCOMUtils.defineLazyGetter(this, "SecurityLevelStrings", function() {
+  let sls = null;
+  try {
+    sls = Services.strings.createBundle("chrome://torbutton/locale/securityLevel.properties");
+  } catch(e) { }
+
+  // tries to get the given key from the string bundle, return fallback on failure
+  let getString = function(key, fallback) {
+    let retval = "";
+    if (sls) {
+      try {
+        retval = sls.GetStringFromName(key);
+      } catch(e) { }
+    }
+    if (retval == "") {
+      retval = fallback;
+    }
+    return retval;
+  };
+
+  // read localized strings from torbutton; but use hard-coded en-US strings as fallbacks in case of error
+  let retval = {
+    securityLevel : getString("securityLevel.securityLevel", "Security Level"),
+    customWarning : getString("securityLevel.customWarning", "Custom"),
+    overview : getString("securityLevel.overview", "Disable certain web features that can be used to attack your security and anonymity."),
+    standard : {
+      level : getString("securityLevel.standard.level", "Standard"),
+      tooltip : getString("securityLevel.standard.tooltip", "Security Level : Standard"),
+      summary : getString("securityLevel.standard.summary", "All Tor Browser and website features are enabled."),
+    },
+    safer : {
+      level : getString("securityLevel.safer.level", "Safer"),
+      tooltip : getString("securityLevel.safer.tooltip", "Security Level : Safer"),
+      summary : getString("securityLevel.safer.summary", "Disables website features that are often dangerous, causing some sites to lose functionality."),
+      description1 : getString("securityLevel.safer.description1", "JavaScript is disabled on non-HTTPS sites."),
+      description2 : getString("securityLevel.safer.description2", "Some fonts and math symbols are disabled."),
+      description3 : getString("securityLevel.safer.description3", "Audio and video (HTML5 media) are click-to-play."),
+    },
+    safest : {
+      level : getString("securityLevel.safest.level", "Safest"),
+      tooltip : getString("securityLevel.safest.tooltip", "Security Level : Safest"),
+      summary : getString("securityLevel.safest.summary", "Only allows website features required for static sites and basic services. These changes affect images, media, and scripts."),
+      description1 : getString("securityLevel.safest.description1", "JavaScript is disabled by default on all sites."),
+      description2 : getString("securityLevel.safest.description2", "Some fonts, icons, math symbols, and images are disabled."),
+      description3 : getString("securityLevel.safest.description3", "Audio and video (HTML5 media) are click-to-play."),
+    },
+    custom : {
+      summary : getString("securityLevel.custom.summary", "Your custom browser preferences have resulted in unusual security settings. For security and privacy reasons, we recommend you choose one of the default security levels."),
+    },
+    learnMore : getString("securityLevel.learnMore", "Learn more"),
+    learnMoreURL : function() {
+        let locale = "";
+        try {
+          let { getLocale } =
+            Cu.import("resource://torbutton/modules/utils.js", {});
+          locale = getLocale();
+        } catch(e) {}
+
+        if (locale == "") {
+          locale = "en-US";
+        }
+
+        return "https://tb-manual.torproject.org/"; + locale + "/security-settings.html";
+      }(),
+    restoreDefaults : getString("securityLevel.restoreDefaults", "Restore Defaults"),
+    advancedSecuritySettings : getString("securityLevel.advancedSecuritySettings", "Advanced Security Settings\u2026"),
+  };
+
+
+  return retval;
+});
+
+
+/*
+  Security Level Prefs
+
+  Getters and Setters for relevant torbutton prefs
+*/
+const SecurityLevelPrefs = {
+  security_slider_pref : "extensions.torbutton.security_slider",
+  security_custom_pref : "extensions.torbutton.security_custom",
+
+  get securitySlider() {
+    try {
+      return Services.prefs.getIntPref(this.security_slider_pref);
+    } catch(e) {
+      // init pref to 4 (standard)
+      const val = 4;
+      Services.prefs.setIntPref(this.security_slider_pref, val);
+      return val;
+    }
+  },
+
+  set securitySlider(val) {
+    Services.prefs.setIntPref(this.security_slider_pref, val);
+  },
+
+  get securityCustom() {
+    try {
+      return Services.prefs.getBoolPref(this.security_custom_pref);
+    } catch(e) {
+      // init custom to false
+      const val = false;
+      Services.prefs.setBoolPref(this.security_custom_pref, val);
+      return val;
+    }
+  },
+
+  set securityCustom(val) {
+    Services.prefs.setBoolPref(this.security_custom_pref, val);
+  },
+};
+
+/*
+  Security Level Button Code
+
+  Controls init and update of the security level toolbar button
+*/
+
+const SecurityLevelButton = {
+  _securityPrefsBranch : null,
+
+  _populateXUL : function(securityLevelButton) {
+    if (securityLevelButton != null) {
+      securityLevelButton.setAttribute("tooltiptext", SecurityLevelStrings.securityLevel);
+      securityLevelButton.setAttribute("label", SecurityLevelStrings.securityLevel);
+    }
+  },
+
+  _configUIFromPrefs : function(securityLevelButton) {
+    if (securityLevelButton != null) {
+      let securitySlider = SecurityLevelPrefs.securitySlider;
+      let classList = securityLevelButton.classList;
+      classList.remove("standard", "safer", "safest");
+      switch(securitySlider) {
+        case 4:
+          classList.add("standard");
+          securityLevelButton.setAttribute("tooltiptext", SecurityLevelStrings.standard.tooltip);
+          break;
+        case 2:
+          classList.add("safer");
+          securityLevelButton.setAttribute("tooltiptext", SecurityLevelStrings.safer.tooltip);
+          break;
+        case 1:
+          classList.add("safest");
+          securityLevelButton.setAttribute("tooltiptext", SecurityLevelStrings.safest.tooltip);
+          break;
+      }
+    }
+  },
+
+  init : function() {
+    // set the initial class based off of the current pref
+    let button = document.getElementById("security-level-button");
+    this._populateXUL(button);
+    this._configUIFromPrefs(button);
+
+    this._securityPrefsBranch = Services.prefs.getBranch("extensions.torbutton.");
+    this._securityPrefsBranch.addObserver("", this, false);
+
+    CustomizableUI.addListener(this);
+
+    SecurityLevelPanel.init();
+  },
+
+  uninit : function() {
+    CustomizableUI.removeListener(this);
+
+    this._securityPrefsBranch.removeObserver("", this);
+    this._securityPrefsBranch = null;
+
+    SecurityLevelPanel.uninit();
+  },
+
+  observe : function(subject, topic, data) {
+    switch(topic) {
+      case "nsPref:changed":
+        if (data == "security_slider") {
+          this._configUIFromPrefs(document.getElementById("security-level-button"));
+        }
+        break;
+    }
+  },
+
+  // callbacks for entering the 'Customize Firefox' screen to set icon
+  onCustomizeStart : function(window) {
+    let navigatorToolbox = document.getElementById("navigator-toolbox");
+    let button = navigatorToolbox.palette.querySelector("#security-level-button");
+    this._populateXUL(button);
+    this._configUIFromPrefs(button);
+  },
+
+  // callback when CustomizableUI modifies DOM
+  onWidgetAfterDOMChange : function(aNode, aNextNode, aContainer, aWasRemoval) {
+    if (aNode.id == "security-level-button" && !aWasRemoval) {
+      this._populateXUL(aNode);
+      this._configUIFromPrefs(aNode);
+    }
+  },
+
+  // when toolbar button is pressed
+  onCommand : function(anchor, event) {
+    SecurityLevelPanel.show(anchor);
+  },
+};
+
+/*
+  Security Level Panel Code
+
+  Controls init and update of the panel in the security level hanger
+*/
+
+const SecurityLevelPanel = {
+  _securityPrefsBranch : null,
+  _panel : null,
+  _anchor : null,
+  _populated : false,
+
+  _populateXUL : function() {
+    // get the panel elements we need to populate
+    let panelview = document.getElementById("securityLevel-panelview");
+    let labelHeader = panelview.querySelector("#securityLevel-header");
+    let labelCustomWarning = panelview.querySelector("#securityLevel-customWarning")
+    let labelLearnMore = panelview.querySelector("#securityLevel-learnMore");
+    let buttonRestoreDefaults = panelview.querySelector("#securityLevel-restoreDefaults");
+    let buttonAdvancedSecuritySettings = panelview.querySelector("#securityLevel-advancedSecuritySettings");
+
+    labelHeader.setAttribute("value", SecurityLevelStrings.securityLevel);
+    labelCustomWarning.setAttribute("value", SecurityLevelStrings.customWarning);
+    labelLearnMore.setAttribute("value", SecurityLevelStrings.learnMore);
+    labelLearnMore.setAttribute("href", SecurityLevelStrings.learnMoreURL);
+    buttonRestoreDefaults.setAttribute("label", SecurityLevelStrings.restoreDefaults);
+    buttonAdvancedSecuritySettings.setAttribute("label", SecurityLevelStrings.advancedSecuritySettings);
+
+    // rest of the XUL is set based on security prefs
+    this._configUIFromPrefs();
+
+    this._populated = true;
+  },
+
+  _configUIFromPrefs : function() {
+    // get security prefs
+    let securitySlider = SecurityLevelPrefs.securitySlider;
+    let securityCustom = SecurityLevelPrefs.securityCustom;
+
+    // get the panel elements we need to populate
+    let panelview = document.getElementById("securityLevel-panelview");
+    let labelLevel = panelview.querySelector("#securityLevel-level");
+    let labelCustomWarning = panelview.querySelector("#securityLevel-customWarning")
+    let summary = panelview.querySelector("#securityLevel-summary");
+    let buttonRestoreDefaults = panelview.querySelector("#securityLevel-restoreDefaults");
+    let buttonAdvancedSecuritySettings = panelview.querySelector("#securityLevel-advancedSecuritySettings");
+
+    // only visible when user is using custom settings
+    labelCustomWarning.hidden = !securityCustom;
+    buttonRestoreDefaults.hidden = !securityCustom;
+
+    // Descriptions change based on security level
+    switch(securitySlider) {
+      // standard
+      case 4:
+        labelLevel.setAttribute("value", SecurityLevelStrings.standard.level);
+        summary.textContent = SecurityLevelStrings.standard.summary;
+        break;
+      // safer
+      case 2:
+        labelLevel.setAttribute("value", SecurityLevelStrings.safer.level);
+        summary.textContent = SecurityLevelStrings.safer.summary;
+        break;
+      // safest
+      case 1:
+        labelLevel.setAttribute("value", SecurityLevelStrings.safest.level);
+        summary.textContent = SecurityLevelStrings.safest.summary;
+        break;
+    }
+
+    // override the summary text with custom warning
+    if (securityCustom) {
+      summary.textContent = SecurityLevelStrings.custom.summary;
+    }
+  },
+
+  init : function() {
+    this._securityPrefsBranch = Services.prefs.getBranch("extensions.torbutton.");
+    this._securityPrefsBranch.addObserver("", this, false);
+  },
+
+  uninit : function() {
+    this._securityPrefsBranch.removeObserver("", this);
+    this._securityPrefsBranch = null;
+  },
+
+  show : function(anchor) {
+    // we have to defer this until after the browser has finished init'ing before
+    // we can populate the panel
+    if (!this._populated) {
+      this._populateXUL();
+    }
+
+    // save off anchor in case we want to show from our own code
+    this._anchor = anchor;
+
+    let panel = document.getElementById("securityLevel-panel");
+    panel.hidden = false;
+    PanelMultiView.openPopup(panel, anchor, "bottomcenter topright",
+                             0, 0, false, null).catch(Cu.reportError);
+  },
+
+  hide : function() {
+    let panel = document.getElementById("securityLevel-panel");
+    PanelMultiView.hidePopup(panel);
+  },
+
+  // when prefs change
+  observe : function(subject, topic, data) {
+    switch(topic) {
+      case "nsPref:changed":
+        if (data == "security_slider" || data == "security_custom") {
+          this._configUIFromPrefs();
+        }
+        break;
+    }
+  },
+
+  restoreDefaults : function() {
+    SecurityLevelPrefs.securityCustom = false;
+    // hide and reshow so that layout re-renders properly
+    this.hide();
+    this.show(this._anchor);
+  },
+
+  openAdvancedSecuritySettings : async function() {
+    openPreferences("privacy-securitylevel");
+    this.hide();
+  }
+};
+
+/*
+  Security Level Preferences Code
+
+  Code to handle init and update of security level section in about:preferences#privacy
+*/
+
+const SecurityLevelPreferences =
+{
+  _securityPrefsBranch : null,
+
+  _populateXUL : function() {
+    let groupbox = document.getElementById("securityLevel-groupbox");
+
+    let labelHeader = groupbox.querySelector("#securityLevel-header");
+    labelHeader.setAttribute("value", SecurityLevelStrings.securityLevel);
+
+    let spanOverview = groupbox.querySelector("#securityLevel-overview");
+    spanOverview.textContent = SecurityLevelStrings.overview;
+
+    let labelLearnMore = groupbox.querySelector("#securityLevel-learnMore");
+    labelLearnMore.setAttribute("value", SecurityLevelStrings.learnMore);
+    labelLearnMore.setAttribute("href", SecurityLevelStrings.learnMoreURL);
+
+    let populateRadioElements = function(vboxQuery, stringStruct) {
+      let vbox = groupbox.querySelector(vboxQuery);
+
+      let radio = vbox.querySelector("radio");
+      radio.setAttribute("label", stringStruct.level);
+
+      let customWarning = vbox.querySelector("#securityLevel-customWarning");
+      customWarning.setAttribute("value", SecurityLevelStrings.customWarning);
+
+      let labelSummary = vbox.querySelector("#securityLevel-summary");
+      labelSummary.textContent = stringStruct.summary;
+
+      let labelRestoreDefaults = vbox.querySelector("#securityLevel-restoreDefaults");
+      labelRestoreDefaults.setAttribute("value", SecurityLevelStrings.restoreDefaults);
+
+      let description1 = vbox.querySelector("#securityLevel-description1");
+      if (description1) {
+        description1.textContent = stringStruct.description1;
+      }
+      let description2 = vbox.querySelector("#securityLevel-description2");
+      if (description2) {
+        description2.textContent = stringStruct.description2;
+      }
+      let description3 = vbox.querySelector("#securityLevel-description3");
+      if (description3) {
+        description3.textContent = stringStruct.description3;
+      }
+    };
+
+    populateRadioElements("#securityLevel-vbox-standard", SecurityLevelStrings.standard);
+    populateRadioElements("#securityLevel-vbox-safer", SecurityLevelStrings.safer);
+    populateRadioElements("#securityLevel-vbox-safest", SecurityLevelStrings.safest);
+  },
+
+  _configUIFromPrefs : function() {
+    // read our prefs
+    let securitySlider = SecurityLevelPrefs.securitySlider;
+    let securityCustom = SecurityLevelPrefs.securityCustom;
+
+    // get our elements
+    let groupbox = document.getElementById("securityLevel-groupbox");
+
+    let radiogroup =  groupbox.querySelector("#securityLevel-radiogroup");
+    let labelStandardCustom = groupbox.querySelector("#securityLevel-vbox-standard label#securityLevel-customWarning");
+    let labelSaferCustom = groupbox.querySelector("#securityLevel-vbox-safer label#securityLevel-customWarning");
+    let labelSafestCustom = groupbox.querySelector("#securityLevel-vbox-safest label#securityLevel-customWarning");
+    let labelStandardRestoreDefaults = groupbox.querySelector("#securityLevel-vbox-standard label#securityLevel-restoreDefaults");
+    let labelSaferRestoreDefaults = groupbox.querySelector("#securityLevel-vbox-safer label#securityLevel-restoreDefaults");
+    let labelSafestRestoreDefaults = groupbox.querySelector("#securityLevel-vbox-safest label#securityLevel-restoreDefaults");
+
+    // hide custom label by default until we know which level we're at
+    labelStandardCustom.hidden = true;
+    labelSaferCustom.hidden = true;
+    labelSafestCustom.hidden = true;
+
+    labelStandardRestoreDefaults.hidden = true;
+    labelSaferRestoreDefaults.hidden = true;
+    labelSafestRestoreDefaults.hidden = true;
+
+    switch(securitySlider) {
+      // standard
+      case 4:
+        radiogroup.value = "standard";
+        labelStandardCustom.hidden = !securityCustom;
+        labelStandardRestoreDefaults.hidden = !securityCustom;
+        break;
+      // safer
+      case 2:
+        radiogroup.value = "safer";
+        labelSaferCustom.hidden = !securityCustom;
+        labelSaferRestoreDefaults.hidden = !securityCustom;
+        break;
+      // safest
+      case 1:
+        radiogroup.value = "safest";
+        labelSafestCustom.hidden = !securityCustom;
+        labelSafestRestoreDefaults.hidden = !securityCustom;
+        break;
+    }
+  },
+
+  init : function() {
+    // populate XUL with localized strings
+    this._populateXUL();
+
+    // read prefs and populate UI
+    this._configUIFromPrefs();
+
+    // register for pref chagnes
+    this._securityPrefsBranch = Services.prefs.getBranch("extensions.torbutton.");
+    this._securityPrefsBranch.addObserver("", this, false);
+  },
+
+  uninit : function() {
+    // unregister for pref change events
+    this._securityPrefsBranch.removeObserver("", this);
+    this._securityPrefsBranch = null;
+  },
+
+  // callback for when prefs change
+  observe : function(subject, topic, data) {
+    switch(topic) {
+      case "nsPref:changed":
+        if (data == "security_slider" ||
+            data == "security_custom") {
+          this._configUIFromPrefs();
+        }
+        break;
+    }
+  },
+
+  selectSecurityLevel : function() {
+    // radio group elements
+    let radiogroup =  document.getElementById("securityLevel-radiogroup");
+
+    // update pref based on selected radio option
+    switch (radiogroup.value) {
+      case "standard":
+        SecurityLevelPrefs.securitySlider = 4;
+        break;
+      case "safer":
+        SecurityLevelPrefs.securitySlider = 2;
+        break;
+      case "safest":
+        SecurityLevelPrefs.securitySlider = 1;
+        break;
+    }
+
+    this.restoreDefaults();
+  },
+
+  restoreDefaults : function() {
+    SecurityLevelPrefs.securityCustom = false;
+  },
+};
+
+Object.defineProperty(this, "SecurityLevelButton", {
+  value: SecurityLevelButton,
+  enumerable: true,
+  writable: false
+});
+
+Object.defineProperty(this, "SecurityLevelPanel", {
+  value: SecurityLevelPanel,
+  enumerable: true,
+  writable: false
+});
+
+Object.defineProperty(this, "SecurityLevelPreferences", {
+  value: SecurityLevelPreferences,
+  enumerable: true,
+  writable: false
+});
diff --git a/browser/components/securitylevel/content/securityLevelButton.css b/browser/components/securitylevel/content/securityLevelButton.css
new file mode 100644
index 000000000000..81f2365bae28
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelButton.css
@@ -0,0 +1,9 @@
+toolbarbutton#security-level-button.standard {
+  list-style-image: url("chrome://browser/content/securitylevel/securityLevelButton.svg#standard");
+}
+toolbarbutton#security-level-button.safer {
+  list-style-image: url("chrome://browser/content/securitylevel/securityLevelButton.svg#safer");
+}
+toolbarbutton#security-level-button.safest {
+  list-style-image: url("chrome://browser/content/securitylevel/securityLevelButton.svg#safest");
+}
diff --git a/browser/components/securitylevel/content/securityLevelButton.inc.xul b/browser/components/securitylevel/content/securityLevelButton.inc.xul
new file mode 100644
index 000000000000..4ad26f4142bd
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelButton.inc.xul
@@ -0,0 +1,5 @@
+<toolbarbutton id="security-level-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+               removable="true"
+               oncommand="SecurityLevelButton.onCommand(this, event);"
+               closemenu="none"
+               cui-areatype="toolbar"/>
diff --git a/browser/components/securitylevel/content/securityLevelButton.svg b/browser/components/securitylevel/content/securityLevelButton.svg
new file mode 100644
index 000000000000..8535cdcc531e
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelButton.svg
@@ -0,0 +1,21 @@
+<svg width="14px" height="16px" viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>
+  <style>
+    use:not(:target) {
+      display: none;
+    }
+  </style>
+  <defs>
+    <g id="standard_icon" stroke="none" stroke-width="1">
+      <path d="M7.0 2.16583509C7.0 2.16583509 2.0 4.24375717 2.0 4.24375717C2.0 4.24375717 2.0 7.27272727 2.0 7.27272727C2.0 10.2413541 4.13435329 13.0576771 7.0 13.9315843C9.8656467 13.0576771 12.0 10.2413541 12.0 7.27272727C12.0 7.27272727 12.0 4.24375717 12.0 4.24375717C12.0 4.24375717 7.0 2.16583509 7.0 2.16583509C7.0 2.16583509 7.0 2.16583509 7.0 2.16583509M7.0 0.0C7.0 0.0 14.0 2.90909091 14.0 2.90909091C14.0 2.90909091 14.0 7.27272727 14.0 7.27272727C14.0 11.3090909 11.0133333 15.0836364 7.0 16.0C2.98666667 15.0836364 0.0 11.3090909 0.0 7.27272727C0.0 7.27272727 0.0 2.90909091 0.0 2.90909091C0.0 2.90909091 7.0 0.0 7.0 0.0C7.0 0.0 7.0 0.0 7.0 0.0" />
+    </g>
+    <g id="safer_icon" stroke="none" stroke-width="1">
+      <path fill-rule="nonzero" d="M7.0 2.1658351C7.0 13.931584 7.0 2.1658351 7.0 13.931584C9.8656467 13.057677 12.0 10.241354 12.0 7.2727273C12.0 7.2727273 12.0 4.2437572 12.0 4.2437572C12.0 4.2437572 7.0 2.1658351 7.0 2.1658351C7.0 2.1658351 7.0 2.1658351 7.0 2.1658351M7.0 0.0C7.0 0.0 14.0 2.9090909 14.0 2.9090909C14.0 2.9090909 14.0 7.2727273 14.0 7.2727273C14.0 11.309091 11.013333 15.083636 7.0 16.0C2.9866667 15.083636 0.0 11.309091 0.0 7.2727273C0.0 7.2727273 0.0 2.9090909 0.0 2.9090909C0.0 2.9090909 7.0 0.0 7.0 0.0"/>
+    </g>
+    <g id="safest_icon" stroke="none" stroke-width="1">
+      <path d="M7.0 0.0C7.0 0.0 14.0 2.90909091 14.0 2.90909091C14.0 2.90909091 14.0 7.27272727 14.0 7.27272727C14.0 11.3090909 11.0133333 15.0836364 7.0 16.0C2.98666667 15.0836364 0.0 11.3090909 0.0 7.27272727C0.0 7.27272727 0.0 2.90909091 0.0 2.90909091C0.0 2.90909091 7.0 0.0 7.0 0.0C7.0 0.0 7.0 0.0 7.0 0.0" />
+    </g>
+  </defs>
+  <use id="standard" fill="context-fill" fill-opacity="context-fill-opacity" href="#standard_icon" />
+  <use id="safer" fill="context-fill" fill-opacity="context-fill-opacity" href="#safer_icon" />
+  <use id="safest" fill="context-fill" fill-opacity="context-fill-opacity" href="#safest_icon" />
+</svg>
diff --git a/browser/components/securitylevel/content/securityLevelPanel.css b/browser/components/securitylevel/content/securityLevelPanel.css
new file mode 100644
index 000000000000..170bf625ea1d
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelPanel.css
@@ -0,0 +1,82 @@
+/* Security Level CSS */
+
+panel#securityLevel-panel > .panel-arrowcontainer > .panel-arrowcontent {
+  padding: 0;
+}
+
+panelview#securityLevel-panelview {
+  width: 20em;
+}
+
+panelview#securityLevel-panelview>vbox.panel-subview-body {
+  padding: 1em;
+}
+
+label#securityLevel-header {
+  text-transform: uppercase;
+  color: GrayText;
+  font-size: 0.85em;
+  margin: 0 0 0.4em 0;
+  padding: 0;
+}
+
+hbox#securityLevel-levelHbox {
+  margin-bottom: 1em;
+}
+
+label#securityLevel-level {
+  font-size: 1.5em;
+  margin: 0 0.5em 0 0;
+  padding: 0;
+}
+
+label#securityLevel-customWarning {
+  border-radius: 2px;
+  background-color: #ffe845;
+  text-transform: uppercase;
+  font-weight: bolder;
+  font-size: 0.8em;
+  height: 1em;
+  line-height: 1em;
+  vertical-align: middle;
+  margin: auto;
+  padding: 0.4em;
+}
+
+panelview#securityLevel-panelview description {
+  margin: 0 -0.5em 0.5em 0;
+  padding: 0 !important;
+}
+
+label#securityLevel-learnMore {
+  margin: 0 0 1.0em 0;
+  padding: 0;
+}
+
+panelview#securityLevel-panelview button {
+  -moz-appearance: none;
+  background-color: var(--arrowpanel-dimmed);
+}
+
+panelview#securityLevel-panelview button:hover {
+  background-color: var(--arrowpanel-dimmed-further);
+}
+
+panelview#securityLevel-panelview button:active {
+  background-color: var(--arrowpanel-dimmed-even-further);
+}
+
+button#securityLevel-restoreDefaults {
+  margin: 0 0 1.0em 0;
+  padding: 0.45em;
+  color: inherit !important;
+}
+
+button#securityLevel-advancedSecuritySettings {
+  margin: 0 -1.0em -1.0em -1.0em;
+  border-radius: 0;
+  border-top: 1px solid var(--panel-separator-color);
+  padding: 0;
+  height: 3.0em;
+  color: inherit !important;
+}
diff --git a/browser/components/securitylevel/content/securityLevelPanel.inc.xul b/browser/components/securitylevel/content/securityLevelPanel.inc.xul
new file mode 100644
index 000000000000..532e8dd98b32
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelPanel.inc.xul
@@ -0,0 +1,33 @@
+<panel id="securityLevel-panel"
+   role="group"
+   type="arrow"
+   orient="vertical"
+   level="top"
+   hidden="true">
+  <panelmultiview mainViewId="securityLevel-panelview">
+    <panelview id="securityLevel-panelview" descriptionheightworkaround="true">
+      <vbox class="panel-subview-body">
+        <label id="securityLevel-header"/>
+        <hbox id="securityLevel-levelHbox">
+          <label id="securityLevel-level"/>
+          <vbox>
+            <spacer flex="1"/>
+              <label id="securityLevel-customWarning"/>
+            <spacer flex="1"/>
+          </vbox>
+        </hbox>
+        <description id="securityLevel-summary"/>
+        <label
+          id="securityLevel-learnMore"
+          class="learnMore text-link"
+          onclick="SecurityLevelPanel.hide();"/>
+        <button
+          id="securityLevel-restoreDefaults"
+          oncommand="SecurityLevelPanel.restoreDefaults();"/>
+        <button
+          id="securityLevel-advancedSecuritySettings"
+          oncommand="SecurityLevelPanel.openAdvancedSecuritySettings();"/>
+      </vbox>
+    </panelview>
+  </panelmultiview>
+</panel>
diff --git a/browser/components/securitylevel/content/securityLevelPreferences.css b/browser/components/securitylevel/content/securityLevelPreferences.css
new file mode 100644
index 000000000000..0d1040d177d8
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelPreferences.css
@@ -0,0 +1,26 @@
+label#securityLevel-customWarning {
+  border-radius: 2px;
+  background-color: #ffe845;
+  text-transform: uppercase;
+  font-weight: bolder;
+  font-size: 0.7em;
+  height: 1em;
+  line-height: 1em;
+  padding: 0.35em;
+}
+
+radiogroup#securityLevel-radiogroup radio {
+  font-weight: bold;
+}
+
+vbox#securityLevel-vbox-standard,
+vbox#securityLevel-vbox-safer,
+vbox#securityLevel-vbox-safest {
+  margin-top: 0.4em;
+}
+
+vbox#securityLevel-vbox-standard description.indent,
+vbox#securityLevel-vbox-safer description.indent,
+vbox#securityLevel-vbox-safest description.indent {
+  margin-inline-start: 0 !important;
+}
diff --git a/browser/components/securitylevel/content/securityLevelPreferences.inc.xul b/browser/components/securitylevel/content/securityLevelPreferences.inc.xul
new file mode 100644
index 000000000000..0cf05a5f3c9b
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelPreferences.inc.xul
@@ -0,0 +1,66 @@
+<groupbox id="securityLevel-groupbox" data-category="panePrivacy" hidden="true">
+  <caption><label id="securityLevel-header"/></caption>
+  <vbox data-subcategory="securitylevel" flex="1">
+    <description flex="1">
+      <html:span id="securityLevel-overview" class="tail-with-learn-more"/>
+      <label id="securityLevel-learnMore" class="learnMore text-link"/>
+    </description>
+    <radiogroup id="securityLevel-radiogroup"
+                oncommand="SecurityLevelPreferences.selectSecurityLevel();">
+      <vbox id="securityLevel-vbox-standard">
+        <hbox>
+          <radio value="standard"/>
+          <vbox>
+            <spacer flex="1"/>
+            <label id="securityLevel-customWarning"/>
+            <spacer flex="1"/>
+          </vbox>
+        </hbox>
+        <description flex="1">
+          <html:span id="securityLevel-summary" class="tail-with-learn-more"/>
+          <label id="securityLevel-restoreDefaults"
+                 class="learnMore text-link"
+                 onclick="SecurityLevelPreferences.restoreDefaults();"/>
+        </description>
+      </vbox>
+      <vbox id="securityLevel-vbox-safer">
+        <hbox>
+          <radio value="safer"/>
+          <vbox>
+            <spacer flex="1"/>
+            <label id="securityLevel-customWarning"/>
+            <spacer flex="1"/>
+          </vbox>
+        </hbox>
+        <description flex="1">
+          <html:span id="securityLevel-summary" class="tail-with-learn-more"/>
+          <label id="securityLevel-restoreDefaults"
+                 class="learnMore text-link"
+                 onclick="SecurityLevelPreferences.restoreDefaults();"/>
+        </description>
+        <description id="securityLevel-description1" class="indent tip-caption"/>
+        <description id="securityLevel-description2" class="indent tip-caption"/>
+        <description id="securityLevel-description3" class="indent tip-caption"/>
+      </vbox>
+      <vbox id="securityLevel-vbox-safest">
+        <hbox>
+          <radio value="safest"/>
+          <vbox>
+            <spacer flex="1"/>
+            <label id="securityLevel-customWarning"/>
+            <spacer flex="1"/>
+          </vbox>
+        </hbox>
+        <description flex="1">
+          <html:span id="securityLevel-summary" class="tail-with-learn-more"/>
+          <label id="securityLevel-restoreDefaults"
+                 class="learnMore text-link"
+                 onclick="SecurityLevelPreferences.restoreDefaults();"/>
+        </description>
+        <description id="securityLevel-description1" class="indent tip-caption"/>
+        <description id="securityLevel-description2" class="indent tip-caption"/>
+        <description id="securityLevel-description3" class="indent tip-caption"/>
+      </vbox>
+    </radiogroup>
+  </vbox>
+</groupbox>
diff --git a/browser/components/securitylevel/jar.mn b/browser/components/securitylevel/jar.mn
new file mode 100644
index 000000000000..9ac408083fbc
--- /dev/null
+++ b/browser/components/securitylevel/jar.mn
@@ -0,0 +1,6 @@
+browser.jar:
+    content/browser/securitylevel/securityLevel.js             (content/securityLevel.js)
+    content/browser/securitylevel/securityLevelPanel.css       (content/securityLevelPanel.css)
+    content/browser/securitylevel/securityLevelButton.css      (content/securityLevelButton.css)
+    content/browser/securitylevel/securityLevelPreferences.css (content/securityLevelPreferences.css)
+    content/browser/securitylevel/securityLevelButton.svg      (content/securityLevelButton.svg)
diff --git a/browser/components/securitylevel/moz.build b/browser/components/securitylevel/moz.build
new file mode 100644
index 000000000000..7e103239c8d6
--- /dev/null
+++ b/browser/components/securitylevel/moz.build
@@ -0,0 +1 @@
+JAR_MANIFESTS += ['jar.mn']



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits