forked from mirrors/gecko-dev
Bug 1640931 - Allow policy to force addons in private browsing. a=dmeehan
Original Revision: https://phabricator.services.mozilla.com/D228607 Differential Revision: https://phabricator.services.mozilla.com/D238839
This commit is contained in:
parent
e942f3efe9
commit
37a3ea4998
8 changed files with 367 additions and 6 deletions
|
|
@ -710,6 +710,9 @@
|
|||
},
|
||||
"temporarily_allow_weak_signatures": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"private_browsing": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
const { ExtensionPermissions } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ExtensionPermissions.sys.mjs"
|
||||
);
|
||||
|
||||
const ADDON_ID = "policytest@mozilla.com";
|
||||
const BASE_URL =
|
||||
"http://mochi.test:8888/browser/browser/components/enterprisepolicies/tests/browser";
|
||||
|
|
@ -18,6 +22,59 @@ async function isExtensionLockedAndUpdateDisabled(win, addonID) {
|
|||
is(updateRow.hidden, true, "Update row should be hidden");
|
||||
}
|
||||
|
||||
add_task(async function test_addon_private_browser_access_locked() {
|
||||
async function installWithExtensionSettings(extensionSettings = {}) {
|
||||
let installPromise = waitForAddonInstall(ADDON_ID);
|
||||
await setupPolicyEngineWithJson({
|
||||
policies: {
|
||||
ExtensionSettings: {
|
||||
"policytest@mozilla.com": {
|
||||
install_url: `${BASE_URL}/policytest_v0.1.xpi`,
|
||||
installation_mode: "force_installed",
|
||||
updates_disabled: true,
|
||||
...extensionSettings,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await installPromise;
|
||||
let addon = await AddonManager.getAddonByID(ADDON_ID);
|
||||
isnot(addon, null, "Addon not installed.");
|
||||
is(addon.version, "0.1", "Addon version is correct");
|
||||
return addon;
|
||||
}
|
||||
|
||||
let addon = await installWithExtensionSettings();
|
||||
is(
|
||||
Boolean(
|
||||
addon.permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS
|
||||
),
|
||||
true,
|
||||
"Addon should be able to change private browsing setting (not set in policy)."
|
||||
);
|
||||
await addon.uninstall();
|
||||
|
||||
addon = await installWithExtensionSettings({ private_browsing: true });
|
||||
is(
|
||||
Boolean(
|
||||
addon.permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS
|
||||
),
|
||||
false,
|
||||
"Addon should NOT be able to change private browsing setting (set to true in policy)."
|
||||
);
|
||||
await addon.uninstall();
|
||||
|
||||
addon = await installWithExtensionSettings({ private_browsing: false });
|
||||
is(
|
||||
Boolean(
|
||||
addon.permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS
|
||||
),
|
||||
false,
|
||||
"Addon should NOT be able to change private browsing setting (set to false in policy)."
|
||||
);
|
||||
await addon.uninstall();
|
||||
});
|
||||
|
||||
add_task(async function test_addon_install() {
|
||||
let installPromise = waitForAddonInstall(ADDON_ID);
|
||||
await setupPolicyEngineWithJson({
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
webextensions: true,
|
||||
},
|
||||
};
|
||||
|
|
@ -15,6 +15,7 @@ const { ExtensionTestUtils } = ChromeUtils.importESModule(
|
|||
AddonTestUtils.init(this);
|
||||
AddonTestUtils.overrideCertDB();
|
||||
AddonTestUtils.appInfo = getAppInfo();
|
||||
AddonTestUtils.usePrivilegedSignatures = false;
|
||||
ExtensionTestUtils.init(this);
|
||||
|
||||
const server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] });
|
||||
|
|
@ -555,7 +556,7 @@ add_task(async function test_policy_installed_only_addon() {
|
|||
// Setting back the extension settings with installation_mode set to force_installed
|
||||
// will install the extension again, and so we need to wait for that and uninstall
|
||||
// it first (otherwise the addon may endup being installed when the test task is
|
||||
// completed and trigger an intermittent failre).
|
||||
// completed and trigger an intermittent failure).
|
||||
installPromise = waitForAddonInstall(policyOnlyID);
|
||||
await setupPolicyEngineWithJson({
|
||||
policies: {
|
||||
|
|
@ -613,3 +614,103 @@ add_task(async function test_policy_installed_only_addon() {
|
|||
"Got the expect error logged on installing enterprise only extension"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_private_browsing() {
|
||||
async function assertPrivateBrowsingAccess({
|
||||
addonId,
|
||||
extensionSettings,
|
||||
extensionManifest = {},
|
||||
expectedPrivateBrowsingAccess,
|
||||
message,
|
||||
}) {
|
||||
await setupPolicyEngineWithJson({
|
||||
policies: {
|
||||
ExtensionSettings: {
|
||||
[addonId]: { ...extensionSettings },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
let ext = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
browser_specific_settings: {
|
||||
gecko: { id: addonId },
|
||||
},
|
||||
...extensionManifest,
|
||||
},
|
||||
useAddonManager: "temporary",
|
||||
background() {
|
||||
browser.test.onMessage.addListener(async msg => {
|
||||
switch (msg) {
|
||||
case "checkPrivateBrowsing": {
|
||||
let isAllowed =
|
||||
await browser.extension.isAllowedIncognitoAccess();
|
||||
browser.test.sendMessage("privateBrowsing", isAllowed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await ext.startup();
|
||||
|
||||
ext.sendMessage("checkPrivateBrowsing");
|
||||
let isAllowedIncognitoAccess = await ext.awaitMessage("privateBrowsing");
|
||||
Assert.equal(
|
||||
isAllowedIncognitoAccess,
|
||||
expectedPrivateBrowsingAccess,
|
||||
message
|
||||
);
|
||||
|
||||
let addon = await AddonManager.getAddonByID(ext.id);
|
||||
// Sanity check (to ensure the test extension used in this test are not privileged).
|
||||
ok(!addon.isPrivileged, "Addon should not be privileged");
|
||||
|
||||
let expectLocked = typeof extensionSettings?.private_browsing === "boolean";
|
||||
Assert.equal(
|
||||
!(
|
||||
addon.permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS
|
||||
),
|
||||
expectLocked,
|
||||
`Addon should ${expectLocked ? "NOT" : ""} be able to change private browsing setting.`
|
||||
);
|
||||
|
||||
await ext.unload();
|
||||
}
|
||||
|
||||
await assertPrivateBrowsingAccess({
|
||||
addonId: "privatebrowsing-granted-nonprivileged@test",
|
||||
extensionSettings: { private_browsing: true },
|
||||
expectedPrivateBrowsingAccess: true,
|
||||
message:
|
||||
"Should have access to private browsing (set to true in policy extension setting)",
|
||||
});
|
||||
|
||||
await assertPrivateBrowsingAccess({
|
||||
addonId: "privatebrowsing-revoked-nonprivileged@test",
|
||||
extensionSettings: { private_browsing: false },
|
||||
expectedPrivateBrowsingAccess: false,
|
||||
message:
|
||||
"Should NOT have access to private browsing (set to false in policy extension setting)",
|
||||
});
|
||||
|
||||
await assertPrivateBrowsingAccess({
|
||||
addonId: "privatebrowsing-nosetting-nonprivileged@test",
|
||||
extensionSettings: {},
|
||||
expectedPrivateBrowsingAccess: false,
|
||||
message:
|
||||
"Should NOT have access to private browsing (NOT set in policy extension setting)",
|
||||
});
|
||||
|
||||
await assertPrivateBrowsingAccess({
|
||||
addonId: "privatebrowsing-notallowed-nonprivileged@test",
|
||||
extensionSettings: { private_browsing: true },
|
||||
extensionManifest: {
|
||||
incognito: "not_allowed",
|
||||
},
|
||||
expectedPrivateBrowsingAccess: false,
|
||||
message:
|
||||
"incognito 'not_allowed' extensions should NOT have access to private browser",
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3738,7 +3738,8 @@ export class Extension extends ExtensionData {
|
|||
// We automatically add permissions to system/built-in extensions.
|
||||
// Extensions expliticy stating not_allowed will never get permission.
|
||||
let isAllowed = this.permissions.has(PRIVATE_ALLOWED_PERMISSION);
|
||||
if (this.manifest.incognito === "not_allowed") {
|
||||
const hasIncognitoNotAllowed = this.manifest.incognito === "not_allowed";
|
||||
if (hasIncognitoNotAllowed) {
|
||||
// If an extension previously had permission, but upgrades/downgrades to
|
||||
// a version that specifies "not_allowed" in manifest, remove the
|
||||
// permission.
|
||||
|
|
@ -3764,6 +3765,32 @@ export class Extension extends ExtensionData {
|
|||
this.permissions.add(PRIVATE_ALLOWED_PERMISSION);
|
||||
}
|
||||
|
||||
// On builds where Enterprise Policies are supported, grant or revoke
|
||||
// the private browsing access for extensions that are not app provided
|
||||
// (system and builtin add-ons) or hidden.
|
||||
if (
|
||||
Services.policies &&
|
||||
!this.isAppProvided &&
|
||||
!this.isHidden &&
|
||||
!hasIncognitoNotAllowed &&
|
||||
this.type === "extension"
|
||||
) {
|
||||
const settings = Services.policies.getExtensionSettings(this.id);
|
||||
if (settings?.private_browsing) {
|
||||
lazy.ExtensionPermissions.add(this.id, {
|
||||
permissions: [PRIVATE_ALLOWED_PERMISSION],
|
||||
origins: [],
|
||||
});
|
||||
this.permissions.add(PRIVATE_ALLOWED_PERMISSION);
|
||||
} else if (settings?.private_browsing === false) {
|
||||
lazy.ExtensionPermissions.remove(this.id, {
|
||||
permissions: [PRIVATE_ALLOWED_PERMISSION],
|
||||
origins: [],
|
||||
});
|
||||
this.permissions.delete(PRIVATE_ALLOWED_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
// We only want to update the SVG_CONTEXT_PROPERTIES_PERMISSION during
|
||||
// install and upgrade/downgrade startups.
|
||||
if (INSTALL_AND_UPDATE_STARTUP_REASONS.has(this.startupReason)) {
|
||||
|
|
|
|||
|
|
@ -910,9 +910,12 @@ export class AddonInternal {
|
|||
}
|
||||
}
|
||||
|
||||
let settings = Services.policies?.getExtensionSettings(this.id) || {};
|
||||
// The permission to "toggle the private browsing access" is locked down
|
||||
// when the extension has opted out or it gets the permission automatically
|
||||
// on every extension startup (as system, privileged and builtin addons).
|
||||
// on every extension startup (as system, privileged and builtin addons) or
|
||||
// when private browsing access as been set and locked through enterprise
|
||||
// policy settings.
|
||||
if (
|
||||
(this.type === "extension" ||
|
||||
// TODO(Bug 1789718): Remove after the deprecated XPIProvider-based implementation is also removed.
|
||||
|
|
@ -920,7 +923,8 @@ export class AddonInternal {
|
|||
this.incognito !== "not_allowed" &&
|
||||
this.signedState !== lazy.AddonManager.SIGNEDSTATE_PRIVILEGED &&
|
||||
this.signedState !== lazy.AddonManager.SIGNEDSTATE_SYSTEM &&
|
||||
!this.location.isBuiltin
|
||||
!this.location.isBuiltin &&
|
||||
!("private_browsing" in settings)
|
||||
) {
|
||||
permissions |= lazy.AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,10 @@ AddonTestUtils.createAppInfo(
|
|||
"1"
|
||||
);
|
||||
|
||||
async function getWrapper(id, hidden) {
|
||||
async function getWrapper(id, hidden, { manifest } = {}) {
|
||||
let wrapper = await installBuiltinExtension({
|
||||
manifest: {
|
||||
...manifest,
|
||||
browser_specific_settings: { gecko: { id } },
|
||||
hidden,
|
||||
},
|
||||
|
|
@ -147,3 +148,79 @@ add_task(async function test_builtin_update() {
|
|||
await wrapper.unload();
|
||||
await AddonTestUtils.promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Tests private_browsing policy extension settings doesn't apply
|
||||
// to built-in extensions.
|
||||
add_task(
|
||||
// This test is skipped on builds that don't support enterprise policies
|
||||
// (e.g. android builds).
|
||||
{ skip_if: () => !Services.policies },
|
||||
async function test_builtin_private_browsing_policy_setting() {
|
||||
await AddonTestUtils.promiseStartupManager();
|
||||
|
||||
const { EnterprisePolicyTesting } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/EnterprisePolicyTesting.sys.mjs"
|
||||
);
|
||||
|
||||
let id = "builtin-addon@tests.mozilla.org";
|
||||
let idNotAllowed = "builtin-not-allowed@tests.mozilla.org";
|
||||
|
||||
await EnterprisePolicyTesting.setupPolicyEngineWithJson({
|
||||
policies: {
|
||||
ExtensionSettings: {
|
||||
[id]: {
|
||||
private_browsing: false,
|
||||
},
|
||||
[idNotAllowed]: {
|
||||
private_browsing: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Sanity check the policy data has been loaded.
|
||||
Assert.equal(
|
||||
Services.policies.getExtensionSettings(id)?.private_browsing,
|
||||
false,
|
||||
`Got expected policies setting private_browsing for ${id}`
|
||||
);
|
||||
Assert.equal(
|
||||
Services.policies.getExtensionSettings(idNotAllowed)?.private_browsing,
|
||||
true,
|
||||
`Got expected policies setting private_browsing for ${idNotAllowed}`
|
||||
);
|
||||
|
||||
async function assertPrivateBrowsingAllowed({
|
||||
addonId,
|
||||
manifest,
|
||||
expectedPrivateBrowsingAllowed,
|
||||
}) {
|
||||
let wrapper = await getWrapper(addonId, undefined, { manifest });
|
||||
let addon = await promiseAddonByID(addonId);
|
||||
notEqual(addon, null, `${addonId} is installed`);
|
||||
ok(addon.isActive, `${addonId} is active`);
|
||||
ok(addon.isPrivileged, `${addonId} is privileged`);
|
||||
ok(wrapper.extension.isAppProvided, `${addonId} is app provided`);
|
||||
equal(
|
||||
wrapper.extension.privateBrowsingAllowed,
|
||||
expectedPrivateBrowsingAllowed,
|
||||
`Builtin Addon ${addonId} should ${expectedPrivateBrowsingAllowed ? "" : "NOT"} have access private browsing access`
|
||||
);
|
||||
await wrapper.unload();
|
||||
}
|
||||
|
||||
await assertPrivateBrowsingAllowed({
|
||||
addonId: id,
|
||||
expectedPrivateBrowsingAllowed: true,
|
||||
});
|
||||
await assertPrivateBrowsingAllowed({
|
||||
addonId: idNotAllowed,
|
||||
manifest: {
|
||||
incognito: "not_allowed",
|
||||
},
|
||||
expectedPrivateBrowsingAllowed: false,
|
||||
});
|
||||
|
||||
await AddonTestUtils.promiseShutdownManager();
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -13,9 +13,14 @@ AddonTestUtils.createAppInfo(
|
|||
|
||||
AddonTestUtils.usePrivilegedSignatures = id => id.startsWith("system");
|
||||
|
||||
async function promiseInstallSystemProfileExtension(id, hidden) {
|
||||
async function promiseInstallSystemProfileExtension(
|
||||
id,
|
||||
hidden,
|
||||
{ manifest } = {}
|
||||
) {
|
||||
let xpi = await AddonTestUtils.createTempWebExtensionFile({
|
||||
manifest: {
|
||||
...manifest,
|
||||
browser_specific_settings: { gecko: { id } },
|
||||
hidden,
|
||||
},
|
||||
|
|
@ -202,3 +207,83 @@ add_task(async function test_system_profile_location_require_system_cert() {
|
|||
await addon.uninstall();
|
||||
await AddonTestUtils.promiseShutdownManager();
|
||||
});
|
||||
|
||||
// Tests private_browsing policy extension settings doesn't apply
|
||||
// to system addons.
|
||||
add_task(
|
||||
// This test is skipped on builds that don't support enterprise policies
|
||||
// (e.g. android builds).
|
||||
{ skip_if: () => !Services.policies },
|
||||
async function test_builtin_private_browsing_policy_setting() {
|
||||
await AddonTestUtils.promiseStartupManager();
|
||||
|
||||
const { EnterprisePolicyTesting } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/EnterprisePolicyTesting.sys.mjs"
|
||||
);
|
||||
|
||||
let id = "systemaddon@tests.mozilla.org";
|
||||
let idNotAllowed = "systemaddon-not-allowed@tests.mozilla.org";
|
||||
|
||||
await EnterprisePolicyTesting.setupPolicyEngineWithJson({
|
||||
policies: {
|
||||
ExtensionSettings: {
|
||||
[id]: {
|
||||
private_browsing: false,
|
||||
},
|
||||
[idNotAllowed]: {
|
||||
private_browsing: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Sanity check the policy data has been loaded.
|
||||
Assert.equal(
|
||||
Services.policies.getExtensionSettings(id)?.private_browsing,
|
||||
false,
|
||||
`Got expected policies setting private_browsing for ${id}`
|
||||
);
|
||||
Assert.equal(
|
||||
Services.policies.getExtensionSettings(idNotAllowed)?.private_browsing,
|
||||
true,
|
||||
`Got expected policies setting private_browsing for ${idNotAllowed}`
|
||||
);
|
||||
|
||||
async function assertPrivateBrowsingAllowed({
|
||||
addonId,
|
||||
manifest,
|
||||
expectedPrivateBrowsingAllowed,
|
||||
}) {
|
||||
let wrapper = await promiseInstallSystemProfileExtension(
|
||||
addonId,
|
||||
undefined,
|
||||
{ manifest }
|
||||
);
|
||||
let addon = await promiseAddonByID(addonId);
|
||||
notEqual(addon, null, `${addonId} is installed`);
|
||||
ok(addon.isActive, `${addonId} is active`);
|
||||
ok(addon.isPrivileged, `${addonId} is privileged`);
|
||||
ok(wrapper.extension.isAppProvided, `${addonId} is app provided`);
|
||||
equal(
|
||||
wrapper.extension.privateBrowsingAllowed,
|
||||
expectedPrivateBrowsingAllowed,
|
||||
`Builtin Addon ${addonId} should ${expectedPrivateBrowsingAllowed ? "" : "NOT"} have access private browsing access`
|
||||
);
|
||||
await wrapper.unload();
|
||||
}
|
||||
|
||||
await assertPrivateBrowsingAllowed({
|
||||
addonId: id,
|
||||
expectedPrivateBrowsingAllowed: true,
|
||||
});
|
||||
await assertPrivateBrowsingAllowed({
|
||||
addonId: idNotAllowed,
|
||||
manifest: {
|
||||
incognito: "not_allowed",
|
||||
},
|
||||
expectedPrivateBrowsingAllowed: false,
|
||||
});
|
||||
|
||||
await AddonTestUtils.promiseShutdownManager();
|
||||
}
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue