summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/test_sideload_scopes.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_sideload_scopes.js')
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/test_sideload_scopes.js188
1 files changed, 188 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_sideload_scopes.js b/toolkit/mozapps/extensions/test/xpcshell/test_sideload_scopes.js
new file mode 100644
index 0000000000..6631fa47c5
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_sideload_scopes.js
@@ -0,0 +1,188 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+// We refer to addons that were sideloaded prior to disabling sideloading as legacy. We
+// determine that they are legacy because they are in a SCOPE that is not included
+// in AddonSettings.SCOPES_SIDELOAD.
+//
+// test_startup.js tests the legacy sideloading functionality still works as it should
+// for ESR and some 3rd party distributions, which is to allow sideloading in all scopes.
+//
+// This file tests that locking down the sideload functionality works as we expect it to, which
+// is to allow sideloading only in SCOPE_APPLICATION and SCOPE_PROFILE. We also allow the legacy
+// sideloaded addons to be updated or removed.
+//
+// We first change the sideload scope so we can sideload some addons into locations outside
+// the profile (ie. we create some legacy sideloads). We then reset it to test new sideloads.
+//
+// We expect new sideloads to only work in profile.
+// We expect new sideloads to fail elsewhere.
+// We expect to be able to change/uninstall legacy sideloads.
+
+// This test uses add-on versions that follow the toolkit version but we
+// started to encourage the use of a simpler format in Bug 1793925. We disable
+// the pref below to avoid install errors.
+Services.prefs.setBoolPref(
+ "extensions.webextensions.warnings-as-errors",
+ false
+);
+
+// IDs for scopes that should sideload when sideloading
+// is not disabled.
+let legacyIDs = [
+ getID(`legacy-global`),
+ getID(`legacy-user`),
+ getID(`legacy-app`),
+ getID(`legacy-profile`),
+];
+
+add_task(async function test_sideloads_legacy() {
+ let IDs = [];
+
+ // Create a "legacy" addon for each scope.
+ for (let [name, dir] of Object.entries(scopeDirectories)) {
+ let id = getID(`legacy-${name}`);
+ IDs.push(id);
+ await createWebExtension(id, initialVersion(name), dir);
+ }
+
+ await promiseStartupManager();
+
+ // SCOPE_APPLICATION will never sideload, so we expect 3 addons.
+ let sideloaded = await AddonManagerPrivate.getNewSideloads();
+ Assert.equal(sideloaded.length, 4, "four sideloaded addons");
+ let sideloadedIds = sideloaded.map(a => a.id);
+ for (let id of legacyIDs) {
+ Assert.ok(sideloadedIds.includes(id), `${id} is sideloaded`);
+ }
+
+ check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
+
+ await promiseShutdownManager();
+});
+
+// Test that a sideload install in SCOPE_PROFILE is allowed, all others are
+// disallowed.
+add_task(async function test_sideloads_disabled() {
+ // First, reset our scope pref to disable sideloading. head_sideload.js set this to ALL.
+ Services.prefs.setIntPref(
+ "extensions.sideloadScopes",
+ AddonManager.SCOPE_PROFILE
+ );
+
+ // Create 4 new addons, only one of these, "profile" should
+ // sideload.
+ for (let [name, dir] of Object.entries(scopeDirectories)) {
+ await createWebExtension(getID(name), initialVersion(name), dir);
+ }
+
+ await promiseStartupManager();
+
+ // Test that the "profile" addon has been sideloaded.
+ let sideloaded = await AddonManagerPrivate.getNewSideloads();
+ Assert.equal(sideloaded.length, 1, "one sideloaded addon");
+
+ check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, [
+ getID("profile"),
+ ]);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
+
+ for (let [name] of Object.entries(scopeDirectories)) {
+ let id = getID(name);
+ let addon = await promiseAddonByID(id);
+ if (name === "profile") {
+ Assert.notEqual(addon, null);
+ Assert.equal(addon.id, id);
+ Assert.ok(addon.foreignInstall);
+ Assert.equal(addon.scope, AddonManager.SCOPE_PROFILE);
+ Assert.ok(addon.userDisabled);
+ Assert.ok(!addon.seen);
+ } else {
+ Assert.equal(addon, null, `addon ${id} is not installed`);
+ }
+ }
+
+ // Test that we still have the 3 legacy addons from the prior test, plus
+ // the new "profile" addon from this test.
+ let extensionAddons = await AddonManager.getAddonsByTypes(["extension"]);
+ Assert.equal(
+ extensionAddons.length,
+ 5,
+ "five addons expected to be installed"
+ );
+ let IDs = extensionAddons.map(ext => ext.id);
+ for (let id of [getID("profile"), ...legacyIDs]) {
+ Assert.ok(IDs.includes(id), `${id} is installed`);
+ }
+
+ await promiseShutdownManager();
+});
+
+add_task(async function test_sideloads_changed() {
+ // Upgrade the manifest version
+ for (let [name, dir] of Object.entries(scopeDirectories)) {
+ let id = getID(name);
+ await createWebExtension(id, `${name}.1`, dir);
+
+ id = getID(`legacy-${name}`);
+ await createWebExtension(id, `${name}.1`, dir);
+ }
+
+ await promiseStartupManager();
+ let addons = await AddonManager.getAddonsByTypes(["extension"]);
+ Assert.equal(addons.length, 5, "addons installed");
+
+ check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, [
+ getID("profile"),
+ ...legacyIDs,
+ ]);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, []);
+
+ await promiseShutdownManager();
+});
+
+// Remove one just to test the startup changes
+add_task(async function test_sideload_removal() {
+ let id = getID(`legacy-profile`);
+ let file = AddonTestUtils.getFileForAddon(profileDir, id);
+ file.remove(false);
+ Assert.ok(!file.exists());
+
+ await promiseStartupManager();
+
+ check_startup_changes(AddonManager.STARTUP_CHANGE_INSTALLED, []);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_CHANGED, []);
+ check_startup_changes(AddonManager.STARTUP_CHANGE_UNINSTALLED, [id]);
+
+ await promiseShutdownManager();
+});
+
+add_task(async function test_sideload_uninstall() {
+ await promiseStartupManager();
+ let addons = await AddonManager.getAddonsByTypes(["extension"]);
+ Assert.equal(addons.length, 4, "addons installed");
+ for (let addon of addons) {
+ let file = AddonTestUtils.getFileForAddon(
+ scopeToDir.get(addon.scope),
+ addon.id
+ );
+ await addon.uninstall();
+ // Addon file should still exist in non-profile directories.
+ Assert.equal(
+ addon.scope !== AddonManager.SCOPE_PROFILE,
+ file.exists(),
+ `file remains after uninstall for non-profile sideloads, scope ${addon.scope}`
+ );
+ }
+ addons = await AddonManager.getAddonsByTypes(["extension"]);
+ Assert.equal(addons.length, 0, "addons left");
+
+ await promiseShutdownManager();
+});