From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/browser/browser_installtrigger_install.js | 350 +++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js (limited to 'toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js') diff --git a/toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js b/toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js new file mode 100644 index 0000000000..cd2c30be7e --- /dev/null +++ b/toolkit/mozapps/extensions/test/browser/browser_installtrigger_install.js @@ -0,0 +1,350 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { AddonTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/AddonTestUtils.sys.mjs" +); + +const { PermissionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PermissionTestUtils.sys.mjs" +); + +const XPI_URL = `${SECURE_TESTROOT}../xpinstall/amosigned.xpi`; +const XPI_ADDON_ID = "amosigned-xpi@tests.mozilla.org"; + +AddonTestUtils.initMochitest(this); + +AddonTestUtils.hookAMTelemetryEvents(); + +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + ["extensions.webapi.testing", true], + ["extensions.install.requireBuiltInCerts", false], + ["extensions.InstallTrigger.enabled", true], + ["extensions.InstallTriggerImpl.enabled", true], + // Relax the user input requirements while running this test. + ["xpinstall.userActivation.required", false], + ], + }); + + PermissionTestUtils.add( + "https://example.com/", + "install", + Services.perms.ALLOW_ACTION + ); + + registerCleanupFunction(async () => { + PermissionTestUtils.remove("https://example.com", "install"); + await SpecialPowers.popPrefEnv(); + }); +}); + +async function testInstallTrigger( + msg, + tabURL, + contentFnArgs, + contentFn, + expectedTelemetryInfo, + expectBlockedOrigin +) { + await BrowserTestUtils.withNewTab(tabURL, async browser => { + if (expectBlockedOrigin) { + const promiseOriginBlocked = TestUtils.topicObserved( + "addon-install-origin-blocked" + ); + await SpecialPowers.spawn(browser, contentFnArgs, contentFn); + const [subject] = await promiseOriginBlocked; + const installId = subject.wrappedJSObject.installs[0].installId; + + // Select all telemetry events related to the installId. + const telemetryEvents = AddonTestUtils.getAMTelemetryEvents().filter( + ev => { + return ( + ev.method === "install" && + ev.value === `${installId}` && + ev.extra.step === "site_blocked" + ); + } + ); + ok( + !!telemetryEvents.length, + "Found telemetry events for the blocked install" + ); + + if (typeof expectedTelemetryInfo === "function") { + expectedTelemetryInfo(telemetryEvents); + } else { + const source = telemetryEvents[0]?.extra.source; + Assert.deepEqual( + { source }, + expectedTelemetryInfo, + `Got expected telemetry on test case "${msg}"` + ); + } + return; + } + + let installPromptPromise = promisePopupNotificationShown( + "addon-webext-permissions" + ).then(panel => { + panel.button.click(); + }); + + let promptPromise = acceptAppMenuNotificationWhenShown( + "addon-installed", + XPI_ADDON_ID + ); + + await SpecialPowers.spawn(browser, contentFnArgs, contentFn); + + await Promise.all([installPromptPromise, promptPromise]); + + let addon = await promiseAddonByID(XPI_ADDON_ID); + + registerCleanupFunction(async () => { + await addon.uninstall(); + }); + + // Check that the expected installTelemetryInfo has been stored in the + // addon details. + AddonTestUtils.checkInstallInfo( + addon, + { method: "installTrigger", ...expectedTelemetryInfo }, + `on "${msg}"` + ); + + await addon.uninstall(); + }); +} + +add_task(function testInstallAfterHistoryPushState() { + return testInstallTrigger( + "InstallTrigger after history.pushState", + SECURE_TESTROOT, + [SECURE_TESTROOT, XPI_URL], + (secureTestRoot, xpiURL) => { + // `sourceURL` should match the exact location, even after a location + // update using the history API. In this case, we update the URL with + // query parameters and expect `sourceURL` to contain those parameters. + content.history.pushState( + {}, // state + "", // title + `${secureTestRoot}?some=query&par=am` + ); + content.InstallTrigger.install({ URL: xpiURL }); + }, + { + source: "test-host", + sourceURL: + "https://example.com/browser/toolkit/mozapps/extensions/test/browser/?some=query&par=am", + } + ); +}); + +add_task(async function testInstallTriggerFromSubframe() { + function runTestCase(msg, tabURL, testFrameAttrs, expected) { + info( + `InstallTrigger from iframe test: ${msg} - frame attributes ${JSON.stringify( + testFrameAttrs + )}` + ); + return testInstallTrigger( + msg, + tabURL, + [XPI_URL, testFrameAttrs], + async (xpiURL, frameAttrs) => { + const frame = content.document.createElement("iframe"); + if (frameAttrs) { + for (const attr of Object.keys(frameAttrs)) { + let value = frameAttrs[attr]; + if (value === "blob:") { + const blob = new content.Blob(["blob-testpage"]); + value = content.URL.createObjectURL(blob, "text/html"); + } + frame[attr] = value; + } + } + const promiseLoaded = new Promise(resolve => + frame.addEventListener("load", resolve, { once: true }) + ); + content.document.body.appendChild(frame); + await promiseLoaded; + frame.contentWindow.InstallTrigger.install({ URL: xpiURL }); + }, + expected.telemetryInfo, + expected.blockedOrigin + ); + } + + // On Windows "file:///" does not load the default files index html page + // and the test would get stuck. + const fileURL = AppConstants.platform === "win" ? "file:///C:/" : "file:///"; + + const expected = { + http: { + telemetryInfo: { + source: "test-host", + sourceURL: + "https://example.com/browser/toolkit/mozapps/extensions/test/browser/", + }, + blockedOrigin: false, + }, + httpBlob: { + telemetryInfo: { + source: "test-host", + // Example: "blob:https://example.com/BLOB_URL_UUID" + sourceURL: /^blob:https:\/\/example\.com\//, + }, + blockedOrigin: false, + }, + file: { + telemetryInfo: { + source: "unknown", + sourceURL: fileURL, + }, + blockedOrigin: false, + }, + fileBlob: { + telemetryInfo: { + source: "unknown", + // Example: "blob:null/BLOB_URL_UUID" + sourceURL: /^blob:null\//, + }, + blockedOrigin: false, + }, + httpBlockedOnOrigin: { + telemetryInfo: { + source: "test-host", + }, + blockedOrigin: true, + }, + otherBlockedOnOrigin: { + telemetryInfo: { + source: "unknown", + }, + blockedOrigin: true, + }, + }; + + const testCases = [ + ["blank iframe with no attributes", SECURE_TESTROOT, {}, expected.http], + + // These are blocked by a Firefox doorhanger and the user can't allow it neither. + [ + "http page iframe src='blob:...'", + SECURE_TESTROOT, + { src: "blob:" }, + expected.httpBlockedOnOrigin, + ], + [ + "file page iframe src='blob:...'", + fileURL, + { src: "blob:" }, + expected.otherBlockedOnOrigin, + ], + [ + "iframe srcdoc=''", + SECURE_TESTROOT, + { srcdoc: "" }, + expected.httpBlockedOnOrigin, + ], + [ + "blank iframe embedded into a top-level sandbox page", + `${SECURE_TESTROOT}sandboxed.html`, + {}, + expected.httpBlockedOnOrigin, + ], + [ + "blank iframe with sandbox='allow-scripts'", + SECURE_TESTROOT, + { sandbox: "allow-scripts" }, + expected.httpBlockedOnOrigin, + ], + [ + "iframe srcdoc='' sandbox='allow-scripts'", + SECURE_TESTROOT, + { srcdoc: "", sandbox: "allow-scripts" }, + expected.httpBlockedOnOrigin, + ], + [ + "http page iframe src='blob:...' sandbox='allow-scripts'", + SECURE_TESTROOT, + { src: "blob:", sandbox: "allow-scripts" }, + expected.httpBlockedOnOrigin, + ], + [ + "iframe src='data:...'", + SECURE_TESTROOT, + { src: "data:text/html,data-testpage" }, + expected.httpBlockedOnOrigin, + ], + [ + "blank frame embedded in a data url", + "data:text/html,data-testpage", + {}, + expected.otherBlockedOnOrigin, + ], + [ + "blank frame embedded into a about:blank page", + "about:blank", + {}, + expected.otherBlockedOnOrigin, + ], + ]; + + for (const testCase of testCases) { + await runTestCase(...testCase); + } +}); + +add_task(function testInstallBlankFrameNestedIntoBlobURLPage() { + return testInstallTrigger( + "Blank frame nested into a blob url page", + SECURE_TESTROOT, + [XPI_URL], + async xpiURL => { + const url = content.URL.createObjectURL( + new content.Blob(["blob-testpage"]), + "text/html" + ); + const topframe = content.document.createElement("iframe"); + topframe.src = url; + const topframeLoaded = new Promise(resolve => { + topframe.addEventListener("load", resolve, { once: true }); + }); + content.document.body.appendChild(topframe); + await topframeLoaded; + const subframe = topframe.contentDocument.createElement("iframe"); + topframe.contentDocument.body.appendChild(subframe); + subframe.contentWindow.InstallTrigger.install({ URL: xpiURL }); + }, + { + source: "test-host", + }, + /* expectBlockedOrigin */ true + ); +}); + +add_task(function testInstallTriggerTopLevelDataURL() { + return testInstallTrigger( + "Blank frame nested into a blob url page", + "data:text/html,testpage", + [XPI_URL], + async xpiURL => { + this.content.InstallTrigger.install({ URL: xpiURL }); + }, + { + source: "unknown", + }, + /* expectBlockedOrigin */ true + ); +}); + +add_task(function teardown_clearUnexamitedTelemetry() { + // Clear collected telemetry events when we are not going to run any assertion on them. + // (otherwise the test will fail because of unexamined telemetry events). + AddonTestUtils.getAMTelemetryEvents(); +}); -- cgit v1.2.3