From 8ec45b6c748d5a620719978c18c9e9d7ec3a5132 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Mon, 13 Mar 2017 19:46:22 +0000 Subject: [PATCH 1/2] Adding better sanitising of strings by using textContent. Fixes #372 --- webextension/js/popup.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/webextension/js/popup.js b/webextension/js/popup.js index c108558..23a6d66 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -19,15 +19,15 @@ const P_CONTAINER_EDIT = "containerEdit"; const P_CONTAINER_DELETE = "containerDelete"; /** - * Escapes any occurances of &, ", < or > with XML entities. + * Escapes any occurances of &, ", <, > or / with XML entities. * * @param {string} str * The string to escape. * @return {string} The escaped string. */ function escapeXML(str) { - const replacements = {"&": "&", "\"": """, "'": "'", "<": "<", ">": ">"}; - return String(str).replace(/[&"''<>]/g, m => replacements[m]); + const replacements = {"&": "&", "\"": """, "'": "'", "<": "<", ">": ">", "/": "/"}; + return String(str).replace(/[&"'<>/]/g, m => replacements[m]); } /** @@ -278,7 +278,8 @@ Logic.registerPanel(P_CONTAINERS_LIST, { data-identity-color="${identity.color}"> -
${identity.name}
`; +
`; + context.querySelector(".container-name").textContent = identity.name; manage.innerHTML = ""; fragment.appendChild(tr); @@ -353,7 +354,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { fragment.appendChild(incompatEl); incompatEl.setAttribute("id", "container-info-movetabs-incompat"); - incompatEl.innerText = "Incompatible with other Experiments."; + incompatEl.textContent = "Incompatible with other Experiments."; incompatEl.classList.add("container-info-tab-row"); moveTabsEl.parentNode.insertBefore(fragment, moveTabsEl.nextSibling); @@ -377,7 +378,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { const identity = Logic.currentIdentity(); // Populating the panel: name and icon - document.getElementById("container-info-name").innerText = identity.name; + document.getElementById("container-info-name").textContent = identity.name; const icon = document.getElementById("container-info-icon"); icon.setAttribute("data-identity-icon", identity.image); @@ -392,7 +393,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { hideShowIcon.src = identity.hasHiddenTabs ? CONTAINER_UNHIDE_SRC : CONTAINER_HIDE_SRC; const hideShowLabel = document.getElementById("container-info-hideorshow-label"); - hideShowLabel.innerText = identity.hasHiddenTabs ? "Show this container" : "Hide this container"; + hideShowLabel.textContent = identity.hasHiddenTabs ? "Show this container" : "Hide this container"; // Let's remove all the previous tabs. const table = document.getElementById("container-info-table"); @@ -466,21 +467,23 @@ Logic.registerPanel(P_CONTAINERS_EDIT, { data-identity-color="${identity.color}"> -
${identity.name}
+
`; + tr.querySelector(".container-name").textContent = identity.name; + tr.querySelector(".edit-container .pop-button-image").setAttribute("title", `Edit ${identity.name} container`); + tr.querySelector(".remove-container .pop-button-image").setAttribute("title", `Edit ${identity.name} container`); + tr.addEventListener("click", e => { if (e.target.matches(".edit-container-icon") || e.target.parentNode.matches(".edit-container-icon")) { @@ -618,7 +621,7 @@ Logic.registerPanel(P_CONTAINER_DELETE, { const identity = Logic.currentIdentity(); // Populating the panel: name and icon - document.getElementById("delete-container-name").innerText = identity.name; + document.getElementById("delete-container-name").textContent = identity.name; const icon = document.getElementById("delete-container-icon"); icon.setAttribute("data-identity-icon", identity.image); From e3f0d8cc95ad3f09c21bd20bb0c91a5faeed0214 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Wed, 15 Mar 2017 06:34:31 +0000 Subject: [PATCH 2/2] Rename linter used to check for unsafe --- .eslintrc.js | 6 +++--- package.json | 2 +- webextension/js/popup.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 748b27b..d44e921 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -16,7 +16,7 @@ module.exports = { }, "plugins": [ "promise", - "unsafe-property-assignment" + "no-unescaped" ], "root": true, "rules": { @@ -29,8 +29,8 @@ module.exports = { "promise/no-promise-in-callback": "warn", "promise/no-return-wrap": "error", "promise/param-names": "error", - "unsafe-property-assignment/no-key-assignment": ["error"], - "unsafe-property-assignment/enforce-tagged-template-protection": ["error"], + "no-unescaped/no-key-assignment": "error", + "no-unescaped/enforce": "error", "eqeqeq": "error", "indent": ["error", 2], diff --git a/package.json b/package.json index d9eb4f5..33c1ab3 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,8 @@ "addons-linter": "^0.15.14", "deploy-txp": "^1.0.7", "eslint": "^3.17.1", + "eslint-plugin-no-unescaped": "^1.1.0", "eslint-plugin-promise": "^3.4.0", - "eslint-plugin-unsafe-property-assignment": "^1.0.2", "htmllint-cli": "^0.0.5", "jpm": "^1.2.2", "npm-run-all": "^4.0.0", diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 23a6d66..7ed2b50 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -555,7 +555,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { const colorRadioFieldset = document.getElementById("edit-container-panel-choose-color"); colors.forEach((containerColor) => { const templateInstance = document.createElement("span"); - // eslint-disable-next-line unsafe-property-assignment/enforce-tagged-template-protection + // eslint-disable-next-line no-unescaped/enforce templateInstance.innerHTML = colorRadioTemplate(containerColor); colorRadioFieldset.appendChild(templateInstance); }); @@ -568,7 +568,7 @@ Logic.registerPanel(P_CONTAINER_EDIT, { const iconRadioFieldset = document.getElementById("edit-container-panel-choose-icon"); icons.forEach((containerIcon) => { const templateInstance = document.createElement("span"); - // eslint-disable-next-line unsafe-property-assignment/enforce-tagged-template-protection + // eslint-disable-next-line no-unescaped/enforce templateInstance.innerHTML = iconRadioTemplate(containerIcon); iconRadioFieldset.appendChild(templateInstance); });