diff options
Diffstat (limited to 'toolkit/components/extensions/parent/ext-permissions.js')
-rw-r--r-- | toolkit/components/extensions/parent/ext-permissions.js | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/toolkit/components/extensions/parent/ext-permissions.js b/toolkit/components/extensions/parent/ext-permissions.js new file mode 100644 index 0000000000..8639381de7 --- /dev/null +++ b/toolkit/components/extensions/parent/ext-permissions.js @@ -0,0 +1,191 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.sys.mjs", +}); + +var { ExtensionError } = ExtensionUtils; + +XPCOMUtils.defineLazyPreferenceGetter( + this, + "promptsEnabled", + "extensions.webextOptionalPermissionPrompts" +); + +function normalizePermissions(perms) { + perms = { ...perms }; + perms.permissions = perms.permissions.filter( + perm => !perm.startsWith("internal:") + ); + return perms; +} + +this.permissions = class extends ExtensionAPIPersistent { + PERSISTENT_EVENTS = { + onAdded({ fire }) { + let { extension } = this; + let callback = (event, change) => { + if (change.extensionId == extension.id && change.added) { + let perms = normalizePermissions(change.added); + if (perms.permissions.length || perms.origins.length) { + fire.async(perms); + } + } + }; + + extensions.on("change-permissions", callback); + return { + unregister() { + extensions.off("change-permissions", callback); + }, + convert(_fire) { + fire = _fire; + }, + }; + }, + onRemoved({ fire }) { + let { extension } = this; + let callback = (event, change) => { + if (change.extensionId == extension.id && change.removed) { + let perms = normalizePermissions(change.removed); + if (perms.permissions.length || perms.origins.length) { + fire.async(perms); + } + } + }; + + extensions.on("change-permissions", callback); + return { + unregister() { + extensions.off("change-permissions", callback); + }, + convert(_fire) { + fire = _fire; + }, + }; + }, + }; + + getAPI(context) { + let { extension } = context; + + return { + permissions: { + async request(perms) { + let { permissions, origins } = perms; + + let { optionalPermissions } = context.extension; + for (let perm of permissions) { + if (!optionalPermissions.includes(perm)) { + throw new ExtensionError( + `Cannot request permission ${perm} since it was not declared in optional_permissions` + ); + } + } + + let optionalOrigins = context.extension.optionalOrigins; + for (let origin of origins) { + if (!optionalOrigins.subsumes(new MatchPattern(origin))) { + throw new ExtensionError( + `Cannot request origin permission for ${origin} since it was not declared in the manifest` + ); + } + } + + if (promptsEnabled) { + permissions = permissions.filter( + perm => !context.extension.hasPermission(perm) + ); + origins = origins.filter( + origin => + !context.extension.allowedOrigins.subsumes( + new MatchPattern(origin) + ) + ); + + if (!permissions.length && !origins.length) { + return true; + } + + let browser = context.pendingEventBrowser || context.xulBrowser; + let allow = await new Promise(resolve => { + let subject = { + wrappedJSObject: { + browser, + name: context.extension.name, + id: context.extension.id, + icon: context.extension.getPreferredIcon(32), + permissions: { permissions, origins }, + resolve, + }, + }; + Services.obs.notifyObservers( + subject, + "webextension-optional-permission-prompt" + ); + }); + if (!allow) { + return false; + } + } + + await ExtensionPermissions.add(extension.id, perms, extension); + return true; + }, + + async getAll() { + let perms = normalizePermissions(context.extension.activePermissions); + delete perms.apis; + return perms; + }, + + async contains(permissions) { + for (let perm of permissions.permissions) { + if (!context.extension.hasPermission(perm)) { + return false; + } + } + + for (let origin of permissions.origins) { + if ( + !context.extension.allowedOrigins.subsumes( + new MatchPattern(origin) + ) + ) { + return false; + } + } + + return true; + }, + + async remove(permissions) { + await ExtensionPermissions.remove( + extension.id, + permissions, + extension + ); + return true; + }, + + onAdded: new EventManager({ + context, + module: "permissions", + event: "onAdded", + extensionApi: this, + }).api(), + + onRemoved: new EventManager({ + context, + module: "permissions", + event: "onRemoved", + extensionApi: this, + }).api(), + }, + }; + } +}; |