tor-browser

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

browser_test_web_manifest.js (7769B)


      1 /*
      2 * Description of the tests:
      3 *   These tests check for conformance to the CSP spec as they relate to Web Manifests.
      4 *
      5 *   In particular, the tests check that default-src and manifest-src directives are
      6 *   are respected by the ManifestObtainer.
      7 */
      8 /*globals Cu, is, ok*/
      9 "use strict";
     10 const { ManifestObtainer } = ChromeUtils.importESModule(
     11  "resource://gre/modules/ManifestObtainer.sys.mjs"
     12 );
     13 const path = "/tests/dom/security/test/csp/";
     14 const testFile = `${path}file_web_manifest.html`;
     15 const remoteFile = `${path}file_web_manifest_remote.html`;
     16 const httpsManifest = `${path}file_web_manifest_https.html`;
     17 const server = `${path}file_testserver.sjs`;
     18 const defaultURL = new URL(`http://example.org${server}`);
     19 const secureURL = new URL(`https://example.com:443${server}`);
     20 
     21 // Enable web manifest processing.
     22 Services.prefs.setBoolPref("dom.manifest.enabled", true);
     23 
     24 const tests = [
     25  // CSP block everything, so trying to load a manifest
     26  // will result in a policy violation.
     27  {
     28    expected: "default-src 'none' blocks fetching manifest.",
     29    get tabURL() {
     30      const url = new URL(defaultURL);
     31      url.searchParams.append("file", testFile);
     32      url.searchParams.append("csp", "default-src 'none'");
     33      return url.href;
     34    },
     35    run(topic) {
     36      is(topic, "csp-on-violate-policy", this.expected);
     37    },
     38  },
     39  // CSP allows fetching only from mochi.test:8888,
     40  // so trying to load a manifest from same origin
     41  // triggers a CSP violation.
     42  {
     43    expected: "default-src mochi.test:8888 blocks manifest fetching.",
     44    get tabURL() {
     45      const url = new URL(defaultURL);
     46      url.searchParams.append("file", testFile);
     47      url.searchParams.append("csp", "default-src mochi.test:8888");
     48      return url.href;
     49    },
     50    run(topic) {
     51      is(topic, "csp-on-violate-policy", this.expected);
     52    },
     53  },
     54  // CSP restricts fetching to 'self', so allowing the manifest
     55  // to load. The name of the manifest is then checked.
     56  {
     57    expected: "CSP default-src 'self' allows fetch of manifest.",
     58    get tabURL() {
     59      const url = new URL(defaultURL);
     60      url.searchParams.append("file", testFile);
     61      url.searchParams.append("csp", "default-src 'self'");
     62      return url.href;
     63    },
     64    run(manifest) {
     65      is(manifest.name, "loaded", this.expected);
     66    },
     67  },
     68  // CSP only allows fetching from mochi.test:8888 and remoteFile
     69  // requests a manifest from that origin, so manifest should load.
     70  {
     71    expected: "CSP default-src mochi.test:8888 allows fetching manifest.",
     72    get tabURL() {
     73      const url = new URL(defaultURL);
     74      url.searchParams.append("file", remoteFile);
     75      url.searchParams.append("csp", "default-src http://mochi.test:8888");
     76      return url.href;
     77    },
     78    run(manifest) {
     79      is(manifest.name, "loaded", this.expected);
     80    },
     81  },
     82  // default-src blocks everything, so any attempt to
     83  // fetch a manifest from another origin will trigger a
     84  // policy violation.
     85  {
     86    expected: "default-src 'none' blocks mochi.test:8888",
     87    get tabURL() {
     88      const url = new URL(defaultURL);
     89      url.searchParams.append("file", remoteFile);
     90      url.searchParams.append("csp", "default-src 'none'");
     91      return url.href;
     92    },
     93    run(topic) {
     94      is(topic, "csp-on-violate-policy", this.expected);
     95    },
     96  },
     97  // CSP allows fetching from self, so manifest should load.
     98  {
     99    expected: "CSP manifest-src allows self",
    100    get tabURL() {
    101      const url = new URL(defaultURL);
    102      url.searchParams.append("file", testFile);
    103      url.searchParams.append("csp", "manifest-src 'self'");
    104      return url.href;
    105    },
    106    run(manifest) {
    107      is(manifest.name, "loaded", this.expected);
    108    },
    109  },
    110  // CSP allows fetching from example.org, so manifest should load.
    111  {
    112    expected: "CSP manifest-src allows http://example.org",
    113    get tabURL() {
    114      const url = new URL(defaultURL);
    115      url.searchParams.append("file", testFile);
    116      url.searchParams.append("csp", "manifest-src http://example.org");
    117      return url.href;
    118    },
    119    run(manifest) {
    120      is(manifest.name, "loaded", this.expected);
    121    },
    122  },
    123  {
    124    expected: "CSP manifest-src allows mochi.test:8888",
    125    get tabURL() {
    126      const url = new URL(defaultURL);
    127      url.searchParams.append("file", remoteFile);
    128      url.searchParams.append("cors", "*");
    129      url.searchParams.append(
    130        "csp",
    131        "default-src *; manifest-src http://mochi.test:8888"
    132      );
    133      return url.href;
    134    },
    135    run(manifest) {
    136      is(manifest.name, "loaded", this.expected);
    137    },
    138  },
    139  // CSP restricts fetching to mochi.test:8888, but the test
    140  // file is at example.org. Hence, a policy violation is
    141  // triggered.
    142  {
    143    expected: "CSP blocks manifest fetching from example.org.",
    144    get tabURL() {
    145      const url = new URL(defaultURL);
    146      url.searchParams.append("file", testFile);
    147      url.searchParams.append("csp", "manifest-src mochi.test:8888");
    148      return url.href;
    149    },
    150    run(topic) {
    151      is(topic, "csp-on-violate-policy", this.expected);
    152    },
    153  },
    154  // CSP is set to only allow manifest to be loaded from same origin,
    155  // but the remote file attempts to load from a different origin. Thus
    156  // this causes a CSP violation.
    157  {
    158    expected: "CSP manifest-src 'self' blocks cross-origin fetch.",
    159    get tabURL() {
    160      const url = new URL(defaultURL);
    161      url.searchParams.append("file", remoteFile);
    162      url.searchParams.append("csp", "manifest-src 'self'");
    163      return url.href;
    164    },
    165    run(topic) {
    166      is(topic, "csp-on-violate-policy", this.expected);
    167    },
    168  },
    169  // CSP allows fetching over TLS from example.org, so manifest should load.
    170  {
    171    expected: "CSP manifest-src allows example.com over TLS",
    172    get tabURL() {
    173      // secureURL loads https://example.com:443
    174      // and gets manifest from https://example.org:443
    175      const url = new URL(secureURL);
    176      url.searchParams.append("file", httpsManifest);
    177      url.searchParams.append("cors", "*");
    178      url.searchParams.append("csp", "manifest-src https://example.com:443");
    179      return url.href;
    180    },
    181    run(manifest) {
    182      is(manifest.name, "loaded", this.expected);
    183    },
    184  },
    185 ];
    186 
    187 //jscs:disable
    188 add_task(async function () {
    189  //jscs:enable
    190  const testPromises = tests.map(test => {
    191    const tabOptions = {
    192      gBrowser,
    193      url: test.tabURL,
    194      skipAnimation: true,
    195    };
    196    return BrowserTestUtils.withNewTab(tabOptions, browser =>
    197      testObtainingManifest(browser, test)
    198    );
    199  });
    200  await Promise.all(testPromises);
    201 });
    202 
    203 async function testObtainingManifest(aBrowser, aTest) {
    204  const waitForObserver = waitForNetObserver(aBrowser, aTest);
    205  // Expect an exception (from promise rejection) if there a content policy
    206  // that is violated.
    207  try {
    208    const manifest = await ManifestObtainer.browserObtainManifest(aBrowser);
    209    aTest.run(manifest);
    210  } catch (e) {
    211    const wasBlocked = e.message.includes(
    212      "NetworkError when attempting to fetch resource"
    213    );
    214    ok(
    215      wasBlocked,
    216      `Expected promise rejection obtaining ${aTest.tabURL}: ${e.message}`
    217    );
    218  } finally {
    219    await waitForObserver;
    220  }
    221 }
    222 
    223 // Helper object used to observe policy violations when blocking is expected.
    224 function waitForNetObserver(aBrowser, aTest) {
    225  // We don't need to wait for violation, so just resolve
    226  if (!aTest.expected.includes("block")) {
    227    return Promise.resolve();
    228  }
    229 
    230  return ContentTask.spawn(aBrowser, [], () => {
    231    return new Promise(resolve => {
    232      function observe(subject, topic) {
    233        Services.obs.removeObserver(observe, "csp-on-violate-policy");
    234        resolve();
    235      }
    236      Services.obs.addObserver(observe, "csp-on-violate-policy");
    237    });
    238  }).then(() => aTest.run("csp-on-violate-policy"));
    239 }