From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../test_ext_contentscript_module_import.js | 277 +++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 toolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js') diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js new file mode 100644 index 0000000000..3e4e5dd983 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js @@ -0,0 +1,277 @@ +"use strict"; + +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("/script.js", (request, response) => { + ok(false, "Unexpected request to /script.js"); +}); + +/* eslint-disable no-eval, no-implied-eval */ + +const MODULE1 = ` + import {foo} from "./module2.js"; + export let bar = foo; + + let count = 0; + + export function counter () { return count++; } +`; + +const MODULE2 = `export let foo = 2;`; + +add_task(async function test_disallowed_import() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://example.com/dummy"], + js: ["main.js"], + }, + ], + }, + + files: { + "main.js": async function () { + let disallowedURLs = [ + "data:text/javascript,void 0", + "javascript:void 0", + "http://example.com/script.js", + URL.createObjectURL( + new Blob(["void 0", { type: "text/javascript" }]) + ), + ]; + + for (let url of disallowedURLs) { + await browser.test.assertRejects( + import(url), + /error loading dynamically imported module/, + `should reject import("${url}")` + ); + } + + browser.test.sendMessage("done"); + }, + }, + }); + + await extension.startup(); + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://example.com/dummy" + ); + await extension.awaitMessage("done"); + await extension.unload(); + await contentPage.close(); +}); + +add_task(async function test_normal_import() { + Services.prefs.setBoolPref("extensions.content_web_accessible.enabled", true); + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://example.com/dummy"], + js: ["main.js"], + }, + ], + }, + + files: { + "main.js": async function () { + /* global exportFunction */ + const url = browser.runtime.getURL("module1.js"); + + await browser.test.assertRejects( + import(url), + /error loading dynamically imported module/, + "Cannot import script that is not web-accessible from page context" + ); + + await browser.test.assertRejects( + window.eval(`import("${url}")`), + /error loading dynamically imported module/, + "Cannot import script that is not web-accessible from page context" + ); + + let promise = new Promise((resolve, reject) => { + exportFunction(resolve, window, { defineAs: "resolve" }); + exportFunction(reject, window, { defineAs: "reject" }); + }); + + window.setTimeout(`import("${url}").then(resolve, reject)`, 0); + + await browser.test.assertRejects( + promise, + /error loading dynamically imported module/, + "Cannot import script that is not web-accessible from page context" + ); + + browser.test.sendMessage("done"); + }, + "module1.js": MODULE1, + "module2.js": MODULE2, + }, + }); + + await extension.startup(); + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://example.com/dummy" + ); + + await extension.awaitMessage("done"); + + // Web page can not import non-web-accessible files. + await contentPage.spawn([extension.uuid], async uuid => { + let files = ["main.js", "module1.js", "module2.js"]; + + for (let file of files) { + let url = `moz-extension://${uuid}/${file}`; + await Assert.rejects( + content.eval(`import("${url}")`), + /error loading dynamically imported module/, + "Cannot import script that is not web-accessible" + ); + } + }); + + await extension.unload(); + await contentPage.close(); +}); + +add_task(async function test_import_web_accessible() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://example.com/dummy"], + js: ["main.js"], + }, + ], + web_accessible_resources: ["module1.js", "module2.js"], + }, + + files: { + "main.js": async function () { + let mod = await import(browser.runtime.getURL("module1.js")); + browser.test.assertEq(mod.bar, 2); + browser.test.assertEq(mod.counter(), 0); + browser.test.sendMessage("done"); + }, + "module1.js": MODULE1, + "module2.js": MODULE2, + }, + }); + + await extension.startup(); + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://example.com/dummy" + ); + await extension.awaitMessage("done"); + + // Web page can import web-accessible files, + // even after WebExtension imported the same files. + await contentPage.spawn([extension.uuid], async uuid => { + let base = `moz-extension://${uuid}`; + + await Assert.rejects( + content.eval(`import("${base}/main.js")`), + /error loading dynamically imported module/, + "Cannot import script that is not web-accessible" + ); + + let promise = content.eval(`import("${base}/module1.js")`); + let mod = (await promise.wrappedJSObject).wrappedJSObject; + Assert.equal(mod.bar, 2, "exported value should match"); + Assert.equal(mod.counter(), 0, "Counter should be fresh"); + Assert.equal(mod.counter(), 1, "Counter should be fresh"); + + promise = content.eval(`import("${base}/module2.js")`); + mod = (await promise.wrappedJSObject).wrappedJSObject; + Assert.equal(mod.foo, 2, "exported value should match"); + }); + + await extension.unload(); + await contentPage.close(); +}); + +add_task(async function test_import_web_accessible_after_page() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://example.com/dummy"], + js: ["main.js"], + }, + ], + web_accessible_resources: ["module1.js", "module2.js"], + }, + + files: { + "main.js": async function () { + browser.test.onMessage.addListener(async msg => { + browser.test.assertEq(msg, "import"); + + const url = browser.runtime.getURL("module1.js"); + let mod = await import(url); + browser.test.assertEq(mod.bar, 2); + browser.test.assertEq(mod.counter(), 0, "Counter should be fresh"); + + let promise = window.eval(`import("${url}")`); + let mod2 = (await promise.wrappedJSObject).wrappedJSObject; + browser.test.assertEq( + mod2.counter(), + 2, + "Counter should have been incremented by page" + ); + + browser.test.sendMessage("done"); + }); + browser.test.sendMessage("ready"); + }, + "module1.js": MODULE1, + "module2.js": MODULE2, + }, + }); + + await extension.startup(); + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://example.com/dummy" + ); + await extension.awaitMessage("ready"); + + // The web page imports the web-accessible files first, + // when the WebExtension imports the same file, they should + // not be shared. + await contentPage.spawn([extension.uuid], async uuid => { + let base = `moz-extension://${uuid}`; + + await Assert.rejects( + content.eval(`import("${base}/main.js")`), + /error loading dynamically imported module/, + "Cannot import script that is not web-accessible" + ); + + let promise = content.eval(`import("${base}/module1.js")`); + let mod = (await promise.wrappedJSObject).wrappedJSObject; + Assert.equal(mod.bar, 2, "exported value should match"); + Assert.equal(mod.counter(), 0); + Assert.equal(mod.counter(), 1); + + promise = content.eval(`import("${base}/module2.js")`); + mod = (await promise.wrappedJSObject).wrappedJSObject; + Assert.equal(mod.foo, 2, "exported value should match"); + }); + + extension.sendMessage("import"); + + await extension.awaitMessage("done"); + + await extension.unload(); + await contentPage.close(); +}); -- cgit v1.2.3