diff options
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_cors_mozextension.js')
-rw-r--r-- | toolkit/components/extensions/test/xpcshell/test_ext_cors_mozextension.js | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_cors_mozextension.js b/toolkit/components/extensions/test/xpcshell/test_ext_cors_mozextension.js new file mode 100644 index 0000000000..fc50388c77 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_cors_mozextension.js @@ -0,0 +1,220 @@ +"use strict"; + +const server = createHttpServer({ + hosts: ["example.com", "x.example.com"], +}); +server.registerPathHandler("/dummy", (req, res) => { + res.write("dummy"); +}); +server.registerPathHandler("/redir", (req, res) => { + res.setStatusLine(req.httpVersion, 302, "Found"); + res.setHeader("Access-Control-Allow-Origin", "http://example.com"); + res.setHeader("Access-Control-Allow-Credentials", "true"); + res.setHeader("Location", new URLSearchParams(req.queryString).get("url")); +}); + +add_task(async function load_moz_extension_with_and_without_cors() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + web_accessible_resources: ["ok.js"], + }, + files: { + "ok.js": "window.status = 'loaded';", + "deny.js": "window.status = 'unexpected load'", + }, + }); + await extension.startup(); + const EXT_BASE_URL = `moz-extension://${extension.uuid}`; + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://example.com/dummy" + ); + await contentPage.spawn([EXT_BASE_URL], async EXT_BASE_URL => { + const { document, window } = this.content; + async function checkScriptLoad({ setupScript, expectLoad, description }) { + const scriptElem = document.createElement("script"); + setupScript(scriptElem); + return new Promise(resolve => { + window.status = "initial"; + scriptElem.onload = () => { + Assert.equal(window.status, "loaded", "Script executed upon load"); + Assert.ok(expectLoad, `Script loaded - ${description}`); + resolve(); + }; + scriptElem.onerror = () => { + Assert.equal(window.status, "initial", "not executed upon error"); + Assert.ok(!expectLoad, `Script not loaded - ${description}`); + resolve(); + }; + document.head.append(scriptElem); + }); + } + + function sameOriginRedirectUrl(url) { + return `http://example.com/redir?url=` + encodeURIComponent(url); + } + function crossOriginRedirectUrl(url) { + return `http://x.example.com/redir?url=` + encodeURIComponent(url); + } + + // Direct load of web-accessible extension script. + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = `${EXT_BASE_URL}/ok.js`; + }, + expectLoad: true, + description: "web-accessible script, plain load", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = `${EXT_BASE_URL}/ok.js`; + scriptElem.crossOrigin = "anonymous"; + }, + expectLoad: true, + description: "web-accessible script, cors", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = `${EXT_BASE_URL}/ok.js`; + scriptElem.crossOrigin = "use-credentials"; + }, + expectLoad: true, + description: "web-accessible script, cors+credentials", + }); + + // Load of web-accessible extension scripts, after same-origin redirect. + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = sameOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + }, + expectLoad: true, + description: "same-origin redirect to web-accessible script, plain load", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = sameOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + scriptElem.crossOrigin = "anonymous"; + }, + expectLoad: true, + description: "same-origin redirect to web-accessible script, cors", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = sameOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + scriptElem.crossOrigin = "use-credentials"; + }, + expectLoad: true, + description: + "same-origin redirect to web-accessible script, cors+credentials", + }); + + // Load of web-accessible extension scripts, after cross-origin redirect. + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = crossOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + }, + expectLoad: true, + description: "cross-origin redirect to web-accessible script, plain load", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = crossOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + scriptElem.crossOrigin = "anonymous"; + }, + expectLoad: true, + description: "cross-origin redirect to web-accessible script, cors", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = crossOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + scriptElem.crossOrigin = "use-credentials"; + }, + expectLoad: true, + description: + "cross-origin redirect to web-accessible script, cors+credentials", + }); + + // Various loads of non-web-accessible extension script. + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = `${EXT_BASE_URL}/deny.js`; + }, + expectLoad: false, + description: "non-accessible script, plain load", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = `${EXT_BASE_URL}/deny.js`; + scriptElem.crossOrigin = "anonymous"; + }, + expectLoad: false, + description: "non-accessible script, cors", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = sameOriginRedirectUrl(`${EXT_BASE_URL}/deny.js`); + scriptElem.crossOrigin = "anonymous"; + }, + expectLoad: false, + description: "same-origin redirect to non-accessible script, cors", + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = crossOriginRedirectUrl(`${EXT_BASE_URL}/deny.js`); + scriptElem.crossOrigin = "anonymous"; + }, + expectLoad: false, + description: "cross-origin redirect to non-accessible script, cors", + }); + + // Sub-resource integrity usually requires CORS. Verify that web-accessible + // extension resources are still subjected to SRI. + const sriHashOkJs = // SRI hash for "window.status = 'loaded';" (=ok.js). + "sha384-EAofaAZpgy6JshegITJJHeE3ROzn9ngGw1GAuuzjSJV1c/YS9PLvHMt9oh4RovrI"; + + async function testSRI({ integrityMatches }) { + const integrity = integrityMatches ? sriHashOkJs : "sha384-bad-sri-hash"; + const sriDescription = integrityMatches + ? "web-accessible script, good sri, " + : "web-accessible script, sri not matching, "; + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = `${EXT_BASE_URL}/ok.js`; + scriptElem.integrity = integrity; + }, + expectLoad: integrityMatches, + description: `${sriDescription} no cors, plain load`, + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = `${EXT_BASE_URL}/ok.js`; + scriptElem.crossOrigin = "anonymous"; + scriptElem.integrity = integrity; + }, + expectLoad: integrityMatches, + description: `${sriDescription} cors, plain load`, + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = sameOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + scriptElem.crossOrigin = "anonymous"; + scriptElem.integrity = integrity; + }, + expectLoad: integrityMatches, + description: `${sriDescription} cors, same-origin redirect`, + }); + await checkScriptLoad({ + setupScript(scriptElem) { + scriptElem.src = crossOriginRedirectUrl(`${EXT_BASE_URL}/ok.js`); + scriptElem.crossOrigin = "anonymous"; + scriptElem.integrity = integrity; + }, + expectLoad: integrityMatches, + description: `${sriDescription} cors, cross-origin redirect`, + }); + } + await testSRI({ integrityMatches: true }); + await testSRI({ integrityMatches: false }); + }); + await contentPage.close(); + await extension.unload(); +}); |