Commit 1d62ba68 authored by Michael Kaply's avatar Michael Kaply
Browse files

Bug 1449021 - Policy for install/uninstalling add-ons. r=Felipe

MozReview-Commit-ID: HBcbs4hWfEA

--HG--
extra : rebase_source : e2cb628d099d20a36a71b749967b58b83f43fd35
parent 34910378
......@@ -13,6 +13,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gXulStore",
XPCOMUtils.defineLazyModuleGetters(this, {
BookmarksPolicies: "resource:///modules/policies/BookmarksPolicies.jsm",
ProxyPolicies: "resource:///modules/policies/ProxyPolicies.jsm",
AddonManager: "resource://gre/modules/AddonManager.jsm",
});
const PREF_LOGLEVEL = "browser.policies.loglevel";
......@@ -279,6 +280,63 @@ var Policies = {
}
},
"Extensions": {
onBeforeUIStartup(manager, param) {
if ("Install" in param) {
runOncePerModification("extensionsInstall", JSON.stringify(param.Install), () => {
for (let location of param.Install) {
let url;
if (location.includes("://")) {
// Assume location is an URI
url = location;
} else {
// Assume location is a file path
let xpiFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
try {
xpiFile.initWithPath(location);
} catch (e) {
log.error(`Invalid extension path location - ${location}`);
continue;
}
url = Services.io.newFileURI(xpiFile).spec;
}
AddonManager.getInstallForURL(url, (install) => {
let listener = {
onDownloadFailed: () => {
log.error(`Download failed - ${location}`);
},
onInstallFailed: () => {
log.error(`Installation failed - ${location}`);
},
onInstallEnded: () => {
log.debug(`Installation succeeded - ${location}`);
}
};
install.addListener(listener);
install.install();
}, "application/x-xpinstall");
}
});
}
if ("Uninstall" in param) {
runOncePerModification("extensionsUninstall", JSON.stringify(param.Uninstall), () => {
AddonManager.getAddonsByIDs(param.Uninstall, (addons) => {
for (let addon of addons) {
if (addon) {
addon.uninstall();
}
}
});
});
}
if ("Locked" in param) {
for (let ID of param.Locked) {
manager.disallowFeature(`modify-extension:${ID}`);
}
}
}
},
"FlashPlugin": {
onBeforeUIStartup(manager, param) {
addAllowDenyPermissions("plugin:flash", param.Allow, param.Block);
......
......@@ -222,6 +222,34 @@
"required": ["Value"]
},
"Extensions": {
"description": "Install, uninstall or lock extensions. The Install option takes URLs or paths as parameters. The Uninstall and Locked options take extension IDs.",
"first_available": "60.0",
"enterprise_only": true,
"type": "object",
"properties": {
"Install" : {
"type": "array",
"items": {
"type": "string"
}
},
"Uninstall" : {
"type": "array",
"items": {
"type": "string"
}
},
"Locked" : {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"FlashPlugin": {
"description": "Allow or deny flash plugin usage.",
"first_available": "60.0",
......
......@@ -5,6 +5,7 @@ support-files =
config_broken_json.json
opensearch.html
opensearchEngine.xml
policytest.xpi
[browser_policies_basic_tests.js]
[browser_policies_broken_json.js]
......@@ -35,6 +36,7 @@ support-files =
[browser_policy_disable_shield.js]
[browser_policy_display_bookmarks.js]
[browser_policy_display_menu.js]
[browser_policy_extensions.js]
[browser_policy_proxy.js]
[browser_policy_search_engine.js]
[browser_policy_set_homepage.js]
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const addonID = "policytest@mozilla.com";
add_task(async function test_addon_install() {
await setupPolicyEngineWithJson({
"policies": {
"Extensions": {
"Install": [
"http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser/policytest.xpi"
],
"Locked": [
addonID
]
}
}
});
await wait_for_addon_install();
let addon = await AddonManager.getAddonByID(addonID);
isnot(addon, null, "Addon not installed.");
});
add_task(async function test_addon_locked() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
await BrowserOpenAddonsMgr("addons://list/extension");
// eslint-disable-next-line no-shadow
await ContentTask.spawn(tab.linkedBrowser, {addonID}, async function({addonID}) {
let list = content.document.getElementById("addon-list");
let flashEntry = list.getElementsByAttribute("value", addonID)[0];
let disableBtn = content.document.getAnonymousElementByAttribute(flashEntry, "anonid", "disable-btn");
let removeBtn = content.document.getAnonymousElementByAttribute(flashEntry, "anonid", "remove-btn");
is(removeBtn.hidden, true, "Remove button should be hidden");
is(disableBtn.hidden, true, "Disable button should be hidden");
});
BrowserTestUtils.removeTab(tab);
});
add_task(async function test_addon_uninstall() {
await setupPolicyEngineWithJson({
"policies": {
"Extensions": {
"Uninstall": [
addonID
]
}
}
});
let addon = await AddonManager.getAddonByID(addonID);
is(addon, null, "Addon should be uninstalled.");
});
function wait_for_addon_install() {
return new Promise((resolve, reject) => {
AddonManager.addInstallListener({
onInstallEnded(install, addon) {
if (addon.id == addonID)
resolve();
},
onDownloadFailed: (install) => {
reject();
},
onInstallFailed: (install) => {
reject();
},
});
});
}
......@@ -4726,6 +4726,12 @@ AddonInternal.prototype = {
permissions |= AddonManager.PERM_CAN_UNINSTALL;
}
if (Services.policies &&
!Services.policies.isAllowed(`modify-extension:${this.id}`)) {
permissions &= ~AddonManager.PERM_CAN_UNINSTALL;
permissions &= ~AddonManager.PERM_CAN_DISABLE;
}
return permissions;
},
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment