diff options
Diffstat (limited to 'dom/security/test/csp/browser_test_web_manifest.js')
-rw-r--r-- | dom/security/test/csp/browser_test_web_manifest.js | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/dom/security/test/csp/browser_test_web_manifest.js b/dom/security/test/csp/browser_test_web_manifest.js new file mode 100644 index 0000000000..02736f3c08 --- /dev/null +++ b/dom/security/test/csp/browser_test_web_manifest.js @@ -0,0 +1,239 @@ +/* + * Description of the tests: + * These tests check for conformance to the CSP spec as they relate to Web Manifests. + * + * In particular, the tests check that default-src and manifest-src directives are + * are respected by the ManifestObtainer. + */ +/*globals Cu, is, ok*/ +"use strict"; +const { ManifestObtainer } = ChromeUtils.import( + "resource://gre/modules/ManifestObtainer.jsm" +); +const path = "/tests/dom/security/test/csp/"; +const testFile = `${path}file_web_manifest.html`; +const remoteFile = `${path}file_web_manifest_remote.html`; +const httpsManifest = `${path}file_web_manifest_https.html`; +const server = `${path}file_testserver.sjs`; +const defaultURL = new URL(`http://example.org${server}`); +const secureURL = new URL(`https://example.com:443${server}`); + +// Enable web manifest processing. +Services.prefs.setBoolPref("dom.manifest.enabled", true); + +const tests = [ + // CSP block everything, so trying to load a manifest + // will result in a policy violation. + { + expected: "default-src 'none' blocks fetching manifest.", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", testFile); + url.searchParams.append("csp", "default-src 'none'"); + return url.href; + }, + run(topic) { + is(topic, "csp-on-violate-policy", this.expected); + }, + }, + // CSP allows fetching only from mochi.test:8888, + // so trying to load a manifest from same origin + // triggers a CSP violation. + { + expected: "default-src mochi.test:8888 blocks manifest fetching.", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", testFile); + url.searchParams.append("csp", "default-src mochi.test:8888"); + return url.href; + }, + run(topic) { + is(topic, "csp-on-violate-policy", this.expected); + }, + }, + // CSP restricts fetching to 'self', so allowing the manifest + // to load. The name of the manifest is then checked. + { + expected: "CSP default-src 'self' allows fetch of manifest.", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", testFile); + url.searchParams.append("csp", "default-src 'self'"); + return url.href; + }, + run(manifest) { + is(manifest.name, "loaded", this.expected); + }, + }, + // CSP only allows fetching from mochi.test:8888 and remoteFile + // requests a manifest from that origin, so manifest should load. + { + expected: "CSP default-src mochi.test:8888 allows fetching manifest.", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", remoteFile); + url.searchParams.append("csp", "default-src http://mochi.test:8888"); + return url.href; + }, + run(manifest) { + is(manifest.name, "loaded", this.expected); + }, + }, + // default-src blocks everything, so any attempt to + // fetch a manifest from another origin will trigger a + // policy violation. + { + expected: "default-src 'none' blocks mochi.test:8888", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", remoteFile); + url.searchParams.append("csp", "default-src 'none'"); + return url.href; + }, + run(topic) { + is(topic, "csp-on-violate-policy", this.expected); + }, + }, + // CSP allows fetching from self, so manifest should load. + { + expected: "CSP manifest-src allows self", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", testFile); + url.searchParams.append("csp", "manifest-src 'self'"); + return url.href; + }, + run(manifest) { + is(manifest.name, "loaded", this.expected); + }, + }, + // CSP allows fetching from example.org, so manifest should load. + { + expected: "CSP manifest-src allows http://example.org", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", testFile); + url.searchParams.append("csp", "manifest-src http://example.org"); + return url.href; + }, + run(manifest) { + is(manifest.name, "loaded", this.expected); + }, + }, + { + expected: "CSP manifest-src allows mochi.test:8888", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", remoteFile); + url.searchParams.append("cors", "*"); + url.searchParams.append( + "csp", + "default-src *; manifest-src http://mochi.test:8888" + ); + return url.href; + }, + run(manifest) { + is(manifest.name, "loaded", this.expected); + }, + }, + // CSP restricts fetching to mochi.test:8888, but the test + // file is at example.org. Hence, a policy violation is + // triggered. + { + expected: "CSP blocks manifest fetching from example.org.", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", testFile); + url.searchParams.append("csp", "manifest-src mochi.test:8888"); + return url.href; + }, + run(topic) { + is(topic, "csp-on-violate-policy", this.expected); + }, + }, + // CSP is set to only allow manifest to be loaded from same origin, + // but the remote file attempts to load from a different origin. Thus + // this causes a CSP violation. + { + expected: "CSP manifest-src 'self' blocks cross-origin fetch.", + get tabURL() { + const url = new URL(defaultURL); + url.searchParams.append("file", remoteFile); + url.searchParams.append("csp", "manifest-src 'self'"); + return url.href; + }, + run(topic) { + is(topic, "csp-on-violate-policy", this.expected); + }, + }, + // CSP allows fetching over TLS from example.org, so manifest should load. + { + expected: "CSP manifest-src allows example.com over TLS", + get tabURL() { + // secureURL loads https://example.com:443 + // and gets manifest from https://example.org:443 + const url = new URL(secureURL); + url.searchParams.append("file", httpsManifest); + url.searchParams.append("cors", "*"); + url.searchParams.append("csp", "manifest-src https://example.com:443"); + return url.href; + }, + run(manifest) { + is(manifest.name, "loaded", this.expected); + }, + }, +]; + +//jscs:disable +add_task(async function() { + //jscs:enable + const testPromises = tests.map(test => { + const tabOptions = { + gBrowser, + url: test.tabURL, + skipAnimation: true, + }; + return BrowserTestUtils.withNewTab(tabOptions, browser => + testObtainingManifest(browser, test) + ); + }); + await Promise.all(testPromises); +}); + +async function testObtainingManifest(aBrowser, aTest) { + const waitForObserver = waitForNetObserver(aBrowser, aTest); + // Expect an exception (from promise rejection) if there a content policy + // that is violated. + try { + const manifest = await ManifestObtainer.browserObtainManifest(aBrowser); + aTest.run(manifest); + } catch (e) { + const wasBlocked = e.message.includes( + "NetworkError when attempting to fetch resource" + ); + ok( + wasBlocked, + `Expected promise rejection obtaining ${aTest.tabURL}: ${e.message}` + ); + } finally { + await waitForObserver; + } +} + +// Helper object used to observe policy violations when blocking is expected. +function waitForNetObserver(aBrowser, aTest) { + // We don't need to wait for violation, so just resolve + if (!aTest.expected.includes("block")) { + return Promise.resolve(); + } + + return ContentTask.spawn(aBrowser, [], () => { + return new Promise(resolve => { + function observe(subject, topic) { + Services.obs.removeObserver(observe, "csp-on-violate-policy"); + resolve(); + } + Services.obs.addObserver(observe, "csp-on-violate-policy"); + }); + }).then(() => aTest.run("csp-on-violate-policy")); +} |