Bug 1497200: Apply Meta CSP to about:downloads. r=Gijs
authorChristoph Kerschbaumer <ckerschb@christophkerschbaumer.com>
Wed, 25 Sep 2019 13:50:28 +0000
changeset 494915 1572223bd5ecd9ae000be6c766cece6533972735
parent 494913 bf2586dc82562136449ebe14bbc14b609c20c245
child 494916 366b78b3f763f3be8c8ca7d232f2b022f69edda4
push id36618
push userapavel@mozilla.com
push dateWed, 25 Sep 2019 21:51:45 +0000
treeherdermozilla-central@ac2f06a2ddc0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1497200
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1497200: Apply Meta CSP to about:downloads. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D45330
browser/components/downloads/DownloadsViewUI.jsm
browser/components/downloads/content/allDownloadsView.js
browser/components/downloads/content/contentAreaDownloadsView.js
browser/components/downloads/content/contentAreaDownloadsView.xul
browser/components/downloads/content/downloadsCommands.inc.xul
browser/components/downloads/content/downloadsCommands.js
browser/components/downloads/content/downloadsRichListBox.inc.xul
browser/components/downloads/jar.mn
browser/components/places/content/places.xul
dom/security/nsContentSecurityUtils.cpp
editor/libeditor/tests/test_bug629172.html
toolkit/content/editMenuOverlay.js
--- a/browser/components/downloads/DownloadsViewUI.jsm
+++ b/browser/components/downloads/DownloadsViewUI.jsm
@@ -183,30 +183,32 @@ this.DownloadsViewUI.DownloadElementShel
                          crop="end"/>
             <description class="downloadDetails downloadDetailsHover"
                          crop="end"/>
             <description class="downloadDetails downloadDetailsButtonHover"
                          crop="end"/>
           </vbox>
         </hbox>
         <toolbarseparator />
-        <button class="downloadButton"
-                oncommand="DownloadsView.onDownloadButton(event);"/>
+        <button class="downloadButton"/>
       `);
       gDownloadListItemFragments.set(document, downloadListItemFragment);
     }
     this.element.setAttribute("active", true);
     this.element.setAttribute("orient", "horizontal");
-    this.element.setAttribute(
-      "onclick",
-      "DownloadsView.onDownloadClick(event);"
-    );
+    this.element.addEventListener("click", ev => {
+      ev.target.ownerGlobal.DownloadsView.onDownloadClick(ev);
+    });
     this.element.appendChild(
       document.importNode(downloadListItemFragment, true)
     );
+    let downloadButton = this.element.querySelector(".downloadButton");
+    downloadButton.addEventListener("command", function(event) {
+      event.target.ownerGlobal.DownloadsView.onDownloadButton(event);
+    });
     for (let [propertyName, selector] of [
       ["_downloadTypeIcon", ".downloadTypeIcon"],
       ["_downloadTarget", ".downloadTarget"],
       ["_downloadDetailsNormal", ".downloadDetailsNormal"],
       ["_downloadDetailsHover", ".downloadDetailsHover"],
       ["_downloadDetailsButtonHover", ".downloadDetailsButtonHover"],
       ["_downloadButton", ".downloadButton"],
     ]) {
--- a/browser/components/downloads/content/allDownloadsView.js
+++ b/browser/components/downloads/content/allDownloadsView.js
@@ -165,17 +165,17 @@ HistoryDownloadElementShell.prototype = 
         });
     }
   },
 };
 
 /**
  * Relays commands from the download.xml binding to the selected items.
  */
-const DownloadsView = {
+var DownloadsView = {
   onDownloadButton(event) {
     event.target.closest("richlistitem")._shell.onButton();
   },
 
   onDownloadClick() {},
 };
 
 /**
@@ -803,8 +803,38 @@ function goUpdateDownloadCommands() {
       if (DownloadsViewUI.isCommandName(name)) {
         goUpdateCommand(name);
       }
     }
   }
   updateCommandsForObject(DownloadsPlacesView.prototype);
   updateCommandsForObject(HistoryDownloadElementShell.prototype);
 }
+
+document.addEventListener("DOMContentLoaded", function() {
+  let richtListBox = document.getElementById("downloadsRichListBox");
+  richtListBox.addEventListener("scroll", function(event) {
+    return this._placesView.onScroll();
+  });
+  richtListBox.addEventListener("keypress", function(event) {
+    return this._placesView.onKeyPress(event);
+  });
+  richtListBox.addEventListener("dblclick", function(event) {
+    return this._placesView.onDoubleClick(event);
+  });
+  richtListBox.addEventListener("contextmenu", function(event) {
+    return this._placesView.onContextMenu(event);
+  });
+  richtListBox.addEventListener("dragstart", function(event) {
+    this._placesView.onDragStart(event);
+  });
+  richtListBox.addEventListener("dragover", function(event) {
+    this._placesView.onDragOver(event);
+  });
+  richtListBox.addEventListener("drop", function(event) {
+    this._placesView.onDrop(event);
+  });
+  richtListBox.addEventListener("select", function(event) {
+    this._placesView.onSelect();
+  });
+  richtListBox.addEventListener("focus", goUpdateDownloadCommands);
+  richtListBox.addEventListener("blur", goUpdateDownloadCommands);
+});
--- a/browser/components/downloads/content/contentAreaDownloadsView.js
+++ b/browser/components/downloads/content/contentAreaDownloadsView.js
@@ -16,8 +16,12 @@ var ContentAreaDownloadsView = {
     // Do not display the Places downloads in private windows
     if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) {
       view.place = "place:transition=7&sort=4";
     }
     // Set focus to Downloads list once it is created
     document.getElementById("downloadsRichListBox").focus();
   },
 };
+
+window.onload = function() {
+  ContentAreaDownloadsView.init();
+};
--- a/browser/components/downloads/content/contentAreaDownloadsView.xul
+++ b/browser/components/downloads/content/contentAreaDownloadsView.xul
@@ -12,36 +12,43 @@
 
 <!DOCTYPE window [
 <!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
 %downloadsDTD;
 <!ENTITY % editMenuDTD SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
 %editMenuDTD;
 ]>
 
+<!-- @CSP: We have to whitelist the 'oncommand' handler for all the cmd_* fields within
+   - editMenuOverlay.js until Bug 371900 is fixed using 
+   -    sha512-4o5Uf4E4EG+90Mb820FH2YFDf4IuX4bfUwQC7reK1ZhgcXWJBKMK2330XIELaFJJ8HiPffS9mP60MPjuXMIrHA==
+   -->
 <window id="contentAreaDownloadsView"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         title="&downloads.title;"
-        onload="ContentAreaDownloadsView.init();">
+        csp="default-src chrome:; script-src chrome: 'sha512-4o5Uf4E4EG+90Mb820FH2YFDf4IuX4bfUwQC7reK1ZhgcXWJBKMK2330XIELaFJJ8HiPffS9mP60MPjuXMIrHA=='; img-src chrome: moz-icon:;">
 
   <script src="chrome://global/content/globalOverlay.js"/>
   <script src="chrome://browser/content/downloads/contentAreaDownloadsView.js"/>
   <script src="chrome://browser/content/downloads/allDownloadsView.js"/>
   <script src="chrome://global/content/contentAreaUtils.js"/>
   <script src="chrome://global/content/editMenuOverlay.js"/>
 
 #include ../../../../toolkit/content/editMenuKeys.inc.xul
 #ifdef XP_MACOSX
   <keyset id="editMenuKeysExtra">
     <key id="key_delete2" keycode="VK_BACK" command="cmd_delete"/>
   </keyset>
 #endif
 
   <stack flex="1">
-#include downloadsRichListBox.inc.xul
+    <richlistbox flex="1"
+                 seltype="multiple"
+                 id="downloadsRichListBox"
+                 context="downloadsContextMenu"/>
     <description id="downloadsListEmptyDescription"
                  value="&downloadsListEmpty.label;"
                  mousethrough="always"/>
   </stack>
 #include downloadsCommands.inc.xul
 #include downloadsStrings.inc.xul
 #include downloadsContextMenu.inc.xul
 </window>
--- a/browser/components/downloads/content/downloadsCommands.inc.xul
+++ b/browser/components/downloads/content/downloadsCommands.inc.xul
@@ -1,31 +1,21 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+<script src="chrome://browser/content/downloads/downloadsCommands.js"/>
+
 <commandset id="downloadCommands"
             commandupdater="true"
-            events="focus,select,contextmenu"
-            oncommandupdate="goUpdateDownloadCommands();">
-  <command id="downloadsCmd_pauseResume"
-           oncommand="goDoCommand('downloadsCmd_pauseResume')"/>
-  <command id="downloadsCmd_cancel"
-           oncommand="goDoCommand('downloadsCmd_cancel')"/>
-  <command id="downloadsCmd_unblock"
-           oncommand="goDoCommand('downloadsCmd_unblock')"/>
-  <command id="downloadsCmd_chooseUnblock"
-           oncommand="goDoCommand('downloadsCmd_chooseUnblock')"/>
-  <command id="downloadsCmd_chooseOpen"
-           oncommand="goDoCommand('downloadsCmd_chooseOpen')"/>
-  <command id="downloadsCmd_confirmBlock"
-           oncommand="goDoCommand('downloadsCmd_confirmBlock')"/>
-  <command id="downloadsCmd_open"
-           oncommand="goDoCommand('downloadsCmd_open')"/>
-  <command id="downloadsCmd_show"
-           oncommand="goDoCommand('downloadsCmd_show')"/>
-  <command id="downloadsCmd_retry"
-           oncommand="goDoCommand('downloadsCmd_retry')"/>
-  <command id="downloadsCmd_openReferrer"
-           oncommand="goDoCommand('downloadsCmd_openReferrer')"/>
-  <command id="downloadsCmd_clearDownloads"
-           oncommand="goDoCommand('downloadsCmd_clearDownloads')"/>
+            events="focus,select,contextmenu">
+  <command id="downloadsCmd_pauseResume"/>
+  <command id="downloadsCmd_cancel"/>
+  <command id="downloadsCmd_unblock"/>
+  <command id="downloadsCmd_chooseUnblock"/>
+  <command id="downloadsCmd_chooseOpen"/>
+  <command id="downloadsCmd_confirmBlock"/>
+  <command id="downloadsCmd_open"/>
+  <command id="downloadsCmd_show"/>
+  <command id="downloadsCmd_retry"/>
+  <command id="downloadsCmd_openReferrer"/>
+  <command id="downloadsCmd_clearDownloads"/>
 </commandset>
new file mode 100644
--- /dev/null
+++ b/browser/components/downloads/content/downloadsCommands.js
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from allDownloadsView.js */
+/* import-globals-from ../../../../toolkit/content/globalOverlay.js */
+
+document.addEventListener("DOMContentLoaded", function() {
+  let downloadCommands = document.getElementById("downloadCommands");
+  downloadCommands.addEventListener("commandupdate", function() {
+    goUpdateDownloadCommands();
+  });
+  downloadCommands.addEventListener("command", function(event) {
+    let { id } = event.target;
+    goDoCommand(id);
+  });
+});
deleted file mode 100644
--- a/browser/components/downloads/content/downloadsRichListBox.inc.xul
+++ /dev/null
@@ -1,17 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-<richlistbox flex="1"
-             seltype="multiple"
-             id="downloadsRichListBox" context="downloadsContextMenu"
-             onscroll="return this._placesView.onScroll();"
-             onkeypress="return this._placesView.onKeyPress(event);"
-             ondblclick="return this._placesView.onDoubleClick(event);"
-             oncontextmenu="return this._placesView.onContextMenu(event);"
-             ondragstart="this._placesView.onDragStart(event);"
-             ondragover="this._placesView.onDragOver(event);"
-             ondrop="this._placesView.onDrop(event);"
-             onfocus="goUpdateDownloadCommands();"
-             onselect="this._placesView.onSelect();"
-             onblur="goUpdateDownloadCommands();"/>
\ No newline at end of file
--- a/browser/components/downloads/jar.mn
+++ b/browser/components/downloads/jar.mn
@@ -5,8 +5,9 @@
 browser.jar:
         content/browser/downloads/downloads.css          (content/downloads.css)
         content/browser/downloads/downloads.js           (content/downloads.js)
         content/browser/downloads/indicator.js           (content/indicator.js)
         content/browser/downloads/allDownloadsView.js    (content/allDownloadsView.js)
 *       content/browser/downloads/contentAreaDownloadsView.xul (content/contentAreaDownloadsView.xul)
         content/browser/downloads/contentAreaDownloadsView.js  (content/contentAreaDownloadsView.js)
         content/browser/downloads/contentAreaDownloadsView.css (content/contentAreaDownloadsView.css)
+        content/browser/downloads/downloadsCommands.js         (content/downloadsCommands.js)
--- a/browser/components/places/content/places.xul
+++ b/browser/components/places/content/places.xul
@@ -401,17 +401,20 @@
             <treecol label="&col.dateadded.label;" id="placesContentDateAdded" anonid="dateAdded" flex="1" hidden="true"
                       persist="width hidden ordinal sortActive sortDirection"/>
             <splitter class="tree-splitter"/>
             <treecol label="&col.lastmodified.label;" id="placesContentLastModified" anonid="lastModified" flex="1" hidden="true"
                       persist="width hidden ordinal sortActive sortDirection"/>
           </treecols>
           <treechildren flex="1" onclick="ContentTree.onClick(event);"/>
         </tree>
-#include ../../downloads/content/downloadsRichListBox.inc.xul
+        <richlistbox flex="1"
+                     seltype="multiple"
+                     id="downloadsRichListBox"
+                     context="downloadsContextMenu"/>
       </deck>
       <deck id="detailsDeck" style="height: 11em;">
         <vbox id="itemsCountBox" align="center">
           <spacer flex="3"/>
           <label id="itemsCountText"/>
           <spacer flex="1"/>
           <description id="selectItemDescription">
               &detailsPane.selectAnItemText.description;
--- a/dom/security/nsContentSecurityUtils.cpp
+++ b/dom/security/nsContentSecurityUtils.cpp
@@ -461,18 +461,16 @@ void nsContentSecurityUtils::AssertAbout
     // about:blank is a special about page -> no CSP
     NS_LITERAL_CSTRING("about:blank"),
     // about:srcdoc is a special about page -> no CSP
     NS_LITERAL_CSTRING("about:srcdoc"),
     // about:sync-log displays plain text only -> no CSP
     NS_LITERAL_CSTRING("about:sync-log"),
     // about:printpreview displays plain text only -> no CSP
     NS_LITERAL_CSTRING("about:printpreview"),
-    // Bug 1497200: Apply Meta CSP to about:downloads
-    NS_LITERAL_CSTRING("about:downloads"),
 #  if defined(ANDROID)
     NS_LITERAL_CSTRING("about:config"),
 #  endif
   };
 
   for (const nsLiteralCString& allowlistEntry : sAllowedAboutPagesWithNoCSP) {
     // please note that we perform a substring match here on purpose,
     // so we don't have to deal and parse out all the query arguments
--- a/editor/libeditor/tests/test_bug629172.html
+++ b/editor/libeditor/tests/test_bug629172.html
@@ -18,16 +18,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <textarea id="rtl-ref" style="display: none; direction: rtl">test.</textarea>
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 629172 **/
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(async function() {
+  dump("\n\n XXX TEST STARTS HERE \n\n");
   await SpecialPowers.pushPrefEnv({
     set: [["test.events.async.enabled", true]],
   });
 
   let LTRRef = document.getElementById("ltr-ref");
   let RTLRef = document.getElementById("rtl-ref");
   let ReferenceScreenshots = {};
 
--- a/toolkit/content/editMenuOverlay.js
+++ b/toolkit/content/editMenuOverlay.js
@@ -35,38 +35,64 @@ function goUpdateUndoEditMenuItems() {
 function goUpdatePasteMenuItems() {
   goUpdateCommand("cmd_paste");
 }
 
 // Inject the commandset here instead of relying on preprocessor to share this across documents.
 window.addEventListener(
   "DOMContentLoaded",
   () => {
+    // Bug 371900: Remove useless oncommand attribute once bug 371900 is fixed
+    // If you remove/update the oncommand attribute for any of the cmd_*, please
+    // also remove/update the sha512 hash in the CSP within about:downloads
     let container =
       document.querySelector("commandset") || document.documentElement;
-    container.appendChild(
-      MozXULElement.parseXULToFragment(`
-    <commandset id="editMenuCommands">
-      <commandset id="editMenuCommandSetAll" commandupdater="true" events="focus,select"
-                  oncommandupdate="goUpdateGlobalEditMenuItems()"/>
-      <commandset id="editMenuCommandSetUndo" commandupdater="true" events="undo"
-                  oncommandupdate="goUpdateUndoEditMenuItems()"/>
-      <commandset id="editMenuCommandSetPaste" commandupdater="true" events="clipboard"
-                  oncommandupdate="goUpdatePasteMenuItems()"/>
-      <command id="cmd_undo" oncommand="goDoCommand('cmd_undo')"/>
-      <command id="cmd_redo" oncommand="goDoCommand('cmd_redo')"/>
-      <command id="cmd_cut" oncommand="goDoCommand('cmd_cut')"/>
-      <command id="cmd_copy" oncommand="goDoCommand('cmd_copy')"/>
-      <command id="cmd_paste" oncommand="goDoCommand('cmd_paste')"/>
-      <command id="cmd_delete" oncommand="goDoCommand('cmd_delete')"/>
-      <command id="cmd_selectAll" oncommand="goDoCommand('cmd_selectAll')"/>
-      <command id="cmd_switchTextDirection" oncommand="goDoCommand('cmd_switchTextDirection');"/>
-    </commandset>
-  `)
+    let fragment = MozXULElement.parseXULToFragment(`
+      <commandset id="editMenuCommands">
+        <commandset id="editMenuCommandSetAll" commandupdater="true" events="focus,select" />
+        <commandset id="editMenuCommandSetUndo" commandupdater="true" events="undo" />
+        <commandset id="editMenuCommandSetPaste" commandupdater="true" events="clipboard" />
+        <command id="cmd_undo" oncommand=";" />
+        <command id="cmd_redo" oncommand=";" />
+        <command id="cmd_cut" oncommand=";" />
+        <command id="cmd_copy" oncommand=";" />
+        <command id="cmd_paste" oncommand=";" />
+        <command id="cmd_delete" oncommand=";" />
+        <command id="cmd_selectAll" oncommand=";" />
+        <command id="cmd_switchTextDirection" oncommand=";" />
+      </commandset>
+    `);
+
+    let editMenuCommandSetAll = fragment.querySelector(
+      "#editMenuCommandSetAll"
     );
+    editMenuCommandSetAll.addEventListener("commandupdate", function() {
+      goUpdateGlobalEditMenuItems();
+    });
+
+    let editMenuCommandSetUndo = fragment.querySelector(
+      "#editMenuCommandSetUndo"
+    );
+    editMenuCommandSetUndo.addEventListener("commandupdate", function() {
+      goUpdateUndoEditMenuItems();
+    });
+
+    let editMenuCommandSetPaste = fragment.querySelector(
+      "#editMenuCommandSetPaste"
+    );
+    editMenuCommandSetPaste.addEventListener("commandupdate", function() {
+      goUpdatePasteMenuItems();
+    });
+
+    fragment.firstElementChild.addEventListener("command", event => {
+      let commandID = event.target.id;
+      goDoCommand(commandID);
+    });
+
+    container.appendChild(fragment);
   },
   { once: true }
 );
 
 // Support context menus on html textareas in the parent process:
 window.addEventListener("contextmenu", e => {
   const HTML_NS = "http://www.w3.org/1999/xhtml";
   // Note that there's not a risk of e.target being XBL anonymous content for <textbox> (which manages