Commit 90395b29 authored by henry's avatar henry Committed by Richard Pospesel
Browse files

fixup! Bug 40925: Implemented the Security Level component

Bug 32274: Make the security level settings more accessible:

+ We remove the "Restore Defaults" link that was between each radio
  option and place it separately as a button, with some notification
  text.
+ We set the `aria-describedby` attribute on the radio options to point
  to the description.
+ We change the security level popup's button text from "Change" to
  "Change Setting" to give users more of a hint that clicking the button
  will land them in the middle of about:preferences.

We also tidied up the javascript, CSS and xhtml.
parent 9714187f
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -341,11 +341,9 @@ var gPrivacyPane = {
   */
  _initSecurityLevel() {
    SecurityLevelPreferences.init();
    let unload = () => {
      window.removeEventListener("unload", unload);
      SecurityLevelPreferences.uninit();
    };
    window.addEventListener("unload", unload);
    window.addEventListener("unload", () => SecurityLevelPreferences.uninit(), {
      once: true,
    });
  },

  /**
+95 −115
Original line number Diff line number Diff line
@@ -17,13 +17,14 @@ XPCOMUtils.defineLazyGetter(this, "SecurityLevelStrings", () => {
    security_level_restore: "Restore Defaults",
    security_level_learn_more: "Learn more",
    // Panel
    security_level_change: "Change…",
    security_level_change_setting: "Change Setting",
    security_level_standard_summary:
      "All browser and website features are enabled.",
    security_level_safer_summary:
      "Disables website features that are often dangerous, causing some sites to lose functionality.",
    security_level_safest_summary:
      "Only allows website features required for static sites and basic services. These changes affect images, media, and scripts.",
    security_level_custom_heading: "Warning!",
    security_level_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.",
    // Security level section in about:preferences#privacy
@@ -259,7 +260,7 @@ var SecurityLevelPanel = {
    this._elements.restoreDefaultsButton.textContent =
      SecurityLevelStrings.security_level_restore;
    this._elements.settingsButton.textContent =
      SecurityLevelStrings.security_level_change;
      SecurityLevelStrings.security_level_change_setting;

    this._elements.restoreDefaultsButton.addEventListener("command", () => {
      this.restoreDefaults();
@@ -367,120 +368,112 @@ var SecurityLevelPanel = {

var SecurityLevelPreferences = {
  _securityPrefsBranch: null,
  /**
   * The notification box shown when the user has a custom security setting.
   *
   * @type {Element}
   */
  _customNotification: null,
  /**
   * The radiogroup for this preference.
   *
   * @type {Element}
   */
  _radiogroup: null,
  /**
   * A list of radio options and their containers.
   *
   * @type {Array<Object>}
   */
  _radioOptions: null,

  _populateXUL() {
    const groupbox = document.querySelector("#securityLevel-groupbox");
    const radiogroup = groupbox.querySelector("#securityLevel-radiogroup");
    radiogroup.addEventListener(
      "command",
      SecurityLevelPreferences.selectSecurityLevel
    this._customNotification = document.getElementById(
      "securityLevel-customNotification"
    );
    this._radiogroup = document.getElementById("securityLevel-radiogroup");

    groupbox.querySelector("h2").textContent =
    document.querySelector("#securityLevel-groupbox h2").textContent =
      SecurityLevelStrings.security_level;
    groupbox.querySelector("#securityLevel-overview").textContent =
    document.getElementById("securityLevel-overview").textContent =
      SecurityLevelStrings.security_level_overview;
    groupbox
      .querySelector("#securityLevel-learnMore")
    document
      .getElementById("securityLevel-learnMore")
      .setAttribute("value", SecurityLevelStrings.security_level_learn_more);

    const populateRadioElements = (level, descr) => {
      const vbox = groupbox.querySelector(`#securityLevel-vbox-${level}`);
      vbox
        .querySelector("radio")
        .setAttribute("label", SecurityLevelStrings[`security_level_${level}`]);
      vbox
        .querySelector(".securityLevel-customWarning")
        .setAttribute("value", SecurityLevelStrings.security_level_custom);
      vbox.querySelector(".summary").textContent =
        SecurityLevelStrings[`security_level_${level}_summary`];
      const labelRestoreDefaults = vbox.querySelector(
        ".securityLevel-restoreDefaults"
    document.getElementById("securityLevel-customHeading").textContent =
      SecurityLevelStrings.security_level_custom_heading;
    document.getElementById("securityLevel-customDescription").textContent =
      SecurityLevelStrings.security_level_custom_summary;
    const restoreDefaultsButton = document.getElementById(
      "securityLevel-restoreDefaults"
    );
    restoreDefaultsButton.textContent =
      SecurityLevelStrings.security_level_restore;

    this._radioOptions = Array.from(
      this._radiogroup.querySelectorAll(".securityLevel-radio-option"),
      container => {
        return { container, radio: container.querySelector("radio") };
      }
    );
      labelRestoreDefaults.setAttribute(
        "value",
        SecurityLevelStrings.security_level_restore
    const descListItemsMap = {
      safer: [
        SecurityLevelStrings.security_level_js_https_only,
        SecurityLevelStrings.security_level_limit_typography,
        SecurityLevelStrings.security_level_limit_media,
      ],
      safest: [
        SecurityLevelStrings.security_level_js_disabled,
        SecurityLevelStrings.security_level_limit_typography_svg,
        SecurityLevelStrings.security_level_limit_media,
      ],
    };
    for (const { container, radio } of this._radioOptions) {
      const level = radio.value;
      radio.setAttribute(
        "label",
        SecurityLevelStrings[`security_level_${level}`]
      );
      labelRestoreDefaults.addEventListener(
        "click",
        SecurityLevelStrings.restoreDefaults
      container.querySelector(".summary").textContent =
        SecurityLevelStrings[`security_level_${level}_summary`];
      const descListItems = descListItemsMap[level];
      if (!descListItems) {
        continue;
      }
      const descrList = container.querySelector(
        ".securityLevel-descriptionList"
      );
      if (descr) {
        const descrList = vbox.querySelector(".securityLevel-descriptionList");
      // TODO: Add the elements in securityLevelPreferences.inc.xhtml again
      // when we switch to Fluent
        for (const text of descr) {
      for (const text of descListItems) {
        let elem = document.createXULElement("description");
        elem.textContent = text;
        elem.className = "indent";
        descrList.append(elem);
      }
    }
    };
    populateRadioElements("standard");
    populateRadioElements("safer", [
      SecurityLevelStrings.security_level_js_https_only,
      SecurityLevelStrings.security_level_limit_typography,
      SecurityLevelStrings.security_level_limit_media,
    ]);
    populateRadioElements("safest", [
      SecurityLevelStrings.security_level_js_disabled,
      SecurityLevelStrings.security_level_limit_typography_svg,
      SecurityLevelStrings.security_level_limit_media,
    ]);

    restoreDefaultsButton.addEventListener("command", () => {
      SecurityLevelPrefs.securityCustom = false;
    });
    this._radiogroup.addEventListener("select", () => {
      SecurityLevelPrefs.securityLevel = this._radiogroup.value;
    });
  },

  _configUIFromPrefs() {
    // read our prefs
    const securityLevel = SecurityLevelPrefs.securityLevel;
    const securityCustom = SecurityLevelPrefs.securityCustom;

    // get our elements
    const groupbox = document.querySelector("#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"
    this._radiogroup.value = SecurityLevelPrefs.securityLevel;
    const isCustom = SecurityLevelPrefs.securityCustom;
    this._radiogroup.disabled = isCustom;
    this._customNotification.hidden = !isCustom;
    // Have the container's selection CSS class match the selection state of the
    // radio elements.
    for (const { container, radio } of this._radioOptions) {
      container.classList.toggle(
        "securityLevel-radio-option-selected",
        radio.selected
      );

    // 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;

    radiogroup.value = securityLevel;

    switch (securityLevel) {
      case "standard":
        labelStandardCustom.hidden = !securityCustom;
        labelStandardRestoreDefaults.hidden = !securityCustom;
        break;
      case "safer":
        labelSaferCustom.hidden = !securityCustom;
        labelSaferRestoreDefaults.hidden = !securityCustom;
        break;
      case "safest":
        labelSafestCustom.hidden = !securityCustom;
        labelSafestRestoreDefaults.hidden = !securityCustom;
        break;
    }
  },

@@ -514,17 +507,4 @@ var SecurityLevelPreferences = {
        break;
    }
  },

  selectSecurityLevel() {
    // radio group elements
    let radiogroup = document.getElementById("securityLevel-radiogroup");

    // update pref based on selected radio option
    SecurityLevelPrefs.securityLevel = radiogroup.value;
    SecurityLevelPreferences.restoreDefaults();
  },

  restoreDefaults() {
    SecurityLevelPrefs.securityCustom = false;
  },
}; /* SecurityLevelPreferences */
+35 −28
Original line number Diff line number Diff line
label.securityLevel-customWarning {
  border-radius: 4px;
  background-color: var(--yellow-50);
  color: black;
  font-size: 1em;
  height: 1.6em;
  padding: 0.4em 0.5em;
#securityLevel-groupbox {
  --section-highlight-background-color: color-mix(in srgb, var(--in-content-accent-color) 20%, transparent);
}

#securityLevel-customNotification {
  /* Spacing similar to #fpiIncompatibilityWarning. */
  margin-block: 16px;
}

.info-icon.securityLevel-custom-warning-icon {
  list-style-image: url("chrome://global/skin/icons/warning.svg");
}

#securityLevel-customHeading {
  font-weight: bold;
}

radiogroup#securityLevel-radiogroup description {
  color: var(--in-content-page-color)!important;
/* Overwrite indent rule from preferences.css */
#securityLevel-radiogroup description.indent {
  color: var(--in-content-page-color);
}

radiogroup#securityLevel-radiogroup radio {
#securityLevel-radiogroup radio {
  font-weight: bold;
}

radiogroup#securityLevel-radiogroup > vbox {
#securityLevel-radiogroup[disabled] {
  opacity: 0.5;
}

/* Overwrite the rule in common-shared.css so we don't get 0.25 opacity overall
 * on the radio text. */
#securityLevel-radiogroup[disabled] radio[disabled] {
  opacity: 1.0;
}

.securityLevel-radio-option {
  border: 1px solid var(--in-content-box-border-color);
  border-radius: 4px;
  margin: 3px 0;
  padding: 9px;
}

radiogroup#securityLevel-radiogroup[value=standard] > vbox#securityLevel-vbox-standard,
radiogroup#securityLevel-radiogroup[value=safer] > vbox#securityLevel-vbox-safer,
radiogroup#securityLevel-radiogroup[value=safest] > vbox#securityLevel-vbox-safest {
  --section-highlight-background-color: color-mix(in srgb, var(--in-content-accent-color) 20%, transparent);
.securityLevel-radio-option.securityLevel-radio-option-selected {
  background-color: var(--section-highlight-background-color);
  border: 1px solid var(--in-content-accent-color);

}

vbox.securityLevel-descriptionList {
.securityLevel-radio-option:not(
  .securityLevel-radio-option-selected
) .securityLevel-descriptionList {
  display: none;
}

radiogroup#securityLevel-radiogroup[value=safer] vbox#securityLevel-vbox-safer vbox.securityLevel-descriptionList,
radiogroup#securityLevel-radiogroup[value=safest] vbox#securityLevel-vbox-safest vbox.securityLevel-descriptionList {
  display: inherit;
}

vbox.securityLevel-descriptionList description {
.securityLevel-descriptionList description {
  display: list-item;
}

vbox#securityLevel-vbox-standard,
vbox#securityLevel-vbox-safer,
vbox#securityLevel-vbox-safest {
  margin-top: 0.4em;
}
+40 −44
Original line number Diff line number Diff line
@@ -2,62 +2,58 @@
          data-category="panePrivacy"
          data-subcategory="securitylevel"
          hidden="true">
  <label><html:h2/></label>
  <label><html:h2></html:h2></label>
  <vbox flex="1">
    <description flex="1">
      <html:span id="securityLevel-overview" class="tail-with-learn-more"/>
      <html:span id="securityLevel-overview" class="tail-with-learn-more">
      </html:span>
      <label id="securityLevel-learnMore"
             class="learnMore text-link"
             is="text-link"
             href="about:manual#security-settings"
             useoriginprincipal="true"/>
    </description>
    <radiogroup id="securityLevel-radiogroup">
      <vbox id="securityLevel-vbox-standard">
        <hbox>
          <radio value="standard"/>
          <vbox>
            <spacer flex="1"/>
            <label class="securityLevel-customWarning"/>
            <spacer flex="1"/>
          </vbox>
          <spacer flex="1"/>
    <hbox id="securityLevel-customNotification"
          class="info-box-container"
          flex="1">
      <hbox class="info-icon-container">
        <image class="info-icon securityLevel-custom-warning-icon"/>
      </hbox>
        <description flex="1" class="indent">
          <html:span class="summary tail-with-learn-more"/>
          <label class="securityLevel-restoreDefaults learnMore text-link"/>
        </description>
      </vbox>
      <vbox id="securityLevel-vbox-safer">
        <hbox>
          <radio value="safer"/>
          <vbox>
            <spacer flex="1"/>
            <label class="securityLevel-customWarning"/>
            <spacer flex="1"/>
      <vbox flex="1">
        <label id="securityLevel-customHeading"/>
        <description id="securityLevel-customDescription" flex="1"/>
      </vbox>
      <hbox align="center">
        <button id="securityLevel-restoreDefaults"/>
      </hbox>
        <description flex="1" class="indent">
          <html:span class="summary tail-with-learn-more"/>
          <label class="securityLevel-restoreDefaults learnMore text-link"/>
        </description>
        <vbox class="securityLevel-descriptionList indent">
        </vbox>
      </vbox>
      <vbox id="securityLevel-vbox-safest">
        <hbox>
          <radio value="safest"/>
          <vbox>
            <spacer flex="1"/>
            <label class="securityLevel-customWarning"/>
            <spacer flex="1"/>
          </vbox>
    </hbox>
        <description flex="1" class="indent">
          <html:span class="summary tail-with-learn-more"/>
          <label class="securityLevel-restoreDefaults learnMore text-link"/>
        </description>
        <vbox class="securityLevel-descriptionList indent">
    <radiogroup id="securityLevel-radiogroup">
      <vbox class="securityLevel-radio-option">
        <radio value="standard"
               aria-describedby="securityLevelSummary-standard"/>
        <vbox id="securityLevelSummary-standard">
          <description class="summary indent" flex="1"/>
        </vbox>
      </vbox>
      <vbox class="securityLevel-radio-option">
        <!-- NOTE: We point the accessible description to the wrapping vbox
          - rather than its first description element. This means that when the
          - securityLevel-descriptionList is shown or hidden, its text content
          - is included or excluded from the accessible description,
          - respectively. -->
        <radio value="safer"
               aria-describedby="securityLevelSummary-safer"/>
        <vbox id="securityLevelSummary-safer">
          <description class="summary indent" flex="1"/>
          <vbox class="securityLevel-descriptionList indent"/>
        </vbox>
      </vbox>
      <vbox class="securityLevel-radio-option">
        <radio value="safest"
               aria-describedby="securityLevelSummary-safest"/>
        <vbox id="securityLevelSummary-safest">
          <description class="summary indent" flex="1"/>
          <vbox class="securityLevel-descriptionList indent"/>
        </vbox>
      </vbox>
    </radiogroup>
+2 −0
Original line number Diff line number Diff line
@@ -13,9 +13,11 @@ security_level_learn_more = Learn more

# Panel
security_level_change = Change…
security_level_change_setting = Change Setting…
security_level_standard_summary = All browser and website features are enabled.
security_level_safer_summary = Disables website features that are often dangerous, causing some sites to lose functionality.
security_level_safest_summary = Only allows website features required for static sites and basic services. These changes affect images, media, and scripts.
security_level_custom_heading = Warning!
security_level_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.

## Security level section in about:preferences#privacy