"use strict"; Services.prefs.setBoolPref("extensions.manifestV3.enabled", true); const server = createHttpServer({ hosts: ["example.com"] }); server.registerPathHandler("/dummy", (request, response) => { response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "text/html", false); response.write(""); }); server.registerPathHandler("/worker.js", (request, response) => { response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "application/javascript", false); response.write("let x = true;"); }); const baseCSP = []; // Keep in sync with extensions.webextensions.base-content-security-policy baseCSP[2] = { "script-src": [ "'unsafe-eval'", "'wasm-unsafe-eval'", "'unsafe-inline'", "blob:", "filesystem:", "http://localhost:*", "http://127.0.0.1:*", "https://*", "moz-extension:", "'self'", ], }; // Keep in sync with extensions.webextensions.base-content-security-policy.v3 baseCSP[3] = { "script-src": ["'self'", "'wasm-unsafe-eval'"], }; /** * @typedef TestPolicyExpects * @type {object} * @param {boolean} workerEvalAllowed * @param {boolean} workerImportScriptsAllowed * @param {boolean} workerWasmAllowed */ /** * Tests that content security policies for an add-on are actually applied to * * documents that belong to it. This tests both the base policies and add-on * specific policies, and ensures that the parsed policies applied to the * document's principal match what was specified in the policy string. * * @param {object} options * @param {number} [options.manifest_version] * @param {object} [options.customCSP] * @param {TestPolicyExpects} options.expects */ async function testPolicy({ manifest_version = 2, customCSP = null, expects = {}, }) { info( `Enter tests for extension CSP with ${JSON.stringify({ manifest_version, customCSP, })}` ); let baseURL; let addonCSP = { "script-src": ["'self'"], }; if (manifest_version < 3) { addonCSP["script-src"].push("'wasm-unsafe-eval'"); } let content_security_policy = null; if (customCSP) { for (let key of Object.keys(customCSP)) { addonCSP[key] = customCSP[key].split(/\s+/); } content_security_policy = Object.keys(customCSP) .map(key => `${key} ${customCSP[key]}`) .join("; "); } function checkSource(name, policy, expected) { // fallback to script-src when comparing worker-src if policy does not include worker-src let policySrc = name != "worker-src" || policy[name] ? policy[name] : policy["script-src"]; equal( JSON.stringify(policySrc.sort()), JSON.stringify(expected[name].sort()), `Expected value for ${name}` ); } function checkCSP(csp, location) { let policies = csp["csp-policies"]; info(`Base policy for ${location}`); let base = baseCSP[manifest_version]; equal(policies[0]["report-only"], false, "Policy is not report-only"); for (let key in base) { checkSource(key, policies[0], base); } info(`Add-on policy for ${location}`); equal(policies[1]["report-only"], false, "Policy is not report-only"); for (let key in addonCSP) { checkSource(key, policies[1], addonCSP); } } function background() { browser.test.sendMessage( "base-url", browser.runtime.getURL("").replace(/\/$/, "") ); browser.test.sendMessage("background-csp", window.getCsp()); } function tabScript() { browser.test.sendMessage("tab-csp", window.getCsp()); const worker = new Worker("worker.js"); worker.onmessage = event => { browser.test.sendMessage("worker-csp", event.data); }; worker.postMessage({}); } function testWorker(port) { this.onmessage = () => { let importScriptsAllowed; let evalAllowed; let wasmAllowed; try { eval("let y = true;"); // eslint-disable-line no-eval evalAllowed = true; } catch (e) { evalAllowed = false; } try { new WebAssembly.Module( new Uint8Array([0, 0x61, 0x73, 0x6d, 0x1, 0, 0, 0]) ); wasmAllowed = true; } catch (e) { wasmAllowed = false; } try { // eslint-disable-next-line no-undef importScripts(`http://127.0.0.1:${port}/worker.js`); importScriptsAllowed = true; } catch (e) { importScriptsAllowed = false; } postMessage({ evalAllowed, importScriptsAllowed, wasmAllowed }); }; } let web_accessible_resources = ["content.html", "tab.html"]; if (manifest_version == 3) { let extension_pages = content_security_policy; content_security_policy = { extension_pages, }; let resources = web_accessible_resources; web_accessible_resources = [ { resources, matches: ["http://example.com/*"] }, ]; } let extension = ExtensionTestUtils.loadExtension({ background, files: { "tab.html": `