src/amo/components/PermissionsCard/permissions.js (117 lines of code) (raw):
/* @flow */
import * as React from 'react';
import log from 'amo/logger';
import HostPermissions from 'amo/components/HostPermissions';
import Permission from 'amo/components/Permission';
import type { AddonFileType } from 'amo/reducers/versions';
import type { I18nType } from 'amo/types/i18n';
export type GetCurrentPermissionsParams = {|
file: AddonFileType,
|};
/* eslint-disable no-continue */
export class PermissionUtils {
i18n: I18nType;
permissionStrings: Object;
constructor(i18n: I18nType) {
this.i18n = i18n;
// These should be kept in sync with Firefox's strings for webextension
// permissions which can be found in:
// https://searchfox.org/mozilla-central/rev/b0b003e992b199fd8e13999bd5d06d06c84a3fd2/toolkit/components/extensions/ExtensionPermissionMessages.sys.mjs#32
// https://searchfox.org/mozilla-central/rev/b0b003e992b199fd8e13999bd5d06d06c84a3fd2/toolkit/locales/en-US/toolkit/global/extensionPermissions.ftl
this.permissionStrings = {
bookmarks: i18n.gettext('Read and modify bookmarks'),
browserSettings: i18n.gettext('Read and modify browser settings'),
browsingData: i18n.gettext(
'Clear recent browsing history, cookies, and related data',
),
clipboardRead: i18n.gettext('Get data from the clipboard'),
clipboardWrite: i18n.gettext('Input data to the clipboard'),
declarativeNetRequest: i18n.gettext('Block content on any page'),
declarativeNetRequestFeedback: i18n.gettext('Read your browsing history'),
devtools: i18n.gettext(
'Extend developer tools to access your data in open tabs',
),
downloads: i18n.gettext(
'Download files and read and modify the browser’s download history',
),
'downloads.open': i18n.gettext('Open files downloaded to your computer'),
find: i18n.gettext('Read the text of all open tabs'),
geolocation: i18n.gettext('Access your location'),
history: i18n.gettext('Access browsing history'),
management: i18n.gettext('Monitor extension usage and manage themes'),
// In Firefox the following message replaces the name "Firefox" with the
// current brand name, e.g., "Nightly", but we do not need to do that.
nativeMessaging: i18n.gettext(
'Exchange messages with programs other than Firefox',
),
notifications: i18n.gettext('Display notifications to you'),
pkcs11: i18n.gettext('Provide cryptographic authentication services'),
proxy: i18n.gettext('Control browser proxy settings'),
privacy: i18n.gettext('Read and modify privacy settings'),
sessions: i18n.gettext('Access recently closed tabs'),
tabs: i18n.gettext('Access browser tabs'),
tabHide: i18n.gettext('Hide and show browser tabs'),
topSites: i18n.gettext('Access browsing history'),
webNavigation: i18n.gettext('Access browser activity during navigation'),
};
}
// Get lists of optional and required permissions from the correct platform file.
getCurrentPermissions({ file }: GetCurrentPermissionsParams): {
optional: Array<string>,
required: Array<string>,
} {
const permissions = {
optional: [],
required: [],
};
if (!file) {
log.debug('getCurrentPermissions() called with no file');
return permissions;
}
const hostPermissions = file.host_permissions || [];
permissions.optional = [...file.optional_permissions, ...hostPermissions];
permissions.required = file.permissions;
return permissions;
}
// Classify a permission as a host permission or a regular permission.
classifyPermission(permission: string): {|
type: 'permissions' | 'hosts',
value: string,
|} {
const match = /^(\w+)(?:\.(\w+)(?:\.\w+)*)?$/.exec(permission);
let result = { type: 'permissions', value: permission };
if (!match) {
result = { type: 'hosts', value: permission };
}
return result;
}
// Format and sequence all the Permission components.
formatPermissions(addonPermissions: Array<string>): Array<React.Node> {
const permissionsToDisplay = [];
const permissions = { hosts: [], permissions: [] };
// First, categorize them into host permissions and regular permissions.
for (const permission of addonPermissions) {
const { type, value } = this.classifyPermission(permission);
permissions[type].push(value);
}
// Next, show the native messaging permission if it is present.
const nativeMessagingPermission = 'nativeMessaging';
if (permissions.permissions.includes(nativeMessagingPermission)) {
permissionsToDisplay.push(
<Permission
type={nativeMessagingPermission}
description={this.permissionStrings[nativeMessagingPermission]}
key={nativeMessagingPermission}
/>,
);
}
// Next, show remaining permissions, sorted alphabetically by the
// permission string to match Firefox.
const permissionsCopy = permissions.permissions.slice(0);
for (const permission of permissionsCopy.sort()) {
// nativeMessaging is handled above.
if (permission === 'nativeMessaging') {
// eslint-disable-next-line no-continue
continue;
}
// Only output a permission if we have a string defined for it.
if (this.permissionStrings[permission]) {
permissionsToDisplay.push(
<Permission
type={permission}
description={this.permissionStrings[permission]}
key={permission}
/>,
);
}
}
// Finally, Add the host permissions.
if (permissions.hosts.length) {
permissionsToDisplay.push(
<HostPermissions permissions={permissions.hosts} />,
);
}
return permissionsToDisplay;
}
}