Bug 1461308: Fix tests that rely on fake privileged signatures for unpacked extensions. r?aswan
MozReview-Commit-ID: DFN6w5qLIKN
--- a/toolkit/mozapps/extensions/internal/XPIDatabase.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIDatabase.jsm
@@ -2466,36 +2466,44 @@ this.XPIDatabaseReconcile = {
// directory scan.
let isNewInstall = !!aNewAddon || !XPIDatabase.rebuildingDatabase;
// If it's a new install and we haven't yet loaded the manifest then it
// must be something dropped directly into the install location
let isDetectedInstall = isNewInstall && !aNewAddon;
// Load the manifest if necessary and sanity check the add-on ID
+ let unsigned;
try {
if (!aNewAddon) {
// Load the manifest from the add-on.
let file = new nsIFile(aAddonState.path);
aNewAddon = XPIInstall.syncLoadManifestFromFile(file, aInstallLocation);
}
// The add-on in the manifest should match the add-on ID.
if (aNewAddon.id != aId) {
throw new Error("Invalid addon ID: expected addon ID " + aId +
", found " + aNewAddon.id + " in manifest");
}
+
+ unsigned = XPIDatabase.mustSign(aNewAddon.type) && !aNewAddon.isCorrectlySigned;
+ if (unsigned) {
+ throw Error(`Extension ${aNewAddon.id} is not correctly signed`);
+ }
} catch (e) {
logger.warn("addMetadata: Add-on " + aId + " is invalid", e);
// Remove the invalid add-on from the install location if the install
// location isn't locked
if (aInstallLocation.isLinkedAddon(aId))
logger.warn("Not uninstalling invalid item because it is a proxy file");
else if (aInstallLocation.locked)
logger.warn("Could not uninstall invalid item from locked install location");
+ else if (unsigned && !isNewInstall)
+ logger.warn("Not uninstalling existing unsigned add-on");
else
aInstallLocation.uninstallAddon(aId);
return null;
}
// Update the AddonInternal properties.
aNewAddon.installDate = aAddonState.mtime;
aNewAddon.updateDate = aAddonState.mtime;
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_proxy/bootstrap.js
+++ /dev/null
@@ -1,1 +0,0 @@
-ChromeUtils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);
--- a/toolkit/mozapps/extensions/test/xpcshell/test_cache_certdb.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_cache_certdb.js
@@ -18,12 +18,10 @@ add_task(async function() {
await promiseStartupManager();
// Force a rescan of signatures
const { XPIProvider } = ChromeUtils.import("resource://gre/modules/addons/XPIProvider.jsm", {});
await XPIProvider.verifySignatures();
let addon = await AddonManager.getAddonByID(ID);
- Assert.equal(addon.signedState, AddonManager.SIGNEDSTATE_MISSING);
- Assert.ok(!addon.isActive);
- Assert.ok(addon.appDisabled);
+ Assert.equal(addon, null, "Unsigned extensions should not be installed at startup");
});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_proxy.js
@@ -3,94 +3,97 @@
*/
const ID = "proxy1@tests.mozilla.org";
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
BootstrapMonitor.init();
+const BOOTSTRAP_JS = `ChromeUtils.import("resource://xpcshell-data/BootstrapMonitor.jsm").monitor(this);`;
+
// Ensure that a proxy file to an add-on with a valid manifest works.
add_task(async function() {
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
await promiseStartupManager();
let tempdir = gTmpD.clone();
- await promiseWriteInstallRDFToDir({
+ let unpackedAddon = await promiseWriteInstallRDFToDir({
id: ID,
version: "1.0",
bootstrap: true,
unpack: true,
targetApplications: [{
- id: "xpcshell@tests.mozilla.org",
+ id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
- }],
+ }],
name: "Test Bootstrap 1 (proxy)",
- }, tempdir, ID, "bootstrap.js");
-
- let unpackedAddon = tempdir.clone();
- unpackedAddon.append(ID);
- do_get_file("data/test_proxy/bootstrap.js")
- .copyTo(unpackedAddon, "bootstrap.js");
+ }, tempdir, ID, {
+ "bootstrap.js": BOOTSTRAP_JS,
+ });
// create proxy file in profile/extensions dir
let extensionsDir = gProfD.clone();
extensionsDir.append("extensions");
let proxyFile = await promiseWriteProxyFileToDir(extensionsDir, unpackedAddon, ID);
await promiseRestartManager();
- BootstrapMonitor.checkAddonInstalled(ID, "1.0");
- BootstrapMonitor.checkAddonStarted(ID, "1.0");
-
let addon = await promiseAddonByID(ID);
- Assert.notEqual(addon, null);
- Assert.equal(addon.version, "1.0");
- Assert.equal(addon.name, "Test Bootstrap 1 (proxy)");
- Assert.ok(addon.isCompatible);
- Assert.ok(!addon.appDisabled);
- Assert.ok(addon.isActive);
- Assert.equal(addon.type, "extension");
- Assert.equal(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_UNKNOWN : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+ if (AppConstants.MOZ_REQUIRE_SIGNING) {
+ BootstrapMonitor.checkAddonNotInstalled(ID, "1.0");
+ BootstrapMonitor.checkAddonNotStarted(ID, "1.0");
+
+ Assert.equal(addon, null);
+ } else {
+ BootstrapMonitor.checkAddonInstalled(ID, "1.0");
+ BootstrapMonitor.checkAddonStarted(ID, "1.0");
- Assert.ok(proxyFile.exists());
+ Assert.notEqual(addon, null);
+ Assert.equal(addon.version, "1.0");
+ Assert.equal(addon.name, "Test Bootstrap 1 (proxy)");
+ Assert.ok(addon.isCompatible);
+ Assert.ok(!addon.appDisabled);
+ Assert.ok(addon.isActive);
+ Assert.equal(addon.type, "extension");
+ Assert.equal(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_UNKNOWN : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
- addon.uninstall();
+ Assert.ok(proxyFile.exists());
+
+ addon.uninstall();
+ }
unpackedAddon.remove(true);
await promiseRestartManager();
});
// Ensure that a proxy file to an add-on is not removed even
// if the manifest file is invalid. See bug 1195353.
add_task(async function() {
let tempdir = gTmpD.clone();
// use a mismatched ID to make this install.rdf invalid
- await promiseWriteInstallRDFToDir({
+ let unpackedAddon = await promiseWriteInstallRDFToDir({
id: "bad-proxy1@tests.mozilla.org",
version: "1.0",
bootstrap: true,
unpack: true,
targetApplications: [{
- id: "xpcshell@tests.mozilla.org",
+ id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
- }],
+ }],
name: "Test Bootstrap 1 (proxy)",
- }, tempdir, ID, "bootstrap.js");
-
- let unpackedAddon = tempdir.clone();
- unpackedAddon.append(ID);
- do_get_file("data/test_proxy/bootstrap.js")
- .copyTo(unpackedAddon, "bootstrap.js");
+ }, tempdir, ID, {
+ "bootstrap.js": BOOTSTRAP_JS,
+ });
// create proxy file in profile/extensions dir
let extensionsDir = gProfD.clone();
extensionsDir.append("extensions");
let proxyFile = await promiseWriteProxyFileToDir(extensionsDir, unpackedAddon, ID);
await promiseRestartManager();
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_verify.js
@@ -85,78 +85,16 @@ function verify_no_change([startFile, st
// Remove the add-on and restart to let it go away
manuallyUninstall(profileDir, ID);
await promiseRestartManager();
await promiseShutdownManager();
});
}
-function verify_enables([startFile, startState], [endFile, endState]) {
- add_task(async function() {
- info("A switch from " + startFile + " to " + endFile + " should enable the add-on.");
-
- // Install the first add-on
- await manuallyInstall(do_get_file(DATA + startFile), profileDir, ID);
- await promiseStartupManager();
-
- let addon = await promiseAddonByID(ID);
- Assert.notEqual(addon, null);
- Assert.ok(!addon.isActive);
- Assert.equal(addon.pendingOperations, AddonManager.PENDING_NONE);
- Assert.equal(addon.signedState, startState);
-
- // Swap in the files from the next add-on
- manuallyUninstall(profileDir, ID);
- await manuallyInstall(do_get_file(DATA + endFile), profileDir, ID);
-
- let needsRestart = hasFlag(addon.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_ENABLE);
- info(needsRestart);
-
- let events = {};
- if (!needsRestart) {
- events[ID] = [
- ["onPropertyChanged", ["appDisabled"]],
- ["onEnabling", false],
- "onEnabled"
- ];
- } else {
- events[ID] = [
- ["onPropertyChanged", ["appDisabled"]],
- "onEnabling"
- ];
- }
-
- if (startState != endState)
- events[ID].unshift(["onPropertyChanged", ["signedState"]]);
-
- prepare_test(events);
-
- // Trigger the check
- let changes = await verifySignatures();
- Assert.equal(changes.enabled.length, 1);
- Assert.equal(changes.enabled[0], ID);
- Assert.equal(changes.disabled.length, 0);
-
- Assert.ok(!addon.appDisabled);
- if (needsRestart)
- Assert.notEqual(addon.pendingOperations, AddonManager.PENDING_NONE);
- else
- Assert.ok(addon.isActive);
- Assert.equal(addon.signedState, endState);
-
- ensure_test_completed();
-
- // Remove the add-on and restart to let it go away
- manuallyUninstall(profileDir, ID);
- await promiseRestartManager();
- await promiseShutdownManager();
- });
-}
-
function verify_disables([startFile, startState], [endFile, endState]) {
add_task(async function() {
info("A switch from " + startFile + " to " + endFile + " should disable the add-on.");
// Install the first add-on
await manuallyInstall(do_get_file(DATA + startFile), profileDir, ID);
await promiseStartupManager();
@@ -214,25 +152,13 @@ function verify_disables([startFile, sta
}
for (let start of GOOD) {
for (let end of BAD) {
verify_disables(start, end);
}
}
-for (let start of BAD) {
- for (let end of GOOD) {
- verify_enables(start, end);
- }
-}
-
for (let start of GOOD) {
for (let end of GOOD.filter(f => f != start)) {
verify_no_change(start, end);
}
}
-
-for (let start of BAD) {
- for (let end of BAD.filter(f => f != start)) {
- verify_no_change(start, end);
- }
-}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_temporary.js
@@ -167,16 +167,24 @@ add_task(async function() {
}],
name: "Test Bootstrap 1 (temporary)",
}),
"bootstrap.js": bootstrapJS,
};
let target;
if (!packed) {
+ // Unpacked extensions don't support signing, which means that
+ // our mock signing service is not able to give them a
+ // privileged signed state, and we can't install them on release
+ // builds.
+ if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
+ continue;
+ }
+
target = tempdir.clone();
target.append(ID);
await AddonTestUtils.promiseWriteFilesToDir(target.path, files);
} else {
target = tempdir.clone();
target.append(`${ID}.xpi`);
@@ -357,16 +365,21 @@ add_task(async function test_samefile()
Assert.equal(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_PRIVILEGED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
addon.uninstall();
});
// Install a temporary add-on over the top of an existing add-on.
// Uninstall it and make sure the existing add-on comes back.
add_task(async function() {
+ // We can't install unpacked add-ons on release builds. See above.
+ if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
+ return;
+ }
+
await promiseInstallAllFiles([do_get_addon("test_bootstrap1_1")], true);
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
BootstrapMonitor.checkAddonStarted(ID, "1.0");
let tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir({
id: ID,
@@ -459,16 +472,21 @@ add_task(async function() {
BootstrapMonitor.checkAddonNotStarted(ID);
await promiseRestartManager();
});
// Install a temporary add-on as a version upgrade over the top of an
// existing temporary add-on.
add_task(async function() {
+ // We can't install unpacked add-ons on release builds. See above.
+ if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
+ return;
+ }
+
const tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir(sampleRDFManifest, tempdir, "bootstrap1@tests.mozilla.org", "bootstrap.js");
const unpackedAddon = tempdir.clone();
unpackedAddon.append(ID);
do_get_file("data/test_temporary/bootstrap.js")
.copyTo(unpackedAddon, "bootstrap.js");
@@ -510,16 +528,21 @@ add_task(async function() {
unpackedAddon.remove(true);
await promiseRestartManager();
});
// Install a temporary add-on as a version downgrade over the top of an
// existing temporary add-on.
add_task(async function() {
+ // We can't install unpacked add-ons on release builds. See above.
+ if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
+ return;
+ }
+
const tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir(sampleRDFManifest, tempdir, "bootstrap1@tests.mozilla.org", "bootstrap.js");
const unpackedAddon = tempdir.clone();
unpackedAddon.append(ID);
do_get_file("data/test_temporary/bootstrap.js")
.copyTo(unpackedAddon, "bootstrap.js");
@@ -559,16 +582,21 @@ add_task(async function() {
unpackedAddon.remove(true);
await promiseRestartManager();
});
// Installing a temporary add-on over an existing add-on with the same
// version number should be installed as an upgrade.
add_task(async function() {
+ // We can't install unpacked add-ons on release builds. See above.
+ if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
+ return;
+ }
+
const tempdir = gTmpD.clone();
await promiseWriteInstallRDFToDir(sampleRDFManifest, tempdir, "bootstrap1@tests.mozilla.org", "bootstrap.js");
const unpackedAddon = tempdir.clone();
unpackedAddon.append(ID);
do_get_file("data/test_temporary/bootstrap.js")
.copyTo(unpackedAddon, "bootstrap.js");
@@ -616,16 +644,21 @@ add_task(async function() {
unpackedAddon.remove(true);
await promiseRestartManager();
});
// Install a temporary add-on over the top of an existing disabled add-on.
// After restart, the existing add-on should continue to be installed and disabled.
add_task(async function() {
+ // We can't install unpacked add-ons on release builds. See above.
+ if (!AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS) {
+ return;
+ }
+
await promiseInstallAllFiles([do_get_addon("test_bootstrap1_1")], true);
BootstrapMonitor.checkAddonInstalled(ID, "1.0");
BootstrapMonitor.checkAddonStarted(ID, "1.0");
let addon = await promiseAddonByID(ID);
addon.userDisabled = true;