[tor-commits] [tor-browser/tor-browser-84.0-10.0-1] Bug 25658: Replace security slider with security level UI

sysrqb at torproject.org sysrqb at torproject.org
Fri Dec 11 18:25:49 UTC 2020


commit 5500d4ce3c6017000755319ae245c01c66d7502b
Author: Richard Pospesel <richard at torproject.org>
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/base/content/browser.js                    |  10 +
 browser/base/content/browser.xhtml                 |   5 +
 browser/components/moz.build                       |   1 +
 browser/components/preferences/preferences.xhtml   |   1 +
 browser/components/preferences/privacy.inc.xhtml   |   2 +
 browser/components/preferences/privacy.js          |  19 +
 .../securitylevel/content/securityLevel.js         | 501 +++++++++++++++++++++
 .../securitylevel/content/securityLevelButton.css  |   9 +
 .../content/securityLevelButton.inc.xhtml          |   7 +
 .../securitylevel/content/securityLevelButton.svg  |  21 +
 .../securitylevel/content/securityLevelPanel.css   |  82 ++++
 .../content/securityLevelPanel.inc.xhtml           |  38 ++
 .../content/securityLevelPreferences.css           |  26 ++
 .../content/securityLevelPreferences.inc.xhtml     |  62 +++
 browser/components/securitylevel/jar.mn            |   6 +
 browser/components/securitylevel/moz.build         |   1 +
 16 files changed, 791 insertions(+)

diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 9abba4bc420c..d83553c3c0ef 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -215,6 +215,11 @@ XPCOMUtils.defineLazyScriptGetter(
   ["DownloadsButton", "DownloadsIndicatorView"],
   "chrome://browser/content/downloads/indicator.js"
 );
+XPCOMUtils.defineLazyScriptGetter(
+  this,
+  ["SecurityLevelButton"],
+  "chrome://browser/content/securitylevel/securityLevel.js"
+);
 XPCOMUtils.defineLazyScriptGetter(
   this,
   "gEditItemOverlay",
@@ -1876,6 +1881,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
@@ -2557,6 +2565,8 @@ var gBrowserInit = {
 
     DownloadsButton.uninit();
 
+    SecurityLevelButton.uninit();
+
     gAccessibilityServiceIndicator.uninit();
 
     if (gToolbarKeyNavEnabled) {
diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml
index 27e15b92f641..2340bb92e9af 100644
--- a/browser/base/content/browser.xhtml
+++ b/browser/base/content/browser.xhtml
@@ -20,6 +20,8 @@
 <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/tabbrowser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/downloads/downloads.css" type="text/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/" type="text/css"?>
@@ -644,6 +646,7 @@
 #include ../../components/controlcenter/content/protectionsPanel.inc.xhtml
 #include ../../components/downloads/content/downloadsPanel.inc.xhtml
 #include ../../../devtools/startup/enableDevToolsPopup.inc.xhtml
+#include ../../components/securitylevel/content/securityLevelPanel.inc.xhtml
 #include browser-allTabsMenu.inc.xhtml
 
     <hbox id="downloads-animation-container">
@@ -1981,6 +1984,8 @@
             </stack>
           </toolbarbutton>
 
+#include ../../components/securitylevel/content/securityLevelButton.inc.xhtml
+
         <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 7f82f14985fe..5a4144ffa43d 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -51,6 +51,7 @@ DIRS += [
     "protocolhandler",
     "resistfingerprinting",
     "search",
+    "securitylevel",
     "sessionstore",
     "shell",
     "ssb",
diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml
index 99d5ae9892a5..b1e08364e1cc 100644
--- a/browser/components/preferences/preferences.xhtml
+++ b/browser/components/preferences/preferences.xhtml
@@ -12,6 +12,7 @@
 <?xml-stylesheet href="chrome://browser/skin/preferences/search.css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/containers.css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/privacy.css"?>
+<?xml-stylesheet href="chrome://browser/content/securitylevel/securityLevelPreferences.css"?>
 
 <!DOCTYPE html>
 
diff --git a/browser/components/preferences/privacy.inc.xhtml b/browser/components/preferences/privacy.inc.xhtml
index 46445e8dc28f..0f963208e6fe 100644
--- a/browser/components/preferences/privacy.inc.xhtml
+++ b/browser/components/preferences/privacy.inc.xhtml
@@ -922,6 +922,8 @@
   <html:h1 data-l10n-id="security-header"/>
 </hbox>
 
+#include ../securitylevel/content/securityLevelPreferences.inc.xhtml
+
 <!-- addons, forgery (phishing) UI Security -->
 <groupbox id="browsingProtectionGroup" data-category="panePrivacy" hidden="true">
   <label><html:h2 data-l10n-id="security-browsing-protection"/></label>
diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js
index d534d695a5c4..e7c7c331292b 100644
--- a/browser/components/preferences/privacy.js
+++ b/browser/components/preferences/privacy.js
@@ -80,6 +80,12 @@ XPCOMUtils.defineLazyGetter(this, "AlertsServiceDND", function() {
   }
 });
 
+XPCOMUtils.defineLazyScriptGetter(
+  this,
+  ["SecurityLevelPreferences"],
+  "chrome://browser/content/securitylevel/securityLevel.js"
+);
+
 XPCOMUtils.defineLazyServiceGetter(
   this,
   "listManager",
@@ -304,6 +310,18 @@ function setUpContentBlockingWarnings() {
 var gPrivacyPane = {
   _pane: null,
 
+  /**
+   * Show the Security Level UI
+   */
+  _initSecurityLevel() {
+    SecurityLevelPreferences.init();
+    let unload = () => {
+      window.removeEventListener("unload", unload);
+      SecurityLevelPreferences.uninit();
+    };
+    window.addEventListener("unload", unload);
+  },
+
   /**
    * Whether the prompt to restart Firefox should appear when changing the autostart pref.
    */
@@ -515,6 +533,7 @@ var gPrivacyPane = {
     this.trackingProtectionReadPrefs();
     this.networkCookieBehaviorReadPrefs();
     this._initTrackingProtectionExtensionControl();
+    this._initSecurityLevel();
 
     Services.telemetry.setEventRecordingEnabled("pwmgr", true);
 
diff --git a/browser/components/securitylevel/content/securityLevel.js b/browser/components/securitylevel/content/securityLevel.js
new file mode 100644
index 000000000000..b47d0cfb545e
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevel.js
@@ -0,0 +1,501 @@
+"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",
+});
+
+ChromeUtils.defineModuleGetter(
+  this,
+  "TorStrings",
+  "resource:///modules/TorStrings.jsm"
+);
+
+/*
+  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 Prefs */
+
+/*
+  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", TorStrings.securityLevel.securityLevel);
+      securityLevelButton.setAttribute("label", TorStrings.securityLevel.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", TorStrings.securityLevel.standard.tooltip);
+          break;
+        case 2:
+          classList.add("safer");
+          securityLevelButton.setAttribute("tooltiptext", TorStrings.securityLevel.safer.tooltip);
+          break;
+        case 1:
+          classList.add("safest");
+          securityLevelButton.setAttribute("tooltiptext", TorStrings.securityLevel.safest.tooltip);
+          break;
+      }
+    }
+  },
+
+  get button() {
+    let button = document.getElementById("security-level-button");
+    if (!button) {
+      return null;
+    }
+    return button;
+  },
+
+  get anchor() {
+    let anchor = this.button.icon;
+    if (!anchor) {
+      return null;
+    }
+
+    anchor.setAttribute("consumeanchor", SecurityLevelButton.button.id);
+    return anchor;
+  },
+
+  init : function() {
+    // set the initial class based off of the current pref
+    let button = this.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(this.button);
+        }
+        break;
+    }
+  },
+
+  // callback 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);
+    }
+  },
+
+  // for when the toolbar button needs to be activated and displays the Security Level panel
+  //
+  // In the toolbarbutton xul you'll notice we register this callback for both onkeypress and
+  // onmousedown. We do this to match the behavior of other panel spawning buttons such as Downloads,
+  // Library, and the Hamburger menus. Using oncommand alone would result in only getting fired
+  // after onclick, which is mousedown followed by mouseup.
+  onCommand : function(aEvent) {
+    // snippet stolen from /browser/components/downloads/indicator.js DownloadsIndicatorView.onCommand(evt)
+    if (
+      (aEvent.type == "mousedown" && aEvent.button != 0) ||
+      (aEvent.type == "keypress" && aEvent.key != " " && aEvent.key != "Enter")
+    ) {
+      return;
+    }
+
+    // we need to set this attribute for the button to be shaded correctly to look like it is pressed
+    // while the security level panel is open
+    this.button.setAttribute("open", "true");
+    SecurityLevelPanel.show();
+  },
+}; /* Security Level Button */
+
+/*
+  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", TorStrings.securityLevel.securityLevel);
+    labelCustomWarning.setAttribute("value", TorStrings.securityLevel.customWarning);
+    labelLearnMore.setAttribute("value", TorStrings.securityLevel.learnMore);
+    labelLearnMore.setAttribute("href", TorStrings.securityLevel.learnMoreURL);
+    buttonRestoreDefaults.setAttribute("label", TorStrings.securityLevel.restoreDefaults);
+    buttonAdvancedSecuritySettings.setAttribute("label", TorStrings.securityLevel.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", TorStrings.securityLevel.standard.level);
+        summary.textContent = TorStrings.securityLevel.standard.summary;
+        break;
+      // safer
+      case 2:
+        labelLevel.setAttribute("value", TorStrings.securityLevel.safer.level);
+        summary.textContent = TorStrings.securityLevel.safer.summary;
+        break;
+      // safest
+      case 1:
+        labelLevel.setAttribute("value", TorStrings.securityLevel.safest.level);
+        summary.textContent = TorStrings.securityLevel.safest.summary;
+        break;
+    }
+
+    // override the summary text with custom warning
+    if (securityCustom) {
+      summary.textContent = TorStrings.securityLevel.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() {
+    // we have to defer this until after the browser has finished init'ing before
+    // we can populate the panel
+    if (!this._populated) {
+      this._populateXUL();
+    }
+
+    let panel = document.getElementById("securityLevel-panel");
+    panel.hidden = false;
+    PanelMultiView.openPopup(panel, SecurityLevelButton.anchor, "bottomcenter topright",
+                             0, 0, false, null).catch(Cu.reportError);
+  },
+
+  hide : function() {
+    let panel = document.getElementById("securityLevel-panel");
+    PanelMultiView.hidePopup(panel);
+  },
+
+  restoreDefaults : function() {
+    SecurityLevelPrefs.securityCustom = false;
+    // hide and reshow so that layout re-renders properly
+    this.hide();
+    this.show(this._anchor);
+  },
+
+  openAdvancedSecuritySettings : function() {
+    openPreferences("privacy-securitylevel");
+    this.hide();
+  },
+
+  // callback when prefs change
+  observe : function(subject, topic, data) {
+    switch(topic) {
+      case "nsPref:changed":
+        if (data == "security_slider" || data == "security_custom") {
+          this._configUIFromPrefs();
+        }
+        break;
+    }
+  },
+
+  // callback when the panel is displayed
+  onPopupShown : function(event) {
+    SecurityLevelButton.button.setAttribute("open", "true");
+  },
+
+  // callback when the panel is hidden
+  onPopupHidden : function(event) {
+    SecurityLevelButton.button.removeAttribute("open");
+  }
+}; /* Security Level Panel */
+
+/*
+  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.textContent = TorStrings.securityLevel.securityLevel;
+
+    let spanOverview = groupbox.querySelector("#securityLevel-overview");
+    spanOverview.textContent = TorStrings.securityLevel.overview;
+
+    let labelLearnMore = groupbox.querySelector("#securityLevel-learnMore");
+    labelLearnMore.setAttribute("value", TorStrings.securityLevel.learnMore);
+    labelLearnMore.setAttribute("href", TorStrings.securityLevel.learnMoreURL);
+
+    let radiogroup =  document.getElementById("securityLevel-radiogroup");
+    radiogroup.addEventListener("command", SecurityLevelPreferences.selectSecurityLevel);
+
+    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", TorStrings.securityLevel.customWarning);
+
+      let labelSummary = vbox.querySelector("#securityLevel-summary");
+      labelSummary.textContent = stringStruct.summary;
+
+      let labelRestoreDefaults = vbox.querySelector("#securityLevel-restoreDefaults");
+      labelRestoreDefaults.setAttribute("value", TorStrings.securityLevel.restoreDefaults);
+      labelRestoreDefaults.addEventListener("click",  SecurityLevelPreferences.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", TorStrings.securityLevel.standard);
+    populateRadioElements("#securityLevel-vbox-safer", TorStrings.securityLevel.safer);
+    populateRadioElements("#securityLevel-vbox-safest", TorStrings.securityLevel.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;
+    }
+
+    SecurityLevelPreferences.restoreDefaults();
+  },
+
+  restoreDefaults : function() {
+    SecurityLevelPrefs.securityCustom = false;
+  },
+}; /* Security Level Prefereces */
+
+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.xhtml b/browser/components/securitylevel/content/securityLevelButton.inc.xhtml
new file mode 100644
index 000000000000..96ee1ec0ca49
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelButton.inc.xhtml
@@ -0,0 +1,7 @@
+<toolbarbutton id="security-level-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+               badged="true"
+               removable="true"
+               onmousedown="SecurityLevelButton.onCommand(event);"
+               onkeypress="SecurityLevelButton.onCommand(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..70022e2bd4b2
--- /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: var(--panel-disabled-color);
+  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.xhtml b/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml
new file mode 100644
index 000000000000..4abbb12dd856
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelPanel.inc.xhtml
@@ -0,0 +1,38 @@
+<panel id="securityLevel-panel"
+   role="group"
+   type="arrow"
+   orient="vertical"
+   level="top"
+   hidden="true"
+   class="panel-no-padding"
+   onpopupshown="SecurityLevelPanel.onPopupShown(event);"
+   onpopuphidden="SecurityLevelPanel.onPopupHidden(event);"
+   >
+  <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();"
+          is="text-link"/>
+        <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.xhtml b/browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml
new file mode 100644
index 000000000000..a108d44a7b51
--- /dev/null
+++ b/browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml
@@ -0,0 +1,62 @@
+<groupbox id="securityLevel-groupbox" data-category="panePrivacy" hidden="true">
+  <label><html:h2 id="securityLevel-header"/></label>
+  <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" is="text-link"/>
+    </description>
+    <radiogroup id="securityLevel-radiogroup">
+      <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"/>
+        </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"/>
+        </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"/>
+        </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..2661ad7cb9f3
--- /dev/null
+++ b/browser/components/securitylevel/moz.build
@@ -0,0 +1 @@
+JAR_MANIFESTS += ["jar.mn"]





More information about the tor-commits mailing list