summaryrefslogtreecommitdiff
path: root/src/content/sanitizePaste.js
blob: bf427559133f60c8714038ab58f6f7e30a9be816 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
'use strict';
{
  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;

    // 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 {
        let html = container.innerHTML;
        if (sanitizeExtras(container, oldNodes)) {
          let t = e.type.toUpperCase();
          console.log(`[NoScript] Sanitized\n<${t}>\n${html}\n</${t}>\nto\n<${t}>\n${container.innerHTML}\n</${t}>`, container);
        }
      } 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(container,  oldNodes = []) {
    let ret = false;

    // remove attributes from forms
    for (let f of container.getElementsByTagName("form")) {
      if (oldNodes.has(f)) continue;
      for (let a of [...f.attributes]) {
        removeAttribute(f, a.name);
      }
    }

    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))) {
          removeAttribute(node, name, value);
          ret = true;
        }
      }
    }
    return ret;
  }
}