diff options
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_sitePermsAddonProvider.js')
-rw-r--r-- | toolkit/mozapps/extensions/test/xpcshell/test_sitePermsAddonProvider.js | 967 |
1 files changed, 967 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_sitePermsAddonProvider.js b/toolkit/mozapps/extensions/test/xpcshell/test_sitePermsAddonProvider.js new file mode 100644 index 0000000000..51272509da --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_sitePermsAddonProvider.js @@ -0,0 +1,967 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { + addGatedPermissionTypesForXpcShellTests, + SITEPERMS_ADDON_PROVIDER_PREF, + SITEPERMS_ADDON_BLOCKEDLIST_PREF, + SITEPERMS_ADDON_TYPE, +} = ChromeUtils.importESModule( + "resource://gre/modules/addons/siteperms-addon-utils.sys.mjs" +); + +const { PermissionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PermissionTestUtils.sys.mjs" +); + +const addonsBundle = new Localization(["toolkit/about/aboutAddons.ftl"], true); + +let ssm = Services.scriptSecurityManager; +const PRINCIPAL_COM = ssm.createContentPrincipalFromOrigin( + "https://example.com" +); +const PRINCIPAL_ORG = ssm.createContentPrincipalFromOrigin( + "https://example.org" +); +const PRINCIPAL_GITHUB = + ssm.createContentPrincipalFromOrigin("https://github.io"); +const PRINCIPAL_UNSECURE = + ssm.createContentPrincipalFromOrigin("http://example.net"); +const PRINCIPAL_IP = ssm.createContentPrincipalFromOrigin( + "https://18.154.122.194" +); +const PRINCIPAL_PRIVATEBROWSING = ssm.createContentPrincipal( + Services.io.newURI("https://example.withprivatebrowsing.com"), + { privateBrowsingId: 1 } +); +const PRINCIPAL_USERCONTEXT = ssm.createContentPrincipal( + Services.io.newURI("https://example.withusercontext.com"), + { userContextId: 2 } +); +const PRINCIPAL_NULL = ssm.createNullPrincipal({}); + +const URI_USED_IN_MULTIPLE_CONTEXTS = Services.io.newURI( + "https://multiplecontexts.com" +); +const PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR = ssm.createContentPrincipal( + URI_USED_IN_MULTIPLE_CONTEXTS, + {} +); +const PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING = ssm.createContentPrincipal( + URI_USED_IN_MULTIPLE_CONTEXTS, + { privateBrowsingId: 1 } +); +const PRINCIPAL_MULTIPLE_CONTEXTS_USERCONTEXT = ssm.createContentPrincipal( + URI_USED_IN_MULTIPLE_CONTEXTS, + { userContextId: 3 } +); + +const BLOCKED_DOMAIN = "malicious.com"; +const BLOCKED_DOMAIN2 = "someothermalicious.com"; +const BLOCKED_PRINCIPAL = ssm.createContentPrincipalFromOrigin( + `https://${BLOCKED_DOMAIN}` +); +const BLOCKED_PRINCIPAL2 = ssm.createContentPrincipalFromOrigin( + `https://${BLOCKED_DOMAIN2}` +); + +const GATED_SITE_PERM1 = "test/gatedSitePerm"; +const GATED_SITE_PERM2 = "test/anotherGatedSitePerm"; +addGatedPermissionTypesForXpcShellTests([GATED_SITE_PERM1, GATED_SITE_PERM2]); +const NON_GATED_SITE_PERM = "test/nonGatedPerm"; + +// Leave it to throw if the pref doesn't exist anymore, so that a test failure +// will make us notice and confirm if we have enabled it by default or not. +const PERMS_ISOLATE_USERCONTEXT_ENABLED = Services.prefs.getBoolPref( + "permissions.isolateBy.userContext" +); + +// Observers to bypass panels and continue install. +const expectAndHandleInstallPrompts = () => { + TestUtils.topicObserved("addon-install-blocked").then(([subject]) => { + let installInfo = subject.wrappedJSObject; + info("==== test got addon-install-blocked, calling `install`"); + installInfo.install(); + }); + TestUtils.topicObserved("webextension-permission-prompt").then( + ([subject]) => { + info("==== test webextension-permission-prompt, calling `resolve`"); + subject.wrappedJSObject.info.resolve(); + } + ); +}; + +add_setup(async () => { + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + AddonTestUtils.init(this); + await promiseStartupManager(); +}); + +add_task( + { + pref_set: [[SITEPERMS_ADDON_PROVIDER_PREF, false]], + }, + async function test_sitepermsaddon_provider_disabled() { + // The SitePermsAddonProvider does not register until the first content process + // is launched, so we simulate that by firing this notification. + Services.obs.notifyObservers(null, "ipc:first-content-process-created"); + + ok( + !AddonManager.hasProvider("SitePermsAddonProvider"), + "Expect no SitePermsAddonProvider to be registered" + ); + } +); + +add_task( + { + pref_set: [ + [SITEPERMS_ADDON_PROVIDER_PREF, true], + [ + SITEPERMS_ADDON_BLOCKEDLIST_PREF, + `${BLOCKED_DOMAIN},${BLOCKED_DOMAIN2}`, + ], + ], + }, + async function test_sitepermsaddon_provider_enabled() { + // The SitePermsAddonProvider does not register until the first content process + // is launched, so we simulate that by firing this notification. + Services.obs.notifyObservers(null, "ipc:first-content-process-created"); + + ok( + AddonManager.hasProvider("SitePermsAddonProvider"), + "Expect SitePermsAddonProvider to be registered" + ); + + let addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 0, "There's no addons"); + + info("Add a gated permission"); + PermissionTestUtils.add( + PRINCIPAL_COM, + GATED_SITE_PERM1, + Services.perms.ALLOW_ACTION + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 1, "A siteperm addon is now available"); + const comAddon = await promiseAddonByID(addons[0].id); + Assert.equal( + addons[0], + comAddon, + "getAddonByID returns the expected addon" + ); + + Assert.deepEqual( + comAddon.sitePermissions, + [GATED_SITE_PERM1], + "addon has expected sitePermissions" + ); + Assert.equal( + comAddon.type, + SITEPERMS_ADDON_TYPE, + "addon has expected type" + ); + + const localizedExtensionName = await addonsBundle.formatValue( + "addon-sitepermission-host", + { + host: PRINCIPAL_COM.host, + } + ); + Assert.ok(!!localizedExtensionName, "retrieved addonName is not falsy"); + Assert.equal( + comAddon.name, + localizedExtensionName, + "addon has expected name" + ); + + info("Add another gated permission"); + PermissionTestUtils.add( + PRINCIPAL_COM, + GATED_SITE_PERM2, + Services.perms.ALLOW_ACTION + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 1, + "There is no new siteperm addon after adding a permission to the same principal..." + ); + Assert.deepEqual( + comAddon.sitePermissions, + [GATED_SITE_PERM1, GATED_SITE_PERM2], + "...but the new permission is reported by addon.sitePermissions" + ); + + info("Add a non-gated permission"); + PermissionTestUtils.add( + PRINCIPAL_COM, + NON_GATED_SITE_PERM, + Services.perms.ALLOW_ACTION + ); + Assert.equal( + addons.length, + 1, + "There is no new siteperm addon after adding a non gated permission to the same principal..." + ); + Assert.deepEqual( + comAddon.sitePermissions, + [GATED_SITE_PERM1, GATED_SITE_PERM2], + "...and the new permission is not reported by addon.sitePermissions" + ); + + info("Adding a gated permission to another principal"); + PermissionTestUtils.add( + PRINCIPAL_ORG, + GATED_SITE_PERM1, + Services.perms.ALLOW_ACTION + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 2, "A new siteperm addon is now available"); + const orgAddon = await promiseAddonByID(addons[1].id); + Assert.equal( + addons[1], + orgAddon, + "getAddonByID returns the expected addon" + ); + + Assert.deepEqual( + orgAddon.sitePermissions, + [GATED_SITE_PERM1], + "new addon only has a single sitePermission" + ); + + info( + "Passing null or undefined to getAddonsByTypes returns all the addons" + ); + addons = await promiseAddonsByTypes(null); + // We can't do an exact check on all the returned addons as we get other type + // of addons from other providers. + Assert.deepEqual( + addons.filter(a => a.type == SITEPERMS_ADDON_TYPE).map(a => a.id), + [comAddon.id, orgAddon.id], + "Got site perms addons when passing null" + ); + + addons = await promiseAddonsByTypes(); + Assert.deepEqual( + addons.filter(a => a.type == SITEPERMS_ADDON_TYPE).map(a => a.id), + [comAddon.id, orgAddon.id], + "Got site perms addons when passing undefined" + ); + + info("Remove a gated permission"); + PermissionTestUtils.remove(PRINCIPAL_COM, GATED_SITE_PERM2); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "Removing a permission did not removed the addon has it has another permission" + ); + Assert.deepEqual( + comAddon.sitePermissions, + [GATED_SITE_PERM1], + "addon has expected sitePermissions" + ); + + info("Remove last gated permission on PRINCIPAL_COM"); + const promisePrincipalComUninstalling = AddonTestUtils.promiseAddonEvent( + "onUninstalling", + addon => { + return addon.id === comAddon.id; + } + ); + const promisePrincipalComUninstalled = AddonTestUtils.promiseAddonEvent( + "onUninstalled", + addon => { + return addon.id === comAddon.id; + } + ); + PermissionTestUtils.remove(PRINCIPAL_COM, GATED_SITE_PERM1); + info("Wait for onUninstalling addon listener call"); + await promisePrincipalComUninstalling; + info("Wait for onUninstalled addon listener call"); + await promisePrincipalComUninstalled; + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 1, + "Removing the last gated permission removed the addon" + ); + Assert.equal(addons[0], orgAddon); + + info("Uninstall org addon"); + orgAddon.uninstall(); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 0, "org addon is removed"); + Assert.equal( + PermissionTestUtils.testExactPermission(PRINCIPAL_ORG, GATED_SITE_PERM1), + false, + "Permission was removed when the addon was uninstalled" + ); + + info("Add gated permissions"); + PermissionTestUtils.add( + PRINCIPAL_COM, + GATED_SITE_PERM1, + Services.perms.ALLOW_ACTION + ); + PermissionTestUtils.add( + PRINCIPAL_ORG, + GATED_SITE_PERM1, + Services.perms.ALLOW_ACTION + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 2, "2 addons are now available"); + + info("Clear permissions"); + const onAddon1Uninstall = AddonTestUtils.promiseAddonEvent( + "onUninstalled", + addon => addon.id === addons[0].id + ); + const onAddon2Uninstall = AddonTestUtils.promiseAddonEvent( + "onUninstalled", + addon => addon.id === addons[1].id + ); + Services.perms.removeAll(); + + await Promise.all([onAddon1Uninstall, onAddon2Uninstall]); + ok("Addons were properly uninstalled…"); + Assert.equal( + (await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE])).length, + 0, + "… and getAddonsByTypes does not return them anymore" + ); + + info("Adding a permission to a public etld"); + PermissionTestUtils.add( + PRINCIPAL_GITHUB, + GATED_SITE_PERM1, + Services.perms.ALLOW_ACTION + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 0, + "Adding a gated permission to a public etld shouldn't add a new addon" + ); + // Cleanup + PermissionTestUtils.remove(PRINCIPAL_GITHUB, GATED_SITE_PERM1); + + info("Adding a permission to a non secure principal"); + PermissionTestUtils.add( + PRINCIPAL_UNSECURE, + GATED_SITE_PERM1, + Services.perms.ALLOW_ACTION + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 0, + "Adding a gated permission to an unsecure principal shouldn't add a new addon" + ); + + info("Adding a permission to a blocked principal"); + PermissionTestUtils.add( + BLOCKED_PRINCIPAL, + GATED_SITE_PERM1, + Services.perms.ALLOW_ACTION + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 0, + "Adding a gated permission to a blocked principal shouldn't add a new addon" + ); + // Cleanup + PermissionTestUtils.remove(BLOCKED_PRINCIPAL, GATED_SITE_PERM1); + + info("Call installSitePermsAddonFromWebpage without proper principal"); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + // principal + null, + GATED_SITE_PERM1 + ), + /aInstallingPrincipal must be a nsIPrincipal/, + "installSitePermsAddonFromWebpage rejected when called without a principal" + ); + + info( + "Call installSitePermsAddonFromWebpage with non-null, non-element browser" + ); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + "browser", + PRINCIPAL_COM, + GATED_SITE_PERM1 + ), + /aBrowser must be an Element, or null/, + "installSitePermsAddonFromWebpage rejected when called with a non-null, non-element browser" + ); + + info("Call installSitePermsAddonFromWebpage with unsecure principal"); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_UNSECURE, + GATED_SITE_PERM1 + ), + /SitePermsAddons can only be installed from secure origins/, + "installSitePermsAddonFromWebpage rejected when called with unsecure principal" + ); + + info( + "Call installSitePermsAddonFromWebpage for public principal and gated permission" + ); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_GITHUB, + GATED_SITE_PERM1 + ), + /SitePermsAddon can\'t be installed from public eTLDs/, + "installSitePermsAddonFromWebpage rejected when called with public principal" + ); + + info( + "Call installSitePermsAddonFromWebpage for a NullPrincipal as installingPrincipal" + ); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_NULL, + GATED_SITE_PERM1 + ), + /SitePermsAddons can\'t be installed from sandboxed subframes/, + "installSitePermsAddonFromWebpage rejected when called with a NullPrincipal as installing principal" + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 0, "there was no added addon..."); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_GITHUB, + GATED_SITE_PERM1 + ), + false, + "...and no new permission either" + ); + + info( + "Call installSitePermsAddonFromWebpage for plain-ip principal and gated permission" + ); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_IP, + GATED_SITE_PERM1 + ), + /SitePermsAddons install disallowed when the host is an IP address/, + "installSitePermsAddonFromWebpage rejected when called with plain-ip principal" + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 0, "there was no added addon..."); + Assert.equal( + PermissionTestUtils.testExactPermission(PRINCIPAL_IP, GATED_SITE_PERM1), + false, + "...and no new permission either" + ); + + info( + "Call installSitePermsAddonFromWebpage for authorized principal and non-gated permission" + ); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_COM, + NON_GATED_SITE_PERM + ), + new RegExp(`"${NON_GATED_SITE_PERM}" is not a gated permission`), + "installSitePermsAddonFromWebpage rejected for non-gated permission" + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 0, + "installSitePermsAddonFromWebpage with non-gated permission should not add the addon" + ); + + info("Call installSitePermsAddonFromWebpage blocked principals"); + const blockedDomainsPrincipals = { + [BLOCKED_DOMAIN]: BLOCKED_PRINCIPAL, + [BLOCKED_DOMAIN2]: BLOCKED_PRINCIPAL2, + }; + for (const blockedDomain of [BLOCKED_DOMAIN, BLOCKED_DOMAIN2]) { + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + blockedDomainsPrincipals[blockedDomain], + GATED_SITE_PERM1 + ), + /SitePermsAddons can\'t be installed/, + `installSitePermsAddonFromWebpage rejected when called with blocked domain principal: ${blockedDomainsPrincipals[blockedDomain].URI.spec}` + ); + await Assert.rejects( + AddonManager.installSitePermsAddonFromWebpage( + null, + ssm.createContentPrincipalFromOrigin(`https://sub.${blockedDomain}`), + GATED_SITE_PERM1 + ), + /SitePermsAddons can\'t be installed/, + `installSitePermsAddonFromWebpage rejected when called with blocked subdomain principal: https://sub.${blockedDomain}` + ); + } + + info( + "Call installSitePermsAddonFromWebpage for authorized principal and gated permission" + ); + expectAndHandleInstallPrompts(); + const onAddonInstalled = AddonTestUtils.promiseInstallEvent( + "onInstallEnded" + ).then(installs => installs?.[0]?.addon); + + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_COM, + GATED_SITE_PERM1 + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 1, + "installSitePermsAddonFromWebpage should add the addon..." + ); + Assert.equal( + PermissionTestUtils.testExactPermission(PRINCIPAL_COM, GATED_SITE_PERM1), + true, + "...and set the permission" + ); + + // The addon we get here is a SitePermsAddonInstalling instance, and we want to assert + // that its permissions are correct as it may impact addon uninstall later on + Assert.deepEqual( + (await onAddonInstalled).sitePermissions, + [GATED_SITE_PERM1], + "Addon has expected sitePermissions" + ); + + info( + "Call installSitePermsAddonFromWebpage for private browsing principal and gated permission" + ); + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_PRIVATEBROWSING, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + true, + "...and set the permission" + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "installSitePermsAddonFromWebpage should add the addon..." + ); + const [addonWithPrivateBrowsing] = addons.filter( + addon => addon.siteOrigin === PRINCIPAL_PRIVATEBROWSING.siteOriginNoSuffix + ); + Assert.equal( + addonWithPrivateBrowsing?.siteOrigin, + PRINCIPAL_PRIVATEBROWSING.siteOriginNoSuffix, + "Got an addon for the expected siteOriginNoSuffix value" + ); + await addonWithPrivateBrowsing.uninstall(); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + false, + "Uninstalling the addon should clear the permission for the private browsing principal" + ); + + info( + "Call installSitePermsAddonFromWebpage for user context isolated principal and gated permission" + ); + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_USERCONTEXT, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_USERCONTEXT, + GATED_SITE_PERM1 + ), + true, + "...and set the permission" + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "installSitePermsAddonFromWebpage should add the addon..." + ); + const [addonWithUserContextId] = addons.filter( + addon => addon.siteOrigin === PRINCIPAL_USERCONTEXT.siteOriginNoSuffix + ); + Assert.equal( + addonWithUserContextId?.siteOrigin, + PRINCIPAL_USERCONTEXT.siteOriginNoSuffix, + "Got an addon for the expected siteOriginNoSuffix value" + ); + await addonWithUserContextId.uninstall(); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_USERCONTEXT, + GATED_SITE_PERM1 + ), + false, + "Uninstalling the addon should clear the permission for the user context isolated principal" + ); + + info( + "Check calling installSitePermsAddonFromWebpage for same gated permission and same origin on different contexts" + ); + info("First call installSitePermsAddonFromWebpage on regular context"); + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ), + true, + "...and set the permission" + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_USERCONTEXT, + GATED_SITE_PERM1 + ), + // We expect the permission to not be set for user context if + // perms.isolateBy.userContext is set to true. + PERMS_ISOLATE_USERCONTEXT_ENABLED + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + `...and ${ + PERMS_ISOLATE_USERCONTEXT_ENABLED ? "not allowed" : "allowed" + } on the context user specific principal` + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + false, + "...but not on the private browsing principal" + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "installSitePermsAddonFromWebpage should add the addon..." + ); + const [addonMultipleContexts] = addons.filter( + addon => + addon.siteOrigin === + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR.siteOriginNoSuffix + ); + Assert.equal( + addonMultipleContexts?.siteOrigin, + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR.siteOriginNoSuffix, + "Got an addon for the expected siteOriginNoSuffix value" + ); + info("Then call installSitePermsAddonFromWebpage on private context"); + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + true, + "Permission is set for the private context" + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ), + true, + "...and still set on the regular principal" + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_USERCONTEXT, + GATED_SITE_PERM1 + ), + // We expect the permission to not be set for user context if + // perms.isolateBy.userContext is set to true. + PERMS_ISOLATE_USERCONTEXT_ENABLED + ? Services.perms.UNKNOWN_ACTION + : Services.perms.ALLOW_ACTION, + `...and ${ + PERMS_ISOLATE_USERCONTEXT_ENABLED ? "not allowed" : "allowed" + } on the context user specific principal` + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "installSitePermsAddonFromWebpage did not add a new addon" + ); + info("Then call installSitePermsAddonFromWebpage on specific user context"); + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_MULTIPLE_CONTEXTS_USERCONTEXT, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_USERCONTEXT, + GATED_SITE_PERM1 + ), + true, + "Permission is set for the user context" + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ), + true, + "...and still set on the regular principal" + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + true, + "...and on the private principal" + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "installSitePermsAddonFromWebpage did not add a new addon" + ); + + info( + "Uninstalling the addon should remove the permission on the different contexts" + ); + await addonMultipleContexts.uninstall(); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ), + false, + "Uninstalling the addon should clear the permission for regular principal..." + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + false, + "... as well as the private browsing one..." + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_USERCONTEXT, + GATED_SITE_PERM1 + ), + false, + "... and the user context one" + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 1, "addon was properly uninstalled"); + + info("Install the addon for the multiple context origin again"); + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ), + true, + "...and set the permission" + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "installSitePermsAddonFromWebpage should add the addon..." + ); + + info("Then call installSitePermsAddonFromWebpage on private context"); + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + true, + "Permission is set for the private context" + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 2, + "installSitePermsAddonFromWebpage did not add a new addon" + ); + + info("Remove the permission for the private context"); + PermissionTestUtils.remove( + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_PRIVATEBROWSING, + GATED_SITE_PERM1 + ), + false, + "Permission is removed for the private context..." + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 2, "... but it didn't uninstall the addon"); + + info("Remove the permission for the regular context"); + PermissionTestUtils.remove( + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ); + Assert.equal( + PermissionTestUtils.testExactPermission( + PRINCIPAL_MULTIPLE_CONTEXTS_REGULAR, + GATED_SITE_PERM1 + ), + false, + "Permission is removed for the regular context..." + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 1, "...and addon is uninstalled"); + + await addons[0]?.uninstall(); + } +); + +add_task( + { + pref_set: [[SITEPERMS_ADDON_PROVIDER_PREF, true]], + }, + async function test_salted_hash_addon_id() { + // Make sure the test will also be able to run if it is the only one executed. + Services.obs.notifyObservers(null, "ipc:first-content-process-created"); + ok( + AddonManager.hasProvider("SitePermsAddonProvider"), + "Expect SitePermsAddonProvider to be registered" + ); + // Make sure no sitepermission addon is already installed. + let addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 0, "There's no addons"); + + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_COM, + GATED_SITE_PERM1 + ); + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal( + addons.length, + 1, + "installSitePermsAddonFromWebpage should add the addon..." + ); + Assert.equal( + PermissionTestUtils.testExactPermission(PRINCIPAL_COM, GATED_SITE_PERM1), + true, + "...and set the permission" + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 1, "There is an addon installed"); + + const firstSaltedAddonId = addons[0].id; + ok(firstSaltedAddonId, "Got the first addon id"); + + info("Verify addon id after mocking new browsing session"); + + const { generateSalt } = ChromeUtils.importESModule( + "resource://gre/modules/addons/SitePermsAddonProvider.sys.mjs" + ); + generateSalt(); + + await promiseRestartManager(); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 1, "There is an addon installed"); + + const secondSaltedAddonId = addons[0].id; + ok( + secondSaltedAddonId, + "Got the second addon id after mocking new browsing session" + ); + + Assert.notEqual( + firstSaltedAddonId, + secondSaltedAddonId, + "The two addon ids are different" + ); + + // Confirm that new installs from the same siteOrigin will still + // belong to the existing addon entry while the salt isn't expected + // to have changed. + expectAndHandleInstallPrompts(); + await AddonManager.installSitePermsAddonFromWebpage( + null, + PRINCIPAL_COM, + GATED_SITE_PERM1 + ); + + addons = await promiseAddonsByTypes([SITEPERMS_ADDON_TYPE]); + Assert.equal(addons.length, 1, "There is still a single addon installed"); + + await addons[0]?.uninstall(); + } +); |