summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_stashes.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_stashes.js')
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_stashes.js219
1 files changed, 219 insertions, 0 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_stashes.js b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_stashes.js
new file mode 100644
index 0000000000..e129efc793
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/rs-blocklist/test_blocklist_mlbf_stashes.js
@@ -0,0 +1,219 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Services.prefs.setBoolPref("extensions.blocklist.useMLBF", true);
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+
+const ExtensionBlocklistMLBF = getExtensionBlocklistMLBF();
+const MLBF_LOAD_ATTEMPTS = [];
+ExtensionBlocklistMLBF._fetchMLBF = async record => {
+ MLBF_LOAD_ATTEMPTS.push(record);
+ return {
+ generationTime: 0,
+ cascadeFilter: {
+ has(blockKey) {
+ if (blockKey === "@onlyblockedbymlbf:1") {
+ return true;
+ }
+ throw new Error("bloom filter should not be used in this test");
+ },
+ },
+ };
+};
+
+async function checkBlockState(addonId, version, expectBlocked) {
+ let addon = {
+ id: addonId,
+ version,
+ // Note: signedDate is missing, so the MLBF does not apply
+ // and we will effectively only test stashing.
+ };
+ let state = await Blocklist.getAddonBlocklistState(addon);
+ if (expectBlocked) {
+ Assert.equal(state, Ci.nsIBlocklistService.STATE_BLOCKED);
+ } else {
+ Assert.equal(state, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ }
+}
+
+add_task(async function setup() {
+ await promiseStartupManager();
+});
+
+// Tests that add-ons can be blocked / unblocked via the stash.
+add_task(async function basic_stash() {
+ await AddonTestUtils.loadBlocklistRawData({
+ extensionsMLBF: [
+ {
+ stash_time: 0,
+ stash: {
+ blocked: ["@blocked:1"],
+ unblocked: ["@notblocked:2"],
+ },
+ },
+ ],
+ });
+ await checkBlockState("@blocked", "1", true);
+ await checkBlockState("@notblocked", "2", false);
+ // Not in stash (but unsigned, so shouldn't reach MLBF):
+ await checkBlockState("@blocked", "2", false);
+
+ Assert.equal(
+ await Blocklist.getAddonBlocklistState({
+ id: "@onlyblockedbymlbf",
+ version: "1",
+ signedDate: new Date(0), // = the MLBF's generationTime.
+ signedState: AddonManager.SIGNEDSTATE_SIGNED,
+ }),
+ Ci.nsIBlocklistService.STATE_BLOCKED,
+ "falls through to MLBF if entry is not found in stash"
+ );
+
+ Assert.deepEqual(MLBF_LOAD_ATTEMPTS, [null], "MLBF attachment not found");
+});
+
+// To complement the privileged_xpi_not_blocked in test_blocklist_mlbf.js,
+// verify that privileged add-ons can still be blocked through stashes.
+add_task(async function privileged_addon_blocked_by_stash() {
+ const system_addon = {
+ id: "@blocked",
+ version: "1",
+ signedDate: new Date(0), // = the MLBF's generationTime.
+ signedState: AddonManager.SIGNEDSTATE_PRIVILEGED,
+ };
+ Assert.equal(
+ await Blocklist.getAddonBlocklistState(system_addon),
+ Ci.nsIBlocklistService.STATE_BLOCKED,
+ "Privileged add-ons can still be blocked by a stash"
+ );
+
+ system_addon.signedState = AddonManager.SIGNEDSTATE_SYSTEM;
+ Assert.equal(
+ await Blocklist.getAddonBlocklistState(system_addon),
+ Ci.nsIBlocklistService.STATE_BLOCKED,
+ "Privileged system add-ons can still be blocked by a stash"
+ );
+
+ // For comparison, when an add-on is only blocked by a MLBF, the block
+ // decision is ignored.
+ system_addon.id = "@onlyblockedbymlbf";
+ Assert.equal(
+ await Blocklist.getAddonBlocklistState(system_addon),
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
+ "Privileged add-ons cannot be blocked via a MLBF"
+ );
+ // (note that we haven't checked that SIGNEDSTATE_PRIVILEGED is not blocked
+ // via the MLBF, but that is already covered by test_blocklist_mlbf.js ).
+});
+
+// To complement langpack_not_blocked_on_Nightly in test_blocklist_mlbf.js,
+// verify that langpacks can still be blocked through stashes.
+add_task(async function langpack_blocked_by_stash() {
+ const langpack_addon = {
+ id: "@blocked",
+ type: "locale",
+ version: "1",
+ signedDate: new Date(0), // = the MLBF's generationTime.
+ signedState: AddonManager.SIGNEDSTATE_SIGNED,
+ };
+ Assert.equal(
+ await Blocklist.getAddonBlocklistState(langpack_addon),
+ Ci.nsIBlocklistService.STATE_BLOCKED,
+ "Langpack add-ons can still be blocked by a stash"
+ );
+
+ // For comparison, when an add-on is only blocked by a MLBF, the block
+ // decision is ignored on Nightly (but blocked on non-Nightly).
+ langpack_addon.id = "@onlyblockedbymlbf";
+ if (AppConstants.NIGHTLY_BUILD) {
+ Assert.equal(
+ await Blocklist.getAddonBlocklistState(langpack_addon),
+ Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
+ "Langpack add-ons cannot be blocked via a MLBF on Nightly"
+ );
+ } else {
+ Assert.equal(
+ await Blocklist.getAddonBlocklistState(langpack_addon),
+ Ci.nsIBlocklistService.STATE_BLOCKED,
+ "Langpack add-ons can be blocked via a MLBF on non-Nightly"
+ );
+ }
+});
+
+// Tests that invalid stash entries are ignored.
+add_task(async function invalid_stashes() {
+ await AddonTestUtils.loadBlocklistRawData({
+ extensionsMLBF: [
+ {},
+ { stash: null },
+ { stash: 1 },
+ { stash: {} },
+ { stash: { blocked: ["@broken:1", "@okid:1"] } },
+ { stash: { unblocked: ["@broken:2"] } },
+ // The only correct entry:
+ { stash: { blocked: ["@okid:2"], unblocked: ["@okid:1"] } },
+ { stash: { blocked: ["@broken:1", "@okid:1"] } },
+ { stash: { unblocked: ["@broken:2", "@okid:2"] } },
+ ],
+ });
+ // The valid stash entry should be applied:
+ await checkBlockState("@okid", "1", false);
+ await checkBlockState("@okid", "2", true);
+ // Entries from invalid stashes should be ignored:
+ await checkBlockState("@broken", "1", false);
+ await checkBlockState("@broken", "2", false);
+});
+
+// Blocklist stashes should be processed in the reverse chronological order.
+add_task(async function stash_time_order() {
+ await AddonTestUtils.loadBlocklistRawData({
+ extensionsMLBF: [
+ // "@a:1" and "@a:2" are blocked at time 1, but unblocked later.
+ { stash_time: 2, stash: { blocked: [], unblocked: ["@a:1"] } },
+ { stash_time: 1, stash: { blocked: ["@a:1", "@a:2"], unblocked: [] } },
+ { stash_time: 3, stash: { blocked: [], unblocked: ["@a:2"] } },
+
+ // "@b:1" and "@b:2" are unblocked at time 4, but blocked later.
+ { stash_time: 5, stash: { blocked: ["@b:1"], unblocked: [] } },
+ { stash_time: 4, stash: { blocked: [], unblocked: ["@b:1", "@b:2"] } },
+ { stash_time: 6, stash: { blocked: ["@b:2"], unblocked: [] } },
+ ],
+ });
+ await checkBlockState("@a", "1", false);
+ await checkBlockState("@a", "2", false);
+
+ await checkBlockState("@b", "1", true);
+ await checkBlockState("@b", "2", true);
+});
+
+// Attachments with unsupported attachment_type should be ignored.
+add_task(async function mlbf_bloomfilter_full_ignored() {
+ MLBF_LOAD_ATTEMPTS.length = 0;
+
+ await AddonTestUtils.loadBlocklistRawData({
+ extensionsMLBF: [{ attachment_type: "bloomfilter-full", attachment: {} }],
+ });
+
+ // Only bloomfilter-base records should be used.
+ // Since there are no such records, we shouldn't find anything.
+ Assert.deepEqual(MLBF_LOAD_ATTEMPTS, [null], "no matching MLBFs found");
+});
+
+// Tests that the most recent MLBF is downloaded.
+add_task(async function mlbf_generation_time_recent() {
+ MLBF_LOAD_ATTEMPTS.length = 0;
+ const records = [
+ { attachment_type: "bloomfilter-base", attachment: {}, generation_time: 2 },
+ { attachment_type: "bloomfilter-base", attachment: {}, generation_time: 3 },
+ { attachment_type: "bloomfilter-base", attachment: {}, generation_time: 1 },
+ ];
+ await AddonTestUtils.loadBlocklistRawData({ extensionsMLBF: records });
+ Assert.equal(
+ MLBF_LOAD_ATTEMPTS[0].generation_time,
+ 3,
+ "expected to load most recent MLBF"
+ );
+});