summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/test_sideload_scopes.js
blob: 6631fa47c5c4a6428c85929ab4131b07df2afc8e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
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();
});