Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
*/
// Checks that changes that cause an add-on to become unblocked or blocked have
// the right effect
// The tests follow a mostly common pattern. First they start with the add-ons
// unblocked, then they make a change that causes the add-ons to become blocked
// then they make a similar change that keeps the add-ons blocked then they make
// a change that unblocks the add-ons. Some tests skip the initial part and
// start with add-ons detected as blocked.
// softblock1 is enabled/disabled by the blocklist changes so its softDisabled
// property should always match its userDisabled property
// softblock2 gets manually enabled then disabled after it becomes blocked so
// its softDisabled property should never become true after that
// softblock3 does the same as softblock2 however it remains disabled
// softblock4 is disabled while unblocked and so should never have softDisabled
// set to true and stay userDisabled. This add-on is not used in tests that
// start with add-ons blocked as it would be identical to softblock3
const URI_EXTENSION_BLOCKLIST_DIALOG =
// Allow insecure updates
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
// TODO bug 1649906: strip blocklist v2-specific parts of this test.
// All specific logic is already covered by other test files, but the tests
// here trigger the logic via higher-level methods, so it may make sense to
// keep this file even after the removal of blocklist v2.
const useMLBF = Services.prefs.getBoolPref(
"extensions.blocklist.useMLBF",
true
);
var testserver = createHttpServer({ hosts: ["example.com"] });
function permissionPromptHandler(subject) {
ok(
subject?.wrappedJSObject?.info?.resolve,
"Got a permission prompt notification as expected"
);
subject.wrappedJSObject.info.resolve();
}
Services.obs.addObserver(
permissionPromptHandler,
"webextension-permission-prompt"
);
registerCleanupFunction(() => {
Services.obs.removeObserver(
permissionPromptHandler,
"webextension-permission-prompt"
);
});
const XPIS = {};
const ADDON_IDS = [
"softblock1@tests.mozilla.org",
"softblock2@tests.mozilla.org",
"softblock3@tests.mozilla.org",
"softblock4@tests.mozilla.org",
"hardblock@tests.mozilla.org",
"regexpblock@tests.mozilla.org",
];
const BLOCK_APP = [
{
guid: "xpcshell@tests.mozilla.org",
maxVersion: "2.*",
minVersion: "2",
},
];
// JEXL filter expression that matches BLOCK_APP.
const BLOCK_APP_FILTER_EXPRESSION = `env.appinfo.ID == "xpcshell@tests.mozilla.org" && env.appinfo.version >= "2" && env.appinfo.version < "3"`;
function softBlockApp(id) {
return {
guid: `${id}@tests.mozilla.org`,
versionRange: [
{
severity: "1",
targetApplication: BLOCK_APP,
},
],
};
}
function softBlockAddonChange(id) {
return {
guid: `${id}@tests.mozilla.org`,
versionRange: [
{
severity: "1",
minVersion: "2",
maxVersion: "3",
},
],
};
}
function softBlockUpdate2(id) {
return {
guid: `${id}@tests.mozilla.org`,
versionRange: [{ severity: "1" }],
};
}
function softBlockManual(id) {
return {
guid: `${id}@tests.mozilla.org`,
versionRange: [
{
maxVersion: "2",
minVersion: "1",
severity: "1",
},
],
};
}
const BLOCKLIST_DATA = {
empty_blocklist: [],
app_update: [
softBlockApp("softblock1"),
softBlockApp("softblock2"),
softBlockApp("softblock3"),
softBlockApp("softblock4"),
{
guid: "hardblock@tests.mozilla.org",
versionRange: [
{
targetApplication: BLOCK_APP,
},
],
},
{
guid: "/^RegExp/",
versionRange: [
{
severity: "1",
targetApplication: BLOCK_APP,
},
],
},
{
guid: "/^RegExp/i",
versionRange: [
{
targetApplication: BLOCK_APP,
},
],
},
],
addon_change: [
softBlockAddonChange("softblock1"),
softBlockAddonChange("softblock2"),
softBlockAddonChange("softblock3"),
softBlockAddonChange("softblock4"),
{
guid: "hardblock@tests.mozilla.org",
versionRange: [
{
maxVersion: "3",
minVersion: "2",
},
],
},
{
_comment:
"Two RegExp matches, so test flags work - first shouldn't match.",
guid: "/^RegExp/",
versionRange: [
{
maxVersion: "3",
minVersion: "2",
severity: "1",
},
],
},
{
guid: "/^RegExp/i",
versionRange: [
{
maxVersion: "3",
minVersion: "2",
severity: "2",
},
],
},
],
blocklist_update2: [
softBlockUpdate2("softblock1"),
softBlockUpdate2("softblock2"),
softBlockUpdate2("softblock3"),
softBlockUpdate2("softblock4"),
{
guid: "hardblock@tests.mozilla.org",
versionRange: [],
},
{
guid: "/^RegExp/",
versionRange: [{ severity: "1" }],
},
{
guid: "/^RegExp/i",
versionRange: [],
},
],
manual_update: [
softBlockManual("softblock1"),
softBlockManual("softblock2"),
softBlockManual("softblock3"),
softBlockManual("softblock4"),
{
guid: "hardblock@tests.mozilla.org",
versionRange: [
{
maxVersion: "2",
minVersion: "1",
},
],
},
{
guid: "/^RegExp/i",
versionRange: [
{
maxVersion: "2",
minVersion: "1",
},
],
},
],
};
// Blocklist v3 (useMLBF) only supports hard blocks by guid+version. Version
// ranges, regexps and soft blocks are not supported. So adjust expectations to
// ensure that the test passes even if useMLBF=true, by:
// - soft blocks are converted to hard blocks.
// - hard blocks are accepted as-is.
// - regexps blocks are converted to hard blocks.
// - Version ranges are expanded to cover all known versions.
if (useMLBF) {
for (let [key, blocks] of Object.entries(BLOCKLIST_DATA)) {
BLOCKLIST_DATA[key] = [];
for (let block of blocks) {
let { guid } = block;
if (guid.includes("RegExp")) {
guid = "regexpblock@tests.mozilla.org";
} else if (!guid.startsWith("soft") && !guid.startsWith("hard")) {
throw new Error(`Unexpected mock addon ID: ${guid}`);
}
const {
minVersion = "1",
maxVersion = "3",
targetApplication,
} = block.versionRange?.[0] || {};
for (let v = minVersion; v <= maxVersion; ++v) {
BLOCKLIST_DATA[key].push({
// Assume that IF targetApplication is set, that it is BLOCK_APP.
filter_expression: targetApplication && BLOCK_APP_FILTER_EXPRESSION,
stash: {
// XPI files use version `${v}.0`, update manifests use `${v}`.
blocked: [`${guid}:${v}.0`, `${guid}:${v}`],
unblocked: [],
},
});
}
}
}
}
// this code and the related code in Blocklist.sys.mjs (specific to XML blocklist) is
// dead code and can be removed. See https://bugzilla.mozilla.org/show_bug.cgi?id=1549550 .
//
// Don't need the full interface, attempts to call other methods will just
// throw which is just fine
var WindowWatcher = {
openWindow(parent, url, name, features, openArgs) {
// Should be called to list the newly blocklisted items
Assert.equal(url, URI_EXTENSION_BLOCKLIST_DIALOG);
// Simulate auto-disabling any softblocks
var list = openArgs.wrappedJSObject.list;
list.forEach(function (aItem) {
if (!aItem.blocked) {
aItem.disable = true;
}
});
// run the code after the blocklist is closed
Services.obs.notifyObservers(null, "addon-blocklist-closed");
},
QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
};
MockRegistrar.register(
"@mozilla.org/embedcomp/window-watcher;1",
WindowWatcher
);
var InstallConfirm = {
confirm(aWindow, aUrl, aInstalls) {
aInstalls.forEach(function (aInstall) {
aInstall.install();
});
},
QueryInterface: ChromeUtils.generateQI(["amIWebInstallPrompt"]),
};
var InstallConfirmFactory = {
createInstance: function createInstance(iid) {
return InstallConfirm.QueryInterface(iid);
},
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(
Components.ID("{f0863905-4dde-42e2-991c-2dc8209bc9ca}"),
"Fake Install Prompt",
"@mozilla.org/addons/web-install-prompt;1",
InstallConfirmFactory
);
function Pload_blocklist(aId) {
return AddonTestUtils.loadBlocklistRawData({
[useMLBF ? "extensionsMLBF" : "extensions"]: BLOCKLIST_DATA[aId],
});
}
// Does a background update check for add-ons and returns a promise that
// resolves when any started installs complete
function Pbackground_update() {
return new Promise(resolve => {
let installCount = 0;
let backgroundCheckCompleted = false;
AddonManager.addInstallListener({
onNewInstall() {
installCount++;
},
onInstallEnded() {
installCount--;
// Wait until all started installs have completed
if (installCount) {
return;
}
AddonManager.removeInstallListener(this);
// If the background check hasn't yet completed then let that call the
// callback when it is done
if (!backgroundCheckCompleted) {
return;
}
resolve();
},
});
Services.obs.addObserver(function observer() {
Services.obs.removeObserver(
observer,
"addons-background-update-complete"
);
backgroundCheckCompleted = true;
// If any new installs have started then we'll call the callback once they
// are completed
if (installCount) {
return;
}
resolve();
}, "addons-background-update-complete");
AddonManagerPrivate.backgroundUpdateCheck();
});
}
// Manually updates the test add-ons to the given version
function Pmanual_update(aVersion) {
const names = ["soft1", "soft2", "soft3", "soft4", "hard", "regexp"];
return Promise.all(
names.map(async name => {
let url = `http://example.com/addons/blocklist_${name}_${aVersion}.xpi`;
let install = await AddonManager.getInstallForURL(url);
// installAddonFromAOM() does more checking than install.install().
// In particular, it will refuse to install an incompatible addon.
return new Promise(resolve => {
install.addListener({
onDownloadCancelled: resolve,
onInstallEnded: resolve,
});
AddonManager.installAddonFromAOM(null, null, install);
});
})
);
}
// Checks that an add-ons properties match expected values
function check_addon(
aAddon,
aExpectedVersion,
aExpectedUserDisabled,
aExpectedSoftDisabled,
aExpectedState
) {
if (useMLBF) {
if (aAddon.id.startsWith("soft")) {
if (aExpectedState === Ci.nsIBlocklistService.STATE_SOFTBLOCKED) {
// The whole test file assumes that an add-on is "user-disabled" after
// an explicit disable(), or after a soft block (without enable()).
// With useMLBF, soft blocks are not supported, so the "user-disabled"
// state matches the usual behavior of "userDisabled" (=disable()).
aExpectedUserDisabled = aAddon.userDisabled;
aExpectedSoftDisabled = false;
aExpectedState = Ci.nsIBlocklistService.STATE_BLOCKED;
}
}
}
Assert.notEqual(aAddon, null);
info(
"Testing " +
aAddon.id +
" version " +
aAddon.version +
" user " +
aAddon.userDisabled +
" soft " +
aAddon.softDisabled +
" perms " +
aAddon.permissions
);
Assert.equal(aAddon.version, aExpectedVersion);
Assert.equal(aAddon.blocklistState, aExpectedState);
Assert.equal(aAddon.userDisabled, aExpectedUserDisabled);
Assert.equal(aAddon.softDisabled, aExpectedSoftDisabled);
if (aAddon.softDisabled) {
Assert.ok(aAddon.userDisabled);
}
if (aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED) {
info("blocked, PERM_CAN_ENABLE " + aAddon.id);
Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
info("blocked, PERM_CAN_DISABLE " + aAddon.id);
Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
} else if (aAddon.userDisabled) {
info("userDisabled, PERM_CAN_ENABLE " + aAddon.id);
Assert.ok(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
info("userDisabled, PERM_CAN_DISABLE " + aAddon.id);
Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
} else {
info("other, PERM_CAN_ENABLE " + aAddon.id);
Assert.ok(!hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE));
if (aAddon.type != "theme") {
info("other, PERM_CAN_DISABLE " + aAddon.id);
Assert.ok(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE));
}
}
Assert.equal(
aAddon.appDisabled,
aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED
);
let willBeActive = aAddon.isActive;
if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_DISABLE)) {
willBeActive = false;
} else if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_ENABLE)) {
willBeActive = true;
}
if (
aExpectedUserDisabled ||
aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED
) {
Assert.ok(!willBeActive);
} else {
Assert.ok(willBeActive);
}
}
async function promiseRestartManagerWithAppChange(version) {
await promiseShutdownManager();
await promiseStartupManagerWithAppChange(version);
}
async function promiseStartupManagerWithAppChange(version) {
if (version) {
AddonTestUtils.appInfo.version = version;
}
if (useMLBF) {
// The old ExtensionBlocklist enforced the app version/ID part of the block
// when the blocklist entry is checked.
// The new ExtensionBlocklist (with useMLBF=true) does not separately check
// the app version/ID, but the underlying data source (Remote Settings)
// does offer the ability to filter entries with `filter_expression`.
// Force a reload to ensure that the BLOCK_APP_FILTER_EXPRESSION filter in
// this test file is checked again against the new version.
await Blocklist.ExtensionBlocklist._updateMLBF();
}
await promiseStartupManager();
}
add_task(async function setup() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
if (useMLBF) {
const { ClientEnvironmentBase } = ChromeUtils.importESModule(
);
Object.defineProperty(ClientEnvironmentBase, "appinfo", {
configurable: true,
get() {
return gAppInfo;
},
});
}
function getxpibasename(id, version) {
// pattern used to map ids like softblock1 to soft1
let pattern = /^(soft|hard|regexp)block([1-9]*)@/;
let match = id.match(pattern);
return `blocklist_${match[1]}${match[2]}_${version}`;
}
for (let id of ADDON_IDS) {
for (let version of [1, 2, 3, 4]) {
let name = getxpibasename(id, version);
let xpi = createTempWebExtensionFile({
manifest: {
name: "Test",
version: `${version}.0`,
browser_specific_settings: {
gecko: {
id,
// This file is generated below, as updateJson.
update_url: `http://example.com/addon_update${version}.json`,
},
},
},
});
// To test updates, individual tasks in this test file start the test by
// installing a set of add-ons with version |version| and trigger an
// update check, from XPIS.${nameprefix}${version} (version = 1, 2, 3)
if (version != 4) {
XPIS[name] = xpi;
}
// update_url above points to a test manifest that references the next
// version. The xpi is made available on the server, so that the test
// can verify that the blocklist works as intended (i.e. update to newer
// version is blocked).
// There is nothing that updates to version 1, only to versions 2, 3, 4.
if (version != 1) {
testserver.registerFile(`/addons/${name}.xpi`, xpi);
}
}
}
// For each version that this test file uses, create a test manifest that
// references the next version for each id in ADDON_IDS.
for (let version of [1, 2, 3]) {
let updateJson = { addons: {} };
for (let id of ADDON_IDS) {
let nextversion = version + 1;
let name = getxpibasename(id, nextversion);
updateJson.addons[id] = {
updates: [
{
applications: {
gecko: {
strict_min_version: "0",
advisory_max_version: "*",
},
},
version: `${nextversion}.0`,
update_link: `http://example.com/addons/${name}.xpi`,
},
],
};
}
AddonTestUtils.registerJSON(
testserver,
`/addon_update${version}.json`,
updateJson
);
}
await promiseStartupManager();
await promiseInstallFile(XPIS.blocklist_soft1_1);
await promiseInstallFile(XPIS.blocklist_soft2_1);
await promiseInstallFile(XPIS.blocklist_soft3_1);
await promiseInstallFile(XPIS.blocklist_soft4_1);
await promiseInstallFile(XPIS.blocklist_hard_1);
await promiseInstallFile(XPIS.blocklist_regexp_1);
let s4 = await promiseAddonByID("softblock4@tests.mozilla.org");
await s4.disable();
});
// Starts with add-ons unblocked and then switches application versions to
// change add-ons to blocked and back
add_task(async function run_app_update_test() {
await Pload_blocklist("app_update");
await promiseRestartManager();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s2,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
});
add_task(async function app_update_step_2() {
await promiseRestartManagerWithAppChange("2");
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await s2.enable();
await s2.disable();
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
await s3.enable();
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
});
add_task(async function app_update_step_3() {
await promiseRestartManager();
await promiseRestartManagerWithAppChange("2.5");
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
});
add_task(async function app_update_step_4() {
await promiseRestartManagerWithAppChange("1");
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await s1.enable();
await s2.enable();
});
// Starts with add-ons unblocked and then switches application versions to
// change add-ons to blocked and back. A DB schema change is faked to force a
// rebuild when the application version changes
add_task(async function run_app_update_schema_test() {
await promiseRestartManager();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s2,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
});
add_task(async function update_schema_2() {
await promiseShutdownManager();
await changeXPIDBVersion(100);
gAppInfo.version = "2";
await promiseStartupManagerWithAppChange();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await s2.enable();
await s2.disable();
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
await s3.enable();
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
});
add_task(async function update_schema_3() {
await promiseRestartManager();
await promiseShutdownManager();
await changeXPIDBVersion(100);
gAppInfo.version = "2.5";
await promiseStartupManagerWithAppChange();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
});
add_task(async function update_schema_4() {
await promiseShutdownManager();
await changeXPIDBVersion(100);
await promiseStartupManager();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
});
add_task(async function update_schema_5() {
await promiseShutdownManager();
await changeXPIDBVersion(100);
gAppInfo.version = "1";
await promiseStartupManagerWithAppChange();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await s1.enable();
await s2.enable();
});
// Starts with add-ons unblocked and then loads new blocklists to change add-ons
// to blocked and back again.
add_task(async function run_blocklist_update_test() {
await Pload_blocklist("empty_blocklist");
await promiseRestartManager();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s2,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await Pload_blocklist("blocklist_update2");
await promiseRestartManager();
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await s2.enable();
await s2.disable();
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
await s3.enable();
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
await promiseRestartManager();
await Pload_blocklist("blocklist_update2");
await promiseRestartManager();
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await Pload_blocklist("empty_blocklist");
await promiseRestartManager();
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await s1.enable();
await s2.enable();
});
// Starts with add-ons unblocked and then new versions are installed outside of
// the app to change them to blocked and back again.
add_task(async function run_addon_change_test() {
await Pload_blocklist("addon_change");
await promiseRestartManager();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s2,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
});
add_task(async function run_addon_change_2() {
await promiseInstallFile(XPIS.blocklist_soft1_2);
await promiseInstallFile(XPIS.blocklist_soft2_2);
await promiseInstallFile(XPIS.blocklist_soft3_2);
await promiseInstallFile(XPIS.blocklist_soft4_2);
await promiseInstallFile(XPIS.blocklist_hard_2);
await promiseInstallFile(XPIS.blocklist_regexp_2);
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await s2.enable();
await s2.disable();
check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
await s3.enable();
check_addon(
s3,
"2.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
});
add_task(async function run_addon_change_3() {
await promiseInstallFile(XPIS.blocklist_soft1_3);
await promiseInstallFile(XPIS.blocklist_soft2_3);
await promiseInstallFile(XPIS.blocklist_soft3_3);
await promiseInstallFile(XPIS.blocklist_soft4_3);
await promiseInstallFile(XPIS.blocklist_hard_3);
await promiseInstallFile(XPIS.blocklist_regexp_3);
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(
s3,
"3.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
});
add_task(async function run_addon_change_4() {
await promiseInstallFile(XPIS.blocklist_soft1_1);
await promiseInstallFile(XPIS.blocklist_soft2_1);
await promiseInstallFile(XPIS.blocklist_soft3_1);
await promiseInstallFile(XPIS.blocklist_soft4_1);
await promiseInstallFile(XPIS.blocklist_hard_1);
await promiseInstallFile(XPIS.blocklist_regexp_1);
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await s1.enable();
await s2.enable();
});
// Add-ons are initially unblocked then attempts to upgrade to blocked versions
// in the background which should fail
add_task(async function run_background_update_test() {
await promiseRestartManager();
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s2,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await Pbackground_update();
await promiseRestartManager();
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s2,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
});
// Starts with add-ons blocked and then new versions are detected and installed
// automatically for unblocked versions.
add_task(async function run_background_update_2_test() {
await promiseInstallFile(XPIS.blocklist_soft1_3);
await promiseInstallFile(XPIS.blocklist_soft2_3);
await promiseInstallFile(XPIS.blocklist_soft3_3);
await promiseInstallFile(XPIS.blocklist_soft4_3);
await promiseInstallFile(XPIS.blocklist_hard_3);
await promiseInstallFile(XPIS.blocklist_regexp_3);
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await s2.enable();
await s2.disable();
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
await s3.enable();
check_addon(
s3,
"3.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
await Pbackground_update();
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"4.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s2, "4.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(
s3,
"4.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(h, "4.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "4.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await s1.enable();
await s2.enable();
await s4.disable();
});
// The next test task (run_manual_update_test) was written to expect version 1,
// but after the previous test, version 4 of the add-ons were installed.
add_task(async function reset_addons_to_version_1_instead_of_4() {
await promiseInstallFile(XPIS.blocklist_soft1_1);
await promiseInstallFile(XPIS.blocklist_soft2_1);
await promiseInstallFile(XPIS.blocklist_soft3_1);
await promiseInstallFile(XPIS.blocklist_soft4_1);
await promiseInstallFile(XPIS.blocklist_hard_1);
await promiseInstallFile(XPIS.blocklist_regexp_1);
});
// Starts with add-ons blocked and then simulates the user upgrading them to
// unblocked versions.
add_task(async function run_manual_update_test() {
await Pload_blocklist("manual_update");
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await s2.enable();
await s2.disable();
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
await s3.enable();
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
await Pmanual_update("2");
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
// With useMLBF, s1/s2/s3 are hard blocks, so they cannot update.
const sv2 = useMLBF ? "1.0" : "2.0";
check_addon(s1, sv2, true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, sv2, true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, sv2, false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s4, sv2, true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
// Can't manually update to a hardblocked add-on
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await Pmanual_update("3");
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"3.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(
s3,
"3.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
});
// Starts with add-ons blocked and then new versions are installed outside of
// the app to change them to unblocked.
add_task(async function run_manual_update_2_test() {
let addons = await promiseAddonsByIDs(ADDON_IDS);
await Promise.all(addons.map(addon => addon.uninstall()));
await promiseInstallFile(XPIS.blocklist_soft1_1);
await promiseInstallFile(XPIS.blocklist_soft2_1);
await promiseInstallFile(XPIS.blocklist_soft3_1);
await promiseInstallFile(XPIS.blocklist_soft4_1);
await promiseInstallFile(XPIS.blocklist_hard_1);
await promiseInstallFile(XPIS.blocklist_regexp_1);
let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await s2.enable();
await s2.disable();
check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
await s3.enable();
check_addon(
s3,
"1.0",
false,
false,
Ci.nsIBlocklistService.STATE_SOFTBLOCKED
);
await Pmanual_update("2");
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
// With useMLBF, s1/s2/s3 are hard blocks, so they cannot update.
const sv2 = useMLBF ? "1.0" : "2.0";
check_addon(s1, sv2, true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, sv2, true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, sv2, false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
// Can't manually update to a hardblocked add-on
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
await Pmanual_update("3");
[s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(
s1,
"3.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(
s3,
"3.0",
false,
false,
Ci.nsIBlocklistService.STATE_NOT_BLOCKED
);
check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
check_addon(r, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
await s1.enable();
await s2.enable();
await s4.disable();
});
// Uses the API to install blocked add-ons from the local filesystem
add_task(async function run_local_install_test() {
let addons = await promiseAddonsByIDs(ADDON_IDS);
await Promise.all(addons.map(addon => addon.uninstall()));
await promiseInstallAllFiles([
XPIS.blocklist_soft1_1,
XPIS.blocklist_soft2_1,
XPIS.blocklist_soft3_1,
XPIS.blocklist_soft4_1,
XPIS.blocklist_hard_1,
XPIS.blocklist_regexp_1,
]);
let installs = await AddonManager.getAllInstalls();
// Should have finished all installs without needing to restart
Assert.equal(installs.length, 0);
let [s1, s2, s3 /* s4 */, , h, r] = await promiseAddonsByIDs(ADDON_IDS);
check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED);
});