Bug 1280235 Part 2 Allow webextensions apis to be limited to "Mozilla Extensions" signed extensions
MozReview-Commit-ID: DciT0fWTgef
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -1208,18 +1208,34 @@ this.Extension = class extends Extension
this.localeData.messages.set(locale, result);
});
}
get manifestCacheKey() {
return [this.id, this.version, Services.locale.getAppLocaleAsLangTag()];
}
+ async _parseManifest() {
+ let manifest = await super.parseManifest();
+ if (manifest && manifest.permissions.has("mozillaAddons") &&
+ this.addonData.signedState !== AddonManager.SIGNEDSTATE_PRIVILEGED) {
+ Cu.reportError(`Stripping mozillaAddons permission from ${this.id}`);
+ manifest.permissions.delete("mozillaAddons");
+ let i = manifest.manifest.permissions.indexOf("mozillaAddons");
+ if (i >= 0) {
+ manifest.manifest.permissions.splice(i, 1);
+ } else {
+ throw new Error("Could not find mozilaAddons in original permissions array");
+ }
+ }
+ return manifest;
+ }
+
parseManifest() {
- return StartupCache.manifests.get(this.manifestCacheKey, () => super.parseManifest());
+ return StartupCache.manifests.get(this.manifestCacheKey, () => this._parseManifest());
}
async cachePermissions() {
let manifestData = await this.parseManifest();
manifestData.originPermissions = this.whiteListedHosts.patterns.map(pat => pat.pattern);
manifestData.permissions = this.permissions;
return StartupCache.manifests.set(this.manifestCacheKey, manifestData);
--- a/toolkit/components/extensions/schemas/manifest.json
+++ b/toolkit/components/extensions/schemas/manifest.json
@@ -392,16 +392,17 @@
{
"id": "Permission",
"choices": [
{ "$ref": "OptionalPermission" },
{
"type": "string",
"enum": [
"alarms",
+ "mozillaAddons",
"storage",
"unlimitedStorage"
]
}
]
},
{
"id": "PermissionOrOrigin",
--- a/toolkit/components/extensions/test/xpcshell/test_ext_permissions.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_permissions.js
@@ -403,16 +403,17 @@ const GRANTED_WITHOUT_USER_PROMPT = [
"alarms",
"contextMenus",
"contextualIdentities",
"cookies",
"geckoProfiler",
"identity",
"idle",
"menus",
+ "mozillaAddons",
"storage",
"theme",
"webRequest",
"webRequestBlocking",
];
add_task(function test_permissions_have_localization_strings() {
const ns = Schemas.getNamespace("manifest");
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_schemas_privileged.js
@@ -0,0 +1,79 @@
+"use strict";
+
+Components.utils.import("resource://gre/modules/ExtensionCommon.jsm");
+const {ExtensionAPI} = ExtensionCommon;
+
+Components.utils.importGlobalProperties(["Blob", "URL"]);
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+
+add_task(async function() {
+ const schema = [
+ {
+ namespace: "privileged",
+ permissions: ["mozillaAddons"],
+ properties: {
+ "test": {
+ "type": "any",
+ },
+ },
+ },
+ ];
+
+ class API extends ExtensionAPI {
+ getAPI(context) {
+ return {
+ privileged: {
+ test: "hello",
+ },
+ };
+ }
+ }
+
+ const modules = {
+ privileged: {
+ url: URL.createObjectURL(new Blob([API.toString()])),
+ schema: `data:,${JSON.stringify(schema)}`,
+ scopes: ["addon_parent"],
+ paths: [["privileged"]],
+ },
+ };
+
+ const catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
+ catMan.addCategoryEntry("webextension-modules", "test-privileged",
+ `data:,${JSON.stringify(modules)}`, false, false);
+
+ AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
+ await AddonTestUtils.promiseStartupManager();
+
+ // Try accessing the privileged namespace.
+ async function testOnce() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ applications: {gecko: {id: "privilegedapi@tests.mozilla.org"}},
+ permissions: ["mozillaAddons"],
+ },
+ background() {
+ browser.test.sendMessage("result", browser.privileged instanceof Object);
+ },
+ useAddonManager: "permanent",
+ });
+
+ await extension.startup();
+ let result = await extension.awaitMessage("result");
+ await extension.unload();
+ return result;
+ }
+
+ AddonTestUtils.usePrivilegedSignatures = false;
+ let result = await testOnce();
+ equal(result, false, "Privileged namespace should not be accessible to a regular webextension");
+
+ AddonTestUtils.usePrivilegedSignatures = true;
+ result = await testOnce();
+ equal(result, true, "Privileged namespace should be accessible to a webextension signed with Mozilla Extensions");
+
+ await AddonTestUtils.promiseShutdownManager();
+ catMan.deleteCategoryEntry("webextension-modules", "test-privileged", false);
+});
--- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini
@@ -38,16 +38,17 @@ tags = webextensions in-process-webexten
[test_ext_manifest_incognito.js]
[test_ext_manifest_minimum_chrome_version.js]
[test_ext_manifest_minimum_opera_version.js]
[test_ext_manifest_themes.js]
[test_ext_schemas.js]
[test_ext_schemas_async.js]
[test_ext_schemas_allowed_contexts.js]
[test_ext_schemas_interactive.js]
+[test_ext_schemas_privileged.js]
[test_ext_schemas_revoke.js]
[test_ext_themes_supported_properties.js]
[test_ext_unknown_permissions.js]
[test_locale_converter.js]
[test_locale_data.js]
[test_ext_runtime_sendMessage_args.js]
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -4455,17 +4455,18 @@ this.XPIProvider = {
}
}
}
let params = {
id: aAddon.id,
version: aAddon.version,
installPath: aFile.clone(),
- resourceURI: getURIForResourceInFile(aFile, "")
+ resourceURI: getURIForResourceInFile(aFile, ""),
+ signedState: aAddon.signedState,
};
if (aMethod == "startup" && aAddon.startupData) {
params.startupData = aAddon.startupData;
}
if (aExtraParams) {
for (let key in aExtraParams) {