summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_permissions_api.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_permissions_api.js')
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_permissions_api.js464
1 files changed, 464 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_permissions_api.js b/toolkit/components/extensions/test/xpcshell/test_ext_permissions_api.js
new file mode 100644
index 0000000000..526f0a720e
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_permissions_api.js
@@ -0,0 +1,464 @@
+"use strict";
+
+const { AddonManager } = ChromeUtils.importESModule(
+ "resource://gre/modules/AddonManager.sys.mjs"
+);
+const { ExtensionPermissions } = ChromeUtils.importESModule(
+ "resource://gre/modules/ExtensionPermissions.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ ExtensionParent: "resource://gre/modules/ExtensionParent.sys.mjs",
+});
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "42"
+);
+
+let OptionalPermissions;
+
+add_task(async function setup() {
+ // Bug 1646182: Force ExtensionPermissions to run in rkv mode, the legacy
+ // storage mode will run in xpcshell-legacy-ep.ini
+ await ExtensionPermissions._uninit();
+
+ Services.prefs.setBoolPref(
+ "extensions.webextOptionalPermissionPrompts",
+ false
+ );
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("extensions.webextOptionalPermissionPrompts");
+ });
+ await AddonTestUtils.promiseStartupManager();
+ AddonTestUtils.usePrivilegedSignatures = false;
+
+ // We want to get a list of optional permissions prior to loading an extension,
+ // so we'll get ExtensionParent to do that for us.
+ await ExtensionParent.apiManager.lazyInit();
+
+ // These permissions have special behaviors and/or are not mapped directly to an
+ // api namespace. They will have their own tests for specific behavior.
+ let ignore = [
+ "activeTab",
+ "clipboardRead",
+ "clipboardWrite",
+ "declarativeNetRequestFeedback",
+ "devtools",
+ "downloads.open",
+ "geolocation",
+ "management",
+ "menus.overrideContext",
+ "nativeMessaging",
+ "scripting",
+ "search",
+ "tabHide",
+ "tabs",
+ "webRequestBlocking",
+ "webRequestFilterResponse",
+ "webRequestFilterResponse.serviceWorkerScript",
+ ];
+ OptionalPermissions = Schemas.getPermissionNames([
+ "OptionalPermission",
+ "OptionalPermissionNoPrompt",
+ ]).filter(n => !ignore.includes(n));
+});
+
+add_task(async function test_api_on_permissions_changed() {
+ async function background() {
+ let manifest = browser.runtime.getManifest();
+ let permObj = { permissions: manifest.optional_permissions, origins: [] };
+
+ function verifyPermissions(enabled) {
+ for (let perm of manifest.optional_permissions) {
+ browser.test.assertEq(
+ enabled,
+ !!browser[perm],
+ `${perm} API is ${
+ enabled ? "injected" : "removed"
+ } after permission request`
+ );
+ }
+ }
+
+ browser.permissions.onAdded.addListener(details => {
+ browser.test.assertEq(
+ JSON.stringify(details.permissions),
+ JSON.stringify(manifest.optional_permissions),
+ "expected permissions added"
+ );
+ verifyPermissions(true);
+ browser.test.sendMessage("added");
+ });
+
+ browser.permissions.onRemoved.addListener(details => {
+ browser.test.assertEq(
+ JSON.stringify(details.permissions),
+ JSON.stringify(manifest.optional_permissions),
+ "expected permissions removed"
+ );
+ verifyPermissions(false);
+ browser.test.sendMessage("removed");
+ });
+
+ browser.test.onMessage.addListener((msg, enabled) => {
+ if (msg === "request") {
+ browser.permissions.request(permObj);
+ } else if (msg === "verify_access") {
+ verifyPermissions(enabled);
+ browser.test.sendMessage("verified");
+ } else if (msg === "revoke") {
+ browser.permissions.remove(permObj);
+ }
+ });
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ optional_permissions: OptionalPermissions,
+ },
+ useAddonManager: "permanent",
+ });
+ await extension.startup();
+
+ function addPermissions() {
+ extension.sendMessage("request");
+ return extension.awaitMessage("added");
+ }
+
+ function removePermissions() {
+ extension.sendMessage("revoke");
+ return extension.awaitMessage("removed");
+ }
+
+ function verifyPermissions(enabled) {
+ extension.sendMessage("verify_access", enabled);
+ return extension.awaitMessage("verified");
+ }
+
+ await withHandlingUserInput(extension, async () => {
+ await addPermissions();
+ await removePermissions();
+ await addPermissions();
+ });
+
+ // reset handlingUserInput for the restart
+ extensionHandlers.delete(extension);
+
+ // Verify access on restart
+ await AddonTestUtils.promiseRestartManager();
+ await extension.awaitBackgroundStarted();
+ await verifyPermissions(true);
+
+ await withHandlingUserInput(extension, async () => {
+ await removePermissions();
+ });
+
+ // Add private browsing to be sure it doesn't come through.
+ let permObj = {
+ permissions: OptionalPermissions.concat("internal:privateBrowsingAllowed"),
+ origins: [],
+ };
+
+ // enable the permissions while the addon is running
+ await ExtensionPermissions.add(extension.id, permObj, extension.extension);
+ await extension.awaitMessage("added");
+ await verifyPermissions(true);
+
+ // disable the permissions while the addon is running
+ await ExtensionPermissions.remove(extension.id, permObj, extension.extension);
+ await extension.awaitMessage("removed");
+ await verifyPermissions(false);
+
+ // Add private browsing to test internal permission. If it slips through,
+ // we would get an error for an additional added message.
+ await ExtensionPermissions.add(
+ extension.id,
+ { permissions: ["internal:privateBrowsingAllowed"], origins: [] },
+ extension.extension
+ );
+
+ // disable the addon and re-test revoking permissions.
+ await withHandlingUserInput(extension, async () => {
+ await addPermissions();
+ });
+ let addon = await AddonManager.getAddonByID(extension.id);
+ await addon.disable();
+ await ExtensionPermissions.remove(extension.id, permObj);
+ await addon.enable();
+ await extension.awaitStartup();
+
+ await verifyPermissions(false);
+ let perms = await ExtensionPermissions.get(extension.id);
+ equal(perms.permissions.length, 0, "no permissions on startup");
+
+ await extension.unload();
+});
+
+add_task(async function test_geo_permissions() {
+ async function background() {
+ const permObj = { permissions: ["geolocation"] };
+ browser.test.onMessage.addListener(async msg => {
+ if (msg === "request") {
+ await browser.permissions.request(permObj);
+ } else if (msg === "remove") {
+ await browser.permissions.remove(permObj);
+ }
+ let result = await browser.permissions.contains(permObj);
+ browser.test.sendMessage("done", result);
+ });
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ browser_specific_settings: { gecko: { id: "geo-test@test" } },
+ optional_permissions: ["geolocation"],
+ },
+ useAddonManager: "permanent",
+ });
+ await extension.startup();
+
+ let policy = WebExtensionPolicy.getByID(extension.id);
+ let principal = policy.extension.principal;
+ equal(
+ Services.perms.testPermissionFromPrincipal(principal, "geo"),
+ Services.perms.UNKNOWN_ACTION,
+ "geolocation not allowed on install"
+ );
+
+ await withHandlingUserInput(extension, async () => {
+ extension.sendMessage("request");
+ ok(await extension.awaitMessage("done"), "permission granted");
+ equal(
+ Services.perms.testPermissionFromPrincipal(principal, "geo"),
+ Services.perms.ALLOW_ACTION,
+ "geolocation allowed after requested"
+ );
+
+ extension.sendMessage("remove");
+ ok(!(await extension.awaitMessage("done")), "permission revoked");
+
+ equal(
+ Services.perms.testPermissionFromPrincipal(principal, "geo"),
+ Services.perms.UNKNOWN_ACTION,
+ "geolocation not allowed after removed"
+ );
+
+ // re-grant to test update removal
+ extension.sendMessage("request");
+ ok(await extension.awaitMessage("done"), "permission granted");
+ equal(
+ Services.perms.testPermissionFromPrincipal(principal, "geo"),
+ Services.perms.ALLOW_ACTION,
+ "geolocation allowed after re-requested"
+ );
+ });
+
+ // We should not have geo permission after this upgrade.
+ await extension.upgrade({
+ manifest: {
+ browser_specific_settings: { gecko: { id: "geo-test@test" } },
+ },
+ useAddonManager: "permanent",
+ });
+
+ equal(
+ Services.perms.testPermissionFromPrincipal(principal, "geo"),
+ Services.perms.UNKNOWN_ACTION,
+ "geolocation not allowed after upgrade"
+ );
+
+ await extension.unload();
+});
+
+add_task(async function test_browserSetting_permissions() {
+ async function background() {
+ const permObj = { permissions: ["browserSettings"] };
+ browser.test.onMessage.addListener(async msg => {
+ if (msg === "request") {
+ await browser.permissions.request(permObj);
+ await browser.browserSettings.cacheEnabled.set({ value: false });
+ } else if (msg === "remove") {
+ await browser.permissions.remove(permObj);
+ }
+ browser.test.sendMessage("done");
+ });
+ }
+
+ function cacheIsEnabled() {
+ return (
+ Services.prefs.getBoolPref("browser.cache.disk.enable") &&
+ Services.prefs.getBoolPref("browser.cache.memory.enable")
+ );
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ optional_permissions: ["browserSettings"],
+ },
+ useAddonManager: "permanent",
+ });
+ await extension.startup();
+ ok(cacheIsEnabled(), "setting is not set after startup");
+
+ await withHandlingUserInput(extension, async () => {
+ extension.sendMessage("request");
+ await extension.awaitMessage("done");
+ ok(!cacheIsEnabled(), "setting was set after request");
+
+ extension.sendMessage("remove");
+ await extension.awaitMessage("done");
+ ok(cacheIsEnabled(), "setting is reset after remove");
+
+ extension.sendMessage("request");
+ await extension.awaitMessage("done");
+ ok(!cacheIsEnabled(), "setting was set after request");
+ });
+
+ await ExtensionPermissions._uninit();
+ extensionHandlers.delete(extension);
+ await AddonTestUtils.promiseRestartManager();
+ await extension.awaitBackgroundStarted();
+
+ await withHandlingUserInput(extension, async () => {
+ extension.sendMessage("remove");
+ await extension.awaitMessage("done");
+ ok(cacheIsEnabled(), "setting is reset after remove");
+ });
+
+ await extension.unload();
+});
+
+add_task(async function test_privacy_permissions() {
+ async function background() {
+ const permObj = { permissions: ["privacy"] };
+ browser.test.onMessage.addListener(async msg => {
+ if (msg === "request") {
+ await browser.permissions.request(permObj);
+ await browser.privacy.websites.trackingProtectionMode.set({
+ value: "always",
+ });
+ } else if (msg === "remove") {
+ await browser.permissions.remove(permObj);
+ }
+ browser.test.sendMessage("done");
+ });
+ }
+
+ function hasSetting() {
+ return Services.prefs.getBoolPref("privacy.trackingprotection.enabled");
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ optional_permissions: ["privacy"],
+ },
+ useAddonManager: "permanent",
+ });
+ await extension.startup();
+ ok(!hasSetting(), "setting is not set after startup");
+
+ await withHandlingUserInput(extension, async () => {
+ extension.sendMessage("request");
+ await extension.awaitMessage("done");
+ ok(hasSetting(), "setting was set after request");
+
+ extension.sendMessage("remove");
+ await extension.awaitMessage("done");
+ ok(!hasSetting(), "setting is reset after remove");
+
+ extension.sendMessage("request");
+ await extension.awaitMessage("done");
+ ok(hasSetting(), "setting was set after request");
+ });
+
+ await ExtensionPermissions._uninit();
+ extensionHandlers.delete(extension);
+ await AddonTestUtils.promiseRestartManager();
+ await extension.awaitBackgroundStarted();
+
+ await withHandlingUserInput(extension, async () => {
+ extension.sendMessage("remove");
+ await extension.awaitMessage("done");
+ ok(!hasSetting(), "setting is reset after remove");
+ });
+
+ await extension.unload();
+});
+
+add_task(
+ { pref_set: [["extensions.eventPages.enabled", true]] },
+ async function test_permissions_event_page() {
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "permanent",
+ manifest: {
+ optional_permissions: ["privacy"],
+ background: { persistent: false },
+ },
+ background() {
+ browser.permissions.onAdded.addListener(details => {
+ browser.test.sendMessage("added", details);
+ });
+
+ browser.permissions.onRemoved.addListener(details => {
+ browser.test.sendMessage("removed", details);
+ });
+ },
+ });
+
+ await extension.startup();
+ let events = ["onAdded", "onRemoved"];
+ for (let event of events) {
+ assertPersistentListeners(extension, "permissions", event, {
+ primed: false,
+ });
+ }
+
+ await extension.terminateBackground();
+ for (let event of events) {
+ assertPersistentListeners(extension, "permissions", event, {
+ primed: true,
+ });
+ }
+
+ let permObj = {
+ permissions: ["privacy"],
+ origins: [],
+ };
+
+ // enable the permissions while the background is stopped
+ await ExtensionPermissions.add(extension.id, permObj, extension.extension);
+ let details = await extension.awaitMessage("added");
+ Assert.deepEqual(permObj, details, "got added event");
+
+ // Restart and test that permission removal wakes the background.
+ await AddonTestUtils.promiseRestartManager();
+ await extension.awaitStartup();
+
+ for (let event of events) {
+ assertPersistentListeners(extension, "permissions", event, {
+ primed: true,
+ });
+ }
+
+ // remove the permissions while the background is stopped
+ await ExtensionPermissions.remove(
+ extension.id,
+ permObj,
+ extension.extension
+ );
+
+ details = await extension.awaitMessage("removed");
+ Assert.deepEqual(permObj, details, "got removed event");
+
+ await extension.unload();
+ }
+);