mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 04:09:50 +00:00
Bug 1793557 - Convert Extension.jsm strings to Fluent. r=mkmelin,geckoview-reviewers,robwu,flod,owlish
This changes the arguments of `ExtensionData.formatPermissionStrings()`. The second `bundle` arg is dropped, and a `localization` option is added. Call sites in m-c are updated, but this will also need a matching update for Thunderbird. A few Thunderbird test cases will also need to be updated, as they currently point to a non-existing localization file paths "messenger/addons.ftl" and "messenger/addonPermissions.ftl". As discussed at the addon workweek, the Fluent l10n keys for extension permissions match the pattern: webext-perms-description-{name} where `{name}` is the permission's sanitized name. A fluent-lint exception is added for the capitalization of these generated names. To allow for message updates and subsequent l10n identifier updates, a `PERMISSION_L10N_ID_OVERRIDES` map is provided. Because Fluent localization keys are not enumerable and attempting to format a missing key is an error, the `PERMISSIONS_WITH_MESSAGE` set must be kept in sync with message updates. Differential Revision: https://phabricator.services.mozilla.com/D158663
This commit is contained in:
parent
e281133e36
commit
411a529019
@ -179,8 +179,8 @@ add_task(async function test_sideloading() {
|
||||
panel,
|
||||
/\/foo-icon\.png$/,
|
||||
[
|
||||
["webextPerms.hostDescription.allUrls"],
|
||||
["webextPerms.description.history"],
|
||||
["webext-perms-host-description-all-urls"],
|
||||
["webext-perms-description-history"],
|
||||
],
|
||||
kSideloaded
|
||||
);
|
||||
@ -229,7 +229,7 @@ add_task(async function test_sideloading() {
|
||||
checkNotification(
|
||||
panel,
|
||||
DEFAULT_ICON_URL,
|
||||
[["webextPerms.hostDescription.allUrls"]],
|
||||
[["webext-perms-host-description-all-urls"]],
|
||||
kSideloaded
|
||||
);
|
||||
|
||||
@ -296,7 +296,7 @@ add_task(async function test_sideloading() {
|
||||
checkNotification(
|
||||
panel,
|
||||
DEFAULT_ICON_URL,
|
||||
[["webextPerms.hostDescription.allUrls"]],
|
||||
[["webext-perms-host-description-all-urls"]],
|
||||
kSideloaded
|
||||
);
|
||||
|
||||
|
@ -41,12 +41,15 @@ add_task(async function test_unsigned() {
|
||||
let description = panel.querySelector(
|
||||
".popup-notification-description"
|
||||
).textContent;
|
||||
checkPermissionString(
|
||||
description,
|
||||
"webextPerms.headerUnsignedWithPerms",
|
||||
undefined,
|
||||
`Install notification includes unsigned warning`
|
||||
);
|
||||
const expected = formatExtValue("webext-perms-header-unsigned-with-perms", {
|
||||
extension: "<>",
|
||||
});
|
||||
for (let part of expected.split("<>")) {
|
||||
ok(
|
||||
description.includes(part),
|
||||
"Install notification includes unsigned warning"
|
||||
);
|
||||
}
|
||||
|
||||
// cancel the install
|
||||
let promise = promiseInstallEvent({ id: ID }, "onInstallCancelled");
|
||||
|
@ -26,6 +26,26 @@ const { PermissionTestUtils } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/PermissionTestUtils.sys.mjs"
|
||||
);
|
||||
|
||||
let extL10n = null;
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {object} [args]
|
||||
* @returns {string}
|
||||
*/
|
||||
function formatExtValue(id, args) {
|
||||
if (!extL10n) {
|
||||
extL10n = new Localization(
|
||||
[
|
||||
"toolkit/global/extensions.ftl",
|
||||
"toolkit/global/extensionPermissions.ftl",
|
||||
"branding/brand.ftl",
|
||||
],
|
||||
true
|
||||
);
|
||||
}
|
||||
return extL10n.formatValueSync(id, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the given PopupNotification to display
|
||||
*
|
||||
@ -185,37 +205,6 @@ function isDefaultIcon(icon) {
|
||||
return icon == "chrome://mozapps/skin/extensions/extensionGeneric.svg";
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the contents of an individual permission string.
|
||||
* This function is fairly specific to the use here and probably not
|
||||
* suitable for re-use elsewhere...
|
||||
*
|
||||
* @param {string} string
|
||||
* The string value to check (i.e., pulled from the DOM)
|
||||
* @param {string} key
|
||||
* The key in browser.properties for the localized string to
|
||||
* compare with.
|
||||
* @param {string|null} param
|
||||
* Optional string to substitute for %S in the localized string.
|
||||
* @param {string} msg
|
||||
* The message to be emitted as part of the actual test.
|
||||
*/
|
||||
function checkPermissionString(string, key, param, msg) {
|
||||
let localizedString = param
|
||||
? gBrowserBundle.formatStringFromName(key, [param])
|
||||
: gBrowserBundle.GetStringFromName(key);
|
||||
|
||||
// If this is a parameterized string and the parameter isn't given,
|
||||
// just do a simple comparison of the text before and after the %S
|
||||
if (localizedString.includes("%S")) {
|
||||
let i = localizedString.indexOf("%S");
|
||||
ok(string.startsWith(localizedString.slice(0, i)), msg);
|
||||
ok(string.endsWith(localizedString.slice(i + 2)), msg);
|
||||
} else {
|
||||
is(string, localizedString, msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the contents of a permission popup notification
|
||||
*
|
||||
@ -230,7 +219,7 @@ function checkPermissionString(string, key, param, msg) {
|
||||
* @param {array} permissions
|
||||
* The expected entries in the permissions list. Each element
|
||||
* in this array is itself a 2-element array with the string key
|
||||
* for the item (e.g., "webextPerms.description.foo") and an
|
||||
* for the item (e.g., "webext-perms-description-foo") and an
|
||||
* optional formatting parameter.
|
||||
* @param {boolean} sideloaded
|
||||
* Whether the notification is for a sideloaded extenion.
|
||||
@ -255,19 +244,17 @@ function checkNotification(panel, checkIcon, permissions, sideloaded) {
|
||||
let description = panel.querySelector(
|
||||
".popup-notification-description"
|
||||
).textContent;
|
||||
let expectedDescription = "webextPerms.header";
|
||||
let descL10nId = "webext-perms-header";
|
||||
if (permissions.length) {
|
||||
expectedDescription += "WithPerms";
|
||||
descL10nId = "webext-perms-header-with-perms";
|
||||
}
|
||||
if (sideloaded) {
|
||||
expectedDescription = "webextPerms.sideloadHeader";
|
||||
descL10nId = "webext-perms-sideload-header";
|
||||
}
|
||||
checkPermissionString(
|
||||
description,
|
||||
expectedDescription,
|
||||
undefined,
|
||||
`Description is the expected one`
|
||||
);
|
||||
const exp = formatExtValue(descL10nId, { extension: "<>" }).split("<>");
|
||||
ok(description.startsWith(exp.at(0)), "Description is the expected one");
|
||||
ok(description.endsWith(exp.at(-1)), "Description is the expected one");
|
||||
|
||||
is(
|
||||
learnMoreLink.hidden,
|
||||
!permissions.length,
|
||||
@ -293,10 +280,10 @@ function checkNotification(panel, checkIcon, permissions, sideloaded) {
|
||||
);
|
||||
for (let i in permissions) {
|
||||
let [key, param] = permissions[i];
|
||||
checkPermissionString(
|
||||
const expected = formatExtValue(key, param);
|
||||
is(
|
||||
ul.children[i].textContent,
|
||||
key,
|
||||
param,
|
||||
expected,
|
||||
`Permission number ${i + 1} is correct`
|
||||
);
|
||||
}
|
||||
@ -374,13 +361,19 @@ async function testInstallMethod(installFn, telemetryBase) {
|
||||
// path, just make sure we've got a jar url pointing to the right path
|
||||
// inside the jar.
|
||||
checkNotification(panel, /^jar:file:\/\/.*\/icon\.png$/, [
|
||||
["webextPerms.hostDescription.wildcard", "wildcard.domain"],
|
||||
["webextPerms.hostDescription.oneSite", "singlehost.domain"],
|
||||
["webextPerms.description.nativeMessaging"],
|
||||
[
|
||||
"webext-perms-host-description-wildcard",
|
||||
{ domain: "wildcard.domain" },
|
||||
],
|
||||
[
|
||||
"webext-perms-host-description-one-site",
|
||||
{ domain: "singlehost.domain" },
|
||||
],
|
||||
["webext-perms-description-nativeMessaging"],
|
||||
// The below permissions are deliberately in this order as permissions
|
||||
// are sorted alphabetically by the permission string to match AMO.
|
||||
["webextPerms.description.history"],
|
||||
["webextPerms.description.tabs"],
|
||||
["webext-perms-description-history"],
|
||||
["webext-perms-description-tabs"],
|
||||
]);
|
||||
} else if (filename == NO_PERMS_XPI) {
|
||||
checkNotification(panel, isDefaultIcon, []);
|
||||
|
@ -73,153 +73,18 @@ addonInstallBlockedByPolicy=%1$S (%2$S) is blocked by your system administrator.
|
||||
addonDomainBlockedByPolicy=Your system administrator prevented this site from asking you to install software on your computer.
|
||||
addonInstallFullScreenBlocked=Add-on installation is not allowed while in or before entering fullscreen mode.
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.header,webextPerms.headerWithPerms,webextPerms.headerUnsigned,webextPerms.headerUnsignedWithPerms)
|
||||
# This string is used as a header in the webextension permissions dialog,
|
||||
# %S is replaced with the localized name of the extension being installed.
|
||||
# See https://bug1308309.bmoattachments.org/attachment.cgi?id=8814612
|
||||
# for an example of the full dialog.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextPerms.header=Add %S?
|
||||
webextPerms.headerWithPerms=Add %S? This extension will have permission to:
|
||||
webextPerms.headerUnsigned=Add %S? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source.
|
||||
webextPerms.headerUnsignedWithPerms=Add %S? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source. This extension will have permission to:
|
||||
|
||||
webextPerms.learnMore2=Learn more
|
||||
webextPerms.add.label=Add
|
||||
webextPerms.add.accessKey=A
|
||||
webextPerms.cancel.label=Cancel
|
||||
webextPerms.cancel.accessKey=C
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.sideloadMenuItem)
|
||||
# %1$S will be replaced with the localized name of the sideloaded add-on.
|
||||
# %2$S will be replace with the name of the application (e.g., Firefox, Nightly)
|
||||
webextPerms.sideloadMenuItem=%1$S added to %2$S
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.sideloadHeader)
|
||||
# This string is used as a header in the webextension permissions dialog
|
||||
# when the extension is side-loaded.
|
||||
# %S is replaced with the localized name of the extension being installed.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextPerms.sideloadHeader=%S added
|
||||
webextPerms.sideloadText2=Another program on your computer installed an add-on that may affect your browser. Please review this add-on’s permissions requests and choose to Enable or Cancel (to leave it disabled).
|
||||
webextPerms.sideloadTextNoPerms=Another program on your computer installed an add-on that may affect your browser. Please choose to Enable or Cancel (to leave it disabled).
|
||||
|
||||
webextPerms.sideloadEnable.label=Enable
|
||||
webextPerms.sideloadEnable.accessKey=E
|
||||
webextPerms.sideloadCancel.label=Cancel
|
||||
webextPerms.sideloadCancel.accessKey=C
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.updateMenuItem)
|
||||
# %S will be replaced with the localized name of the extension which
|
||||
# has been updated.
|
||||
webextPerms.updateMenuItem=%S requires new permissions
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.updateText)
|
||||
# %S is replaced with the localized name of the updated extension.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextPerms.updateText2=%S has been updated. You must approve new permissions before the updated version will install. Choosing “Cancel” will maintain your current extension version. This extension will have permission to:
|
||||
|
||||
webextPerms.updateAccept.label=Update
|
||||
webextPerms.updateAccept.accessKey=U
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.optionalPermsHeader)
|
||||
# %S is replace with the localized name of the extension requested new
|
||||
# permissions.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextPerms.optionalPermsHeader=%S requests additional permissions.
|
||||
webextPerms.optionalPermsListIntro=It wants to:
|
||||
webextPerms.optionalPermsAllow.label=Allow
|
||||
webextPerms.optionalPermsAllow.accessKey=A
|
||||
webextPerms.optionalPermsDeny.label=Deny
|
||||
webextPerms.optionalPermsDeny.accessKey=D
|
||||
|
||||
webextPerms.description.bookmarks=Read and modify bookmarks
|
||||
webextPerms.description.browserSettings=Read and modify browser settings
|
||||
webextPerms.description.browsingData=Clear recent browsing history, cookies, and related data
|
||||
webextPerms.description.clipboardRead=Get data from the clipboard
|
||||
webextPerms.description.clipboardWrite=Input data to the clipboard
|
||||
webextPerms.description.declarativeNetRequest=Block content on any page
|
||||
webextPerms.description.declarativeNetRequestFeedback=Read your browsing history
|
||||
webextPerms.description.devtools=Extend developer tools to access your data in open tabs
|
||||
webextPerms.description.downloads=Download files and read and modify the browser’s download history
|
||||
webextPerms.description.downloads.open=Open files downloaded to your computer
|
||||
webextPerms.description.find=Read the text of all open tabs
|
||||
webextPerms.description.geolocation=Access your location
|
||||
webextPerms.description.history=Access browsing history
|
||||
webextPerms.description.management=Monitor extension usage and manage themes
|
||||
# LOCALIZATION NOTE (webextPerms.description.nativeMessaging)
|
||||
# %S will be replaced with the name of the application
|
||||
webextPerms.description.nativeMessaging=Exchange messages with programs other than %S
|
||||
webextPerms.description.notifications=Display notifications to you
|
||||
webextPerms.description.pkcs11=Provide cryptographic authentication services
|
||||
webextPerms.description.privacy=Read and modify privacy settings
|
||||
webextPerms.description.proxy=Control browser proxy settings
|
||||
webextPerms.description.sessions=Access recently closed tabs
|
||||
webextPerms.description.tabs=Access browser tabs
|
||||
webextPerms.description.tabHide=Hide and show browser tabs
|
||||
webextPerms.description.topSites=Access browsing history
|
||||
webextPerms.description.webNavigation=Access browser activity during navigation
|
||||
|
||||
webextPerms.hostDescription.allUrls=Access your data for all websites
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.wildcard)
|
||||
# %S will be replaced by the DNS domain for which a webextension
|
||||
# is requesting access (e.g., mozilla.org)
|
||||
webextPerms.hostDescription.wildcard=Access your data for sites in the %S domain
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManyWildcards):
|
||||
# Semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 will be replaced by an integer indicating the number of additional
|
||||
# domains for which this webextension is requesting permission.
|
||||
webextPerms.hostDescription.tooManyWildcards=Access your data in #1 other domain;Access your data in #1 other domains
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.oneSite)
|
||||
# %S will be replaced by the DNS host name for which a webextension
|
||||
# is requesting access (e.g., www.mozilla.org)
|
||||
webextPerms.hostDescription.oneSite=Access your data for %S
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManySites)
|
||||
# Semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 will be replaced by an integer indicating the number of additional
|
||||
# hosts for which this webextension is requesting permission.
|
||||
webextPerms.hostDescription.tooManySites=Access your data on #1 other site;Access your data on #1 other sites
|
||||
|
||||
# LOCALIZATION NOTE (webextSitePerms.headerWithPerms,webextSitePerms.headerUnsignedWithPerms)
|
||||
# This string is used as a header in the webextension permissions dialog,
|
||||
# %1$S is replaced with the localized name of the extension being installed.
|
||||
# %2$S will be replaced by the DNS host name for which a webextension enables permissions
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextSitePerms.headerWithPerms=Add %1$S? This extension grants the following capabilities to %2$S:
|
||||
webextSitePerms.headerUnsignedWithPerms=Add %1$S? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source. This extension grants the following capabilities to %2$S:
|
||||
|
||||
# LOCALIZATION NOTE (webextSitePerms.headerWithGatedPerms.midi)
|
||||
# This string is used as a header in the webextension permissions dialog for synthetic add-ons.
|
||||
# The part of the string describing what privileges the extension gives should be consistent
|
||||
# with the value of webextSitePerms.description.{sitePermission}.
|
||||
# %S is the hostname of the site the add-on is being installed from.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextSitePerms.headerWithGatedPerms.midi=This add-on gives %S access to your MIDI devices.
|
||||
|
||||
# LOCALIZATION NOTE (webextSitePerms.headerWithGatedPerms.midi-sysex)
|
||||
# This string is used as a header in the webextension permissions dialog for synthetic add-ons.
|
||||
# The part of the string describing what privileges the extension gives should be consistent
|
||||
# with the value of webextSitePerms.description.{sitePermission}.
|
||||
# %S is the hostname of the site the add-on is being installed from.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextSitePerms.headerWithGatedPerms.midi-sysex=This add-on gives %S access to your MIDI devices (with SysEx support).
|
||||
|
||||
# LOCALIZATION NOTE (webextSitePerms.descriptionGatedPerms)
|
||||
# This string is used as description in the webextension permissions dialog for synthetic add-ons.
|
||||
# Note, the \n\n is used to create a line break between the two sections.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextSitePerms.descriptionGatedPerms.midi=These are usually plug-in devices like audio synthesizers, but might also be built into your computer.\n\nWebsites are normally not allowed to access MIDI devices. Improper usage could cause damage or compromise security.
|
||||
|
||||
# These should remain in sync with permissions.NAME.label in sitePermissions.properties
|
||||
webextSitePerms.description.midi=Access MIDI devices
|
||||
webextSitePerms.description.midi-sysex=Access MIDI devices with SysEx support
|
||||
|
||||
# LOCALIZATION NOTE (webext.defaultSearch.description)
|
||||
# %1$S is replaced with the localized named of the extension that is asking to change the default search engine.
|
||||
# %2$S is replaced with the name of the current search engine
|
||||
|
@ -31,7 +31,6 @@ const DEFAULT_EXTENSION_ICON =
|
||||
"chrome://mozapps/skin/extensions/extensionGeneric.svg";
|
||||
|
||||
const BROWSER_PROPERTIES = "chrome://browser/locale/browser.properties";
|
||||
const BRAND_PROPERTIES = "chrome://branding/locale/brand.properties";
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
||||
@ -317,11 +316,8 @@ var ExtensionsUI = {
|
||||
// Create a set of formatted strings for a permission prompt
|
||||
_buildStrings(info) {
|
||||
let bundle = Services.strings.createBundle(BROWSER_PROPERTIES);
|
||||
let brandBundle = Services.strings.createBundle(BRAND_PROPERTIES);
|
||||
let appName = brandBundle.GetStringFromName("brandShortName");
|
||||
let info2 = Object.assign({ appName }, info);
|
||||
|
||||
let strings = lazy.ExtensionData.formatPermissionStrings(info2, bundle, {
|
||||
let strings = lazy.ExtensionData.formatPermissionStrings(info, {
|
||||
collapseOrigins: true,
|
||||
});
|
||||
strings.addonName = info.addon.name;
|
||||
|
@ -12,6 +12,15 @@ const PAGE_WITH_IFRAMES_URL = `https://example.org/document-builder.sjs?html=
|
||||
'https://example.net/document-builder.sjs?html=CrossOrigin"'
|
||||
)}"></iframe>`;
|
||||
|
||||
const l10n = new Localization(
|
||||
[
|
||||
"toolkit/global/extensions.ftl",
|
||||
"toolkit/global/extensionPermissions.ftl",
|
||||
"branding/brand.ftl",
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
@ -141,19 +150,16 @@ add_task(async function testRequestMIDIAccess() {
|
||||
let installDialog = await dialogPromise;
|
||||
is(
|
||||
installDialog.querySelector(".popup-notification-description").textContent,
|
||||
gNavigatorBundle.getFormattedString(
|
||||
"webextSitePerms.headerWithGatedPerms.midi-sysex",
|
||||
[testPageHost]
|
||||
l10n.formatValueSync(
|
||||
"webext-site-perms-header-with-gated-perms-midi-sysex",
|
||||
{ hostname: testPageHost }
|
||||
),
|
||||
"Install dialog has expected header text"
|
||||
);
|
||||
is(
|
||||
installDialog.querySelector("popupnotificationcontent description")
|
||||
.textContent,
|
||||
gNavigatorBundle.getFormattedString(
|
||||
"webextSitePerms.descriptionGatedPerms.midi",
|
||||
[testPageHost]
|
||||
),
|
||||
l10n.formatValueSync("webext-site-perms-description-gated-perms-midi"),
|
||||
"Install dialog has expected description"
|
||||
);
|
||||
|
||||
@ -288,19 +294,15 @@ add_task(async function testRequestMIDIAccess() {
|
||||
|
||||
is(
|
||||
installDialog.querySelector(".popup-notification-description").textContent,
|
||||
gNavigatorBundle.getFormattedString(
|
||||
"webextSitePerms.headerWithGatedPerms.midi",
|
||||
[testPageHost]
|
||||
),
|
||||
l10n.formatValueSync("webext-site-perms-header-with-gated-perms-midi", {
|
||||
hostname: testPageHost,
|
||||
}),
|
||||
"Install dialog has expected header text"
|
||||
);
|
||||
is(
|
||||
installDialog.querySelector("popupnotificationcontent description")
|
||||
.textContent,
|
||||
gNavigatorBundle.getFormattedString(
|
||||
"webextSitePerms.descriptionGatedPerms.midi",
|
||||
[testPageHost]
|
||||
),
|
||||
l10n.formatValueSync("webext-site-perms-description-gated-perms-midi"),
|
||||
"Install dialog has expected description"
|
||||
);
|
||||
|
||||
|
@ -2,99 +2,6 @@
|
||||
# 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/.
|
||||
|
||||
# In Extension.jsm
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.header)
|
||||
# This string is used as a header in the webextension permissions dialog,
|
||||
# %S is replaced with the localized name of the extension being installed.
|
||||
# See https://bug1308309.bmoattachments.org/attachment.cgi?id=8814612
|
||||
# for an example of the full dialog.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextPerms.header=Add %S?
|
||||
webextPerms.headerWithPerms=Add %S? This extension will have permission to:
|
||||
webextPerms.headerUnsigned=Add %S? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source.
|
||||
webextPerms.headerUnsignedWithPerms=Add %S? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source. This extension will have permission to:
|
||||
|
||||
webextPerms.add.label=Add
|
||||
webextPerms.cancel.label=Cancel
|
||||
|
||||
# LOCALIZATION NOTE (webextSitePerms.headerWithPerms,webextSitePerms.headerUnsignedWithPerms)
|
||||
# This string is used as a header in the webextension permissions dialog,
|
||||
# %1$S is replaced with the localized name of the extension being installed.
|
||||
# %2$S will be replaced by the DNS host name for which a webextension enables permissions
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webextSitePerms.headerWithPerms=Add %1$S? This extension grants the following capabilities to %2$S:
|
||||
webextSitePerms.headerUnsignedWithPerms=Add %1$S? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source. This extension grants the following capabilities to %2$S:
|
||||
|
||||
# These should remain in sync with permissions.NAME.label in sitePermissions.properties
|
||||
webextSitePerms.description.midi=Access MIDI devices
|
||||
webextSitePerms.description.midi-sysex=Access MIDI devices with SysEx support
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.updateText)
|
||||
# %S is replaced with the localized name of the updated extension.
|
||||
webextPerms.updateText=%S has been updated. You must approve new permissions before the updated version will install. Choosing “Cancel” will maintain your current add-on version.
|
||||
|
||||
webextPerms.updateAccept.label=Update
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.optionalPermsHeader)
|
||||
# %S is replaced with the localized name of the extension requesting new
|
||||
# permissions.
|
||||
webextPerms.optionalPermsHeader=%S requests additional permissions.
|
||||
webextPerms.optionalPermsListIntro=It wants to:
|
||||
webextPerms.optionalPermsAllow.label=Allow
|
||||
webextPerms.optionalPermsDeny.label=Deny
|
||||
|
||||
webextPerms.description.bookmarks=Read and modify bookmarks
|
||||
webextPerms.description.browserSettings=Read and modify browser settings
|
||||
webextPerms.description.browsingData=Clear recent browsing history, cookies, and related data
|
||||
webextPerms.description.clipboardRead=Get data from the clipboard
|
||||
webextPerms.description.clipboardWrite=Input data to the clipboard
|
||||
webextPerms.description.declarativeNetRequest=Block content on any page
|
||||
webextPerms.description.declarativeNetRequestFeedback=Read your browsing history
|
||||
webextPerms.description.devtools=Extend developer tools to access your data in open tabs
|
||||
webextPerms.description.downloads=Download files and read and modify the browser’s download history
|
||||
webextPerms.description.downloads.open=Open files downloaded to your computer
|
||||
webextPerms.description.find=Read the text of all open tabs
|
||||
webextPerms.description.geolocation=Access your location
|
||||
webextPerms.description.history=Access browsing history
|
||||
webextPerms.description.management=Monitor extension usage and manage themes
|
||||
# LOCALIZATION NOTE (webextPerms.description.nativeMessaging)
|
||||
# %S will be replaced with the name of the application
|
||||
webextPerms.description.nativeMessaging=Exchange messages with programs other than %S
|
||||
webextPerms.description.notifications=Display notifications to you
|
||||
webextPerms.description.privacy=Read and modify privacy settings
|
||||
webextPerms.description.proxy=Control browser proxy settings
|
||||
webextPerms.description.sessions=Access recently closed tabs
|
||||
webextPerms.description.tabs=Access browser tabs
|
||||
webextPerms.description.topSites=Access browsing history
|
||||
webextPerms.description.webNavigation=Access browser activity during navigation
|
||||
|
||||
webextPerms.hostDescription.allUrls=Access your data for all websites
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.wildcard)
|
||||
# %S will be replaced by the DNS domain for which a webextension
|
||||
# is requesting access (e.g., mozilla.org)
|
||||
webextPerms.hostDescription.wildcard=Access your data for sites in the %S domain
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManyWildcards):
|
||||
# Semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 will be replaced by an integer indicating the number of additional
|
||||
# domains for which this webextension is requesting permission.
|
||||
webextPerms.hostDescription.tooManyWildcards=Access your data in #1 other domain;Access your data in #1 other domains
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.oneSite)
|
||||
# %S will be replaced by the DNS host name for which a webextension
|
||||
# is requesting access (e.g., www.mozilla.org)
|
||||
webextPerms.hostDescription.oneSite=Access your data for %S
|
||||
|
||||
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManySites)
|
||||
# Semi-colon list of plural forms.
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 will be replaced by an integer indicating the number of additional
|
||||
# hosts for which this webextension is requesting permission.
|
||||
webextPerms.hostDescription.tooManySites=Access your data on #1 other site;Access your data on #1 other sites
|
||||
|
||||
# Web Console API (in GeckoViewConsole.jsm)
|
||||
stacktrace.anonymousFunction=<anonymous>
|
||||
stacktrace.outputMessage=Stack trace from %S, function %S, line %S.
|
||||
|
391
python/l10n/fluent_migrations/bug_1793557_extensions.py
Normal file
391
python/l10n/fluent_migrations/bug_1793557_extensions.py
Normal file
@ -0,0 +1,391 @@
|
||||
# Any copyright is dedicated to the Public Domain.
|
||||
# http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
import fluent.syntax.ast as FTL
|
||||
from fluent.migrate.helpers import TERM_REFERENCE, VARIABLE_REFERENCE
|
||||
from fluent.migrate.transforms import COPY, PLURALS, REPLACE, REPLACE_IN_TEXT
|
||||
|
||||
|
||||
def migrate(ctx):
|
||||
"""Bug 1793557 - Convert Extension.jsm to Fluent, part {index}."""
|
||||
|
||||
source = "browser/chrome/browser/browser.properties"
|
||||
extensions = "toolkit/toolkit/global/extensions.ftl"
|
||||
permissions = "toolkit/toolkit/global/extensionPermissions.ftl"
|
||||
|
||||
ctx.add_transforms(
|
||||
extensions,
|
||||
extensions,
|
||||
[
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-header"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.header",
|
||||
{"%1$S": VARIABLE_REFERENCE("extension")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-header-with-perms"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.headerWithPerms",
|
||||
{"%1$S": VARIABLE_REFERENCE("extension")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-header-unsigned"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.headerUnsigned",
|
||||
{"%1$S": VARIABLE_REFERENCE("extension")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-header-unsigned-with-perms"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.headerUnsignedWithPerms",
|
||||
{"%1$S": VARIABLE_REFERENCE("extension")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-add"),
|
||||
attributes=[
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("label"),
|
||||
value=COPY(source, "webextPerms.add.label"),
|
||||
),
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("accesskey"),
|
||||
value=COPY(source, "webextPerms.add.accessKey"),
|
||||
),
|
||||
],
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-cancel"),
|
||||
attributes=[
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("label"),
|
||||
value=COPY(source, "webextPerms.cancel.label"),
|
||||
),
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("accesskey"),
|
||||
value=COPY(source, "webextPerms.cancel.accessKey"),
|
||||
),
|
||||
],
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-sideload-header"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.sideloadHeader",
|
||||
{"%1$S": VARIABLE_REFERENCE("extension")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-sideload-text"),
|
||||
value=COPY(source, "webextPerms.sideloadText2"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-sideload-text-no-perms"),
|
||||
value=COPY(source, "webextPerms.sideloadTextNoPerms"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-sideload-enable"),
|
||||
attributes=[
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("label"),
|
||||
value=COPY(source, "webextPerms.sideloadEnable.label"),
|
||||
),
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("accesskey"),
|
||||
value=COPY(source, "webextPerms.sideloadEnable.accessKey"),
|
||||
),
|
||||
],
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-sideload-cancel"),
|
||||
attributes=[
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("label"),
|
||||
value=COPY(source, "webextPerms.sideloadCancel.label"),
|
||||
),
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("accesskey"),
|
||||
value=COPY(source, "webextPerms.sideloadCancel.accessKey"),
|
||||
),
|
||||
],
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-update-text"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.updateText2",
|
||||
{"%1$S": VARIABLE_REFERENCE("extension")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-update-accept"),
|
||||
attributes=[
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("label"),
|
||||
value=COPY(source, "webextPerms.updateAccept.label"),
|
||||
),
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("accesskey"),
|
||||
value=COPY(source, "webextPerms.updateAccept.accessKey"),
|
||||
),
|
||||
],
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-optional-perms-header"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.optionalPermsHeader",
|
||||
{"%1$S": VARIABLE_REFERENCE("extension")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-optional-perms-list-intro"),
|
||||
value=COPY(source, "webextPerms.optionalPermsListIntro"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-optional-perms-allow"),
|
||||
attributes=[
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("label"),
|
||||
value=COPY(source, "webextPerms.optionalPermsAllow.label"),
|
||||
),
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("accesskey"),
|
||||
value=COPY(source, "webextPerms.optionalPermsAllow.accessKey"),
|
||||
),
|
||||
],
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-optional-perms-deny"),
|
||||
attributes=[
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("label"),
|
||||
value=COPY(source, "webextPerms.optionalPermsDeny.label"),
|
||||
),
|
||||
FTL.Attribute(
|
||||
id=FTL.Identifier("accesskey"),
|
||||
value=COPY(source, "webextPerms.optionalPermsDeny.accessKey"),
|
||||
),
|
||||
],
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-host-description-all-urls"),
|
||||
value=COPY(source, "webextPerms.hostDescription.allUrls"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-host-description-wildcard"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.hostDescription.wildcard",
|
||||
{"%1$S": VARIABLE_REFERENCE("domain")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-host-description-too-many-wildcards"),
|
||||
value=PLURALS(
|
||||
source,
|
||||
"webextPerms.hostDescription.tooManyWildcards",
|
||||
VARIABLE_REFERENCE("domainCount"),
|
||||
foreach=lambda n: REPLACE_IN_TEXT(
|
||||
n,
|
||||
{"#1": VARIABLE_REFERENCE("domainCount")},
|
||||
),
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-host-description-one-site"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.hostDescription.oneSite",
|
||||
{"%1$S": VARIABLE_REFERENCE("domain")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-host-description-too-many-sites"),
|
||||
value=PLURALS(
|
||||
source,
|
||||
"webextPerms.hostDescription.tooManySites",
|
||||
VARIABLE_REFERENCE("domainCount"),
|
||||
foreach=lambda n: REPLACE_IN_TEXT(
|
||||
n,
|
||||
{"#1": VARIABLE_REFERENCE("domainCount")},
|
||||
),
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-site-perms-header-with-gated-perms-midi"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextSitePerms.headerWithGatedPerms.midi",
|
||||
{
|
||||
"%1$S": VARIABLE_REFERENCE("hostname"),
|
||||
},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier(
|
||||
"webext-site-perms-header-with-gated-perms-midi-sysex"
|
||||
),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextSitePerms.headerWithGatedPerms.midi-sysex",
|
||||
{
|
||||
"%1$S": VARIABLE_REFERENCE("hostname"),
|
||||
},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-site-perms-description-gated-perms-midi"),
|
||||
value=COPY(source, "webextSitePerms.descriptionGatedPerms.midi"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-site-perms-header-with-perms"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextSitePerms.headerWithPerms",
|
||||
{
|
||||
"%1$S": VARIABLE_REFERENCE("extension"),
|
||||
"%2$S": VARIABLE_REFERENCE("hostname"),
|
||||
},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-site-perms-header-unsigned-with-perms"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextSitePerms.headerUnsignedWithPerms",
|
||||
{
|
||||
"%1$S": VARIABLE_REFERENCE("extension"),
|
||||
"%2$S": VARIABLE_REFERENCE("hostname"),
|
||||
},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-site-perms-midi"),
|
||||
value=COPY(source, "webextSitePerms.description.midi"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-site-perms-midi-sysex"),
|
||||
value=COPY(source, "webextSitePerms.description.midi-sysex"),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
ctx.add_transforms(
|
||||
permissions,
|
||||
permissions,
|
||||
[
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-bookmarks"),
|
||||
value=COPY(source, "webextPerms.description.bookmarks"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-browserSettings"),
|
||||
value=COPY(source, "webextPerms.description.browserSettings"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-browsingData"),
|
||||
value=COPY(source, "webextPerms.description.browsingData"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-clipboardRead"),
|
||||
value=COPY(source, "webextPerms.description.clipboardRead"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-clipboardWrite"),
|
||||
value=COPY(source, "webextPerms.description.clipboardWrite"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-declarativeNetRequest"),
|
||||
value=COPY(source, "webextPerms.description.declarativeNetRequest"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier(
|
||||
"webext-perms-description-declarativeNetRequestFeedback"
|
||||
),
|
||||
value=COPY(
|
||||
source, "webextPerms.description.declarativeNetRequestFeedback"
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-devtools"),
|
||||
value=COPY(source, "webextPerms.description.devtools"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-downloads"),
|
||||
value=COPY(source, "webextPerms.description.downloads"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-downloads-open"),
|
||||
value=COPY(source, "webextPerms.description.downloads.open"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-find"),
|
||||
value=COPY(source, "webextPerms.description.find"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-geolocation"),
|
||||
value=COPY(source, "webextPerms.description.geolocation"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-history"),
|
||||
value=COPY(source, "webextPerms.description.history"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-management"),
|
||||
value=COPY(source, "webextPerms.description.management"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-nativeMessaging"),
|
||||
value=REPLACE(
|
||||
source,
|
||||
"webextPerms.description.nativeMessaging",
|
||||
{"%1$S": TERM_REFERENCE("brand-short-name")},
|
||||
),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-notifications"),
|
||||
value=COPY(source, "webextPerms.description.notifications"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-pkcs11"),
|
||||
value=COPY(source, "webextPerms.description.pkcs11"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-privacy"),
|
||||
value=COPY(source, "webextPerms.description.privacy"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-proxy"),
|
||||
value=COPY(source, "webextPerms.description.proxy"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-sessions"),
|
||||
value=COPY(source, "webextPerms.description.sessions"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-tabs"),
|
||||
value=COPY(source, "webextPerms.description.tabs"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-tabHide"),
|
||||
value=COPY(source, "webextPerms.description.tabHide"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-topSites"),
|
||||
value=COPY(source, "webextPerms.description.topSites"),
|
||||
),
|
||||
FTL.Message(
|
||||
id=FTL.Identifier("webext-perms-description-webNavigation"),
|
||||
value=COPY(source, "webextPerms.description.webNavigation"),
|
||||
),
|
||||
],
|
||||
)
|
@ -56,6 +56,8 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
||||
ExtensionDNR: "resource://gre/modules/ExtensionDNR.sys.mjs",
|
||||
ExtensionDNRStore: "resource://gre/modules/ExtensionDNRStore.sys.mjs",
|
||||
Log: "resource://gre/modules/Log.sys.mjs",
|
||||
permissionToL10nId:
|
||||
"resource://gre/modules/ExtensionPermissionMessages.sys.mjs",
|
||||
SITEPERMS_ADDON_TYPE:
|
||||
"resource://gre/modules/addons/siteperms-addon-utils.sys.mjs",
|
||||
});
|
||||
@ -75,7 +77,6 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
ExtensionTelemetry: "resource://gre/modules/ExtensionTelemetry.jsm",
|
||||
LightweightThemeManager: "resource://gre/modules/LightweightThemeManager.jsm",
|
||||
NetUtil: "resource://gre/modules/NetUtil.jsm",
|
||||
PluralForm: "resource://gre/modules/PluralForm.jsm",
|
||||
Schemas: "resource://gre/modules/Schemas.jsm",
|
||||
ServiceWorkerCleanUp: "resource://gre/modules/ServiceWorkerCleanUp.jsm",
|
||||
});
|
||||
@ -86,6 +87,20 @@ XPCOMUtils.defineLazyGetter(lazy, "resourceProtocol", () =>
|
||||
.QueryInterface(Ci.nsIResProtocolHandler)
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(
|
||||
lazy,
|
||||
"l10n",
|
||||
() =>
|
||||
new Localization(
|
||||
[
|
||||
"toolkit/global/extensions.ftl",
|
||||
"toolkit/global/extensionPermissions.ftl",
|
||||
"branding/brand.ftl",
|
||||
],
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
const { ExtensionCommon } = ChromeUtils.import(
|
||||
"resource://gre/modules/ExtensionCommon.jsm"
|
||||
);
|
||||
@ -2179,30 +2194,29 @@ class ExtensionData {
|
||||
return { allUrls, wildcards, sites, wildcardsMap, sitesMap };
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} Permissions
|
||||
* @property {Array<string>} origins Origin permissions.
|
||||
* @property {Array<string>} permissions Regular (non-origin) permissions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Formats all the strings for a permissions dialog/notification.
|
||||
*
|
||||
* @param {object} info Information about the permissions being requested.
|
||||
*
|
||||
* @param {Array<string>} info.permissions.origins
|
||||
* Origin permissions requested.
|
||||
* @param {Array<string>} info.permissions.permissions
|
||||
* Regular (non-origin) permissions requested.
|
||||
* @param {Array<string>} info.optionalPermissions.origins
|
||||
* Optional origin permissions listed in the manifest.
|
||||
* @param {Array<string>} info.optionalPermissions.permissions
|
||||
* Optional (non-origin) permissions listed in the manifest.
|
||||
* @param {object} [info.addon] Optional information about the addon.
|
||||
* @param {Permissions} [info.optionalPermissions]
|
||||
* Optional permissions listed in the manifest.
|
||||
* @param {Permissions} info.permissions Requested permissions.
|
||||
* @param {string} info.siteOrigin
|
||||
* @param {Array<string>} [info.sitePermissions]
|
||||
* @param {boolean} info.unsigned
|
||||
* True if the prompt is for installing an unsigned addon.
|
||||
* @param {string} info.type
|
||||
* The type of prompt being shown. May be one of "update",
|
||||
* "sideload", "optional", or omitted for a regular
|
||||
* install prompt.
|
||||
* @param {string} info.appName
|
||||
* The localized name of the application, to be substituted
|
||||
* in computed strings as needed.
|
||||
* @param {nsIStringBundle} bundle
|
||||
* The string bundle to use for l10n.
|
||||
* @param {object} options
|
||||
* @param {boolean} options.collapseOrigins
|
||||
* Wether to limit the number of displayed host permissions.
|
||||
@ -2210,13 +2224,8 @@ class ExtensionData {
|
||||
* @param {boolean} options.buildOptionalOrigins
|
||||
* Wether to build optional origins Maps for permission
|
||||
* controls. Defaults to false.
|
||||
* @param {Function} options.getKeyForPermission
|
||||
* An optional callback function that returns the locale key for a given
|
||||
* permission name (set by default to a callback returning the locale
|
||||
* key following the default convention `webextPerms.description.PERMNAME`).
|
||||
* Overriding the default mapping can become necessary, when a permission
|
||||
* description needs to be modified and a non-default locale key has to be
|
||||
* used. There is at least one non-default locale key used in Thunderbird.
|
||||
* @param {Localization} options.localization
|
||||
* Optional custom localization instance.
|
||||
*
|
||||
* @returns {object} An object with properties containing localized strings
|
||||
* for various elements of a permission dialog. The "header"
|
||||
@ -2234,32 +2243,58 @@ class ExtensionData {
|
||||
* all url style permissions are included.
|
||||
*/
|
||||
static formatPermissionStrings(
|
||||
info,
|
||||
bundle,
|
||||
{
|
||||
collapseOrigins = false,
|
||||
buildOptionalOrigins = false,
|
||||
getKeyForPermission = perm => `webextPerms.description.${perm}`,
|
||||
} = {}
|
||||
addon,
|
||||
optionalPermissions,
|
||||
permissions,
|
||||
siteOrigin,
|
||||
sitePermissions,
|
||||
type,
|
||||
unsigned,
|
||||
},
|
||||
{ collapseOrigins = false, buildOptionalOrigins = false, localization } = {}
|
||||
) {
|
||||
let result = {
|
||||
const l10n = localization ?? lazy.l10n;
|
||||
|
||||
const msgIds = [];
|
||||
const headerArgs = { extension: "<>" };
|
||||
let acceptId = "webext-perms-add";
|
||||
let cancelId = "webext-perms-cancel";
|
||||
|
||||
const result = {
|
||||
msgs: [],
|
||||
optionalPermissions: {},
|
||||
optionalOrigins: {},
|
||||
text: "",
|
||||
listIntro: "",
|
||||
};
|
||||
|
||||
const haveAccessKeys = AppConstants.platform !== "android";
|
||||
// To keep the label & accesskey in sync for localizations,
|
||||
// they need to be stored as attributes of the same Fluent message.
|
||||
// This unpacks them into the shape expected of them in `result`.
|
||||
function setAcceptCancel(acceptId, cancelId) {
|
||||
const haveAccessKeys = AppConstants.platform !== "android";
|
||||
|
||||
let headerKey;
|
||||
result.text = "";
|
||||
result.listIntro = "";
|
||||
result.acceptText = bundle.GetStringFromName("webextPerms.add.label");
|
||||
result.cancelText = bundle.GetStringFromName("webextPerms.cancel.label");
|
||||
if (haveAccessKeys) {
|
||||
result.acceptKey = bundle.GetStringFromName("webextPerms.add.accessKey");
|
||||
result.cancelKey = bundle.GetStringFromName(
|
||||
"webextPerms.cancel.accessKey"
|
||||
);
|
||||
const [accept, cancel] = l10n.formatMessagesSync([
|
||||
{ id: acceptId },
|
||||
{ id: cancelId },
|
||||
]);
|
||||
|
||||
for (let { name, value } of accept.attributes) {
|
||||
if (name === "label") {
|
||||
result.acceptText = value;
|
||||
} else if (name === "accesskey" && haveAccessKeys) {
|
||||
result.acceptKey = value;
|
||||
}
|
||||
}
|
||||
|
||||
for (let { name, value } of cancel.attributes) {
|
||||
if (name === "label") {
|
||||
result.cancelText = value;
|
||||
} else if (name === "accesskey" && haveAccessKeys) {
|
||||
result.cancelKey = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Synthetic addon install can only grant access to a single permission so we can have
|
||||
@ -2267,252 +2302,230 @@ class ExtensionData {
|
||||
// NOTE: this is used as part of the synthetic addon install flow implemented for the
|
||||
// SitePermissionAddonProvider.
|
||||
// (and so it should not be removed as part of Bug 1789718 changes, while this additional note should be).
|
||||
if (info.addon?.type === lazy.SITEPERMS_ADDON_TYPE) {
|
||||
// FIXME
|
||||
if (addon?.type === lazy.SITEPERMS_ADDON_TYPE) {
|
||||
// We simplify the origin to make it more user friendly. The origin is assured to be
|
||||
// available because the SitePermsAddon install is always expected to be triggered
|
||||
// from a website, making the siteOrigin always available through the installing principal.
|
||||
const host = new URL(info.siteOrigin).hostname;
|
||||
headerArgs.hostname = new URL(siteOrigin).hostname;
|
||||
|
||||
// messages are specific to the type of gated permission being installed
|
||||
result.header = bundle.formatStringFromName(
|
||||
`webextSitePerms.headerWithGatedPerms.${info.sitePermissions[0]}`,
|
||||
[host]
|
||||
);
|
||||
const headerId =
|
||||
sitePermissions[0] === "midi-sysex"
|
||||
? "webext-site-perms-header-with-gated-perms-midi-sysex"
|
||||
: "webext-site-perms-header-with-gated-perms-midi";
|
||||
result.header = l10n.formatValueSync(headerId, headerArgs);
|
||||
|
||||
// We use the same string for midi and midi-sysex, and don't support any
|
||||
// other types of site permission add-ons. So we just hard-code the
|
||||
// descriptor for now. See bug 1826747.
|
||||
result.text = bundle.GetStringFromName(
|
||||
`webextSitePerms.descriptionGatedPerms.midi`
|
||||
result.text = l10n.formatValueSync(
|
||||
"webext-site-perms-description-gated-perms-midi"
|
||||
);
|
||||
|
||||
setAcceptCancel(acceptId, cancelId);
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO(Bug 1789718): Remove after the deprecated XPIProvider-based implementation is also removed.
|
||||
if (info.sitePermissions) {
|
||||
// Generate a map of site_permission names to permission strings for site permissions.
|
||||
for (let permission of info.sitePermissions) {
|
||||
try {
|
||||
result.msgs.push(
|
||||
bundle.GetStringFromName(
|
||||
`webextSitePerms.description.${permission}`
|
||||
)
|
||||
);
|
||||
} catch (err) {
|
||||
Cu.reportError(
|
||||
`site_permission ${permission} missing readable text property`
|
||||
);
|
||||
// We must never have a DOM api permission that is hidden so in
|
||||
// the case of any error, we'll use the plain permission string.
|
||||
// test_ext_sitepermissions.js tests for no missing messages, this
|
||||
// is just an extra fallback.
|
||||
result.msgs.push(permission);
|
||||
if (sitePermissions) {
|
||||
for (let permission of sitePermissions) {
|
||||
let permMsg;
|
||||
switch (permission) {
|
||||
case "midi":
|
||||
permMsg = l10n.formatValueSync("webext-site-perms-midi");
|
||||
break;
|
||||
case "midi-sysex":
|
||||
permMsg = l10n.formatValueSync("webext-site-perms-midi-sysex");
|
||||
break;
|
||||
default:
|
||||
Cu.reportError(
|
||||
`site_permission ${permission} missing readable text property`
|
||||
);
|
||||
// We must never have a DOM api permission that is hidden so in
|
||||
// the case of any error, we'll use the plain permission string.
|
||||
// test_ext_sitepermissions.js tests for no missing messages, this
|
||||
// is just an extra fallback.
|
||||
permMsg = permission;
|
||||
}
|
||||
result.msgs.push(permMsg);
|
||||
}
|
||||
|
||||
// We simplify the origin to make it more user friendly. The origin is
|
||||
// assured to be available via schema requirement.
|
||||
const host = new URL(info.siteOrigin).hostname;
|
||||
|
||||
headerKey = info.unsigned
|
||||
? "webextSitePerms.headerUnsignedWithPerms"
|
||||
: "webextSitePerms.headerWithPerms";
|
||||
result.header = bundle.formatStringFromName(headerKey, ["<>", host]);
|
||||
headerArgs.hostname = new URL(siteOrigin).hostname;
|
||||
|
||||
const headerId = unsigned
|
||||
? "webext-site-perms-header-unsigned-with-perms"
|
||||
: "webext-site-perms-header-with-perms";
|
||||
result.header = l10n.formatValueSync(headerId, headerArgs);
|
||||
setAcceptCancel(acceptId, cancelId);
|
||||
return result;
|
||||
}
|
||||
|
||||
let perms = info.permissions || { origins: [], permissions: [] };
|
||||
let optional_permissions = info.optionalPermissions || {
|
||||
origins: [],
|
||||
permissions: [],
|
||||
};
|
||||
if (permissions) {
|
||||
// First classify our host permissions
|
||||
let { allUrls, wildcards, sites } =
|
||||
ExtensionData.classifyOriginPermissions(permissions.origins);
|
||||
|
||||
// First classify our host permissions
|
||||
let { allUrls, wildcards, sites } = ExtensionData.classifyOriginPermissions(
|
||||
perms.origins
|
||||
);
|
||||
// Format the host permissions. If we have a wildcard for all urls,
|
||||
// a single string will suffice. Otherwise, show domain wildcards
|
||||
// first, then individual host permissions.
|
||||
if (allUrls) {
|
||||
msgIds.push("webext-perms-host-description-all-urls");
|
||||
} else {
|
||||
// Formats a list of host permissions. If we have 4 or fewer, display
|
||||
// them all, otherwise display the first 3 followed by an item that
|
||||
// says "...plus N others"
|
||||
const addMessages = (set, l10nId, moreL10nId) => {
|
||||
if (collapseOrigins && set.size > 4) {
|
||||
for (let domain of Array.from(set).slice(0, 3)) {
|
||||
msgIds.push({ id: l10nId, args: { domain } });
|
||||
}
|
||||
msgIds.push({
|
||||
id: moreL10nId,
|
||||
args: { domainCount: set.size - 3 },
|
||||
});
|
||||
} else {
|
||||
for (let domain of set) {
|
||||
msgIds.push({ id: l10nId, args: { domain } });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Format the host permissions. If we have a wildcard for all urls,
|
||||
// a single string will suffice. Otherwise, show domain wildcards
|
||||
// first, then individual host permissions.
|
||||
if (allUrls) {
|
||||
result.msgs.push(
|
||||
bundle.GetStringFromName("webextPerms.hostDescription.allUrls")
|
||||
);
|
||||
} else {
|
||||
// Formats a list of host permissions. If we have 4 or fewer, display
|
||||
// them all, otherwise display the first 3 followed by an item that
|
||||
// says "...plus N others"
|
||||
let format = (list, itemKey, moreKey) => {
|
||||
function formatItems(items) {
|
||||
result.msgs.push(
|
||||
...items.map(item => bundle.formatStringFromName(itemKey, [item]))
|
||||
);
|
||||
}
|
||||
if (list.length < 5 || !collapseOrigins) {
|
||||
formatItems(list);
|
||||
} else {
|
||||
formatItems(list.slice(0, 3));
|
||||
|
||||
let remaining = list.length - 3;
|
||||
result.msgs.push(
|
||||
lazy.PluralForm.get(
|
||||
remaining,
|
||||
bundle.GetStringFromName(moreKey)
|
||||
).replace("#1", remaining)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
format(
|
||||
Array.from(wildcards),
|
||||
"webextPerms.hostDescription.wildcard",
|
||||
"webextPerms.hostDescription.tooManyWildcards"
|
||||
);
|
||||
format(
|
||||
Array.from(sites),
|
||||
"webextPerms.hostDescription.oneSite",
|
||||
"webextPerms.hostDescription.tooManySites"
|
||||
);
|
||||
}
|
||||
|
||||
// Next, show the native messaging permission if it is present.
|
||||
const NATIVE_MSG_PERM = "nativeMessaging";
|
||||
if (perms.permissions.includes(NATIVE_MSG_PERM)) {
|
||||
result.msgs.push(
|
||||
bundle.formatStringFromName(getKeyForPermission(NATIVE_MSG_PERM), [
|
||||
info.appName,
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
// Finally, show remaining permissions, in the same order as AMO.
|
||||
// The permissions are sorted alphabetically by the permission
|
||||
// string to match AMO.
|
||||
let permissionsCopy = perms.permissions.slice(0);
|
||||
for (let permission of permissionsCopy.sort()) {
|
||||
// Handled above
|
||||
if (permission == NATIVE_MSG_PERM) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
result.msgs.push(
|
||||
bundle.GetStringFromName(getKeyForPermission(permission))
|
||||
addMessages(
|
||||
wildcards,
|
||||
"webext-perms-host-description-wildcard",
|
||||
"webext-perms-host-description-too-many-wildcards"
|
||||
);
|
||||
} catch (err) {
|
||||
addMessages(
|
||||
sites,
|
||||
"webext-perms-host-description-one-site",
|
||||
"webext-perms-host-description-too-many-sites"
|
||||
);
|
||||
}
|
||||
|
||||
// Finally, show remaining permissions, in the same order as AMO.
|
||||
// The permissions are sorted alphabetically by the permission
|
||||
// string to match AMO.
|
||||
// Show the native messaging permission first if it is present.
|
||||
const NATIVE_MSG_PERM = "nativeMessaging";
|
||||
const permissionsSorted = permissions.permissions.sort((a, b) => {
|
||||
if (a === NATIVE_MSG_PERM) {
|
||||
return -1;
|
||||
} else if (b === NATIVE_MSG_PERM) {
|
||||
return 1;
|
||||
}
|
||||
return a < b ? -1 : 1;
|
||||
});
|
||||
for (let permission of permissionsSorted) {
|
||||
const l10nId = lazy.permissionToL10nId(permission);
|
||||
// We deliberately do not include all permissions in the prompt.
|
||||
// So if we don't find one then just skip it.
|
||||
if (l10nId) {
|
||||
msgIds.push(l10nId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a map of permission names to permission strings for optional
|
||||
// permissions. The key is necessary to handle toggling those permissions.
|
||||
for (let permission of optional_permissions.permissions) {
|
||||
if (permission == NATIVE_MSG_PERM) {
|
||||
result.optionalPermissions[permission] = bundle.formatStringFromName(
|
||||
getKeyForPermission(permission),
|
||||
[info.appName]
|
||||
);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
result.optionalPermissions[permission] = bundle.GetStringFromName(
|
||||
getKeyForPermission(permission)
|
||||
);
|
||||
} catch (err) {
|
||||
// We deliberately do not have strings for all permissions.
|
||||
if (optionalPermissions) {
|
||||
// Generate a map of permission names to permission strings for optional
|
||||
// permissions. The key is necessary to handle toggling those permissions.
|
||||
const opKeys = [];
|
||||
const opL10nIds = [];
|
||||
for (let permission of optionalPermissions.permissions) {
|
||||
const l10nId = lazy.permissionToL10nId(permission);
|
||||
// We deliberately do not include all permissions in the prompt.
|
||||
// So if we don't find one then just skip it.
|
||||
if (l10nId) {
|
||||
opKeys.push(permission);
|
||||
opL10nIds.push(l10nId);
|
||||
}
|
||||
}
|
||||
if (opKeys.length) {
|
||||
const opRes = l10n.formatValuesSync(opL10nIds);
|
||||
for (let i = 0; i < opKeys.length; ++i) {
|
||||
result.optionalPermissions[opKeys[i]] = opRes[i];
|
||||
}
|
||||
}
|
||||
|
||||
const { allUrls, sitesMap, wildcardsMap } =
|
||||
ExtensionData.classifyOriginPermissions(
|
||||
optionalPermissions.origins,
|
||||
true
|
||||
);
|
||||
const ooKeys = [];
|
||||
const ooL10nIds = [];
|
||||
if (allUrls) {
|
||||
ooKeys.push(allUrls);
|
||||
ooL10nIds.push("webext-perms-host-description-all-urls");
|
||||
}
|
||||
|
||||
// Current UX controls are meant for developer testing with mv3.
|
||||
if (buildOptionalOrigins) {
|
||||
for (let [pattern, domain] of wildcardsMap.entries()) {
|
||||
ooKeys.push(pattern);
|
||||
ooL10nIds.push({
|
||||
id: "webext-perms-host-description-wildcard",
|
||||
args: { domain },
|
||||
});
|
||||
}
|
||||
for (let [pattern, domain] of sitesMap.entries()) {
|
||||
ooKeys.push(pattern);
|
||||
ooL10nIds.push({
|
||||
id: "webext-perms-host-description-one-site",
|
||||
args: { domain },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (ooKeys.length) {
|
||||
const res = l10n.formatValuesSync(ooL10nIds);
|
||||
for (let i = 0; i < res.length; ++i) {
|
||||
result.optionalOrigins[ooKeys[i]] = res[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let optionalInfo = ExtensionData.classifyOriginPermissions(
|
||||
optional_permissions.origins,
|
||||
true
|
||||
);
|
||||
if (optionalInfo.allUrls) {
|
||||
result.optionalOrigins[optionalInfo.allUrls] = bundle.GetStringFromName(
|
||||
"webextPerms.hostDescription.allUrls"
|
||||
);
|
||||
let headerId;
|
||||
switch (type) {
|
||||
case "sideload":
|
||||
headerId = "webext-perms-sideload-header";
|
||||
acceptId = "webext-perms-sideload-enable";
|
||||
cancelId = "webext-perms-sideload-cancel";
|
||||
result.text = l10n.formatValueSync(
|
||||
msgIds.length
|
||||
? "webext-perms-sideload-text"
|
||||
: "webext-perms-sideload-text-no-perms"
|
||||
);
|
||||
break;
|
||||
case "update":
|
||||
headerId = "webext-perms-update-text";
|
||||
acceptId = "webext-perms-update-accept";
|
||||
break;
|
||||
case "optional":
|
||||
headerId = "webext-perms-optional-perms-header";
|
||||
acceptId = "webext-perms-optional-perms-allow";
|
||||
cancelId = "webext-perms-optional-perms-deny";
|
||||
result.listIntro = l10n.formatValueSync(
|
||||
"webext-perms-optional-perms-list-intro"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
if (msgIds.length) {
|
||||
headerId = unsigned
|
||||
? "webext-perms-header-unsigned-with-perms"
|
||||
: "webext-perms-header-with-perms";
|
||||
} else {
|
||||
headerId = unsigned
|
||||
? "webext-perms-header-unsigned"
|
||||
: "webext-perms-header";
|
||||
}
|
||||
}
|
||||
|
||||
// Current UX controls are meant for developer testing with mv3.
|
||||
if (buildOptionalOrigins) {
|
||||
for (let [pattern, originLabel] of optionalInfo.wildcardsMap.entries()) {
|
||||
let key = "webextPerms.hostDescription.wildcard";
|
||||
let str = bundle.formatStringFromName(key, [originLabel]);
|
||||
result.optionalOrigins[pattern] = str;
|
||||
}
|
||||
for (let [pattern, originLabel] of optionalInfo.sitesMap.entries()) {
|
||||
let key = "webextPerms.hostDescription.oneSite";
|
||||
let str = bundle.formatStringFromName(key, [originLabel]);
|
||||
result.optionalOrigins[pattern] = str;
|
||||
}
|
||||
}
|
||||
|
||||
if (info.type == "sideload") {
|
||||
headerKey = "webextPerms.sideloadHeader";
|
||||
let key = !result.msgs.length
|
||||
? "webextPerms.sideloadTextNoPerms"
|
||||
: "webextPerms.sideloadText2";
|
||||
result.text = bundle.GetStringFromName(key);
|
||||
result.acceptText = bundle.GetStringFromName(
|
||||
"webextPerms.sideloadEnable.label"
|
||||
);
|
||||
result.cancelText = bundle.GetStringFromName(
|
||||
"webextPerms.sideloadCancel.label"
|
||||
);
|
||||
if (haveAccessKeys) {
|
||||
result.acceptKey = bundle.GetStringFromName(
|
||||
"webextPerms.sideloadEnable.accessKey"
|
||||
);
|
||||
result.cancelKey = bundle.GetStringFromName(
|
||||
"webextPerms.sideloadCancel.accessKey"
|
||||
);
|
||||
}
|
||||
} else if (info.type == "update") {
|
||||
headerKey = "webextPerms.updateText2";
|
||||
result.text = "";
|
||||
result.acceptText = bundle.GetStringFromName(
|
||||
"webextPerms.updateAccept.label"
|
||||
);
|
||||
if (haveAccessKeys) {
|
||||
result.acceptKey = bundle.GetStringFromName(
|
||||
"webextPerms.updateAccept.accessKey"
|
||||
);
|
||||
}
|
||||
} else if (info.type == "optional") {
|
||||
headerKey = "webextPerms.optionalPermsHeader";
|
||||
result.text = "";
|
||||
result.listIntro = bundle.GetStringFromName(
|
||||
"webextPerms.optionalPermsListIntro"
|
||||
);
|
||||
result.acceptText = bundle.GetStringFromName(
|
||||
"webextPerms.optionalPermsAllow.label"
|
||||
);
|
||||
result.cancelText = bundle.GetStringFromName(
|
||||
"webextPerms.optionalPermsDeny.label"
|
||||
);
|
||||
if (haveAccessKeys) {
|
||||
result.acceptKey = bundle.GetStringFromName(
|
||||
"webextPerms.optionalPermsAllow.accessKey"
|
||||
);
|
||||
result.cancelKey = bundle.GetStringFromName(
|
||||
"webextPerms.optionalPermsDeny.accessKey"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
headerKey = "webextPerms.header";
|
||||
if (result.msgs.length) {
|
||||
headerKey = info.unsigned
|
||||
? "webextPerms.headerUnsignedWithPerms"
|
||||
: "webextPerms.headerWithPerms";
|
||||
} else if (info.unsigned) {
|
||||
headerKey = "webextPerms.headerUnsigned";
|
||||
}
|
||||
}
|
||||
result.header = bundle.formatStringFromName(headerKey, ["<>"]);
|
||||
result.header = l10n.formatValueSync(headerId, headerArgs);
|
||||
result.msgs = l10n.formatValuesSync(msgIds);
|
||||
setAcceptCancel(acceptId, cancelId);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
/* 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/. */
|
||||
|
||||
/**
|
||||
* List of permissions that are associated with a permission message.
|
||||
*
|
||||
* Keep this list in sync with:
|
||||
* - The messages in `toolkit/locales/en-US/toolkit/global/extensionPermissions.ftl`
|
||||
* - `permissionToTranslation` at https://github.com/mozilla-mobile/firefox-android/blob/d9c08c387917e3e53963386ad53229e69d52da6e/android-components/components/feature/addons/src/main/java/mozilla/components/feature/addons/Addon.kt#L174-L206
|
||||
* - https://extensionworkshop.com/documentation/develop/request-the-right-permissions/#advised-permissions
|
||||
* - https://support.mozilla.org/en-US/kb/permission-request-messages-firefox-extensions
|
||||
*
|
||||
* This is exported to allow builds (e.g. Thunderbird) to extend or modify the set.
|
||||
*/
|
||||
export const PERMISSIONS_WITH_MESSAGE = new Set([
|
||||
"bookmarks",
|
||||
"browserSettings",
|
||||
"browsingData",
|
||||
"clipboardRead",
|
||||
"clipboardWrite",
|
||||
"declarativeNetRequest",
|
||||
"declarativeNetRequestFeedback",
|
||||
"devtools",
|
||||
"downloads",
|
||||
"downloads.open",
|
||||
"find",
|
||||
"geolocation",
|
||||
"history",
|
||||
"management",
|
||||
"nativeMessaging",
|
||||
"notifications",
|
||||
"pkcs11",
|
||||
"privacy",
|
||||
"proxy",
|
||||
"sessions",
|
||||
"tabs",
|
||||
"tabHide",
|
||||
"topSites",
|
||||
"webNavigation",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Overrides for permission description l10n identifiers,
|
||||
* which by default use the pattern `webext-perms-description-${permission}`
|
||||
* where `permission` is sanitized to be a valid Fluent identifier.
|
||||
*
|
||||
* This is exported to allow builds (e.g. Thunderbird) to extend or modify the map.
|
||||
*/
|
||||
export const PERMISSION_L10N_ID_OVERRIDES = new Map();
|
||||
|
||||
/**
|
||||
* Maps a permission name to its l10n identifier.
|
||||
*
|
||||
* Returns `null` for permissions not in `PERMISSIONS_WITH_MESSAGE`.
|
||||
*
|
||||
* The default `webext-perms-description-${permission}` mapping
|
||||
* may be overridden by entries in `PERMISSION_L10N_ID_OVERRIDES`.
|
||||
*
|
||||
* @param {string} permission
|
||||
* @returns {string | null}
|
||||
*/
|
||||
export function permissionToL10nId(permission) {
|
||||
if (!PERMISSIONS_WITH_MESSAGE.has(permission)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (PERMISSION_L10N_ID_OVERRIDES.has(permission)) {
|
||||
return PERMISSION_L10N_ID_OVERRIDES.get(permission);
|
||||
}
|
||||
|
||||
// Sanitize input to end up with a valid l10n id.
|
||||
// E.g. "<all_urls>" to "all-urls", "downloads.open" to "downloads-open".
|
||||
const sanitized = permission
|
||||
.replace(/[^a-zA-Z0-9]+/g, "-")
|
||||
.replace(/^-|-$/g, "");
|
||||
|
||||
return `webext-perms-description-${sanitized}`;
|
||||
}
|
@ -23,6 +23,7 @@ EXTRA_JS_MODULES += [
|
||||
"ExtensionDNRStore.sys.mjs",
|
||||
"ExtensionPageChild.jsm",
|
||||
"ExtensionParent.jsm",
|
||||
"ExtensionPermissionMessages.sys.mjs",
|
||||
"ExtensionPermissions.jsm",
|
||||
"ExtensionPreferencesManager.jsm",
|
||||
"ExtensionProcessScript.jsm",
|
||||
|
@ -4,19 +4,26 @@ let { ExtensionTestCommon } = ChromeUtils.import(
|
||||
"resource://testing-common/ExtensionTestCommon.jsm"
|
||||
);
|
||||
|
||||
let bundle;
|
||||
if (AppConstants.MOZ_APP_NAME == "thunderbird") {
|
||||
bundle = Services.strings.createBundle(
|
||||
"chrome://messenger/locale/addons.properties"
|
||||
);
|
||||
} else {
|
||||
// For Android, these strings are only used in tests. In the actual UI, the
|
||||
// warnings are in Android-Components, as explained in bug 1671453.
|
||||
bundle = Services.strings.createBundle(
|
||||
"chrome://browser/locale/browser.properties"
|
||||
);
|
||||
}
|
||||
const DUMMY_APP_NAME = "Dummy brandName";
|
||||
const { PERMISSION_L10N_ID_OVERRIDES } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ExtensionPermissionMessages.sys.mjs"
|
||||
);
|
||||
|
||||
const EXTENSION_L10N_PATHS =
|
||||
AppConstants.MOZ_APP_NAME == "thunderbird"
|
||||
? [
|
||||
"messenger/addons.ftl", // FIXME: mock path, file does not exist
|
||||
"messenger/addonPermissions.ftl", // FIXME: mock path, file does not exist
|
||||
"branding/brand.ftl",
|
||||
]
|
||||
: [
|
||||
"toolkit/global/extensions.ftl",
|
||||
"toolkit/global/extensionPermissions.ftl",
|
||||
"branding/brand.ftl",
|
||||
];
|
||||
|
||||
// For Android, these strings are only used in tests. In the actual UI, the
|
||||
// warnings are in Android-Components, as explained in bug 1671453.
|
||||
const l10n = new Localization(EXTENSION_L10N_PATHS, true);
|
||||
|
||||
// nativeMessaging is in PRIVILEGED_PERMS on Android.
|
||||
const IS_NATIVE_MESSAGING_PRIVILEGED = AppConstants.platform == "android";
|
||||
@ -50,18 +57,9 @@ async function getManifestPermissions(extensionData) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getPermissionWarnings(
|
||||
manifestPermissions,
|
||||
options,
|
||||
stringBundle = bundle
|
||||
) {
|
||||
let info = {
|
||||
permissions: manifestPermissions,
|
||||
appName: DUMMY_APP_NAME,
|
||||
};
|
||||
function getPermissionWarnings(permissions, options) {
|
||||
let { msgs } = ExtensionData.formatPermissionStrings(
|
||||
info,
|
||||
stringBundle,
|
||||
{ permissions },
|
||||
options
|
||||
);
|
||||
return msgs;
|
||||
@ -80,44 +78,53 @@ async function getPermissionWarningsForUpdate(
|
||||
// Tests that the callers of ExtensionData.formatPermissionStrings can customize the
|
||||
// mapping between the permission names and related localized strings.
|
||||
add_task(async function customized_permission_keys_mapping() {
|
||||
const mockBundle = {
|
||||
// Mocked nsIStringBundle getStringFromName to returns a fake localized string.
|
||||
GetStringFromName: key => `Fake localized ${key}`,
|
||||
formatStringFromName: (name, params) => "Fake formatted string",
|
||||
const mockLocalization = {
|
||||
formatMessagesSync: args =>
|
||||
args.map(arg => ({
|
||||
value: `Fake localized ${arg.id ?? arg}`,
|
||||
attributes: [],
|
||||
})),
|
||||
formatValueSync: key => `Fake localized ${key}`,
|
||||
formatValuesSync: args =>
|
||||
args.map(arg => `Fake localized ${arg.id ?? arg}`),
|
||||
};
|
||||
|
||||
// Define a non-default mapping for permission names -> locale keys.
|
||||
const getKeyForPermission = perm => `customWebExtPerms.description.${perm}`;
|
||||
const getKeyForPermission = perm => `custom-webext-perms-description-${perm}`;
|
||||
|
||||
const manifest = {
|
||||
permissions: ["downloads", "proxy"],
|
||||
};
|
||||
const expectedWarnings = manifest.permissions.map(k =>
|
||||
mockBundle.GetStringFromName(getKeyForPermission(k))
|
||||
const expectedWarnings = mockLocalization.formatValuesSync(
|
||||
manifest.permissions.map(getKeyForPermission)
|
||||
);
|
||||
const manifestPermissions = await getManifestPermissions({ manifest });
|
||||
|
||||
// Pass the callback function for the non-default key mapping to
|
||||
// ExtensionData.formatPermissionStrings() and verify it being used.
|
||||
const warnings = getPermissionWarnings(
|
||||
manifestPermissions,
|
||||
{ getKeyForPermission },
|
||||
mockBundle
|
||||
);
|
||||
deepEqual(
|
||||
warnings,
|
||||
expectedWarnings,
|
||||
"Got the expected string from customized permission mapping"
|
||||
);
|
||||
try {
|
||||
for (let perm of manifest.permissions) {
|
||||
PERMISSION_L10N_ID_OVERRIDES.set(perm, getKeyForPermission(perm));
|
||||
}
|
||||
const manifestPermissions = await getManifestPermissions({ manifest });
|
||||
|
||||
// Pass the callback function for the non-default key mapping to
|
||||
// ExtensionData.formatPermissionStrings() and verify it being used.
|
||||
const warnings = getPermissionWarnings(manifestPermissions, {
|
||||
localization: mockLocalization,
|
||||
});
|
||||
deepEqual(
|
||||
warnings,
|
||||
expectedWarnings,
|
||||
"Got the expected string from customized permission mapping"
|
||||
);
|
||||
} finally {
|
||||
for (let perm of manifest.permissions) {
|
||||
PERMISSION_L10N_ID_OVERRIDES.delete(perm);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Tests that the expected permission warnings are generated for various
|
||||
// combinations of host permissions.
|
||||
add_task(async function host_permissions() {
|
||||
let { PluralForm } = ChromeUtils.import(
|
||||
"resource://gre/modules/PluralForm.jsm"
|
||||
);
|
||||
|
||||
let permissionTestCases = [
|
||||
{
|
||||
description: "Empty manifest without permissions",
|
||||
@ -167,7 +174,7 @@ add_task(async function host_permissions() {
|
||||
},
|
||||
expectedOrigins: ["<all_urls>"],
|
||||
expectedWarnings: [
|
||||
bundle.GetStringFromName("webextPerms.hostDescription.allUrls"),
|
||||
l10n.formatValueSync("webext-perms-host-description-all-urls"),
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -177,7 +184,7 @@ add_task(async function host_permissions() {
|
||||
},
|
||||
expectedOrigins: ["file://*/"],
|
||||
expectedWarnings: [
|
||||
bundle.GetStringFromName("webextPerms.hostDescription.allUrls"),
|
||||
l10n.formatValueSync("webext-perms-host-description-all-urls"),
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -187,7 +194,7 @@ add_task(async function host_permissions() {
|
||||
},
|
||||
expectedOrigins: ["http://*/"],
|
||||
expectedWarnings: [
|
||||
bundle.GetStringFromName("webextPerms.hostDescription.allUrls"),
|
||||
l10n.formatValueSync("webext-perms-host-description-all-urls"),
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -197,7 +204,7 @@ add_task(async function host_permissions() {
|
||||
},
|
||||
expectedOrigins: ["*://*/"],
|
||||
expectedWarnings: [
|
||||
bundle.GetStringFromName("webextPerms.hostDescription.allUrls"),
|
||||
l10n.formatValueSync("webext-perms-host-description-all-urls"),
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -214,7 +221,7 @@ add_task(async function host_permissions() {
|
||||
},
|
||||
expectedOrigins: ["https://*/"],
|
||||
expectedWarnings: [
|
||||
bundle.GetStringFromName("webextPerms.hostDescription.allUrls"),
|
||||
l10n.formatValueSync("webext-perms-host-description-all-urls"),
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -223,18 +230,21 @@ add_task(async function host_permissions() {
|
||||
permissions: ["http://a/", "http://*.b/", "http://c/*"],
|
||||
},
|
||||
expectedOrigins: ["http://a/", "http://*.b/", "http://c/*"],
|
||||
expectedWarnings: [
|
||||
expectedWarnings: l10n.formatValuesSync([
|
||||
// Wildcard hosts take precedence in the permission list.
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"b",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"a",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"c",
|
||||
]),
|
||||
],
|
||||
{
|
||||
id: "webext-perms-host-description-wildcard",
|
||||
args: { domain: "b" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-one-site",
|
||||
args: { domain: "a" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-one-site",
|
||||
args: { domain: "c" },
|
||||
},
|
||||
]),
|
||||
},
|
||||
{
|
||||
description: "many host permission",
|
||||
@ -262,34 +272,41 @@ add_task(async function host_permissions() {
|
||||
"http://*.3/",
|
||||
"http://*.4/",
|
||||
],
|
||||
expectedWarnings: [
|
||||
expectedWarnings: l10n.formatValuesSync([
|
||||
// Wildcard hosts take precedence in the permission list.
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"1",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"2",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"3",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"4",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"a",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"b",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"c",
|
||||
]),
|
||||
PluralForm.get(
|
||||
2,
|
||||
bundle.GetStringFromName("webextPerms.hostDescription.tooManySites")
|
||||
).replace("#1", "2"),
|
||||
],
|
||||
{
|
||||
id: "webext-perms-host-description-wildcard",
|
||||
args: { domain: "1" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-wildcard",
|
||||
args: { domain: "2" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-wildcard",
|
||||
args: { domain: "3" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-wildcard",
|
||||
args: { domain: "4" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-one-site",
|
||||
args: { domain: "a" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-one-site",
|
||||
args: { domain: "b" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-one-site",
|
||||
args: { domain: "c" },
|
||||
},
|
||||
{
|
||||
id: "webext-perms-host-description-too-many-sites",
|
||||
args: { domainCount: 2 },
|
||||
},
|
||||
]),
|
||||
options: {
|
||||
collapseOrigins: true,
|
||||
},
|
||||
@ -323,38 +340,18 @@ add_task(async function host_permissions() {
|
||||
"http://*.4/",
|
||||
"http://*.5/",
|
||||
],
|
||||
expectedWarnings: [
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"1",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"2",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"3",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"4",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"5",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"a",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"b",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"c",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"d",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", [
|
||||
"e",
|
||||
]),
|
||||
],
|
||||
expectedWarnings: l10n.formatValuesSync([
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "1" } },
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "2" } },
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "3" } },
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "4" } },
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "5" } },
|
||||
{ id: "webext-perms-host-description-one-site", args: { domain: "a" } },
|
||||
{ id: "webext-perms-host-description-one-site", args: { domain: "b" } },
|
||||
{ id: "webext-perms-host-description-one-site", args: { domain: "c" } },
|
||||
{ id: "webext-perms-host-description-one-site", args: { domain: "d" } },
|
||||
{ id: "webext-perms-host-description-one-site", args: { domain: "e" } },
|
||||
]),
|
||||
},
|
||||
];
|
||||
for (let manifest_version of [2, 3]) {
|
||||
@ -423,24 +420,18 @@ add_task(async function api_permissions() {
|
||||
|
||||
deepEqual(
|
||||
getPermissionWarnings(manifestPermissions),
|
||||
[
|
||||
l10n.formatValuesSync([
|
||||
// Host permissions first, with wildcards on top.
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"x",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"tld",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.oneSite", ["x"]),
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "x" } },
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "tld" } },
|
||||
{ id: "webext-perms-host-description-one-site", args: { domain: "x" } },
|
||||
// nativeMessaging permission warning first of all permissions.
|
||||
bundle.formatStringFromName("webextPerms.description.nativeMessaging", [
|
||||
DUMMY_APP_NAME,
|
||||
]),
|
||||
"webext-perms-description-nativeMessaging",
|
||||
// Other permissions in alphabetical order.
|
||||
// Note: activeTab has no permission warning string.
|
||||
bundle.GetStringFromName("webextPerms.description.tabs"),
|
||||
bundle.GetStringFromName("webextPerms.description.webNavigation"),
|
||||
],
|
||||
"webext-perms-description-tabs",
|
||||
"webext-perms-description-webNavigation",
|
||||
]),
|
||||
"Expected warnings"
|
||||
);
|
||||
});
|
||||
@ -492,14 +483,10 @@ add_task(
|
||||
|
||||
deepEqual(
|
||||
getPermissionWarnings(manifestPermissions),
|
||||
[
|
||||
bundle.GetStringFromName(
|
||||
"webextPerms.description.declarativeNetRequest"
|
||||
),
|
||||
bundle.GetStringFromName(
|
||||
"webextPerms.description.declarativeNetRequestFeedback"
|
||||
),
|
||||
],
|
||||
l10n.formatValuesSync([
|
||||
"webext-perms-description-declarativeNetRequest",
|
||||
"webext-perms-description-declarativeNetRequestFeedback",
|
||||
]),
|
||||
"Expected warnings"
|
||||
);
|
||||
}
|
||||
@ -553,7 +540,7 @@ add_task(async function privileged_with_mozillaAddons() {
|
||||
|
||||
deepEqual(
|
||||
getPermissionWarnings(manifestPermissions),
|
||||
[bundle.GetStringFromName("webextPerms.hostDescription.allUrls")],
|
||||
[l10n.formatValueSync("webext-perms-host-description-all-urls")],
|
||||
"Expected warnings for privileged add-on with mozillaAddons permission."
|
||||
);
|
||||
});
|
||||
@ -584,7 +571,11 @@ add_task(async function unprivileged_with_mozillaAddons() {
|
||||
|
||||
deepEqual(
|
||||
getPermissionWarnings(manifestPermissions),
|
||||
[bundle.formatStringFromName("webextPerms.hostDescription.oneSite", ["a"])],
|
||||
[
|
||||
l10n.formatValueSync("webext-perms-host-description-one-site", {
|
||||
domain: "a",
|
||||
}),
|
||||
],
|
||||
"Expected warnings for unprivileged add-on with mozillaAddons permission."
|
||||
);
|
||||
});
|
||||
@ -671,14 +662,10 @@ add_task(async function update_change_permissions() {
|
||||
);
|
||||
deepEqual(
|
||||
warnings,
|
||||
[
|
||||
bundle.formatStringFromName("webextPerms.hostDescription.wildcard", [
|
||||
"c",
|
||||
]),
|
||||
bundle.formatStringFromName("webextPerms.description.proxy", [
|
||||
DUMMY_APP_NAME,
|
||||
]),
|
||||
],
|
||||
l10n.formatValuesSync([
|
||||
{ id: "webext-perms-host-description-wildcard", args: { domain: "c" } },
|
||||
"webext-perms-description-proxy",
|
||||
]),
|
||||
"Expected permission warnings for new permissions only"
|
||||
);
|
||||
});
|
||||
@ -702,7 +689,11 @@ add_task(async function update_privileged_with_mozillaAddons() {
|
||||
);
|
||||
deepEqual(
|
||||
warnings,
|
||||
[bundle.formatStringFromName("webextPerms.hostDescription.oneSite", ["b"])],
|
||||
[
|
||||
l10n.formatValueSync("webext-perms-host-description-one-site", {
|
||||
domain: "b",
|
||||
}),
|
||||
],
|
||||
"Expected permission warnings for new host only"
|
||||
);
|
||||
});
|
||||
|
@ -20,7 +20,13 @@ ChromeUtils.defineModuleGetter(
|
||||
"resource://gre/modules/ExtensionParent.jsm"
|
||||
);
|
||||
|
||||
const BROWSER_PROPERTIES = "chrome://browser/locale/browser.properties";
|
||||
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-add");
|
||||
|
||||
AddonTestUtils.init(this);
|
||||
AddonTestUtils.overrideCertDB();
|
||||
@ -677,7 +683,7 @@ const GRANTED_WITHOUT_USER_PROMPT = [
|
||||
"webRequestFilterResponse.serviceWorkerScript",
|
||||
];
|
||||
|
||||
add_task(function test_permissions_have_localization_strings() {
|
||||
add_task(async function test_permissions_have_localization_strings() {
|
||||
let noPromptNames = Schemas.getPermissionNames([
|
||||
"PermissionNoPrompt",
|
||||
"OptionalPermissionNoPrompt",
|
||||
@ -689,11 +695,10 @@ add_task(function test_permissions_have_localization_strings() {
|
||||
"List of no-prompt permissions is correct."
|
||||
);
|
||||
|
||||
const bundle = Services.strings.createBundle(BROWSER_PROPERTIES);
|
||||
|
||||
for (const perm of Schemas.getPermissionNames()) {
|
||||
try {
|
||||
const str = bundle.GetStringFromName(`webextPerms.description.${perm}`);
|
||||
const permId = perm.replace(/\./g, "-");
|
||||
const str = await l10n.formatValue(`webext-perms-description-${permId}`);
|
||||
|
||||
ok(str.length, `Found localization string for '${perm}' permission`);
|
||||
} catch (e) {
|
||||
|
@ -28,10 +28,13 @@ AddonTestUtils.createAppInfo(
|
||||
"42"
|
||||
);
|
||||
|
||||
const BROWSER_PROPERTIES =
|
||||
AppConstants.MOZ_APP_NAME == "thunderbird"
|
||||
? "chrome://messenger/locale/addons.properties"
|
||||
: "chrome://browser/locale/browser.properties";
|
||||
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-add");
|
||||
|
||||
// Lazily import ExtensionParent to allow AddonTestUtils.createAppInfo to
|
||||
// override Services.appinfo.
|
||||
@ -371,13 +374,10 @@ add_task(async function test_site_permissions_have_localization_strings() {
|
||||
]);
|
||||
ok(SCHEMA_SITE_PERMISSIONS.length, "we have site permissions");
|
||||
|
||||
const bundle = Services.strings.createBundle(BROWSER_PROPERTIES);
|
||||
|
||||
for (const perm of SCHEMA_SITE_PERMISSIONS) {
|
||||
const l10nId = `webext-site-perms-${perm}`;
|
||||
try {
|
||||
const str = bundle.GetStringFromName(
|
||||
`webextSitePerms.description.${perm}`
|
||||
);
|
||||
const str = await l10n.formatValue(l10nId);
|
||||
|
||||
ok(str.length, `Found localization string for '${perm}' site permission`);
|
||||
} catch (e) {
|
||||
|
@ -0,0 +1,32 @@
|
||||
# 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/.
|
||||
|
||||
## Extension permission description keys are derived from permission names.
|
||||
## Permissions for which the message has been changed and the key updated
|
||||
## must have a corresponding entry in the `PERMISSION_L10N_ID_OVERRIDES` map.
|
||||
|
||||
webext-perms-description-bookmarks = Read and modify bookmarks
|
||||
webext-perms-description-browserSettings = Read and modify browser settings
|
||||
webext-perms-description-browsingData = Clear recent browsing history, cookies, and related data
|
||||
webext-perms-description-clipboardRead = Get data from the clipboard
|
||||
webext-perms-description-clipboardWrite = Input data to the clipboard
|
||||
webext-perms-description-declarativeNetRequest = Block content on any page
|
||||
webext-perms-description-declarativeNetRequestFeedback = Read your browsing history
|
||||
webext-perms-description-devtools = Extend developer tools to access your data in open tabs
|
||||
webext-perms-description-downloads = Download files and read and modify the browser’s download history
|
||||
webext-perms-description-downloads-open = Open files downloaded to your computer
|
||||
webext-perms-description-find = Read the text of all open tabs
|
||||
webext-perms-description-geolocation = Access your location
|
||||
webext-perms-description-history = Access browsing history
|
||||
webext-perms-description-management = Monitor extension usage and manage themes
|
||||
webext-perms-description-nativeMessaging = Exchange messages with programs other than { -brand-short-name }
|
||||
webext-perms-description-notifications = Display notifications to you
|
||||
webext-perms-description-pkcs11 = Provide cryptographic authentication services
|
||||
webext-perms-description-privacy = Read and modify privacy settings
|
||||
webext-perms-description-proxy = Control browser proxy settings
|
||||
webext-perms-description-sessions = Access recently closed tabs
|
||||
webext-perms-description-tabs = Access browser tabs
|
||||
webext-perms-description-tabHide = Hide and show browser tabs
|
||||
webext-perms-description-topSites = Access browsing history
|
||||
webext-perms-description-webNavigation = Access browser activity during navigation
|
111
toolkit/locales/en-US/toolkit/global/extensions.ftl
Normal file
111
toolkit/locales/en-US/toolkit/global/extensions.ftl
Normal file
@ -0,0 +1,111 @@
|
||||
# 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/.
|
||||
|
||||
## Headers used in the webextension permissions dialog,
|
||||
## See https://bug1308309.bmoattachments.org/attachment.cgi?id=8814612
|
||||
## for an example of the full dialog.
|
||||
## Note: This string will be used as raw markup. Avoid characters like <, >, &
|
||||
## Variables:
|
||||
## $extension (String): replaced with the localized name of the extension.
|
||||
|
||||
webext-perms-header = Add { $extension }?
|
||||
webext-perms-header-with-perms = Add { $extension }? This extension will have permission to:
|
||||
webext-perms-header-unsigned = Add { $extension }? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source.
|
||||
webext-perms-header-unsigned-with-perms = Add { $extension }? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source. This extension will have permission to:
|
||||
webext-perms-sideload-header = { $extension } added
|
||||
webext-perms-optional-perms-header = { $extension } requests additional permissions.
|
||||
|
||||
##
|
||||
|
||||
webext-perms-add =
|
||||
.label = Add
|
||||
.accesskey = A
|
||||
webext-perms-cancel =
|
||||
.label = Cancel
|
||||
.accesskey = C
|
||||
|
||||
webext-perms-sideload-text = Another program on your computer installed an add-on that may affect your browser. Please review this add-on’s permissions requests and choose to Enable or Cancel (to leave it disabled).
|
||||
webext-perms-sideload-text-no-perms = Another program on your computer installed an add-on that may affect your browser. Please choose to Enable or Cancel (to leave it disabled).
|
||||
webext-perms-sideload-enable =
|
||||
.label = Enable
|
||||
.accesskey = E
|
||||
webext-perms-sideload-cancel =
|
||||
.label = Cancel
|
||||
.accesskey = C
|
||||
|
||||
# Variables:
|
||||
# $extension (String): replaced with the localized name of the extension.
|
||||
webext-perms-update-text = { $extension } has been updated. You must approve new permissions before the updated version will install. Choosing “Cancel” will maintain your current extension version. This extension will have permission to:
|
||||
webext-perms-update-accept =
|
||||
.label = Update
|
||||
.accesskey = U
|
||||
|
||||
webext-perms-optional-perms-list-intro = It wants to:
|
||||
webext-perms-optional-perms-allow =
|
||||
.label = Allow
|
||||
.accesskey = A
|
||||
webext-perms-optional-perms-deny =
|
||||
.label = Deny
|
||||
.accesskey = D
|
||||
|
||||
webext-perms-host-description-all-urls = Access your data for all websites
|
||||
|
||||
# Variables:
|
||||
# $domain (String): will be replaced by the DNS domain for which a webextension is requesting access (e.g., mozilla.org)
|
||||
webext-perms-host-description-wildcard = Access your data for sites in the { $domain } domain
|
||||
|
||||
# Variables:
|
||||
# $domainCount (Number): Integer indicating the number of additional
|
||||
# hosts for which this webextension is requesting permission.
|
||||
webext-perms-host-description-too-many-wildcards =
|
||||
{ $domainCount ->
|
||||
[one] Access your data in { $domainCount } other domain
|
||||
*[other] Access your data in { $domainCount } other domains
|
||||
}
|
||||
# Variables:
|
||||
# $domain (String): will be replaced by the DNS host name for which a webextension is requesting access (e.g., www.mozilla.org)
|
||||
webext-perms-host-description-one-site = Access your data for { $domain }
|
||||
|
||||
# Variables:
|
||||
# $domainCount (Number): Integer indicating the number of additional
|
||||
# hosts for which this webextension is requesting permission.
|
||||
webext-perms-host-description-too-many-sites =
|
||||
{ $domainCount ->
|
||||
[one] Access your data on { $domainCount } other site
|
||||
*[other] Access your data on { $domainCount } other sites
|
||||
}
|
||||
|
||||
## Headers used in the webextension permissions dialog for synthetic add-ons.
|
||||
## The part of the string describing what privileges the extension gives should be consistent
|
||||
## with the value of webext-site-perms-description-gated-perms-{sitePermission}.
|
||||
## Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
## Variables:
|
||||
## $hostname (String): the hostname of the site the add-on is being installed from.
|
||||
|
||||
webext-site-perms-header-with-gated-perms-midi = This add-on gives { $hostname } access to your MIDI devices.
|
||||
webext-site-perms-header-with-gated-perms-midi-sysex = This add-on gives { $hostname } access to your MIDI devices (with SysEx support).
|
||||
|
||||
##
|
||||
|
||||
# This string is used as description in the webextension permissions dialog for synthetic add-ons.
|
||||
# Note, the empty line is used to create a line break between the two sections.
|
||||
# Note, this string will be used as raw markup. Avoid characters like <, >, &
|
||||
webext-site-perms-description-gated-perms-midi =
|
||||
These are usually plug-in devices like audio synthesizers, but might also be built into your computer.
|
||||
|
||||
Websites are normally not allowed to access MIDI devices. Improper usage could cause damage or compromise security.
|
||||
|
||||
## Headers used in the webextension permissions dialog.
|
||||
## Note: This string will be used as raw markup. Avoid characters like <, >, &
|
||||
## Variables:
|
||||
## $extension (String): replaced with the localized name of the extension being installed.
|
||||
## $hostname (String): will be replaced by the DNS host name for which a webextension enables permissions.
|
||||
|
||||
webext-site-perms-header-with-perms = Add { $extension }? This extension grants the following capabilities to { $hostname }:
|
||||
webext-site-perms-header-unsigned-with-perms = Add { $extension }? This extension is unverified. Malicious extensions can steal your private information or compromise your computer. Only add it if you trust the source. This extension grants the following capabilities to { $hostname }:
|
||||
|
||||
## These should remain in sync with permissions.NAME.label in sitePermissions.properties
|
||||
|
||||
webext-site-perms-midi = Access MIDI devices
|
||||
webext-site-perms-midi-sysex = Access MIDI devices with SysEx support
|
@ -25,16 +25,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "browserBundle", () => {
|
||||
return Services.strings.createBundle(
|
||||
"chrome://browser/locale/browser.properties"
|
||||
);
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "brandBundle", () => {
|
||||
return Services.strings.createBundle(
|
||||
"chrome://branding/locale/brand.properties"
|
||||
);
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "extensionStylesheets", () => {
|
||||
const { ExtensionParent } = ChromeUtils.import(
|
||||
"resource://gre/modules/ExtensionParent.jsm"
|
||||
@ -1945,8 +1935,6 @@ class AddonPermissionsList extends HTMLElement {
|
||||
}
|
||||
|
||||
async render() {
|
||||
let appName = brandBundle.GetStringFromName("brandShortName");
|
||||
|
||||
let empty = { origins: [], permissions: [] };
|
||||
let requiredPerms = { ...(this.addon.userPermissions ?? empty) };
|
||||
let optionalPerms = { ...(this.addon.optionalPermissions ?? empty) };
|
||||
@ -1966,9 +1954,7 @@ class AddonPermissionsList extends HTMLElement {
|
||||
{
|
||||
permissions: requiredPerms,
|
||||
optionalPermissions: optionalPerms,
|
||||
appName,
|
||||
},
|
||||
browserBundle,
|
||||
{ buildOptionalOrigins: manifestV3enabled }
|
||||
);
|
||||
let optionalEntries = [
|
||||
@ -2049,15 +2035,10 @@ class AddonSitePermissionsList extends HTMLElement {
|
||||
}
|
||||
|
||||
async render() {
|
||||
let appName = brandBundle.GetStringFromName("brandShortName");
|
||||
let permissions = Extension.formatPermissionStrings(
|
||||
{
|
||||
sitePermissions: this.addon.sitePermissions,
|
||||
siteOrigin: this.addon.siteOrigin,
|
||||
appName,
|
||||
},
|
||||
browserBundle
|
||||
);
|
||||
let permissions = Extension.formatPermissionStrings({
|
||||
sitePermissions: this.addon.sitePermissions,
|
||||
siteOrigin: this.addon.siteOrigin,
|
||||
});
|
||||
|
||||
this.textContent = "";
|
||||
let frag = importTemplate("addon-sitepermissions-list");
|
||||
|
@ -82,6 +82,9 @@ ID01:
|
||||
# policies-descriptions.ftl: These IDs are generated programmatically
|
||||
# from policy names.
|
||||
- browser/locales/en-US/browser/policies/policies-descriptions.ftl
|
||||
# The webext-perms-description-* IDs are generated programmatically
|
||||
# from permission names
|
||||
- toolkit/locales/en-US/toolkit/global/extensionPermissions.ftl
|
||||
ID02:
|
||||
messages:
|
||||
# browser/components/ion/content/ion.ftl
|
||||
@ -185,6 +188,8 @@ CO01:
|
||||
- about-telemetry-firefox-data-doc
|
||||
- about-telemetry-telemetry-client-doc
|
||||
- about-telemetry-telemetry-dashboard
|
||||
# toolkit/locales/en-US/toolkit/global/extensionPermissions.ftl
|
||||
- webext-perms-description-management
|
||||
# toolkit/locales/en-US/toolkit/global/processTypes.ftl
|
||||
- process-type-privilegedmozilla
|
||||
files:
|
||||
|
Loading…
x
Reference in New Issue
Block a user