[tbb-commits] [Git][tpo/applications/tor-browser][tor-browser-102.12.0esr-12.5-1] amend! Bug 40701: Add in pane security warning when downloading a file

ma1 (@ma1) git at gitlab.torproject.org
Tue Jun 6 20:54:35 UTC 2023



ma1 pushed to branch tor-browser-102.12.0esr-12.5-1 at The Tor Project / Applications / Tor Browser


Commits:
787ac906 by Dan Ballard at 2023-06-06T20:52:51+00:00
amend! Bug 40701: Add in pane security warning when downloading a file

Bug 40701: Add security warning when downloading a file

Shown in the downloads panel, about:downloads and places.xhtml.

- - - - -


11 changed files:

- browser/components/downloads/content/allDownloadsView.js
- browser/components/downloads/content/contentAreaDownloadsView.js
- browser/components/downloads/content/contentAreaDownloadsView.xhtml
- browser/components/downloads/content/downloads.css
- browser/components/downloads/content/downloads.js
- browser/components/downloads/content/downloadsPanel.inc.xhtml
- browser/components/places/content/places.css
- browser/components/places/content/places.js
- browser/components/places/content/places.xhtml
- browser/themes/shared/customizableui/panelUI-shared.css
- browser/themes/shared/downloads/contentAreaDownloadsView.css


Changes:

=====================================
browser/components/downloads/content/allDownloadsView.js
=====================================
@@ -212,6 +212,7 @@ var DownloadsView = {
  */
 function DownloadsPlacesView(
   aRichListBox,
+  torWarningMessageBar,
   aActive = true,
   aSuppressionFlag = DownloadsCommon.SUPPRESS_ALL_DOWNLOADS_OPEN
 ) {
@@ -241,6 +242,46 @@ function DownloadsPlacesView(
     ).attentionSuppressed |= aSuppressionFlag;
   }
 
+  // Tor browser warning message/alert shown above the list.
+
+  const PREF_SHOW_DOWNLOAD_WARNING = "browser.download.showTorWarning";
+  // Observe changes to the tor warning pref.
+  const torWarningPrefObserver = () => {
+    if (Services.prefs.getBoolPref(PREF_SHOW_DOWNLOAD_WARNING)) {
+      torWarningMessageBar.hidden = false;
+    } else {
+      // Re-assign focus if it is about to be lost.
+      if (torWarningMessageBar.contains(document.activeElement)) {
+        // Try and focus the downloads list.
+        // NOTE: If #downloadsListBox is still hidden, this will do nothing.
+        // But in this case there are no other focusable targets within the
+        // view, so we just leave it up to the focus handler.
+        this._richlistbox.focus({ preventFocusRing: true });
+      }
+      torWarningMessageBar.hidden = true;
+    }
+  };
+
+  Services.prefs.addObserver(
+    PREF_SHOW_DOWNLOAD_WARNING,
+    torWarningPrefObserver
+  );
+  // Initialize.
+  torWarningPrefObserver();
+
+  window.addEventListener("unload", () => {
+    Services.prefs.removeObserver(
+      PREF_SHOW_DOWNLOAD_WARNING,
+      torWarningPrefObserver
+    );
+  });
+
+  torWarningMessageBar
+    .querySelector(".downloads-tor-warning-dismiss-button")
+    .addEventListener("click", event => {
+      Services.prefs.setBoolPref(PREF_SHOW_DOWNLOAD_WARNING, false);
+    });
+
   // Make sure to unregister the view if the window is closed.
   window.addEventListener(
     "unload",


=====================================
browser/components/downloads/content/contentAreaDownloadsView.js
=====================================
@@ -10,6 +10,9 @@ const { PrivateBrowsingUtils } = ChromeUtils.import(
 
 var ContentAreaDownloadsView = {
   init() {
+    const torWarningMessage = document.getElementById(
+      "aboutDownloadsTorWarning"
+    );
     let box = document.getElementById("downloadsListBox");
     let suppressionFlag = DownloadsCommon.SUPPRESS_CONTENT_AREA_DOWNLOADS_OPEN;
     box.addEventListener(
@@ -17,9 +20,22 @@ var ContentAreaDownloadsView = {
       () => {
         // Set focus to Downloads list once it is created
         // And prevent it from showing the focus ring around the richlistbox (Bug 1702694)
-        document
-          .getElementById("downloadsListBox")
-          .focus({ preventFocusRing: true });
+        // Prevent focusing the list whilst the tor browser warning is shown.
+        // Some screen readers (tested with Orca and NVDA) will not read out
+        // alerts if they are already present on page load. In that case, a
+        // screen reader user may not be aware of the warning before they
+        // interact with the downloads list, which we do not want.
+        // Some hacky workarounds were tested with Orca to get it to read back
+        // the alert before the focus is read, but this was inconsistent and the
+        // experience was bad.
+        // Without auto-focusing the downloads list, a screen reader should not
+        // skip beyond the alert's content.
+        if (torWarningMessage.hidden) {
+          document
+            .getElementById("downloadsListBox")
+            .focus({ preventFocusRing: true });
+        }
+
         // Pause the indicator if the browser is active.
         if (document.visibilityState === "visible") {
           DownloadsCommon.getIndicatorData(
@@ -29,7 +45,12 @@ var ContentAreaDownloadsView = {
       },
       { once: true }
     );
-    let view = new DownloadsPlacesView(box, true, suppressionFlag);
+    let view = new DownloadsPlacesView(
+      box,
+      torWarningMessage,
+      true,
+      suppressionFlag
+    );
     document.addEventListener("visibilitychange", aEvent => {
       let indicator = DownloadsCommon.getIndicatorData(window);
       if (document.visibilityState === "visible") {
@@ -42,6 +63,53 @@ var ContentAreaDownloadsView = {
     if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) {
       view.place = "place:transition=7&sort=4";
     }
+
+    torWarningMessage.querySelector(
+      ".downloads-tor-warning-title"
+    ).textContent = this._getTorString("torbutton.download.warning.title");
+
+    const tailsLink = document.createElement("a");
+    tailsLink.href = "https://tails.boum.org/";
+    tailsLink.target = "_blank";
+    tailsLink.textContent = this._getTorString(
+      "torbutton.download.warning.tails_brand_name"
+    );
+
+    const [beforeLink, afterLink] = this._getTorString(
+      "torbutton.download.warning.description"
+    ).split("%S");
+
+    torWarningMessage
+      .querySelector(".downloads-tor-warning-description")
+      .append(beforeLink, tailsLink, afterLink);
+
+    torWarningMessage.querySelector(
+      ".downloads-tor-warning-dismiss-button"
+    ).textContent = this._getTorString("torbutton.download.warning.dismiss");
+  },
+
+  /**
+   * Get a string from the properties bundle.
+   *
+   * @param {string} name - The string name.
+   *
+   * @return {string} The string.
+   */
+  _getTorString(name) {
+    if (!this._stringBundle) {
+      this._stringBundle = Services.strings.createBundle(
+        "chrome://torbutton/locale/torbutton.properties"
+      );
+    }
+    try {
+      return this._stringBundle.GetStringFromName(name);
+    } catch {}
+    if (!this._fallbackStringBundle) {
+      this._fallbackStringBundle = Services.strings.createBundle(
+        "resource://torbutton/locale/en-US/torbutton.properties"
+      );
+    }
+    return this._fallbackStringBundle.GetStringFromName(name);
   },
 };
 


=====================================
browser/components/downloads/content/contentAreaDownloadsView.xhtml
=====================================
@@ -39,6 +39,23 @@
   </keyset>
 #endif
 
+  <html:message-bar id="aboutDownloadsTorWarning"
+                    class="downloads-tor-warning-message-bar"
+                    role="alert"
+                    aria-labelledby="aboutDownloadsTorWarningTitle"
+                    aria-describedby="aboutDownloadsTorWarningDescription">
+    <html:div class="downloads-tor-warning-grid">
+      <html:p id="aboutDownloadsTorWarningTitle"
+              class="downloads-tor-warning-title">
+      </html:p>
+      <html:p id="aboutDownloadsTorWarningDescription"
+              class="downloads-tor-warning-description">
+      </html:p>
+      <html:button class="downloads-tor-warning-dismiss-button">
+      </html:button>
+    </html:div>
+  </html:message-bar>
+
   <richlistbox flex="1"
                seltype="multiple"
                id="downloadsListBox"


=====================================
browser/components/downloads/content/downloads.css
=====================================
@@ -104,18 +104,52 @@
   flex-direction: column;
 }
 
-#downloadsWarning p {
-  padding-inline: 8px;
-  margin-block-start: 8px;
-  margin-block-end: 0;
+.downloads-tor-warning-grid {
+  display: grid;
+  grid-template:
+    "title button" min-content
+    "description button" auto
+    / 1fr max-content;
+  gap: 8px;
+  margin-block: 8px;
+  /* Some extra space between the text and the icon. */
+  margin-inline-start: 8px;
+}
+
+.downloads-tor-warning-grid .downloads-tor-warning-title {
+  grid-area: title;
+  margin: 0;
+}
+
+.downloads-tor-warning-grid .downloads-tor-warning-description {
+  grid-area: description;
+  margin: 0;
+}
+
+.downloads-tor-warning-grid .downloads-tor-warning-dismiss-button {
+  grid-area: button;
+  align-self: center;
+}
+
+.downloads-tor-warning-description,
+.downloads-tor-warning-title {
   line-height: 1.4;
 }
 
-#downloadsWarningHeaderTitle {
+.downloads-tor-warning-title {
   font-weight: bold;
 }
 
-#downloadsWarningDescription {
+#downloadsPanelTorWarning :is(
+  .downloads-tor-warning-description,
+  .downloads-tor-warning-title
+) {
+  padding-inline: 8px;
+  margin-block-start: 8px;
+  margin-block-end: 0;
+}
+
+#downloadsPanelTorWarningDescription {
   /* Make sure we wrap the text rather than request the default max-content
    * width from the parent XUL -moz-box. */
   width: 0;


=====================================
browser/components/downloads/content/downloads.js
=====================================
@@ -33,8 +33,6 @@
 
 const PREF_SHOW_DOWNLOAD_WARNING = "browser.download.showTorWarning";
 
-const TAILS_URI = "https://tails.boum.org/";
-
 var { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
@@ -143,13 +141,28 @@ var DownloadsPanel = {
       );
     }
 
-    let showDownloadWarning = Services.prefs.getBoolPref(
-      PREF_SHOW_DOWNLOAD_WARNING
+    const torWarningMessage = document.getElementById(
+      "downloadsPanelTorWarning"
     );
-    if (!showDownloadWarning) {
-      document.getElementById("downloadsWarning").hidden = true;
-    } else {
-      document.getElementById("downloadsWarning").hidden = false;
+    if (!this._torWarningPrefObserver) {
+      // Observe changes to the tor warning pref.
+      this._torWarningPrefObserver = () => {
+        if (Services.prefs.getBoolPref(PREF_SHOW_DOWNLOAD_WARNING)) {
+          torWarningMessage.hidden = false;
+        } else {
+          // Re-assign focus if it is about to be lost.
+          if (torWarningMessage.contains(document.activeElement)) {
+            this._focusPanel(true);
+          }
+          torWarningMessage.hidden = true;
+        }
+      };
+      Services.prefs.addObserver(
+        PREF_SHOW_DOWNLOAD_WARNING,
+        this._torWarningPrefObserver
+      );
+      // Initialize
+      this._torWarningPrefObserver();
     }
 
     if (this._state != this.kStateUninitialized) {
@@ -175,42 +188,40 @@ var DownloadsPanel = {
       DownloadsSummary
     );
 
-    if (this._torWarningInitialized == 0) {
-      document.getElementById(
-        "downloadsWarningHeaderTitle"
-      ).textContent = this._getString("torbutton.download.warning.title");
-      let tailsBrandName = this._getString(
-        "torbutton.download.warning.tails_brand_name"
-      );
+    if (!this._torWarningInitialized) {
+      torWarningMessage.querySelector(
+        ".downloads-tor-warning-title"
+      ).textContent = this._getTorString("torbutton.download.warning.title");
 
-      let warningDescriptionText = this._getString(
-        "torbutton.download.warning.description"
-      );
-      let [head, rest] = warningDescriptionText.split("%S");
       const tailsLink = document.createElement("a");
-      tailsLink.setAttribute("href", TAILS_URI);
-      tailsLink.textContent = tailsBrandName.trim();
+      tailsLink.href = "https://tails.boum.org/";
+      tailsLink.textContent = this._getTorString(
+        "torbutton.download.warning.tails_brand_name"
+      );
       tailsLink.addEventListener("click", event => {
         event.preventDefault();
         this.hidePanel();
-        openWebLinkIn(TAILS_URI, "tab");
+        openWebLinkIn(tailsLink.href, "tab");
       });
 
-      let downloadsWarningDescription = document.getElementById(
-        "downloadsWarningDescription"
-      );
-      downloadsWarningDescription.append(head, tailsLink, rest);
+      const [beforeLink, afterLink] = this._getTorString(
+        "torbutton.download.warning.description"
+      ).split("%S");
+
+      torWarningMessage
+        .querySelector(".downloads-tor-warning-description")
+        .append(beforeLink, tailsLink, afterLink);
 
-      let dismissBtn = document.getElementById(
-        "downloadWarningDismiss"
+      let dismissButton = torWarningMessage.querySelector(
+        ".downloads-tor-warning-dismiss-button"
       );
-      dismissBtn.textContent = this._getString("torbutton.download.warning.dismiss");
-      dismissBtn.addEventListener("click", event => {
+      dismissButton.textContent = this._getTorString(
+        "torbutton.download.warning.dismiss"
+      );
+      dismissButton.addEventListener("click", event => {
         Services.prefs.setBoolPref(PREF_SHOW_DOWNLOAD_WARNING, false);
-        document.getElementById("downloadsWarning").hidden = true;
-        this._focusPanel(true);
       });
-      this._torWarningInitialized = 1;
+      this._torWarningInitialized = true;
     }
 
     DownloadsCommon.log(
@@ -254,6 +265,14 @@ var DownloadsPanel = {
       );
     }
 
+    if (this._torWarningPrefObserver) {
+      Services.prefs.removeObserver(
+        PREF_SHOW_DOWNLOAD_WARNING,
+        this._torWarningPrefObserver
+      );
+      delete this._torWarningPrefObserver;
+    }
+
     this._state = this.kStateUninitialized;
 
     DownloadsSummary.active = false;
@@ -591,14 +610,17 @@ var DownloadsPanel = {
    *
    * @param {bool} [forceFocus=false] - Whether to force move the focus.
    */
-  _focusPanel(forceFocus=false) {
+  _focusPanel(forceFocus = false) {
     if (!forceFocus) {
       // We may be invoked while the panel is still waiting to be shown.
       if (this._state != this.kStateShown) {
         return;
       }
 
-      if (document.activeElement && this.panel.contains(document.activeElement)) {
+      if (
+        document.activeElement &&
+        this.panel.contains(document.activeElement)
+      ) {
         return;
       }
     }
@@ -729,7 +751,7 @@ var DownloadsPanel = {
    *
    * @return {string} The string.
    */
-  _getString(name) {
+  _getTorString(name) {
     if (!this._stringBundle) {
       this._stringBundle = Services.strings.createBundle(
         "chrome://torbutton/locale/torbutton.properties"


=====================================
browser/components/downloads/content/downloadsPanel.inc.xhtml
=====================================
@@ -124,16 +124,19 @@
                   disablekeynav="true">
 
     <panelview id="downloadsPanel-mainView">
-      <vbox id="downloadsWarning">
+      <vbox id="downloadsPanelTorWarning">
         <vbox role="alert"
-              aria-labelledby="downloadsWarningHeaderTitle"
-              aria-describedby="downloadsWarningDescription">
-          <html:p id="downloadsWarningHeaderTitle"></html:p>
-          <html:p id="downloadsWarningDescription">
+              aria-labelledby="downloadsPanelTorWarningTitle"
+              aria-describedby="downloadsPanelTorWarningDescription">
+          <html:p id="downloadsPanelTorWarningTitle"
+                  class="downloads-tor-warning-title">
+          </html:p>
+          <html:p id="downloadsPanelTorWarningDescription"
+                  class="downloads-tor-warning-description">
           </html:p>
 
           <html:div class="panel-footer">
-            <html:button id="downloadWarningDismiss">
+            <html:button class="downloads-tor-warning-dismiss-button">
             </html:button>
           </html:div>
         </vbox>


=====================================
browser/components/places/content/places.css
=====================================
@@ -126,3 +126,7 @@ tree[is="places-tree"] > treechildren::-moz-tree-cell {
   margin: 2px 4px;
   color: currentColor;
 }
+
+#placesDownloadsTorWarning:not(.downloads-visible) {
+  display: none;
+}


=====================================
browser/components/places/content/places.js
=====================================
@@ -6,6 +6,7 @@
 /* import-globals-from instantEditBookmark.js */
 /* import-globals-from /toolkit/content/contentAreaUtils.js */
 /* import-globals-from /browser/components/downloads/content/allDownloadsView.js */
+/* import-globals-from /browser/base/content/utilityOverlay.js */
 
 /* Shared Places Import - change other consumers if you change this: */
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
@@ -164,11 +165,15 @@ var PlacesOrganizer = {
       "&sort=" +
       Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
 
+    const torWarningMessage = document.getElementById(
+      "placesDownloadsTorWarning"
+    );
     ContentArea.setContentViewForQueryString(
       DOWNLOADS_QUERY,
       () =>
         new DownloadsPlacesView(
           document.getElementById("downloadsListBox"),
+          torWarningMessage,
           false
         ),
       {
@@ -178,6 +183,33 @@ var PlacesOrganizer = {
       }
     );
 
+    // Initialize tor warning text content.
+    torWarningMessage.querySelector(
+      ".downloads-tor-warning-title"
+    ).textContent = this._getTorString("torbutton.download.warning.title");
+
+    const tailsLink = document.createElement("a");
+    tailsLink.href = "https://tails.boum.org/";
+    tailsLink.textContent = this._getTorString(
+      "torbutton.download.warning.tails_brand_name"
+    );
+    tailsLink.addEventListener("click", event => {
+      event.preventDefault();
+      openWebLinkIn(tailsLink.href, "tab");
+    });
+
+    const [beforeLink, afterLink] = this._getTorString(
+      "torbutton.download.warning.description"
+    ).split("%S");
+
+    torWarningMessage
+      .querySelector(".downloads-tor-warning-description")
+      .append(beforeLink, tailsLink, afterLink);
+
+    torWarningMessage.querySelector(
+      ".downloads-tor-warning-dismiss-button"
+    ).textContent = this._getTorString("torbutton.download.warning.dismiss");
+
     ContentArea.init();
 
     this._places = document.getElementById("placesList");
@@ -246,6 +278,30 @@ var PlacesOrganizer = {
     ContentArea.focus();
   },
 
+  /**
+   * Get a string from the properties bundle.
+   *
+   * @param {string} name - The string name.
+   *
+   * @returns {string} The string.
+   */
+  _getTorString(name) {
+    if (!this._stringBundle) {
+      this._stringBundle = Services.strings.createBundle(
+        "chrome://torbutton/locale/torbutton.properties"
+      );
+    }
+    try {
+      return this._stringBundle.GetStringFromName(name);
+    } catch {}
+    if (!this._fallbackStringBundle) {
+      this._fallbackStringBundle = Services.strings.createBundle(
+        "resource://torbutton/locale/en-US/torbutton.properties"
+      );
+    }
+    return this._fallbackStringBundle.GetStringFromName(name);
+  },
+
   QueryInterface: ChromeUtils.generateQI([]),
 
   handleEvent: function PO_handleEvent(aEvent) {
@@ -1386,9 +1442,20 @@ var ContentArea = {
       oldView.associatedElement.hidden = true;
       aNewView.associatedElement.hidden = false;
 
+      const isDownloads = aNewView.associatedElement.id === "downloadsListBox";
+      const torWarningMessage = document.getElementById(
+        "placesDownloadsTorWarning"
+      );
+      const torWarningLoosingFocus =
+        torWarningMessage.contains(document.activeElement) && !isDownloads;
+      torWarningMessage.classList.toggle("downloads-visible", isDownloads);
+
       // If the content area inactivated view was focused, move focus
       // to the new view.
-      if (document.activeElement == oldView.associatedElement) {
+      if (
+        document.activeElement == oldView.associatedElement ||
+        torWarningLoosingFocus
+      ) {
         aNewView.associatedElement.focus();
       }
     }


=====================================
browser/components/places/content/places.xhtml
=====================================
@@ -345,6 +345,21 @@
     </tree>
     <splitter collapse="none" persist="state"></splitter>
     <vbox id="contentView" flex="4">
+      <html:message-bar id="placesDownloadsTorWarning"
+                        role="alert"
+                        aria-labelledby="placesDownloadsTorWarningTitle"
+                        aria-describedby="placesDownloadsTorWarningDescription">
+        <html:div class="downloads-tor-warning-grid">
+          <html:p id="placesDownloadsTorWarningTitle"
+                  class="downloads-tor-warning-title">
+          </html:p>
+          <html:p id="placesDownloadsTorWarningDescription"
+                  class="downloads-tor-warning-description">
+          </html:p>
+          <html:button class="downloads-tor-warning-dismiss-button">
+          </html:button>
+        </html:div>
+      </html:message-bar>
       <vbox id="placesViewsBox" flex="1">
         <tree id="placeContent"
               class="plain placesTree"


=====================================
browser/themes/shared/customizableui/panelUI-shared.css
=====================================
@@ -1324,7 +1324,7 @@ panelview .toolbarbutton-1 {
 #downloadsFooterButtons > toolbarseparator,
 .cui-widget-panelview menuseparator,
 .cui-widget-panel toolbarseparator,
-#downloadsWarning toolbarseparator,
+#downloadsPanelTorWarning toolbarseparator,
 #securityLevel-panel toolbarseparator {
   appearance: none;
   min-height: 0;


=====================================
browser/themes/shared/downloads/contentAreaDownloadsView.css
=====================================
@@ -25,3 +25,7 @@
   text-align: center;
   color: var(--in-content-deemphasized-text);
 }
+
+#aboutDownloadsTorWarning {
+  margin-block-end: 8px;
+}



View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/787ac9062bc132ac6c05564c295845f4d6c91c68

-- 
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/787ac9062bc132ac6c05564c295845f4d6c91c68
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tbb-commits/attachments/20230606/70ca68b9/attachment-0001.htm>


More information about the tbb-commits mailing list