Bug 1371586 - Improve security of media query links. r=pbro, a=lizzard
☠☠ backed out by af94af58d1f3 ☠ ☠
authorTim Nguyen <ntim.bugs@gmail.com>
Mon, 26 Jun 2017 19:23:49 -0400
changeset 603638 3433056bbedb6eb9995c9052df0d83f3d604b3d8
parent 603637 4190681892060e7cabb1d104ee744688778382f2
child 603639 aea0295302b43dc8bd1b444856f3e3e164c07a1d
push id66829
push userbmo:m_kato@ga2.so-net.ne.jp
push dateTue, 04 Jul 2017 09:55:15 +0000
reviewerspbro, lizzard
bugs1371586
milestone55.0
Bug 1371586 - Improve security of media query links. r=pbro, a=lizzard
devtools/client/styleeditor/StyleEditorUI.jsm
--- a/devtools/client/styleeditor/StyleEditorUI.jsm
+++ b/devtools/client/styleeditor/StyleEditorUI.jsm
@@ -890,29 +890,24 @@ StyleEditorUI.prototype = {
         inSource = true;
 
         let div = this._panelDoc.createElement("div");
         div.className = "media-rule-label";
         div.addEventListener("click",
                              this._jumpToLocation.bind(this, location));
 
         let cond = this._panelDoc.createElement("div");
-        cond.textContent = rule.conditionText;
         cond.className = "media-rule-condition";
         if (!rule.matches) {
           cond.classList.add("media-condition-unmatched");
         }
         if (this._target.tab.tagName == "tab") {
-          const minMaxPattern = /(min\-|max\-)(width|height):\s\d+(px)/ig;
-          const replacement =
-                "<a href='#' class='media-responsive-mode-toggle'>$&</a>";
-
-          cond.innerHTML = cond.textContent.replace(minMaxPattern, replacement);
-          cond.addEventListener("click",
-                                this._onMediaConditionClick.bind(this));
+          this._setConditionContents(cond, rule.conditionText);
+        } else {
+          cond.textContent = rule.conditionText;
         }
         div.appendChild(cond);
 
         let link = this._panelDoc.createElement("div");
         link.className = "media-rule-line theme-link";
         if (location.line != -1) {
           link.textContent = ":" + location.line;
         }
@@ -923,26 +918,56 @@ StyleEditorUI.prototype = {
 
       sidebar.hidden = !showSidebar || !inSource;
 
       this.emit("media-list-changed", editor);
     }.bind(this)).then(null, e => console.error(e));
   },
 
   /**
-    * Called when a media condition is clicked
-    * If a responsive mode link is clicked, it will launch it.
-    *
-    * @param {object} e
-    *        Event object
-    */
+   * Used to safely inject media query links
+   *
+   * @param {HTMLElement} element
+   *        The element corresponding to the media sidebar condition
+   * @param {String} text
+   *        The raw condition text to parse
+   */
+  _setConditionContents(element, text) {
+    const minMaxPattern = /(min\-|max\-)(width|height):\s\d+(px)/ig;
+
+    let match = minMaxPattern.exec(text);
+    let lastParsed = 0;
+    while (match && match.index != minMaxPattern.lastIndex) {
+      let matchEnd = match.index + match[0].length;
+      let node = this._panelDoc.createTextNode(text.substring(lastParsed, match.index));
+      element.appendChild(node);
+
+      let link = this._panelDoc.createElement("a");
+      link.href = "#";
+      link.className = "media-responsive-mode-toggle";
+      link.textContent = text.substring(match.index, matchEnd);
+      link.addEventListener("click", this._onMediaConditionClick.bind(this));
+      element.appendChild(link);
+
+      match = minMaxPattern.exec(text);
+      lastParsed = matchEnd;
+    }
+
+    let node = this._panelDoc.createTextNode(text.substring(lastParsed, text.length));
+    element.appendChild(node);
+  },
+
+  /**
+   * Called when a media condition is clicked
+   * If a responsive mode link is clicked, it will launch it.
+   *
+   * @param {object} e
+   *        Event object
+   */
   _onMediaConditionClick: function (e) {
-    if (!e.target.matches(".media-responsive-mode-toggle")) {
-      return;
-    }
     let conditionText = e.target.textContent;
     let isWidthCond = conditionText.toLowerCase().indexOf("width") > -1;
     let mediaVal = parseInt(/\d+/.exec(conditionText), 10);
 
     let options = isWidthCond ? {width: mediaVal} : {height: mediaVal};
     this._launchResponsiveMode(options);
     e.preventDefault();
     e.stopPropagation();