diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js | |
parent | Initial commit. (diff) | |
download | thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js b/toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js new file mode 100644 index 0000000000..49f3b336c7 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_installOrigins.js @@ -0,0 +1,535 @@ +/* Any copyright is dedicated to the Public Domain. +http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PermissionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PermissionTestUtils.sys.mjs" +); + +AddonTestUtils.init(this); +AddonTestUtils.overrideCertDB(); +AddonTestUtils.usePrivilegedSignatures = false; +AddonTestUtils.createAppInfo( + "xpcshell@tests.mozilla.org", + "XPCShell", + "42", + "42" +); + +Services.prefs.setBoolPref("extensions.manifestV3.enabled", true); +// This pref is not set in Thunderbird, and needs to be true for the test to pass. +Services.prefs.setBoolPref("extensions.postDownloadThirdPartyPrompt", true); + +let server = AddonTestUtils.createHttpServer({ + hosts: ["example.com", "example.org", "amo.example.com", "github.io"], +}); + +server.registerFile( + `/addons/origins.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 2, + name: "Install Origins test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "origins@example.com", + }, + }, + install_origins: ["http://example.com"], + }, + }) +); + +server.registerFile( + `/addons/sitepermission.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 2, + name: "Install Origins sitepermission test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "sitepermission@example.com", + }, + }, + install_origins: ["http://example.com"], + site_permissions: ["midi"], + }, + }) +); + +server.registerFile( + `/addons/sitepermission-suffix.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 2, + name: "Install Origins sitepermission public suffix test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "sitepermission-suffix@github.io", + }, + }, + install_origins: ["http://github.io"], + site_permissions: ["midi"], + }, + }) +); + +server.registerFile( + `/addons/two_origins.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 2, + name: "Install Origins test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "two_origins@example.com", + }, + }, + install_origins: ["http://example.com", "http://example.org"], + }, + }) +); + +server.registerFile( + `/addons/no_origins.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 2, + name: "Install Origins test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "no_origins@example.com", + }, + }, + }, + }) +); + +server.registerFile( + `/addons/empty_origins.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 2, + name: "Install Origins test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "no_origins@example.com", + }, + }, + install_origins: [], + }, + }) +); + +server.registerFile( + `/addons/v3_origins.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 3, + name: "Install Origins test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "v3_origins@example.com", + }, + }, + install_origins: ["http://example.com"], + }, + }) +); + +server.registerFile( + `/addons/v3_no_origins.xpi`, + AddonTestUtils.createTempXPIFile({ + "manifest.json": { + manifest_version: 3, + name: "Install Origins test", + version: "1.0", + browser_specific_settings: { + gecko: { + id: "v3_no_origins@example.com", + }, + }, + }, + }) +); + +function testInstallEvent(expectTelemetry) { + const snapshot = Services.telemetry.snapshotEvents( + Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, + true + ); + + ok( + snapshot.parent && !!snapshot.parent.length, + "Got parent telemetry events in the snapshot" + ); + + let events = snapshot.parent + .filter( + ([timestamp, category, method, object, value, extra]) => + category === "addonsManager" && + method == "install" && + extra.step == expectTelemetry.step + ) + .map(event => event[5]); + equal(events.length, 1, "one event for install completion"); + Assert.deepEqual(events[0], expectTelemetry, "telemetry matches"); +} + +function promiseCompleteWebInstall( + install, + triggeringPrincipal, + expectPrompts = true +) { + let listener; + return new Promise(_resolve => { + let resolve = () => { + install.removeListener(listener); + _resolve(); + }; + + listener = { + onDownloadFailed: resolve, + onDownloadCancelled: resolve, + onInstallFailed: resolve, + onInstallCancelled: resolve, + onInstallEnded: resolve, + onInstallPostponed: resolve, + }; + + install.addListener(listener); + + // Observers to bypass panels and continue install. + if (expectPrompts) { + TestUtils.topicObserved("addon-install-blocked").then(([subject]) => { + let installInfo = subject.wrappedJSObject; + info(`==== test got addon-install-blocked ${subject} ${installInfo}`); + installInfo.install(); + }); + + TestUtils.topicObserved("addon-install-confirmation").then( + (subject, data) => { + info(`==== test got addon-install-confirmation`); + let installInfo = subject.wrappedJSObject; + for (let installer of installInfo.installs) { + installer.install(); + } + } + ); + TestUtils.topicObserved("webextension-permission-prompt").then( + ([subject]) => { + const { info } = subject.wrappedJSObject || {}; + info.resolve(); + } + ); + } + + AddonManager.installAddonFromWebpage( + "application/x-xpinstall", + null /* aBrowser */, + triggeringPrincipal, + install + ); + }); +} + +async function testAddonInstall(test) { + let { name, xpiUrl, installPrincipal, expectState, expectTelemetry } = test; + info(`testAddonInstall: ${name}`); + let expectInstall = expectState == AddonManager.STATE_INSTALLED; + let install = await AddonManager.getInstallForURL(xpiUrl, { + triggeringPrincipal: installPrincipal, + }); + await promiseCompleteWebInstall(install, installPrincipal, expectInstall); + + // Test origins telemetry + testInstallEvent(expectTelemetry); + + if (expectInstall) { + equal( + install.state, + expectState, + `${name} ${install.addon.id} install was completed` + ); + // Wait the extension startup to ensure manifest.json has been read, + // otherwise we get NS_ERROR_FILE_NOT_FOUND log spam. + await WebExtensionPolicy.getByID(install.addon.id)?.readyPromise; + await install.addon.uninstall(); + } else { + equal( + install.state, + expectState, + `${name} ${install.addon?.id} install failed` + ); + } +} + +let ssm = Services.scriptSecurityManager; +const PRINCIPAL_AMO = ssm.createContentPrincipalFromOrigin( + "https://amo.example.com" +); +const PRINCIPAL_COM = + ssm.createContentPrincipalFromOrigin("http://example.com"); +const SUB_PRINCIPAL_COM = ssm.createContentPrincipalFromOrigin( + "http://abc.example.com" +); +const THIRDPARTY_PRINCIPAL_COM = ssm.createContentPrincipalFromOrigin( + "http://fake-example.com" +); +const PRINCIPAL_ORG = + ssm.createContentPrincipalFromOrigin("http://example.org"); +const PRINCIPAL_ETLD = ssm.createContentPrincipalFromOrigin("http://github.io"); + +const TESTS = [ + { + name: "Install MV2 with install_origins", + xpiUrl: "http://example.com/addons/origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "origins@example.com", + install_origins: "1", + }, + }, + { + name: "Install MV2 without install_origins", + xpiUrl: "http://example.com/addons/no_origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "no_origins@example.com", + install_origins: "0", + }, + }, + { + name: "Install valid xpi location from invalid website", + xpiUrl: "http://example.com/addons/origins.xpi", + installPrincipal: PRINCIPAL_ORG, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "origins@example.com", + error: "ERROR_INVALID_DOMAIN", + install_origins: "1", + }, + }, + { + name: "Install invalid xpi location from valid website", + xpiUrl: "http://example.org/addons/origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "origins@example.com", + error: "ERROR_INVALID_DOMAIN", + install_origins: "1", + }, + }, + { + name: "Install MV3 with install_origins", + xpiUrl: "http://example.com/addons/v3_origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "v3_origins@example.com", + install_origins: "1", + }, + }, + { + name: "Install MV3 with install_origins from AMO", + xpiUrl: "http://example.com/addons/v3_origins.xpi", + installPrincipal: PRINCIPAL_AMO, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "v3_origins@example.com", + install_origins: "1", + }, + }, + { + name: "Install MV3 without install_origins", + xpiUrl: "http://example.com/addons/v3_no_origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "v3_no_origins@example.com", + error: "ERROR_INVALID_DOMAIN", + install_origins: "0", + }, + }, + { + // An installing principal with install permission is + // considered "AMO" in code, and will always be allowed. + name: "Install MV3 without install_origins from AMO", + xpiUrl: "http://example.com/addons/v3_no_origins.xpi", + installPrincipal: PRINCIPAL_AMO, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "v3_no_origins@example.com", + install_origins: "0", + }, + }, + { + name: "Install MV3 without install_origins from null principal", + xpiUrl: "http://example.com/addons/v3_no_origins.xpi", + installPrincipal: Services.scriptSecurityManager.createNullPrincipal({}), + expectState: AddonManager.STATE_CANCELLED, + expectTelemetry: { step: "site_blocked", install_origins: "0" }, + }, + { + name: "Install addon with two install_origins", + xpiUrl: "http://example.com/addons/two_origins.xpi", + installPrincipal: PRINCIPAL_ORG, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "two_origins@example.com", + install_origins: "1", + }, + }, + { + name: "Install addon with two install_origins", + xpiUrl: "http://example.com/addons/two_origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "two_origins@example.com", + install_origins: "1", + }, + }, + { + name: "Install from site with empty install_origins", + xpiUrl: "http://example.com/addons/empty_origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "no_origins@example.com", + error: "ERROR_INVALID_DOMAIN", + install_origins: "1", + }, + }, + { + name: "Install from site with empty install_origins", + xpiUrl: "http://example.com/addons/empty_origins.xpi", + installPrincipal: PRINCIPAL_ORG, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "no_origins@example.com", + error: "ERROR_INVALID_DOMAIN", + install_origins: "1", + }, + }, + { + name: "Install with empty install_origins from AMO", + xpiUrl: "http://amo.example.com/addons/empty_origins.xpi", + installPrincipal: PRINCIPAL_AMO, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "no_origins@example.com", + install_origins: "1", + }, + }, + { + name: "Install sitepermission from domain", + xpiUrl: "http://example.com/addons/sitepermission.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "sitepermission@example.com", + install_origins: "1", + }, + }, + { + name: "Install sitepermission from subdomain", + xpiUrl: "http://example.com/addons/sitepermission.xpi", + installPrincipal: SUB_PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "sitepermission@example.com", + install_origins: "1", + }, + }, + { + name: "Install sitepermission from thirdparty domain should fail", + xpiUrl: "http://example.com/addons/sitepermission.xpi", + installPrincipal: THIRDPARTY_PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "sitepermission@example.com", + error: "ERROR_INVALID_DOMAIN", + install_origins: "1", + }, + }, + { + name: "Install sitepermission from different domain", + xpiUrl: "http://example.com/addons/sitepermission.xpi", + installPrincipal: PRINCIPAL_ORG, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "sitepermission@example.com", + error: "ERROR_INVALID_DOMAIN", + install_origins: "1", + }, + }, + { + name: "Install sitepermission from public suffix domain", + xpiUrl: "http://github.io/addons/sitepermission-suffix.xpi", + installPrincipal: PRINCIPAL_ETLD, + expectState: AddonManager.STATE_INSTALL_FAILED, + expectTelemetry: { + step: "failed", + addon_id: "sitepermission-suffix@github.io", + error: "ERROR_INVALID_DOMAIN", + install_origins: "1", + }, + }, +]; + +add_task(async function test_install_url() { + Services.prefs.setBoolPref("extensions.install_origins.enabled", true); + PermissionTestUtils.add( + PRINCIPAL_AMO, + "install", + Services.perms.ALLOW_ACTION + ); + await promiseStartupManager(); + + for (let test of TESTS) { + await testAddonInstall(test); + } +}); + +add_task(async function test_install_origins_disabled() { + Services.prefs.setBoolPref("extensions.install_origins.enabled", false); + await testAddonInstall({ + name: "Install MV3 without install_origins, verification disabled", + xpiUrl: "http://example.com/addons/v3_no_origins.xpi", + installPrincipal: PRINCIPAL_COM, + expectState: AddonManager.STATE_INSTALLED, + expectTelemetry: { + step: "completed", + addon_id: "v3_no_origins@example.com", + }, + }); +}); |