DXR will be turned off on Tuesday, December 29th. It will redirect to Searchfox.
See the announcement on Discourse.

DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (c68fe15a81fc)

VCS Links

Line Code
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 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
<!DOCTYPE html>
<html>
<head>
  <script src="/resources/testharness.js"></script>
  <script src="/resources/testharnessreport.js"></script>
  <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script';">
</head>
<body>
<div id="container"></div>
<script id="script1">"hello world!";</script>
<script id="trigger"></script>
<script>
  var container = document.querySelector("#container");
  const policy_dict = {
    createScript: s => (s.includes("fail") ? null : s.replace("default", "count")),
    createHTML: s => s.replace(/2/g, "3"),
  };
  const policy = trustedTypes.createPolicy("policy", policy_dict);

  // Regression tests for 'Bypass via insertAdjacentText', reported at
  // https://github.com/WICG/trusted-types/issues/133

  // We are trying to assert that scripts do _not_ get executed. We
  // accomplish by having the script under examination containing a
  // postMessage, and to send a second guaranteed-to-execute postMessage
  // so there's a point in time when we're sure the first postMessage
  // must have arrived (if indeed it had been sent).
  //
  // We'll interpret the message data as follows:
  // - includes "block": error (this message should have been blocked by TT)
  // - includes "count": Count these, and later check against expect_count.
  // - includes "done": Unregister the event handler and finish the test.
  // - all else: Reject, as this is probably an error in the test.
  function checkMessage(expect_count) {
    postMessage("done", "*");
    return new Promise((resolve, reject) => {
      let count = 0;
      globalThis.addEventListener("message", function handler(e) {
        if (e.data.includes("block")) {
          reject(`'block' received (${e.data})`);
        } else if (e.data.includes("count")) {
          count = count + 1;
        } else if (e.data.includes("done")) {
          globalThis.removeEventListener("message", handler);
          if (expect_count && count != expect_count) {
            reject(
                `'done' received, but unexpected counts: expected ${expect_count} != actual ${count} (${e.data})`);
          } else {
            resolve(e.data);
          }
        } else {
          reject("unexpected message received: " + e.data);
        }
      });
    });
  }

  function checkSecurityPolicyViolationEvent(expect_count) {
    return new Promise((resolve, reject) => {
      let count = 0;
      document.addEventListener("securitypolicyviolation", e => {
        if (e.sample.includes("trigger")) {
          if (expect_count && count != expect_count) {
            reject(
                `'trigger' received, but unexpected counts: expected ${expect_count} != actual ${count}`);
          } else {
            resolve();
          }
        } else {
          count = count + 1;
        }
      });
      try {
        document.getElementById("trigger").text = "trigger fail";
      } catch(e) { }
    });
  }

  // Original report:
  promise_test(t => {
    // Setup: Create a <script> element with a <p> child.
    let s = document.createElement("script");

    // Sanity check: Element child content (<p>) doesn't count as source text.
    let p = document.createElement("p");
    p.text = "hello('world');";
    s.appendChild(p);
    container.appendChild(s);
    assert_equals(s.text, "");

    // Try to insertAdjacentText into the <script>, starting from the <p>
    p.insertAdjacentText("beforebegin",
                         "postMessage('beforebegin should be blocked', '*');");
    assert_true(s.text.includes("postMessage"));
    p.insertAdjacentText("afterend",
                         "postMessage('afterend should be blocked', '*');");
    assert_true(s.text.includes("after"));
    return checkMessage();
  }, "Regression test: Bypass via insertAdjacentText, initial comment.");

  const script_elements = {
    "script": doc => doc.createElement("script"),
    "svg:script": doc => doc.createElementNS("http://www.w3.org/2000/svg", "script"),
  };
  for (let [element, create_element] of Object.entries(script_elements)) {
    // Like the "Original Report" test case above, but avoids use of the "text"
    // accessor that <svg:script> doesn't support.
    promise_test(t => {
      let s = create_element(document);

      // Sanity check: Element child content (<p>) doesn't count as source text.
      let p = document.createElement("p");
      p.textContent = "hello('world');";
      s.appendChild(p);
      container.appendChild(s);

      // Try to insertAdjacentText into the <script>, starting from the <p>
      p.insertAdjacentText("beforebegin",
                           "postMessage('beforebegin should be blocked', '*');");
      assert_true(s.textContent.includes("postMessage"));
      p.insertAdjacentText("afterend",
                           "postMessage('afterend should be blocked', '*');");
      assert_true(s.textContent.includes("after"));
      return checkMessage();
    }, "Regression test: Bypass via insertAdjacentText, initial comment. " + element);

    // Variant: Create a <script> element and create & insert a text node. Then
    // insert it into the document container to make it live.
    promise_test(t => {
      // Setup: Create a <script> element, and insert text via a text node.
      let s = create_element(document);
      let text = document.createTextNode("postMessage('appendChild with a " +
                                         "text node should be blocked', '*');");
      s.appendChild(text);
      container.appendChild(s);
      return checkMessage();
    }, "Regression test: Bypass via appendChild into off-document script element" + element);

    // Variant: Create a <script> element and insert it into the document. Then
    // create a text node and insert it into the live <script> element.
    promise_test(t => {
      // Setup: Create a <script> element, insert it into the doc, and then create
      // and insert text via a text node.
      let s = create_element(document);
      container.appendChild(s);
      let text = document.createTextNode("postMessage('appendChild with a live " +
                                         "text node should be blocked', '*');");
      s.appendChild(text);
      return checkMessage();
    }, "Regression test: Bypass via appendChild into live script element " + element);
  }

  promise_test(t => {
    return checkSecurityPolicyViolationEvent();
  }, "Prep for subsequent tests: Clear SPV event queue.");

  promise_test(t => {
    const inserted_script = document.getElementById("script1");
    assert_throws_js(TypeError, _ => {
        inserted_script.innerHTML = "2+2";
    });

    let new_script = document.createElement("script");
    assert_throws_js(TypeError, _ => {
      new_script.innerHTML = "2+2";
      container.appendChild(new_script);
    });

    const trusted_html = policy.createHTML("2*4");
    assert_equals("" + trusted_html, "3*4");
    inserted_script.innerHTML = trusted_html;
    assert_equals(inserted_script.textContent, "3*4");

    new_script = document.createElement("script");
    new_script.innerHTML = trusted_html;
    container.appendChild(new_script);
    assert_equals(inserted_script.textContent, "3*4");

    // We expect 3 SPV events: two for the two assert_throws_js cases, and one
    // for script element, which will be rejected at the time of execution.
    return checkSecurityPolicyViolationEvent(3);
  }, "Spot tests around script + innerHTML interaction.");


  // Create default policy. Wrapped in a promise_test to ensure it runs only
  // after the other tests.
  let default_policy;
  promise_test(t => {
    default_policy = trustedTypes.createPolicy("default", policy_dict);
    return Promise.resolve();
  }, "Prep for subsequent tests: Create default policy.");

  for (let [element, create_element] of Object.entries(script_elements)) {
    promise_test(t => {
      let s = create_element(document);
      let text = document.createTextNode("postMessage('default', '*');");
      s.appendChild(text);
      container.appendChild(s);
      return Promise.all([checkMessage(1),
                            checkSecurityPolicyViolationEvent(0)]);
    }, "Test that default policy applies. " + element);

    promise_test(t => {
      let s = create_element(document);
      let text = document.createTextNode("fail");
      s.appendChild(text);
      container.appendChild(s);
      return Promise.all([checkMessage(0),
                          checkSecurityPolicyViolationEvent(1)]);
    }, "Test a failing default policy. " + element);
  }

  promise_test(t => {
    const inserted_script = document.getElementById("script1");
    inserted_script.innerHTML = "2+2";
    assert_equals(inserted_script.textContent, "3+3");

    let new_script = document.createElement("script");
    new_script.innerHTML = "2+2";
    container.appendChild(new_script);
    assert_equals(inserted_script.textContent, "3+3");

    const trusted_html = default_policy.createHTML("2*4");
    assert_equals("" + trusted_html, "3*4");
    inserted_script.innerHTML = trusted_html;
    assert_equals(inserted_script.textContent, "3*4");

    new_script = document.createElement("script");
    new_script.innerHTML = trusted_html;
    container.appendChild(new_script);
    assert_equals(inserted_script.textContent, "3*4");

    return checkSecurityPolicyViolationEvent(0);
  }, "Spot tests around script + innerHTML interaction with default policy.");
</script>
</body>
</html>