tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_csp_policy_container_migration.js (3852B)


      1 "use strict";
      2 
      3 // We use data URL because CSP_ShouldURIInheritCSP requires the URL to be
      4 // about:blank, abour:srcdoc, or be a blob, filesystem, data, or javascript scheme.
      5 const URL = `data:text/html,<html><body> <span id="change_me">Original</span> <script> document.getElementById("change_me").textContent = "Modified"; </script></body></html>`;
      6 
      7 const CSP_JSON = `{"csp-policies":[{"default-src":["'self'"],"report-only":false}]}`;
      8 
      9 const CSP_SERIALIZED =
     10  "CdntGuXUQAS/4CfOuSPZrAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAKmh0dHBzOi8vYi5jb21wYXNzLWRlbW8uY29tL2NzcF9wbGF5Z3JvdW5kLwAAAAAAAAAFAAAACAAAABIAAAAI/////wAAAAj/////AAAACAAAABIAAAAaAAAAEAAAABoAAAAQAAAAGgAAABAAAAAqAAAAAAAAACr/////AAAAAP////8AAAAa/////wAAABr/////AQAAAAAAAAAAADh7IjEiOnsiMCI6Imh0dHBzOi8vYi5jb21wYXNzLWRlbW8uY29tL2NzcF9wbGF5Z3JvdW5kLyJ9fQAAAAEAAAASAGQAZQBmAGEAdQBsAHQALQBzAHIAYwAgACcAcwBlAGwAZgAnAAAA";
     11 
     12 // Same CSP, but serialized as a policy container
     13 const POLICY_CONTAINER_SERIALIZED =
     14  "ydqGXsPXSqGicQ9XHwE8MAAAAAAAAAAAwAAAAAAAAEYAAAABAQnZ7Rrl1EAEv+Anzrkj2awdYyAIbJdIrqUcFuLaoPT2Ad6UctCANBHTk5kAEEug/UCSBzpUbXhPMJE6uHGBMgjGAAAAAv////8AAAG7AQAAACpodHRwczovL2IuY29tcGFzcy1kZW1vLmNvbS9jc3BfcGxheWdyb3VuZC8AAAAAAAAABQAAAAgAAAASAAAACP////8AAAAI/////wAAAAgAAAASAAAAGgAAABAAAAAaAAAAEAAAABoAAAAQAAAAKgAAAAAAAAAq/////wAAAAD/////AAAAGv////8AAAAa/////wEAAAAAAAAAAAA4eyIxIjp7IjAiOiJodHRwczovL2IuY29tcGFzcy1kZW1vLmNvbS9jc3BfcGxheWdyb3VuZC8ifX0AAAABAAAAEgBkAGUAZgBhAHUAbAB0AC0AcwByAGMAIAAnAHMAZQBsAGYAJwAAAAFIEv8yG/9CO5f8QKVpba0iSBL/Mhv/QjuX/EClaW2tIgAAAAEAAA==";
     15 
     16 /*
     17 * Tests that whether we pass a serialized CSP or policy container
     18 * to the session store, it gets deserialized correctly and restored
     19 * in the tab state.
     20 */
     21 add_task(async function () {
     22  // Sanity check: ensure that the CSP JSON and serialized CSP match
     23  is(
     24    E10SUtils.deserializeCSP(CSP_SERIALIZED).toJSON(),
     25    CSP_JSON,
     26    "CSP should deserialize correctly from serialized CSP string"
     27  );
     28 
     29  // Sanity check
     30  await checkScriptRunsWithoutCSP({
     31    url: URL,
     32  });
     33 
     34  // Firefox 142 and earlier writes entry.csp;
     35  await checkCSPWithSessionHistoryEntry({ url: URL, csp: CSP_SERIALIZED });
     36  // Firefox 143 and later writes to policyContainer (bug 1974070).
     37  await checkCSPWithSessionHistoryEntry({
     38    url: URL,
     39    policyContainer: POLICY_CONTAINER_SERIALIZED,
     40  });
     41 });
     42 
     43 async function checkCSPWithSessionHistoryEntry(entry) {
     44  // Create session history entry with `csp` property
     45  const tab = await createTabWithSessionHistoryEntry(entry);
     46 
     47  // check that the inline script is blocked
     48  is(await didScriptRun(tab.linkedBrowser), false);
     49 
     50  is(
     51    tab.linkedBrowser.policyContainer.csp.toJSON(),
     52    CSP_JSON,
     53    "CSP should be restored correctly from session history entry"
     54  );
     55 
     56  // cleanup
     57  BrowserTestUtils.removeTab(tab);
     58 }
     59 
     60 async function checkScriptRunsWithoutCSP(entry) {
     61  // Create session history entry without `csp` property
     62  const tab = await createTabWithSessionHistoryEntry(entry);
     63 
     64  // check that the inline script runs
     65  is(await didScriptRun(tab.linkedBrowser), true);
     66 
     67  is(
     68    tab.linkedBrowser.policyContainer.csp.toJSON(),
     69    `{"csp-policies":[]}`,
     70    "CSP should not be restored when not present in session history entry"
     71  );
     72 
     73  // cleanup
     74  BrowserTestUtils.removeTab(tab);
     75 }
     76 
     77 async function createTabWithSessionHistoryEntry(entry) {
     78  const state = {
     79    entries: [entry],
     80  };
     81 
     82  // create a new tab
     83  const tab = BrowserTestUtils.addTab(gBrowser);
     84 
     85  // set the tab's state
     86  ss.setTabState(tab, JSON.stringify(state));
     87 
     88  // wait for the tab to be loaded
     89  await promiseBrowserLoaded(tab.linkedBrowser);
     90 
     91  return tab;
     92 }
     93 
     94 function didScriptRun(browser) {
     95  return SpecialPowers.spawn(browser, [], function () {
     96    return (
     97      content.document.getElementById("change_me").innerText === "Modified"
     98    );
     99  });
    100 }