diff options
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_site_permissions.js')
-rw-r--r-- | toolkit/components/extensions/test/xpcshell/test_site_permissions.js | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_site_permissions.js b/toolkit/components/extensions/test/xpcshell/test_site_permissions.js new file mode 100644 index 0000000000..652c9ae3ac --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_site_permissions.js @@ -0,0 +1,385 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +// TODO(Bug 1789718): adapt to synthetic addon type implemented by the SitePermAddonProvider +// or remove if redundant, after the deprecated XPIProvider-based implementation is also removed. + +const { AddonManager } = ChromeUtils.importESModule( + "resource://gre/modules/AddonManager.sys.mjs" +); +const { TestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TestUtils.sys.mjs" +); + +const { TelemetryController } = ChromeUtils.importESModule( + "resource://gre/modules/TelemetryController.sys.mjs" +); +const { TelemetryTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TelemetryTestUtils.sys.mjs" +); + +AddonTestUtils.init(this); +AddonTestUtils.overrideCertDB(); +AddonTestUtils.createAppInfo( + "xpcshell@tests.mozilla.org", + "XPCShell", + "42", + "42" +); + +const l10n = new Localization([ + "toolkit/global/extensions.ftl", + "toolkit/global/extensionPermissions.ftl", + "branding/brand.ftl", +]); +// Localization resources need to be first iterated outside a test +l10n.formatValue("webext-perms-sideload-text"); + +// Lazily import ExtensionParent to allow AddonTestUtils.createAppInfo to +// override Services.appinfo. +ChromeUtils.defineESModuleGetters(this, { + ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs", +}); + +async function _test_manifest(manifest, expectedError) { + ExtensionTestUtils.failOnSchemaWarnings(false); + let normalized = await ExtensionTestUtils.normalizeManifest( + manifest, + "manifest.WebExtensionSitePermissionsManifest" + ); + ExtensionTestUtils.failOnSchemaWarnings(true); + + if (expectedError) { + ok( + normalized.error.includes(expectedError), + `The manifest error ${JSON.stringify( + normalized.error + )} must contain ${JSON.stringify(expectedError)}` + ); + } else { + equal(normalized.error, undefined, "Should not have an error"); + } + equal(normalized.errors.length, 0, "Should have no warning"); +} + +add_setup(async () => { + // Telemetry test setup needed to ensure that the builtin events are defined + // and they can be collected and verified. + await TelemetryController.testSetup(); + + // This is actually only needed on Android, because it does not properly support unified telemetry + // and so, if not enabled explicitly here, it would make these tests to fail when running on + // release builds. + const oldCanRecordBase = Services.telemetry.canRecordBase; + Services.telemetry.canRecordBase = true; + registerCleanupFunction(() => { + Services.telemetry.canRecordBase = oldCanRecordBase; + }); +}); + +add_task(async function test_manifest_site_permissions() { + await _test_manifest({ + site_permissions: ["midi"], + install_origins: ["http://example.com"], + }); + await _test_manifest({ + site_permissions: ["midi-sysex"], + install_origins: ["http://example.com"], + }); + await _test_manifest( + { + site_permissions: ["unknown_site_permission"], + install_origins: ["http://example.com"], + }, + `Error processing site_permissions.0: Invalid enumeration value "unknown_site_permission"` + ); + await _test_manifest( + { + site_permissions: ["unknown_site_permission"], + install_origins: [], + }, + `Error processing install_origins: Array requires at least 1 items;` + ); + await _test_manifest( + { + site_permissions: ["unknown_site_permission"], + }, + `Property "install_origins" is required` + ); + await _test_manifest( + { + install_origins: ["http://example.com"], + }, + `Property "site_permissions" is required` + ); + // test any extra manifest entries not part of a site permissions addon will cause an error. + await _test_manifest( + { + site_permissions: ["midi"], + install_origins: ["http://example.com"], + permissions: ["webRequest"], + }, + `Unexpected property` + ); +}); + +add_task(async function test_sitepermission_telemetry() { + await AddonTestUtils.promiseStartupManager(); + + Services.telemetry.clearEvents(); + + const addon_id = "webmidi@test"; + const origin = "https://example.com"; + const permName = "midi"; + + let site_permission = { + "manifest.json": { + name: "test Site Permission", + version: "1.0", + manifest_version: 2, + browser_specific_settings: { + gecko: { id: addon_id }, + }, + install_origins: [origin], + site_permissions: [permName], + }, + }; + + let [, { addon }] = await Promise.all([ + TestUtils.topicObserved("webextension-sitepermissions-startup"), + AddonTestUtils.promiseInstallXPI(site_permission), + ]); + + await addon.uninstall(); + + await TelemetryTestUtils.assertEvents( + [ + [ + "addonsManager", + "install", + "siteperm_deprecated", + /.*/, + { + step: "started", + addon_id, + }, + ], + [ + "addonsManager", + "install", + "siteperm_deprecated", + /.*/, + { + step: "completed", + addon_id, + }, + ], + ["addonsManager", "uninstall", "siteperm_deprecated", addon_id], + ], + { + category: "addonsManager", + method: /^install|uninstall$/, + } + ); + + await AddonTestUtils.promiseShutdownManager(); +}); + +async function _test_ext_site_permissions(site_permissions, install_origins) { + ExtensionTestUtils.failOnSchemaWarnings(false); + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + install_origins, + site_permissions, + }, + }); + await extension.startup(); + await extension.unload(); + ExtensionTestUtils.failOnSchemaWarnings(true); +} + +add_task(async function test_ext_site_permissions() { + await _test_ext_site_permissions(["midi"], ["http://example.com"]); + + await _test_ext_site_permissions( + ["midi"], + ["http://example.com", "http://foo.com"] + ).catch(e => { + Assert.ok( + e.message.includes( + "Error processing install_origins: Array requires at most 1 items; you have 2" + ), + "Site permissions can only contain one install origin: " + ); + }); +}); + +add_task(async function test_sitepermission_type() { + await AddonTestUtils.promiseStartupManager(); + + // Test more than one perm to make sure both are added. + // While this is allowed, midi-sysex overrides. + let perms = ["midi", "midi-sysex"]; + let id = "@test-permission"; + let origin = "http://example.com"; + let uri = Services.io.newURI(origin); + let principal = Services.scriptSecurityManager.createContentPrincipal( + uri, + {} + ); + + // give the site some other permission (geo) + Services.perms.addFromPrincipal( + principal, + "geo", + Services.perms.ALLOW_ACTION, + Services.perms.EXPIRE_NEVER + ); + + let assertGeo = () => { + Assert.equal( + Services.perms.testExactPermissionFromPrincipal(principal, "geo"), + Ci.nsIPermissionManager.ALLOW_ACTION, + "site still has geo permission" + ); + }; + + let checkPerms = (perms, action, msg) => { + for (let permName of perms) { + let permission = Services.perms.testExactPermissionFromPrincipal( + principal, + permName + ); + Assert.equal(permission, action, `${permName}: ${msg}`); + } + }; + + checkPerms( + perms, + Ci.nsIPermissionManager.UNKNOWN_ACTION, + "no permission for site" + ); + + let site_permission = { + "manifest.json": { + name: "test Site Permission", + version: "1.0", + manifest_version: 2, + browser_specific_settings: { + gecko: { + id, + }, + }, + install_origins: [origin], + site_permissions: perms, + }, + }; + + let [, { addon }] = await Promise.all([ + TestUtils.topicObserved("webextension-sitepermissions-startup"), + AddonTestUtils.promiseInstallXPI(site_permission), + ]); + + checkPerms( + perms, + Ci.nsIPermissionManager.ALLOW_ACTION, + "extension enabled permission for site" + ); + assertGeo(); + + // Test the permission is retained on restart. + await AddonTestUtils.promiseRestartManager(); + addon = await AddonManager.getAddonByID(id); + + checkPerms( + perms, + Ci.nsIPermissionManager.ALLOW_ACTION, + "extension enabled permission for site" + ); + assertGeo(); + + // Test that a removed permission is added on restart + Services.perms.removeFromPrincipal(principal, perms[0]); + await AddonTestUtils.promiseRestartManager(); + addon = await AddonManager.getAddonByID(id); + + checkPerms( + perms, + Ci.nsIPermissionManager.ALLOW_ACTION, + "extension enabled permission for site" + ); + assertGeo(); + + // Test that a changed permission is not changed on restart + Services.perms.addFromPrincipal( + principal, + perms[0], + Services.perms.DENY_ACTION, + Services.perms.EXPIRE_NEVER + ); + + await AddonTestUtils.promiseRestartManager(); + addon = await AddonManager.getAddonByID(id); + + checkPerms( + [perms[0]], + Ci.nsIPermissionManager.DENY_ACTION, + "extension enabled permission for site" + ); + checkPerms( + [perms[1]], + Ci.nsIPermissionManager.ALLOW_ACTION, + "extension enabled permission for site" + ); + assertGeo(); + + // Test permission removal when addon disabled + await addon.disable(); + + checkPerms( + perms, + Ci.nsIPermissionManager.UNKNOWN_ACTION, + "no permission for site" + ); + assertGeo(); + + // Enabling an addon will always force ALLOW_ACTION + await addon.enable(); + + checkPerms( + perms, + Ci.nsIPermissionManager.ALLOW_ACTION, + "extension enabled permission for site" + ); + assertGeo(); + + // Test permission removal when addon uninstalled + await addon.uninstall(); + + checkPerms( + perms, + Ci.nsIPermissionManager.UNKNOWN_ACTION, + "no permission for site" + ); + assertGeo(); +}); + +add_task(async function test_site_permissions_have_localization_strings() { + await ExtensionParent.apiManager.lazyInit(); + const SCHEMA_SITE_PERMISSIONS = Schemas.getPermissionNames([ + "SitePermission", + ]); + ok(SCHEMA_SITE_PERMISSIONS.length, "we have site permissions"); + + for (const perm of SCHEMA_SITE_PERMISSIONS) { + const l10nId = `webext-site-perms-${perm}`; + try { + const str = await l10n.formatValue(l10nId); + + ok(str.length, `Found localization string for '${perm}' site permission`); + } catch (e) { + ok(false, `Site permission missing '${perm}'`); + } + } +}); |