summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/parent/ext-permissions.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/parent/ext-permissions.js')
-rw-r--r--toolkit/components/extensions/parent/ext-permissions.js191
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(),
+ },
+ };
+ }
+};