From 4385dce6fc73aa640c6154645c221f97da19094f Mon Sep 17 00:00:00 2001 From: William Durand Date: Wed, 10 Apr 2024 21:48:40 +0000 Subject: [PATCH] Bug 1787379 - Add `origin` to `runtime.MessageSender`. r=robwu,zombie,geckoview-reviewers Note that we intentionally return "null" for null principals *and* file scheme, which is - at the time of writing - different than Chromium. Differential Revision: https://phabricator.services.mozilla.com/D206989 --- .../browser_ext_contentscript_nontab_connect.js | 6 + .../browser_ext_contentscript_sender_url.js | 21 ++- .../test_ext_native_messaging_permissions.js | 4 +- .../components/extensions/ExtensionParent.sys.mjs | 10 +- .../test/mochitest/test_ext_runtime_connect.html | 1 + .../test/mochitest/test_ext_runtime_connect2.html | 1 + .../mochitest/test_ext_runtime_connect_iframe.html | 6 + .../test/mochitest/test_ext_tabs_sendMessage.html | 180 +++++++++++++++++++++ 8 files changed, 225 insertions(+), 4 deletions(-) diff --git a/browser/components/extensions/test/browser/browser_ext_contentscript_nontab_connect.js b/browser/components/extensions/test/browser/browser_ext_contentscript_nontab_connect.js index 548c35399f80..33ad85f26849 100644 --- a/browser/components/extensions/test/browser/browser_ext_contentscript_nontab_connect.js +++ b/browser/components/extensions/test/browser/browser_ext_contentscript_nontab_connect.js @@ -8,11 +8,17 @@ function extensionScript() { let FRAME_URL = browser.runtime.getManifest().content_scripts[0].matches[0]; // Cannot use :8888 in the manifest because of bug 1468162. FRAME_URL = FRAME_URL.replace("mochi.test", "mochi.test:8888"); + let FRAME_ORIGIN = new URL(FRAME_URL).origin; browser.runtime.onConnect.addListener(port => { browser.test.assertEq(port.sender.tab, undefined, "Sender is not a tab"); browser.test.assertEq(port.sender.frameId, undefined, "frameId unset"); browser.test.assertEq(port.sender.url, FRAME_URL, "Expected sender URL"); + browser.test.assertEq( + port.sender.origin, + FRAME_ORIGIN, + "Expected sender origin" + ); port.onMessage.addListener(msg => { browser.test.assertEq("pong", msg, "Reply from content script"); diff --git a/browser/components/extensions/test/browser/browser_ext_contentscript_sender_url.js b/browser/components/extensions/test/browser/browser_ext_contentscript_sender_url.js index f751c3c20276..08f19013c414 100644 --- a/browser/components/extensions/test/browser/browser_ext_contentscript_sender_url.js +++ b/browser/components/extensions/test/browser/browser_ext_contentscript_sender_url.js @@ -2,12 +2,16 @@ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; +const FILE_URL = Services.io.newFileURI( + new FileUtils.File(getTestFilePath("file_dummy.html")) +).spec; + add_task(async function test_sender_url() { let extension = ExtensionTestUtils.loadExtension({ manifest: { content_scripts: [ { - matches: ["http://mochi.test/*"], + matches: ["http://mochi.test/*", "file:///*"], run_at: "document_start", js: ["script.js"], }, @@ -18,6 +22,7 @@ add_task(async function test_sender_url() { browser.runtime.onMessage.addListener((msg, sender) => { browser.test.log("Message received."); browser.test.sendMessage("sender.url", sender.url); + browser.test.sendMessage("sender.origin", sender.origin); }); }, @@ -53,6 +58,9 @@ add_task(async function test_sender_url() { let url = await extension.awaitMessage("sender.url"); is(url, image, `Correct sender.url: ${url}`); + let origin = await extension.awaitMessage("sender.origin"); + is(origin, "http://mochi.test:8888", `Correct sender.origin: ${origin}`); + let wentBack = awaitNewTab(); await browser.goBack(); await wentBack; @@ -60,6 +68,17 @@ add_task(async function test_sender_url() { await browser.goForward(); url = await extension.awaitMessage("sender.url"); is(url, image, `Correct sender.url: ${url}`); + + origin = await extension.awaitMessage("sender.origin"); + is(origin, "http://mochi.test:8888", `Correct sender.origin: ${origin}`); + }); + + await BrowserTestUtils.withNewTab(FILE_URL, async () => { + let url = await extension.awaitMessage("sender.url"); + ok(url.endsWith("/file_dummy.html"), `Correct sender.url: ${url}`); + + let origin = await extension.awaitMessage("sender.origin"); + is(origin, "null", `Correct sender.origin: ${origin}`); }); await extension.unload(); diff --git a/mobile/android/components/extensions/test/xpcshell/test_ext_native_messaging_permissions.js b/mobile/android/components/extensions/test/xpcshell/test_ext_native_messaging_permissions.js index 63f64b487e9f..88fdda9bf342 100644 --- a/mobile/android/components/extensions/test/xpcshell/test_ext_native_messaging_permissions.js +++ b/mobile/android/components/extensions/test/xpcshell/test_ext_native_messaging_permissions.js @@ -97,7 +97,7 @@ add_task(async function test_geckoViewAddons_missing() { const ERROR_NATIVE_MESSAGE_FROM_BACKGROUND = "Native manifests are not supported on android"; const ERROR_NATIVE_MESSAGE_FROM_CONTENT = - /^Native messaging not allowed: \{.*"envType":"content_child","url":"http:\/\/example\.com\/dummy"\}$/; + /^Native messaging not allowed: \{.*"envType":"content_child","url":"http:\/\/example\.com\/dummy"\,"origin":"http:\/\/example\.com"}$/; async function testBackground() { await browser.test.assertRejects( @@ -136,7 +136,7 @@ add_task(async function test_geckoViewAddons_missing() { // without the nativeMessagingFromContent permission. add_task(async function test_nativeMessagingFromContent_missing() { const ERROR_NATIVE_MESSAGE_FROM_CONTENT_NO_PERM = - /^Unexpected messaging sender: \{.*"envType":"content_child","url":"http:\/\/example\.com\/dummy"\}$/; + /^Unexpected messaging sender: \{.*"envType":"content_child","url":"http:\/\/example\.com\/dummy"\,"origin":"http:\/\/example\.com"}$/; function testBackground() { // sendNativeMessage / connectNative are expected to succeed, but we // are not testing that here because XpcshellTestRunnerService does not diff --git a/toolkit/components/extensions/ExtensionParent.sys.mjs b/toolkit/components/extensions/ExtensionParent.sys.mjs index c22e00684b72..f9514337135c 100644 --- a/toolkit/components/extensions/ExtensionParent.sys.mjs +++ b/toolkit/components/extensions/ExtensionParent.sys.mjs @@ -303,7 +303,8 @@ const ProxyMessenger = { }; if (JSWindowActorParent.isInstance(source.actor)) { - let browser = source.actor.browsingContext.top.embedderElement; + let { currentWindowContext, top } = source.actor.browsingContext; + let browser = top.embedderElement; let data = browser && apiManager.global.tabTracker.getBrowserData(browser); if (data?.tabId > 0) { @@ -311,6 +312,13 @@ const ProxyMessenger = { // frameId is documented to only be set if sender.tab is set. sender.frameId = source.frameId; } + + let principal = currentWindowContext.documentPrincipal; + // We intend the serialization of null principals *and* file scheme to be + // "null". + sender.origin = new URL(principal.originNoSuffix).origin; + } else if (source.verified) { + sender.origin = `moz-extension://${extension.uuid}`; } return sender; diff --git a/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect.html b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect.html index 85f98d503411..d474a7caee14 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect.html @@ -18,6 +18,7 @@ function background() { browser.test.assertTrue(port.sender.url.endsWith("file_sample.html"), "URL correct"); browser.test.assertTrue(port.sender.tab.url.endsWith("file_sample.html"), "tab URL correct"); browser.test.assertEq(port.sender.frameId, 0, "frameId of top frame"); + browser.test.assertEq(new URL(port.sender.url).origin, port.sender.origin, "sender origin correct"); let expected = "message 1"; port.onMessage.addListener(msg => { diff --git a/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect2.html b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect2.html index 13b9029c482b..32620b5b3ba5 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect2.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect2.html @@ -21,6 +21,7 @@ function backgroundScript(token) { browser.runtime.onConnect.addListener(port => { browser.test.assertTrue(port.sender.url.endsWith("file_sample.html"), "sender url correct"); browser.test.assertTrue(port.sender.tab.url.endsWith("file_sample.html"), "sender url correct"); + browser.test.assertEq(new URL(port.sender.url).origin, port.sender.origin, "sender origin correct"); let tabId = port.sender.tab.id; browser.tabs.connect(tabId, {name: token}); diff --git a/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect_iframe.html b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect_iframe.html index 9c64635063f8..e3e0e80f2ae3 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect_iframe.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect_iframe.html @@ -30,12 +30,15 @@ add_task(async function connect_from_background_frame() { } async function background() { const FRAME_URL = "https://example.com/tests/toolkit/components/extensions/test/mochitest/file_sample.html"; + const FRAME_ORIGIN = new URL(FRAME_URL).origin; + browser.runtime.onConnect.addListener(port => { // The next two assertions are the reason for this being a mochitest // instead of a xpcshell test. browser.test.assertEq(port.sender.tab, undefined, "Sender is not a tab"); browser.test.assertEq(port.sender.frameId, undefined, "frameId unset"); browser.test.assertEq(port.sender.url, FRAME_URL, "Expected sender URL"); + browser.test.assertEq(port.sender.origin, FRAME_ORIGIN, "Expected sender origin"); port.onMessage.addListener(msg => { browser.test.assertEq("pong", msg, "Reply from content script"); port.disconnect(); @@ -88,6 +91,8 @@ add_task(async function connect_from_content_script_in_frame() { async function background() { const TAB_URL = "https://example.org/tests/toolkit/components/extensions/test/mochitest/file_contains_iframe.html"; const FRAME_URL = "https://example.org/tests/toolkit/components/extensions/test/mochitest/file_contains_img.html"; + const FRAME_ORIGIN = new URL(FRAME_URL).origin; + let createdTab; browser.runtime.onConnect.addListener(port => { // The next two assertions are the reason for this being a mochitest @@ -95,6 +100,7 @@ add_task(async function connect_from_content_script_in_frame() { browser.test.assertEq(port.sender.tab.url, TAB_URL, "Sender is the tab"); browser.test.assertTrue(port.sender.frameId > 0, "frameId is set"); browser.test.assertEq(port.sender.url, FRAME_URL, "Expected sender URL"); + browser.test.assertEq(port.sender.origin, FRAME_ORIGIN, "Expected sender origin"); browser.test.assertEq(createdTab.id, port.sender.tab.id, "Tab to close"); browser.tabs.remove(port.sender.tab.id).then(() => { diff --git a/toolkit/components/extensions/test/mochitest/test_ext_tabs_sendMessage.html b/toolkit/components/extensions/test/mochitest/test_ext_tabs_sendMessage.html index 4b230c258cf0..8c6dfeee7c40 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_tabs_sendMessage.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_tabs_sendMessage.html @@ -11,6 +11,10 @@ -- 2.11.4.GIT