summaryrefslogtreecommitdiffstats
path: root/dom/security/sanitizer/tests/mochitest/test_sanitizer_api.html
blob: bfa1fdf6c82acba7b34193097fa944fc363b5c8e (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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<!DOCTYPE HTML>
<title>Test sanitizer api</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
"use strict";
/* global Sanitizer */
// we're not done after "onload"
SimpleTest.waitForExplicitFinish();
(async function() {
  // Ensure Sanitizer is not exposed when the pref is false
  const isEnabled = SpecialPowers.getBoolPref("dom.security.sanitizer.enabled");
  if (!isEnabled) {
    ok(false, "This test should only be run with dom.security.sanitizer.enabled set to true");
    SimpleTest.finish();
  }

  function* possibleInputTypes(inputStr) {
    /* This generator function, given a string, yields all possible input objects
    for our sanitizer API (string, docfragment, document).
    */

    // 1) as string
    yield ({testInput: inputStr, testType: "String" });
    // 2) as DocumentFragment
    let temp = document.createElement('template');
    // asking eslint to skip this: innerHTML is safe for template elements.
    temp.innerHTML = inputStr;
    yield ({testInput: temp.content, testType: "DocumentFragment" });
    // 3) as HTMLDocument
    const parser = new DOMParser;
    yield ({testInput: parser.parseFromString(inputStr, "text/html"), testType: "Document" });
  }
  // basic interface smoke test
  ok(typeof Sanitizer === "function", "Sanitizer constructor exposed when preffed on");
  const mySanitizer = new Sanitizer();
  ok(mySanitizer, "Sanitizer constructor works");
  ok(mySanitizer.sanitize, "sanitize function exists");
  ok("setHTML" in Element.prototype, "Element.setHTML exists");

  // testing sanitizer results
  const testCases = [
    {
      testString: "<p>hello</p>",
      testExpected: "<p>hello</p>",
      sanitizerOptions: {}
    },
    {
      // script element encoded to not confuse the HTML parser and end execution here
      testString: "<p>second test</p><script>alert(1)\x3C/script>",
      testExpected: "<p>second test</p>",
      sanitizerOptions: {},
    },
    {
      // test for the elements option
      testString: "<p>hello <i>folks</i></p>",
      testExpected: "<p>hello folks</p>",
      sanitizerOptions: { elements: ["p"] },
    },
    {
      // test for the replaceWithChildrenElements option
      testString: "<p>hello <i>folks</i></p>",
      testExpected: "<p>hello folks</p>",
      sanitizerOptions: { replaceWithChildrenElements: ["i"] },
    },
    // TODO: Unknown attributes aren't supported yet.
    // {
    //   // test for the allowAttributes option
    //   testString: `<p haha="lol">hello</p>`,
    //   testExpected: `<p haha="lol">hello</p>`,
    //   sanitizerOptions: { unknownMarkup: true, attributes: ["haha"] },
    // },
    {
      // confirming the inverse
      testString: `<p haha="lol">hello</p>`,
      testExpected: `<p>hello</p>`,
      sanitizerOptions: {},
    },
    {
      // test for the removeAttributes option
      testString: `<p title="dropme">hello</p>`,
      testExpected: `<p>hello</p>`,
      sanitizerOptions: { removeAttributes: ['title'] },
    },
    {
      // confirming the inverse
      testString: `<p title="dontdropme">hello</p>`,
      testExpected: `<p title="dontdropme">hello</p>`,
      sanitizerOptions: {},
    },
    {
      // if an attribute is allowed and removed, the remove will take preference
      testString: `<p title="lol">hello</p>`,
      testExpected: `<p>hello</p>`,
      sanitizerOptions: {
        attributes: ["title"],
        removeAttributes: ["title"],
      },
    },
  ];


  const div = document.createElement("div");
  for (let test of testCases) {
    const {testString, testExpected, sanitizerOptions} = test;
    const testSanitizer = new Sanitizer(sanitizerOptions);

    for (let testInputAndType of possibleInputTypes(testString)) {
      const {testInput, testType} = testInputAndType;

      if (testType != "String") {
        // test sanitize(document/fragment)
        try {
          div.innerHTML = "";
          const docFragment = testSanitizer.sanitize(testInput);
          div.append(docFragment);
          is(div.innerHTML, testExpected, `Sanitizer.sanitize() should turn (${testType}) '${testInput}' into '${testExpected}'`);
        }
        catch (e) {
          ok(false, 'Error in sanitize() test: ' + e)
        }
      }
      else {
        // test setHTML:
        try {
          div.setHTML(testString, { sanitizer: sanitizerOptions });
          is(div.innerHTML, testExpected, `div.setHTML() should turn(${testType}) '${testInput}' into '${testExpected}'`);
        }
        catch (e) {
          ok(false, 'Error in setHTML() test: ' + e)
        }
      }
    }
  }

  SimpleTest.finish();
})();
</script>