From 7aab9ae4266d70344f7d1b2f185c760b19cb6908 Mon Sep 17 00:00:00 2001
From: hackademix
Date: Wed, 24 Jul 2019 22:48:02 +0200
Subject: Fix paste sanitization bugs and make it work on drag and drop too.
---
src/content/sanitizePaste.js | 71 ++++++++++++++++++++++++--------------------
1 file changed, 38 insertions(+), 33 deletions(-)
(limited to 'src/content')
diff --git a/src/content/sanitizePaste.js b/src/content/sanitizePaste.js
index 703f5b3..a1bcf53 100644
--- a/src/content/sanitizePaste.js
+++ b/src/content/sanitizePaste.js
@@ -1,58 +1,63 @@
'use strict';
-
-window.addEventListener("paste", e => {
- let data = e.clipboardData;
- let html = data.getData("text/html");
- let t = e.target;
- if (t.nodeType !== 1) t = t.parentElement;
-
- try {
- let node = t.cloneNode();
-
- node.innerHTML = html;
-
- if (sanitizeExtras(node)) {
- let sanitized = node.innerHTML;
- setTimeout(function() { try {
- if (sanitizeExtras(t)) {
- console.log(`[NoScript] Sanitized\n\n${html}\nto\n\n${t.innerHTML}\n`, t);
+{
+ let urlAttributes = ['href', 'to', 'from', 'by', 'values'];
+ let selector = urlAttributes.map(a => `[${a}]`).join(',');
+
+ for (let evType of ["drop", "paste"]) window.addEventListener(evType, e => {
+ let container = e.target;
+ let editing = false;
+ for (let el = container; el; el = el.parentElement) {
+ if (el.setRangeText || el.contentEditable) {
+ editing = true;
+ break;
+ }
+ }
+ if (!editing) return;
+
+ let html = container.innerHTML;
+ // we won't touch DOM elements which are already there
+ let oldNodes = new Set(container.querySelectorAll(selector + ",form"));
+ window.setTimeout(() => {
+ // we delay our custom sanitization after the browser performed the paste
+ // or drop job, rather than replacing it, in order to avoid interferences
+ // with built-in sanitization
+ try {
+ if (sanitizeExtras(container, oldNodes)) {
+ let t = e.type;
+ console.log(`[NoScript] Sanitized\n<${t}>\n${html}\n${t}>to\n<${t}>\n${container.innerHTML}\n${t}>`, container);
}
} catch(ex) {
console.log(ex);
- }}, 0);
- }
- } catch(ex) {
- console.log(ex);
- }
+ }
+ }, 0);
+ }, true);
function removeAttribute(node, name, value = node.getAttribute(name)) {
node.setAttribute(`data-noscript-removed-${name}`, value);
node.removeAttribute(name);
}
- function sanitizeExtras(el) {
+ function sanitizeExtras(container, oldNodes = []) {
let ret = false;
// remove attributes from forms
- for (let f of el.getElementsByTagName("form")) {
- for (let a of f.attributes) {
- f.removeAttribute(a.name);
- ret = true;
+ for (let f of container.getElementsByTagName("form")) {
+ if (oldNodes.has(f)) continue;
+ for (let a of [...f.attributes]) {
+ removeAttribute(f, a.name);
}
}
- let urlAttributes = ['href', 'to', 'from', 'by', 'values'];
- let selector = urlAttributes.map(a => `[${a}]`).join(',');
- for (let node of el.querySelectorAll(selector)) {
+ for (let node of container.querySelectorAll(selector)) {
+ if (oldNodes.has(node)) continue;
for (let name of urlAttributes) {
let value = node.getAttribute(name);
if (/^\W*(?:(?:javascript|data):|https?:[\s\S]+[[(<])/i.test(unescape(value))) {
- node.setAttribute(`data-noscript-removed-${name}`, value);
- node.removeAttribute(name);
+ removeAttribute(node, name, value);
ret = true;
}
}
}
return ret;
}
-}, true);
+}
--
cgit v1.2.3