// Enable signature checks for these tests gUseRealCertChecks = true; // Disable update security Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false); const DATA = "data/signing_checks/"; const ADDONS = { bootstrap: { unsigned: "unsigned_bootstrap_2.xpi", badid: "signed_bootstrap_badid_2.xpi", signed: "signed_bootstrap_2.xpi", preliminary: "preliminary_bootstrap_2.xpi", }, nonbootstrap: { unsigned: "unsigned_nonbootstrap_2.xpi", badid: "signed_nonbootstrap_badid_2.xpi", signed: "signed_nonbootstrap_2.xpi", }, }; const ID = "test@tests.mozilla.org"; const profileDir = gProfD.clone(); profileDir.append("extensions"); // Deletes a file from the test add-on in the profile function breakAddon(file) { if (TEST_UNPACKED) { let f = file.clone(); f.append("test.txt"); f.remove(true); f = file.clone(); f.append("install.rdf"); f.lastModifiedTime = Date.now(); } else { var zipW = Cc["@mozilla.org/zipwriter;1"].createInstance(Ci.nsIZipWriter); zipW.open(file, FileUtils.MODE_RDWR | FileUtils.MODE_APPEND); zipW.removeEntry("test.txt", false); zipW.close(); } } function resetPrefs() { Services.prefs.setIntPref("bootstraptest.active_version", -1); Services.prefs.setIntPref("bootstraptest.installed_version", -1); Services.prefs.setIntPref("bootstraptest.startup_reason", -1); Services.prefs.setIntPref("bootstraptest.shutdown_reason", -1); Services.prefs.setIntPref("bootstraptest.install_reason", -1); Services.prefs.setIntPref("bootstraptest.uninstall_reason", -1); Services.prefs.setIntPref("bootstraptest.startup_oldversion", -1); Services.prefs.setIntPref("bootstraptest.shutdown_newversion", -1); Services.prefs.setIntPref("bootstraptest.install_oldversion", -1); Services.prefs.setIntPref("bootstraptest.uninstall_newversion", -1); } function clearCache(file) { if (TEST_UNPACKED) { return; } Services.obs.notifyObservers(file, "flush-cache-entry"); } function getActiveVersion() { return Services.prefs.getIntPref("bootstraptest.active_version"); } add_task(async function setup() { createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "4", "4"); // Start and stop the manager to initialise everything in the profile before // actual testing await promiseStartupManager(); await promiseShutdownManager(); resetPrefs(); }); // Injecting into profile (bootstrap) add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.bootstrap.unsigned), profileDir, ID ); await promiseStartupManager(); // Currently we leave the sideloaded add-on there but just don't run it let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_MISSING); Assert.equal(getActiveVersion(), -1); await addon.uninstall(); await promiseShutdownManager(); resetPrefs(); Assert.ok(!file.exists()); clearCache(file); }); add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.bootstrap.signed), profileDir, ID ); breakAddon(file); await promiseStartupManager(); // Currently we leave the sideloaded add-on there but just don't run it let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN); Assert.equal(getActiveVersion(), -1); await addon.uninstall(); await promiseShutdownManager(); resetPrefs(); Assert.ok(!file.exists()); clearCache(file); }); add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.bootstrap.badid), profileDir, ID ); await promiseStartupManager(); // Currently we leave the sideloaded add-on there but just don't run it let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN); Assert.equal(getActiveVersion(), -1); await addon.uninstall(); await promiseShutdownManager(); resetPrefs(); Assert.ok(!file.exists()); clearCache(file); }); // Installs a signed add-on then modifies it in place breaking its signing add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.bootstrap.signed), profileDir, ID ); // Make it appear to come from the past so when we modify it later it is // detected during startup. Obviously malware can bypass this method of // detection but the periodic scan will catch that await promiseSetExtensionModifiedTime(file.path, Date.now() - 600000); await promiseStartupManager(); let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(!addon.appDisabled); Assert.ok(addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_SIGNED); Assert.equal(getActiveVersion(), 2); await promiseShutdownManager(); Assert.equal(getActiveVersion(), 0); clearCache(file); breakAddon(file); resetPrefs(); await promiseStartupManager(); addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN); Assert.equal(getActiveVersion(), -1); let ids = AddonManager.getStartupChanges( AddonManager.STARTUP_CHANGE_DISABLED ); Assert.equal(ids.length, 1); Assert.equal(ids[0], ID); await addon.uninstall(); await promiseShutdownManager(); resetPrefs(); Assert.ok(!file.exists()); clearCache(file); }); // Injecting into profile (non-bootstrap) add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.nonbootstrap.unsigned), profileDir, ID ); await promiseStartupManager(); // Currently we leave the sideloaded add-on there but just don't run it let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_MISSING); await addon.uninstall(); await promiseRestartManager(); await promiseShutdownManager(); Assert.ok(!file.exists()); clearCache(file); }); add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.nonbootstrap.signed), profileDir, ID ); breakAddon(file); await promiseStartupManager(); // Currently we leave the sideloaded add-on there but just don't run it let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN); await addon.uninstall(); await promiseRestartManager(); await promiseShutdownManager(); Assert.ok(!file.exists()); clearCache(file); }); add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.nonbootstrap.badid), profileDir, ID ); await promiseStartupManager(); // Currently we leave the sideloaded add-on there but just don't run it let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN); await addon.uninstall(); await promiseRestartManager(); await promiseShutdownManager(); Assert.ok(!file.exists()); clearCache(file); }); // Installs a signed add-on then modifies it in place breaking its signing add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.nonbootstrap.signed), profileDir, ID ); // Make it appear to come from the past so when we modify it later it is // detected during startup. Obviously malware can bypass this method of // detection but the periodic scan will catch that await promiseSetExtensionModifiedTime(file.path, Date.now() - 60000); await promiseStartupManager(); let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(!addon.appDisabled); Assert.ok(addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_SIGNED); await promiseShutdownManager(); clearCache(file); breakAddon(file); await promiseStartupManager(); addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(addon.appDisabled); Assert.ok(!addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN); let ids = AddonManager.getStartupChanges( AddonManager.STARTUP_CHANGE_DISABLED ); Assert.equal(ids.length, 1); Assert.equal(ids[0], ID); await addon.uninstall(); await promiseRestartManager(); await promiseShutdownManager(); Assert.ok(!file.exists()); clearCache(file); }); // Stage install then modify before startup (non-bootstrap) add_task(async function () { await promiseStartupManager(); await promiseInstallAllFiles([ do_get_file(DATA + ADDONS.nonbootstrap.signed), ]); await promiseShutdownManager(); let staged = profileDir.clone(); staged.append("staged"); staged.append(do_get_expected_addon_name(ID)); Assert.ok(staged.exists()); breakAddon(staged); await promiseStartupManager(); // Should have refused to install the broken staged version let addon = await promiseAddonByID(ID); Assert.equal(addon, null); clearCache(staged); await promiseShutdownManager(); }); // Manufacture staged install (bootstrap) add_task(async function () { let stage = profileDir.clone(); stage.append("staged"); let file = await manuallyInstall( do_get_file(DATA + ADDONS.bootstrap.signed), stage, ID ); breakAddon(file); await promiseStartupManager(); // Should have refused to install the broken staged version let addon = await promiseAddonByID(ID); Assert.equal(addon, null); Assert.equal(getActiveVersion(), -1); Assert.ok(!file.exists()); clearCache(file); await promiseShutdownManager(); resetPrefs(); }); // Preliminarily-signed sideloaded add-ons should work add_task(async function () { let file = await manuallyInstall( do_get_file(DATA + ADDONS.bootstrap.preliminary), profileDir, ID ); await promiseStartupManager(); let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(!addon.appDisabled); Assert.ok(addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_PRELIMINARY); Assert.equal(getActiveVersion(), 2); await addon.uninstall(); await promiseShutdownManager(); resetPrefs(); Assert.ok(!file.exists()); clearCache(file); }); // Preliminarily-signed sideloaded add-ons should work via staged install add_task(async function () { let stage = profileDir.clone(); stage.append("staged"); let file = await manuallyInstall( do_get_file(DATA + ADDONS.bootstrap.preliminary), stage, ID ); await promiseStartupManager(); let addon = await promiseAddonByID(ID); Assert.notEqual(addon, null); Assert.ok(!addon.appDisabled); Assert.ok(addon.isActive); Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_PRELIMINARY); Assert.equal(getActiveVersion(), 2); await addon.uninstall(); await promiseShutdownManager(); resetPrefs(); Assert.ok(!file.exists()); clearCache(file); });