Backed out changeset 3b48e1a81a17 (bug 1038068) for xpcshell orange even after a clobbering IGNORE IDL

--HG--
extra : amend_source : 086173e953ae46aa2292993601380ab04884b1ac
This commit is contained in:
Wes Kocher 2015-04-21 18:21:52 -07:00
parent 7167becd52
commit 9adc1fecb8
40 changed files with 325 additions and 1300 deletions

View File

@ -69,9 +69,6 @@ pref("extensions.hotfix.certs.1.sha1Fingerprint", "91:53:98:0C:C1:86:DF:47:8F:35
// See the SCOPE constants in AddonManager.jsm for values to use here.
pref("extensions.autoDisableScopes", 15);
// Don't require signed add-ons by default
pref("xpinstall.signatures.required", false);
// Dictionary download preference
pref("browser.dictionaries.download.url", "https://addons.mozilla.org/%LOCALE%/firefox/dictionaries/");

View File

@ -69,22 +69,20 @@ addonsInstalledNeedsRestart=#1 will be installed after you restart #3.;#2 add-on
addonInstallRestartButton=Restart Now
addonInstallRestartButton.accesskey=R
# LOCALIZATION NOTE (addonError-1, addonError-2, addonError-3, addonError-4, addonError-5):
# LOCALIZATION NOTE (addonError-1, addonError-2, addonError-3, addonError-4):
# #1 is the add-on name, #2 is the host name, #3 is the application name
# #4 is the application version
addonError-1=The add-on could not be downloaded because of a connection failure on #2.
addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected.
addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt.
addonError-4=#1 could not be installed because #3 cannot modify the needed file.
addonError-5=#3 has prevented this site from installing an unverified add-on.
# LOCALIZATION NOTE (addonLocalError-1, addonLocalError-2, addonLocalError-3, addonLocalError-4, addonLocalError-5, addonErrorIncompatible, addonErrorBlocklisted):
# LOCALIZATION NOTE (addonLocalError-1, addonLocalError-2, addonLocalError-3, addonLocalError-4, addonErrorIncompatible, addonErrorBlocklisted):
# #1 is the add-on name, #3 is the application name, #4 is the application version
addonLocalError-1=This add-on could not be installed because of a filesystem error.
addonLocalError-2=This add-on could not be installed because it does not match the add-on #3 expected.
addonLocalError-3=This add-on could not be installed because it appears to be corrupt.
addonLocalError-4=#1 could not be installed because #3 cannot modify the needed file.
addonLocalError-5=This add-on could not be installed because it has not been verified.
addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4.
addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems.

View File

@ -223,8 +223,6 @@ class RefTest(object):
# And for about:newtab content fetch and pings.
prefs['browser.newtabpage.directory.source'] = 'data:application/json,{"reftest":1}'
prefs['browser.newtabpage.directory.ping'] = ''
# Allow unsigned add-ons
prefs['xpinstall.signatures.required'] = False
#Don't use auto-enabled e10s
prefs['browser.tabs.remote.autostart.1'] = False

View File

@ -4115,8 +4115,6 @@ pref("browser.history.maxStateObjectSize", 655360);
// XPInstall prefs
pref("xpinstall.whitelist.required", true);
// Only Firefox requires add-on signatures
pref("xpinstall.signatures.required", false);
pref("extensions.alwaysUnpack", false);
pref("extensions.minCompatiblePlatformVersion", "2.0");

View File

@ -23,9 +23,6 @@
// Trusted Hosted Apps Certificates
#include "manifest-signing-root.inc"
#include "manifest-signing-test-root.inc"
// Add-on signing Certificates
#include "addons-public.inc"
#include "addons-stage.inc"
using namespace mozilla::pkix;
@ -96,16 +93,6 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
trustedDER.len = mozilla::ArrayLength(trustedAppTestRoot);
break;
case nsIX509CertDB::AddonsPublicRoot:
trustedDER.data = const_cast<uint8_t*>(addonsPublicRoot);
trustedDER.len = mozilla::ArrayLength(addonsPublicRoot);
break;
case nsIX509CertDB::AddonsStageRoot:
trustedDER.data = const_cast<uint8_t*>(addonsStageRoot);
trustedDER.len = mozilla::ArrayLength(addonsStageRoot);
break;
default:
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return SECFailure;

Binary file not shown.

Binary file not shown.

View File

@ -35,8 +35,6 @@ array_names = [
'trustedAppPublicRoot',
'trustedAppTestRoot',
'xpcshellRoot',
'addonsPublicRoot',
'addonsStageRoot',
]
for n in array_names:

View File

@ -34,8 +34,6 @@ headers_arrays_certs = [
('manifest-signing-root.inc', 'trustedAppPublicRoot', 'trusted-app-public.der'),
('manifest-signing-test-root.inc', 'trustedAppTestRoot', test_ssl_path + '/test_signed_manifest/trusted_ca1.der'),
('xpcshell.inc', 'xpcshellRoot', test_ssl_path + '/test_signed_apps/trusted_ca1.der'),
('addons-public.inc', 'addonsPublicRoot', 'addons-public.crt'),
('addons-stage.inc', 'addonsStageRoot', 'addons-stage.crt'),
]
for header, array_name, cert in headers_arrays_certs:

View File

@ -311,8 +311,6 @@ interface nsIX509CertDB : nsISupports {
const AppTrustedRoot AppXPCShellRoot = 6;
const AppTrustedRoot TrustedHostedAppPublicRoot = 7;
const AppTrustedRoot TrustedHostedAppTestRoot = 8;
const AppTrustedRoot AddonsPublicRoot = 9;
const AppTrustedRoot AddonsStageRoot = 10;
void openSignedAppFileAsync(in AppTrustedRoot trustedRoot,
in nsIFile aJarFile,
in nsIOpenSignedAppFileCallback callback);

View File

@ -76,8 +76,6 @@ user_pref("extensions.getAddons.cache.enabled", false);
user_pref("extensions.installDistroAddons", false);
// XPI extensions are required for test harnesses to load
user_pref("extensions.defaultProviders.enabled", true);
// Disable signature requirements where possible
user_pref("xpinstall.signatures.required", false);
user_pref("geo.wifi.uri", "http://%(server)s/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs");
user_pref("geo.wifi.timeToWaitBeforeSending", 2000);

View File

@ -2672,8 +2672,6 @@ this.AddonManager = {
ERROR_CORRUPT_FILE: -3,
// An error occured trying to write to the filesystem.
ERROR_FILE_ACCESS: -4,
// The add-on must be signed and isn't.
ERROR_SIGNEDSTATE_REQUIRED: -5,
// These must be kept in sync with AddonUpdateChecker.
// No error was encountered.
@ -2809,20 +2807,6 @@ this.AddonManager = {
// add-ons that were pending being enabled the last time the application ran.
STARTUP_CHANGE_ENABLED: "enabled",
// Constants for Addon.signedState. Any states that should cause an add-on
// to be unusable in builds that require signing should have negative values.
// Add-on is signed but signature verification has failed.
SIGNEDSTATE_BROKEN: -2,
// Add-on may be signed but by an certificate that doesn't chain to our
// our trusted certificate.
SIGNEDSTATE_UNKNOWN: -1,
// Add-on is unsigned.
SIGNEDSTATE_MISSING: 0,
// Add-on is preliminarily reviewed.
SIGNEDSTATE_PRELIMINARY: 1,
// Add-on is fully reviewed.
SIGNEDSTATE_SIGNED: 2,
// Constants for the Addon.userDisabled property
// Indicates that the userDisabled state of this add-on is currently
// ask-to-activate. That is, it can be conditionally enabled on a

View File

@ -78,9 +78,6 @@ const PREF_XPI_ENABLED = "xpinstall.enabled";
const PREF_XPI_WHITELIST_REQUIRED = "xpinstall.whitelist.required";
const PREF_XPI_DIRECT_WHITELISTED = "xpinstall.whitelist.directRequest";
const PREF_XPI_FILE_WHITELISTED = "xpinstall.whitelist.fileRequest";
// xpinstall.signatures.required only supported in dev builds
const PREF_XPI_SIGNATURES_REQUIRED = "xpinstall.signatures.required";
const PREF_XPI_SIGNATURES_DEV_ROOT = "xpinstall.signatures.dev-root";
const PREF_XPI_PERMISSIONS_BRANCH = "xpinstall.";
const PREF_XPI_UNPACK = "extensions.alwaysUnpack";
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
@ -103,6 +100,7 @@ const STRING_TYPE_NAME = "type.%ID%.name";
const DIR_EXTENSIONS = "extensions";
const DIR_STAGE = "staged";
const DIR_XPI_STAGE = "staged-xpis";
const DIR_TRASH = "trash";
const FILE_DATABASE = "extensions.json";
@ -192,19 +190,6 @@ const RESTARTLESS_TYPES = new Set([
"locale",
]);
const SIGNED_TYPES = new Set([
"extension",
"experiment",
]);
// Whether add-on signing is required.
function mustSign(aType) {
if (!SIGNED_TYPES.has(aType))
return false;
return REQUIRE_SIGNING || Preferences.get(PREF_XPI_SIGNATURES_REQUIRED, false);
}
// Keep track of where we are in startup for telemetry
// event happened during XPIDatabase.startup()
const XPI_STARTING = "XPIStarting";
@ -645,9 +630,6 @@ function isUsableAddon(aAddon) {
if (aAddon.type == "theme" && aAddon.internalName == XPIProvider.defaultSkin)
return true;
if (mustSign(aAddon.type) && aAddon.signedState <= AddonManager.SIGNEDSTATE_MISSING)
return false;
if (aAddon.blocklistState == Blocklist.STATE_BLOCKED)
return false;
@ -1017,7 +999,7 @@ function loadManifestFromRDF(aUri, aStream) {
* @return an AddonInternal object
* @throws if the directory does not contain a valid install manifest
*/
let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
function loadManifestFromDir(aDir) {
function getFileSize(aFile) {
if (aFile.isSymlink())
return 0;
@ -1058,11 +1040,6 @@ let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
"binary-component");
if (SIGNED_TYPES.has(addon.type))
addon.signedState = yield verifyDirSignedState(aDir, addon.id);
else
addon.signedState = AddonManager.SIGNEDSTATE_MISSING;
addon.appDisabled = !isUsableAddon(addon);
return addon;
}
@ -1070,7 +1047,7 @@ let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
bis.close();
fis.close();
}
});
}
/**
* Loads an AddonInternal object from an nsIZipReader for an add-on.
@ -1080,7 +1057,7 @@ let loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir) {
* @return an AddonInternal object
* @throws if the XPI file does not contain a valid install manifest
*/
let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(aZipReader) {
function loadManifestFromZipReader(aZipReader) {
let zis = aZipReader.getInputStream(FILE_INSTALL_MANIFEST);
let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
createInstance(Ci.nsIBufferedInputStream);
@ -1106,11 +1083,6 @@ let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
addon.hasBinaryComponents = false;
}
if (SIGNED_TYPES.has(addon.type))
addon.signedState = yield verifyZipSignedState(aZipReader.file, addon.id, addon.version);
else
addon.signedState = AddonManager.SIGNEDSTATE_MISSING;
addon.appDisabled = !isUsableAddon(addon);
return addon;
}
@ -1118,7 +1090,7 @@ let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
bis.close();
zis.close();
}
});
}
/**
* Loads an AddonInternal object from an add-on in an XPI file.
@ -1128,22 +1100,18 @@ let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a
* @return an AddonInternal object
* @throws if the XPI file does not contain a valid install manifest
*/
let loadManifestFromZipFile = Task.async(function* loadManifestFromZipFile(aXPIFile) {
function loadManifestFromZipFile(aXPIFile) {
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
createInstance(Ci.nsIZipReader);
try {
zipReader.open(aXPIFile);
// Can't return this promise because that will make us close the zip reader
// before it has finished loading the manifest. Wait for the result and then
// return.
let manifest = yield loadManifestFromZipReader(zipReader);
return manifest;
return loadManifestFromZipReader(zipReader);
}
finally {
zipReader.close();
}
});
}
function loadManifestFromFile(aFile) {
if (aFile.isFile())
@ -1152,32 +1120,6 @@ function loadManifestFromFile(aFile) {
return loadManifestFromDir(aFile);
}
/**
* A synchronous method for loading an add-on's manifest. This should only ever
* be used during startup or a sync load of the add-ons DB
*/
function syncLoadManifestFromFile(aFile) {
let success = undefined;
let result = null;
loadManifestFromFile(aFile).then(val => {
success = true;
result = val;
}, val => {
success = false;
result = val
});
let thread = Services.tm.currentThread;
while (success === undefined)
thread.processNextEvent(true);
if (!success)
throw result;
return result;
}
/**
* Gets an nsIURI for a file within another file, either a directory or an XPI
* file. If aFile is a directory then this will return a file: URI, if it is an
@ -1284,81 +1226,6 @@ function verifyZipSigning(aZip, aCertificate) {
return aZip.manifestEntriesCount == count;
}
/**
* Returns the signedState for a given return code and certificate by verifying
* it against the expected ID.
*/
function getSignedStatus(aRv, aCert, aExpectedID) {
switch (aRv) {
case Cr.NS_OK:
if (aExpectedID != aCert.commonName)
return AddonManager.SIGNEDSTATE_BROKEN;
return /preliminary/i.test(aCert.organizationalUnit)
? AddonManager.SIGNEDSTATE_PRELIMINARY
: AddonManager.SIGNEDSTATE_SIGNED;
break;
case Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED:
return AddonManager.SIGNEDSTATE_MISSING;
break;
case Cr.NS_ERROR_SIGNED_JAR_MANIFEST_INVALID:
case Cr.NS_ERROR_SIGNED_JAR_ENTRY_INVALID:
case Cr.NS_ERROR_SIGNED_JAR_ENTRY_MISSING:
case Cr.NS_ERROR_SIGNED_JAR_ENTRY_TOO_LARGE:
case Cr.NS_ERROR_SIGNED_JAR_UNSIGNED_ENTRY:
case Cr.NS_ERROR_SIGNED_JAR_MODIFIED_ENTRY:
return AddonManager.SIGNEDSTATE_BROKEN;
break;
default:
// Any other error indicates that either the add-on isn't signed or it
// is signed by a signature that doesn't chain to the trusted root.
return AddonManager.SIGNEDSTATE_UNKNOWN;
break;
}
}
/**
* Verifies that a zip file's contents are all correctly signed by an
* AMO-issued certificate
*
* @param aFile
* the xpi file to check
* @param aExpectedID
* the expected ID of the signature
* @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
*/
function verifyZipSignedState(aFile, aExpectedID, aVersion) {
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
let root = Ci.nsIX509CertDB.AddonsPublicRoot;
if (!REQUIRE_SIGNING && Preferences.get(PREF_XPI_SIGNATURES_DEV_ROOT, false))
root = Ci.nsIX509CertDB.AddonsStageRoot;
return new Promise(resolve => {
certDB.openSignedAppFileAsync(root, aFile, (aRv, aZipReader, aCert) => {
if (aZipReader)
aZipReader.close();
resolve(getSignedStatus(aRv, aCert, aExpectedID));
});
});
}
/**
* Verifies that a directory's contents are all correctly signed by an
* AMO-issued certificate
*
* @param aDir
* the directory to check
* @param aExpectedID
* the expected ID of the signature
* @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
*/
function verifyDirSignedState(aDir, aExpectedID) {
// TODO: Get the certificate for an unpacked add-on (bug 1038072)
return Promise.resolve(AddonManager.SIGNEDSTATE_MISSING);
}
/**
* Replaces %...% strings in an addon url (update and updateInfo) with
* appropriate values.
@ -2214,8 +2081,6 @@ this.XPIProvider = {
Services.prefs.addObserver(PREF_EM_MIN_COMPAT_APP_VERSION, this, false);
Services.prefs.addObserver(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, this, false);
if (!REQUIRE_SIGNING)
Services.prefs.addObserver(PREF_XPI_SIGNATURES_REQUIRED, this, false);
Services.obs.addObserver(this, NOTIFICATION_FLUSH_PERMISSIONS, false);
if (Cu.isModuleLoaded("resource:///modules/devtools/ToolboxProcess.jsm")) {
// If BrowserToolboxProcess is already loaded, set the boolean to true
@ -2559,8 +2424,95 @@ this.XPIProvider = {
if (aLocation.locked)
return;
let stagedXPIDir = aLocation.getXPIStagingDir();
let stagingDir = aLocation.getStagingDir();
if (stagedXPIDir.exists() && stagedXPIDir.isDirectory()) {
let entries = stagedXPIDir.directoryEntries
.QueryInterface(Ci.nsIDirectoryEnumerator);
while (entries.hasMoreElements()) {
let stageDirEntry = entries.nextFile;
if (!stageDirEntry.isDirectory()) {
logger.warn("Ignoring file in XPI staging directory: " + stageDirEntry.path);
continue;
}
// Find the last added XPI file in the directory
let stagedXPI = null;
var xpiEntries = stageDirEntry.directoryEntries
.QueryInterface(Ci.nsIDirectoryEnumerator);
while (xpiEntries.hasMoreElements()) {
let file = xpiEntries.nextFile;
if (file.isDirectory())
continue;
let extension = file.leafName;
extension = extension.substring(extension.length - 4);
if (extension != ".xpi" && extension != ".jar")
continue;
stagedXPI = file;
}
xpiEntries.close();
if (!stagedXPI)
continue;
let addon = null;
try {
addon = loadManifestFromZipFile(stagedXPI);
}
catch (e) {
logger.error("Unable to read add-on manifest from " + stagedXPI.path, e);
continue;
}
logger.debug("Migrating staged install of " + addon.id + " in " + aLocation.name);
if (addon.unpack || Preferences.get(PREF_XPI_UNPACK, false)) {
let targetDir = stagingDir.clone();
targetDir.append(addon.id);
try {
targetDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
}
catch (e) {
logger.error("Failed to create staging directory for add-on " + addon.id, e);
continue;
}
try {
ZipUtils.extractFiles(stagedXPI, targetDir);
}
catch (e) {
logger.error("Failed to extract staged XPI for add-on " + addon.id + " in " +
aLocation.name, e);
}
}
else {
try {
stagedXPI.moveTo(stagingDir, addon.id + ".xpi");
}
catch (e) {
logger.error("Failed to move staged XPI for add-on " + addon.id + " in " +
aLocation.name, e);
}
}
}
entries.close();
}
if (stagedXPIDir.exists()) {
try {
recursiveRemove(stagedXPIDir);
}
catch (e) {
// Non-critical, just saves some perf on startup if we clean this up.
logger.debug("Error removing XPI staging dir " + stagedXPIDir.path, e);
}
}
try {
if (!stagingDir || !stagingDir.exists() || !stagingDir.isDirectory())
return;
@ -2641,7 +2593,7 @@ this.XPIProvider = {
jsonfile.append(id + ".json");
try {
aManifests[aLocation.name][id] = syncLoadManifestFromFile(stageDirEntry);
aManifests[aLocation.name][id] = loadManifestFromFile(stageDirEntry);
}
catch (e) {
logger.error("Unable to read add-on manifest from " + stageDirEntry.path, e);
@ -2651,15 +2603,6 @@ this.XPIProvider = {
continue;
}
let addon = aManifests[aLocation.name][id];
if ((addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) && mustSign(addon.type)) {
logger.warn("Refusing to install staged add-on " + id + " with signed state " + addon.signedState);
seenFiles.push(stageDirEntry.leafName);
seenFiles.push(jsonfile.leafName);
continue;
}
// Check for a cached metadata for this add-on, it may contain updated
// compatibility information
if (jsonfile.exists()) {
@ -2672,7 +2615,7 @@ this.XPIProvider = {
try {
fis.init(jsonfile, -1, 0, 0);
let metadata = json.decodeFromStream(fis, jsonfile.fileSize);
addon.importMetadata(metadata);
aManifests[aLocation.name][id].importMetadata(metadata);
}
catch (e) {
// If some data can't be recovered from the cached metadata then it
@ -2686,7 +2629,7 @@ this.XPIProvider = {
}
seenFiles.push(jsonfile.leafName);
existingAddonID = addon.existingAddonID || id;
existingAddonID = aManifests[aLocation.name][id].existingAddonID || id;
var oldBootstrap = null;
logger.debug("Processing install of " + id + " in " + aLocation.name);
@ -2699,7 +2642,7 @@ this.XPIProvider = {
// We'll be replacing a currently active bootstrapped add-on so
// call its uninstall method
let newVersion = addon.version;
let newVersion = aManifests[aLocation.name][id].version;
let oldVersion = oldBootstrap.version;
let uninstallReason = Services.vc.compare(oldVersion, newVersion) < 0 ?
BOOTSTRAP_REASONS.ADDON_UPGRADE :
@ -2717,15 +2660,17 @@ this.XPIProvider = {
}
try {
addon._sourceBundle = aLocation.installAddon(id, stageDirEntry,
existingAddonID);
var addonInstallLocation = aLocation.installAddon(id, stageDirEntry,
existingAddonID);
if (aManifests[aLocation.name][id])
aManifests[aLocation.name][id]._sourceBundle = addonInstallLocation;
}
catch (e) {
logger.error("Failed to install staged add-on " + id + " in " + aLocation.name,
e);
// Re-create the staged install
AddonInstall.createStagedInstall(aLocation, stageDirEntry,
addon);
aManifests[aLocation.name][id]);
// Make sure not to delete the cached manifest json file
seenFiles.pop();
@ -2811,7 +2756,7 @@ this.XPIProvider = {
let addon;
try {
addon = syncLoadManifestFromFile(entry);
addon = loadManifestFromFile(entry);
}
catch (e) {
logger.warn("File entry " + entry.path + " contains an invalid add-on", e);
@ -2834,7 +2779,7 @@ this.XPIProvider = {
if (existingEntry) {
let existingAddon;
try {
existingAddon = syncLoadManifestFromFile(existingEntry);
existingAddon = loadManifestFromFile(existingEntry);
if (Services.vc.compare(addon.version, existingAddon.version) <= 0)
continue;
@ -2929,7 +2874,7 @@ this.XPIProvider = {
// If not load it
if (!newAddon) {
let file = aInstallLocation.getLocationForID(aOldAddon.id);
newAddon = syncLoadManifestFromFile(file);
newAddon = loadManifestFromFile(file);
applyBlocklistChanges(aOldAddon, newAddon);
// Carry over any pendingUninstall state to add-ons modified directly
@ -2972,11 +2917,6 @@ this.XPIProvider = {
// Remember add-ons that were changed during startup
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
newDBAddon.id);
if (aOldAddon.active == newDBAddon.disabled) {
let change = aOldAddon.active ? AddonManager.STARTUP_CHANGE_DISABLED
: AddonManager.STARTUP_CHANGE_ENABLED;
AddonManagerPrivate.addStartupChange(change, newDBAddon.id);
}
// If this was the active theme and it is now disabled then enable the
// default theme
@ -3101,16 +3041,7 @@ this.XPIProvider = {
let wasAppDisabled = aOldAddon.appDisabled;
let wasUserDisabled = aOldAddon.userDisabled;
let wasSoftDisabled = aOldAddon.softDisabled;
let updateDB = false;
// If updating from a version of the app that didn't support signedState
// then fetch that property now
if (aOldAddon.signedState === undefined) {
let file = aInstallLocation.getLocationForID(aOldAddon.id);
let manifest = syncLoadManifestFromFile(file);
aOldAddon.signedState = manifest.signedState;
updateDB = true;
}
// This updates the addon's JSON cached data in place
applyBlocklistChanges(aOldAddon, aOldAddon, aOldAppVersion,
aOldPlatformVersion);
@ -3119,7 +3050,7 @@ this.XPIProvider = {
let isDisabled = aOldAddon.disabled;
// If either property has changed update the database.
if (updateDB || wasAppDisabled != aOldAddon.appDisabled ||
if (wasAppDisabled != aOldAddon.appDisabled ||
wasUserDisabled != aOldAddon.userDisabled ||
wasSoftDisabled != aOldAddon.softDisabled) {
logger.debug("Add-on " + aOldAddon.id + " changed appDisabled state to " +
@ -3240,7 +3171,7 @@ this.XPIProvider = {
if (!newAddon) {
// Load the manifest from the add-on.
let file = aInstallLocation.getLocationForID(aId);
newAddon = syncLoadManifestFromFile(file);
newAddon = loadManifestFromFile(file);
}
// The add-on in the manifest should match the add-on ID.
if (newAddon.id != aId) {
@ -4163,18 +4094,13 @@ this.XPIProvider = {
if (aTopic == "nsPref:changed") {
switch (aData) {
case PREF_EM_MIN_COMPAT_APP_VERSION:
case PREF_EM_MIN_COMPAT_PLATFORM_VERSION:
this.minCompatibleAppVersion = Preferences.get(PREF_EM_MIN_COMPAT_APP_VERSION,
null);
this.updateAddonAppDisabledStates();
break;
case PREF_EM_MIN_COMPAT_PLATFORM_VERSION:
this.minCompatiblePlatformVersion = Preferences.get(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
null);
this.updateAddonAppDisabledStates();
break;
case PREF_XPI_SIGNATURES_REQUIRED:
this.updateAddonAppDisabledStates();
break;
}
}
},
@ -4988,45 +4914,49 @@ AddonInstall.prototype = {
}
}
let self = this;
this.loadManifest().then(() => {
XPIDatabase.getVisibleAddonForID(self.addon.id, function initLocalInstall_getVisibleAddon(aAddon) {
self.existingAddon = aAddon;
if (aAddon)
applyBlocklistChanges(aAddon, self.addon);
self.addon.updateDate = Date.now();
self.addon.installDate = aAddon ? aAddon.installDate : self.addon.updateDate;
try {
let self = this;
this.loadManifest(function initLocalInstall_loadManifest() {
XPIDatabase.getVisibleAddonForID(self.addon.id, function initLocalInstall_getVisibleAddon(aAddon) {
self.existingAddon = aAddon;
if (aAddon)
applyBlocklistChanges(aAddon, self.addon);
self.addon.updateDate = Date.now();
self.addon.installDate = aAddon ? aAddon.installDate : self.addon.updateDate;
if (!self.addon.isCompatible) {
// TODO Should we send some event here?
self.state = AddonManager.STATE_CHECKING;
new UpdateChecker(self.addon, {
onUpdateFinished: function updateChecker_onUpdateFinished(aAddon) {
self.state = AddonManager.STATE_DOWNLOADED;
XPIProvider.installs.push(self);
AddonManagerPrivate.callInstallListeners("onNewInstall",
self.listeners,
self.wrapper);
if (!self.addon.isCompatible) {
// TODO Should we send some event here?
self.state = AddonManager.STATE_CHECKING;
new UpdateChecker(self.addon, {
onUpdateFinished: function updateChecker_onUpdateFinished(aAddon) {
self.state = AddonManager.STATE_DOWNLOADED;
XPIProvider.installs.push(self);
AddonManagerPrivate.callInstallListeners("onNewInstall",
self.listeners,
self.wrapper);
aCallback(self);
}
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
}
else {
XPIProvider.installs.push(self);
AddonManagerPrivate.callInstallListeners("onNewInstall",
self.listeners,
self.wrapper);
aCallback(self);
}
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
}
else {
XPIProvider.installs.push(self);
AddonManagerPrivate.callInstallListeners("onNewInstall",
self.listeners,
self.wrapper);
aCallback(self);
}
aCallback(self);
}
});
});
}, ([error, message]) => {
logger.warn("Invalid XPI", message);
}
catch (e) {
logger.warn("Invalid XPI", e);
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
this.error = error;
this.error = AddonManager.ERROR_CORRUPT_FILE;
aCallback(this);
});
return;
}
},
/**
@ -5215,7 +5145,8 @@ AddonInstall.prototype = {
* loaded. Because this loadMultipackageManifests is an internal API
* we don't exception-wrap this callback
*/
_loadMultipackageManifests: Task.async(function* AI_loadMultipackageManifests(aZipReader) {
_loadMultipackageManifests: function AI_loadMultipackageManifests(aZipReader,
aCallback) {
let files = [];
let entries = aZipReader.findEntries("(*.[Xx][Pp][Ii]|*.[Jj][Aa][Rr])");
while (entries.hasMore()) {
@ -5248,7 +5179,7 @@ AddonInstall.prototype = {
this.file = files.shift();
this.ownsTempFile = true;
try {
addon = yield loadManifestFromZipFile(this.file);
addon = loadManifestFromZipFile(this.file);
break;
}
catch (e) {
@ -5259,6 +5190,7 @@ AddonInstall.prototype = {
if (!addon) {
// No valid add-on was found
aCallback();
return;
}
@ -5280,28 +5212,36 @@ AddonInstall.prototype = {
// Create new AddonInstall instances for every remaining file
if (files.length > 0) {
this.linkedInstalls = [];
let count = 0;
let self = this;
for (let file of files) {
let install = yield new Promise(resolve => AddonInstall.createInstall(resolve, file));
files.forEach(function(file) {
AddonInstall.createInstall(function loadMultipackageManifests_createInstall(aInstall) {
// Ignore bad add-ons (createInstall will have logged the error)
if (aInstall.state == AddonManager.STATE_DOWNLOAD_FAILED) {
// Manually remove the temporary file
file.remove(true);
}
else {
// Make the new install own its temporary file
aInstall.ownsTempFile = true;
// Ignore bad add-ons (createInstall will have logged the error)
if (install.state == AddonManager.STATE_DOWNLOAD_FAILED) {
// Manually remove the temporary file
file.remove(true);
}
else {
// Make the new install own its temporary file
install.ownsTempFile = true;
self.linkedInstalls.push(aInstall)
self.linkedInstalls.push(install)
aInstall.sourceURI = self.sourceURI;
aInstall.releaseNotesURI = self.releaseNotesURI;
aInstall.updateAddonURIs();
}
install.sourceURI = self.sourceURI;
install.releaseNotesURI = self.releaseNotesURI;
install.updateAddonURIs();
}
}
count++;
if (count == files.length)
aCallback();
}, file);
}, this);
}
}),
else {
aCallback();
}
},
/**
* Called after the add-on is a local file and the signature and install
@ -5312,7 +5252,36 @@ AddonInstall.prototype = {
* @throws if the add-on does not contain a valid install manifest or the
* XPI is incorrectly signed
*/
loadManifest: Task.async(function* AI_loadManifest() {
loadManifest: function AI_loadManifest(aCallback) {
aCallback = makeSafe(aCallback);
let self = this;
function addRepositoryData(aAddon) {
// Try to load from the existing cache first
AddonRepository.getCachedAddonByID(aAddon.id, function loadManifest_getCachedAddonByID(aRepoAddon) {
if (aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
self.name = self.name || aAddon._repositoryAddon.name;
aAddon.compatibilityOverrides = aRepoAddon.compatibilityOverrides;
aAddon.appDisabled = !isUsableAddon(aAddon);
aCallback();
return;
}
// It wasn't there so try to re-download it
AddonRepository.cacheAddons([aAddon.id], function loadManifest_cacheAddons() {
AddonRepository.getCachedAddonByID(aAddon.id, function loadManifest_getCachedAddonByID(aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
self.name = self.name || aAddon._repositoryAddon.name;
aAddon.compatibilityOverrides = aRepoAddon ?
aRepoAddon.compatibilityOverrides :
null;
aAddon.appDisabled = !isUsableAddon(aAddon);
aCallback();
});
});
});
}
let zipreader = Cc["@mozilla.org/libjar/zip-reader;1"].
createInstance(Ci.nsIZipReader);
try {
@ -5320,56 +5289,39 @@ AddonInstall.prototype = {
}
catch (e) {
zipreader.close();
return Promise.reject([AddonManager.ERROR_CORRUPT_FILE, e]);
throw e;
}
let x509 = zipreader.getSigningCert(null);
if (x509) {
logger.debug("Verifying XPI signature");
if (verifyZipSigning(zipreader, x509)) {
this.certificate = x509;
if (this.certificate.commonName.length > 0) {
this.certName = this.certificate.commonName;
} else {
this.certName = this.certificate.organization;
}
} else {
zipreader.close();
throw new Error("XPI is incorrectly signed");
}
}
try {
// loadManifestFromZipReader performs the certificate verification for us
this.addon = yield loadManifestFromZipReader(zipreader);
this.addon = loadManifestFromZipReader(zipreader);
}
catch (e) {
zipreader.close();
return Promise.reject([AddonManager.ERROR_CORRUPT_FILE, e]);
throw e;
}
if (mustSign(this.addon.type)) {
if (this.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
// This add-on isn't properly signed by a signature that chains to the
// trusted root.
let state = this.addon.signedState;
this.addon = null;
zipreader.close();
if (state == AddonManager.SIGNEDSTATE_MISSING)
return Promise.reject([AddonManager.ERROR_SIGNEDSTATE_REQUIRED,
"signature is required but missing"])
return Promise.reject([AddonManager.ERROR_CORRUPT_FILE,
"signature verification failed"])
}
if (this.addon.type == "multipackage") {
this._loadMultipackageManifests(zipreader, function loadManifest_loadMultipackageManifests() {
addRepositoryData(self.addon);
});
return;
}
else if (this.addon.signedState == AddonManager.SIGNEDSTATE_UNKNOWN) {
// Check object signing certificate, if any
let x509 = zipreader.getSigningCert(null);
if (x509) {
logger.debug("Verifying XPI signature");
if (verifyZipSigning(zipreader, x509)) {
this.certificate = x509;
if (this.certificate.commonName.length > 0) {
this.certName = this.certificate.commonName;
} else {
this.certName = this.certificate.organization;
}
} else {
zipreader.close();
return Promise.reject([AddonManager.ERROR_CORRUPT_FILE,
"XPI is incorrectly signed"]);
}
}
}
if (this.addon.type == "multipackage")
return this._loadMultipackageManifests(zipreader);
zipreader.close();
@ -5386,22 +5338,8 @@ AddonInstall.prototype = {
//if (newIcon)
// this.iconURL = newIcon;
// Try to load from the existing cache first
let repoAddon = yield new Promise(resolve => AddonRepository.getCachedAddonByID(this.addon.id, resolve));
// It wasn't there so try to re-download it
if (!repoAddon) {
yield new Promise(resolve => AddonRepository.cacheAddons([this.addon.id], resolve));
repoAddon = yield new Promise(resolve => AddonRepository.getCachedAddonByID(this.addon.id, resolve));
}
this.addon._repositoryAddon = repoAddon;
this.name = this.name || this.addon._repositoryAddon.name;
this.addon.compatibilityOverrides = repoAddon ?
repoAddon.compatibilityOverrides :
null;
this.addon.appDisabled = !isUsableAddon(this.addon);
}),
addRepositoryData(this.addon);
},
observe: function AI_observe(aSubject, aTopic, aData) {
// Network is going offline
@ -5637,24 +5575,26 @@ AddonInstall.prototype = {
") did not match provided hash (" + this.hash.data + ")");
return;
}
let self = this;
this.loadManifest().then(() => {
if (self.addon.isCompatible) {
self.downloadCompleted();
}
else {
// TODO Should we send some event here (bug 557716)?
self.state = AddonManager.STATE_CHECKING;
new UpdateChecker(self.addon, {
onUpdateFinished: function onStopRequest_onUpdateFinished(aAddon) {
self.downloadCompleted();
}
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
}
}, ([error, message]) => {
this.downloadFailed(error, message);
});
try {
let self = this;
this.loadManifest(function onStopRequest_loadManifest() {
if (self.addon.isCompatible) {
self.downloadCompleted();
}
else {
// TODO Should we send some event here (bug 557716)?
self.state = AddonManager.STATE_CHECKING;
new UpdateChecker(self.addon, {
onUpdateFinished: function onStopRequest_onUpdateFinished(aAddon) {
self.downloadCompleted();
}
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
}
});
}
catch (e) {
this.downloadFailed(AddonManager.ERROR_CORRUPT_FILE, e);
}
}
else {
if (aRequest instanceof Ci.nsIHttpChannel)
@ -6679,7 +6619,7 @@ function AddonWrapper(aAddon) {
"providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled",
"softDisabled", "skinnable", "size", "foreignInstall", "hasBinaryComponents",
"strictCompatibility", "compatibilityOverrides", "updateURL",
"getDataDirectory", "multiprocessCompatible", "signedState"].forEach(function(aProp) {
"getDataDirectory", "multiprocessCompatible"].forEach(function(aProp) {
this.__defineGetter__(aProp, function AddonWrapper_propertyGetter() aAddon[aProp]);
}, this);
@ -7251,7 +7191,7 @@ DirectoryInstallLocation.prototype = {
for (let entry of entries) {
let id = entry.leafName;
if (id == DIR_STAGE || id == DIR_TRASH)
if (id == DIR_STAGE || id == DIR_XPI_STAGE || id == DIR_TRASH)
continue;
let directLoad = false;
@ -7394,6 +7334,18 @@ DirectoryInstallLocation.prototype = {
}
},
/**
* Gets the directory used by old versions for staging XPI and JAR files ready
* to be installed.
*
* @return an nsIFile
*/
getXPIStagingDir: function DirInstallLocation_getXPIStagingDir() {
let dir = this._directory.clone();
dir.append(DIR_XPI_STAGE);
return dir;
},
/**
* Returns a directory that is normally on the same filesystem as the rest of
* the install location and can be used for temporarily storing files during
@ -7770,19 +7722,6 @@ WinRegInstallLocation.prototype = {
};
#endif
// Make this a non-changable property so it can't be manipulated from other
// code in the app.
Object.defineProperty(this, "REQUIRE_SIGNING", {
configurable: false,
enumerable: false,
writable: false,
#ifdef MOZ_REQUIRE_SIGNING
value: true,
#else
value: false,
#endif
});
let addonTypes = [
new AddonManagerPrivate.AddonType("extension", URI_EXTENSION_STRINGS,
STRING_TYPE_NAME,

View File

@ -70,7 +70,7 @@ const PROP_JSON_FIELDS = ["id", "syncGUID", "location", "version", "type",
"skinnable", "size", "sourceURI", "releaseNotesURI",
"softDisabled", "foreignInstall", "hasBinaryComponents",
"strictCompatibility", "locales", "targetApplications",
"targetPlatforms", "multiprocessCompatible", "signedState"];
"targetPlatforms", "multiprocessCompatible"];
// Time to wait before async save of XPI JSON database, in milliseconds
const ASYNC_SAVE_DELAY_MS = 20;

View File

@ -28,7 +28,7 @@ EXTRA_PP_JS_MODULES.addons += [
# This is used in multiple places, so is defined here to avoid it getting
# out of sync.
DEFINES['MOZ_EXTENSIONS_DB_SCHEMA'] = 17
DEFINES['MOZ_EXTENSIONS_DB_SCHEMA'] = 16
# Additional debugging info is exposed in debug builds
if CONFIG['MOZ_EM_DEBUG']:

View File

@ -1,29 +0,0 @@
Components.utils.import("resource://gre/modules/Services.jsm");
const VERSION = 1;
// Test steps chain from pref observers on *_reason,
// so always set that last
function install(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", VERSION);
Services.prefs.setIntPref("bootstraptest.install_oldversion", data.oldVersion);
Services.prefs.setIntPref("bootstraptest.install_reason", reason);
}
function startup(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", VERSION);
Services.prefs.setIntPref("bootstraptest.startup_oldversion", data.oldVersion);
Services.prefs.setIntPref("bootstraptest.startup_reason", reason);
}
function shutdown(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", 0);
Services.prefs.setIntPref("bootstraptest.shutdown_newversion", data.newVersion);
Services.prefs.setIntPref("bootstraptest.shutdown_reason", reason);
}
function uninstall(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", 0);
Services.prefs.setIntPref("bootstraptest.uninstall_newversion", data.newVersion);
Services.prefs.setIntPref("bootstraptest.uninstall_reason", reason);
}

View File

@ -1,24 +0,0 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>test@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>Test Add-on</em:name>
<em:updateURL>http://localhost:4444/update.rdf</em:updateURL>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>2</em:minVersion>
<em:maxVersion>5</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -1 +0,0 @@
This test file can be altered to break signing checks.

View File

@ -1,29 +0,0 @@
Components.utils.import("resource://gre/modules/Services.jsm");
const VERSION = 2;
// Test steps chain from pref observers on *_reason,
// so always set that last
function install(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", VERSION);
Services.prefs.setIntPref("bootstraptest.install_oldversion", data.oldVersion);
Services.prefs.setIntPref("bootstraptest.install_reason", reason);
}
function startup(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", VERSION);
Services.prefs.setIntPref("bootstraptest.startup_oldversion", data.oldVersion);
Services.prefs.setIntPref("bootstraptest.startup_reason", reason);
}
function shutdown(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", 0);
Services.prefs.setIntPref("bootstraptest.shutdown_newversion", data.newVersion);
Services.prefs.setIntPref("bootstraptest.shutdown_reason", reason);
}
function uninstall(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", 0);
Services.prefs.setIntPref("bootstraptest.uninstall_newversion", data.newVersion);
Services.prefs.setIntPref("bootstraptest.uninstall_reason", reason);
}

View File

@ -1,24 +0,0 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>test@tests.mozilla.org</em:id>
<em:version>2.0</em:version>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>Test Add-on</em:name>
<em:updateURL>http://localhost:4444/update.rdf</em:updateURL>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>4</em:minVersion>
<em:maxVersion>6</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -1 +0,0 @@
This test file can be altered to break signing checks.

View File

@ -1,23 +0,0 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>test@tests.mozilla.org</em:id>
<em:version>1.0</em:version>
<!-- Front End MetaData -->
<em:name>Test Add-on</em:name>
<em:updateURL>http://localhost:4444/update.rdf</em:updateURL>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>2</em:minVersion>
<em:maxVersion>5</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -1 +0,0 @@
This test file can be altered to break signing checks.

View File

@ -1,23 +0,0 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>test@tests.mozilla.org</em:id>
<em:version>2.0</em:version>
<!-- Front End MetaData -->
<em:name>Test Add-on</em:name>
<em:updateURL>http://localhost:4444/update.rdf</em:updateURL>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>4</em:minVersion>
<em:maxVersion>6</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -1 +0,0 @@
This test file can be altered to break signing checks.

View File

@ -14,7 +14,6 @@ const PREF_EM_MIN_COMPAT_APP_VERSION = "extensions.minCompatibleAppVersion"
const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_GETADDONS_BYIDS_PERFORMANCE = "extensions.getAddons.getWithPerformance.url";
const PREF_XPI_SIGNATURES_REQUIRED = "xpinstall.signatures.required";
// Forcibly end the test if it runs longer than 15 minutes
const TIMEOUT_MS = 900000;
@ -1454,9 +1453,6 @@ Services.prefs.setCharPref("extensions.hotfix.id", "");
Services.prefs.setCharPref(PREF_EM_MIN_COMPAT_APP_VERSION, "0");
Services.prefs.setCharPref(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, "0");
// Disable signature checks for most tests
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, false);
// Register a temporary directory for the tests.
const gTmpD = gProfD.clone();
gTmpD.append("temp");
@ -1534,6 +1530,9 @@ do_register_cleanup(function addon_cleanup() {
testDir.leafName = "staged";
pathShouldntExist(testDir);
testDir.leafName = "staged-xpis";
pathShouldntExist(testDir);
shutdownManager();
// Clear commonly set prefs.

View File

@ -197,11 +197,35 @@ function run_test() {
do_check_false(isExtensionInAddonsList(profileDir, a5.id));
do_check_false(a5.hasBinaryComponents);
// addon6, addon7 and addon8 will have been lost as they were staged in the
// pre-Firefox 4.0 directory
do_check_eq(a6, null);
do_check_eq(a7, null);
do_check_eq(a8, null);
// addon6 should be installed and compatible and packed unless unpacking is
// forced
do_check_neq(a6, null);
do_check_false(a6.userDisabled);
do_check_false(a6.appDisabled);
do_check_true(a6.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a6.id));
if (Services.prefs.getBoolPref("extensions.alwaysUnpack"))
do_check_eq(a6.getResourceURI("install.rdf").scheme, "file");
else
do_check_eq(a6.getResourceURI("install.rdf").scheme, "jar");
do_check_false(a6.hasBinaryComponents);
// addon7 should be installed and compatible and unpacked
do_check_neq(a7, null);
do_check_false(a7.userDisabled);
do_check_false(a7.appDisabled);
do_check_true(a7.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a7.id));
do_check_eq(a7.getResourceURI("install.rdf").scheme, "file");
do_check_false(a7.hasBinaryComponents);
// addon8 should be installed and compatible and have binary components
do_check_neq(a8, null);
do_check_false(a8.userDisabled);
do_check_false(a8.appDisabled);
do_check_true(a8.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a8.id));
do_check_true(a8.hasBinaryComponents);
// Theme 1 was previously enabled
do_check_neq(t1, null);
@ -219,6 +243,8 @@ function run_test() {
do_check_false(isThemeInAddonsList(profileDir, t2.id));
do_check_true(hasFlag(t2.permissions, AddonManager.PERM_CAN_ENABLE));
do_check_false(stagedXPIs.exists());
do_execute_soon(do_test_finished);
});
}

View File

@ -196,10 +196,25 @@ function run_test() {
do_check_false(a5.isActive);
do_check_false(isExtensionInAddonsList(profileDir, a5.id));
// addon6 and addon7 will have been lost as they were staged in the
// pre-Firefox 4.0 directory
do_check_eq(a6, null);
do_check_eq(a7, null);
// addon6 should be installed and compatible and packed unless unpacking is
// forced
do_check_neq(a6, null);
do_check_false(a6.userDisabled);
do_check_false(a6.appDisabled);
do_check_true(a6.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a6.id));
if (Services.prefs.getBoolPref("extensions.alwaysUnpack"))
do_check_eq(a6.getResourceURI("install.rdf").scheme, "file");
else
do_check_eq(a6.getResourceURI("install.rdf").scheme, "jar");
// addon7 should be installed and compatible and unpacked
do_check_neq(a7, null);
do_check_false(a7.userDisabled);
do_check_false(a7.appDisabled);
do_check_true(a7.isActive);
do_check_true(isExtensionInAddonsList(profileDir, a7.id));
do_check_eq(a7.getResourceURI("install.rdf").scheme, "file");
// Theme 1 was previously disabled
do_check_neq(t1, null);
@ -217,6 +232,8 @@ function run_test() {
do_check_false(isThemeInAddonsList(profileDir, t2.id));
do_check_true(hasFlag(t2.permissions, AddonManager.PERM_CAN_ENABLE));
do_check_false(stagedXPIs.exists());
do_execute_soon(do_test_finished);
});
}

View File

@ -1,320 +0,0 @@
// Enable signature checks for these tests
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, 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",
},
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) {
file.append("test.txt");
file.remove(true);
}
else {
var zipW = AM_Cc["@mozilla.org/zipwriter;1"].
createInstance(AM_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 getActiveVersion() {
return Services.prefs.getIntPref("bootstraptest.active_version");
}
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "4", "4");
// Start and stop the manager to initialise everything in the profile before
// actual testing
startupManager();
shutdownManager();
resetPrefs();
run_next_test();
}
// Injecting into profile (bootstrap)
add_task(function*() {
manuallyInstall(do_get_file(DATA + ADDONS.bootstrap.unsigned), profileDir, ID);
startupManager();
// Currently we leave the sideloaded add-on there but just don't run it
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_MISSING);
do_check_eq(getActiveVersion(), -1);
addon.uninstall();
yield promiseShutdownManager();
resetPrefs();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
add_task(function*() {
manuallyInstall(do_get_file(DATA + ADDONS.bootstrap.signed), profileDir, ID);
breakAddon(getFileForAddon(profileDir, ID));
startupManager();
// Currently we leave the sideloaded add-on there but just don't run it
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
do_check_eq(getActiveVersion(), -1);
addon.uninstall();
yield promiseShutdownManager();
resetPrefs();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
add_task(function*() {
manuallyInstall(do_get_file(DATA + ADDONS.bootstrap.badid), profileDir, ID);
startupManager();
// Currently we leave the sideloaded add-on there but just don't run it
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
do_check_eq(getActiveVersion(), -1);
addon.uninstall();
yield promiseShutdownManager();
resetPrefs();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
// Installs a signed add-on then modifies it in place breaking its signing
add_task(function*() {
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
yield promiseSetExtensionModifiedTime(getFileForAddon(profileDir, ID).path, Date.now() - 600000);
startupManager();
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_SIGNED);
do_check_eq(getActiveVersion(), 2);
yield promiseShutdownManager();
do_check_eq(getActiveVersion(), 0);
breakAddon(getFileForAddon(profileDir, ID));
resetPrefs();
startupManager();
addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
do_check_eq(getActiveVersion(), -1);
let ids = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_DISABLED);
do_check_eq(ids.length, 1);
do_check_eq(ids[0], ID);
addon.uninstall();
yield promiseShutdownManager();
resetPrefs();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
// Injecting into profile (non-bootstrap)
add_task(function*() {
manuallyInstall(do_get_file(DATA + ADDONS.nonbootstrap.unsigned), profileDir, ID);
startupManager();
// Currently we leave the sideloaded add-on there but just don't run it
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_MISSING);
do_check_false(isExtensionInAddonsList(profileDir, ID));
addon.uninstall();
yield promiseRestartManager();
yield promiseShutdownManager();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
add_task(function*() {
manuallyInstall(do_get_file(DATA + ADDONS.nonbootstrap.signed), profileDir, ID);
breakAddon(getFileForAddon(profileDir, ID));
startupManager();
// Currently we leave the sideloaded add-on there but just don't run it
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
do_check_false(isExtensionInAddonsList(profileDir, ID));
addon.uninstall();
yield promiseRestartManager();
yield promiseShutdownManager();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
add_task(function*() {
manuallyInstall(do_get_file(DATA + ADDONS.nonbootstrap.badid), profileDir, ID);
startupManager();
// Currently we leave the sideloaded add-on there but just don't run it
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
do_check_false(isExtensionInAddonsList(profileDir, ID));
addon.uninstall();
yield promiseRestartManager();
yield promiseShutdownManager();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
// Installs a signed add-on then modifies it in place breaking its signing
add_task(function*() {
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
yield promiseSetExtensionModifiedTime(getFileForAddon(profileDir, ID).path, Date.now() - 60000);
startupManager();
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_SIGNED);
do_check_true(isExtensionInAddonsList(profileDir, ID));
yield promiseShutdownManager();
breakAddon(getFileForAddon(profileDir, ID));
startupManager();
addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_BROKEN);
do_check_false(isExtensionInAddonsList(profileDir, ID));
let ids = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_DISABLED);
do_check_eq(ids.length, 1);
do_check_eq(ids[0], ID);
addon.uninstall();
yield promiseRestartManager();
yield promiseShutdownManager();
do_check_false(getFileForAddon(profileDir, ID).exists());
});
// Stage install then modify before startup (non-bootstrap)
add_task(function*() {
startupManager();
yield promiseInstallAllFiles([do_get_file(DATA + ADDONS.nonbootstrap.signed)]);
yield promiseShutdownManager();
let staged = profileDir.clone();
staged.append("staged");
staged.append(do_get_expected_addon_name(ID));
do_check_true(staged.exists());
breakAddon(staged);
startupManager();
// Should have refused to install the broken staged version
let addon = yield promiseAddonByID(ID);
do_check_eq(addon, null);
let install = getFileForAddon(profileDir, ID);
do_check_false(install.exists());
yield promiseShutdownManager();
});
// Manufacture staged install (bootstrap)
add_task(function*() {
let stage = profileDir.clone();
stage.append("staged");
let file = manuallyInstall(do_get_file(DATA + ADDONS.bootstrap.signed), stage, ID);
breakAddon(file);
startupManager();
// Should have refused to install the broken staged version
let addon = yield promiseAddonByID(ID);
do_check_eq(addon, null);
do_check_eq(getActiveVersion(), -1);
let install = getFileForAddon(profileDir, ID);
do_check_false(install.exists());
yield promiseShutdownManager();
resetPrefs();
});

View File

@ -1,265 +0,0 @@
// Enable signature checks for these tests
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, 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",
preliminary: "preliminary_bootstrap_2.xpi",
signed: "signed_bootstrap_2.xpi",
},
};
const WORKING = "signed_bootstrap_1.xpi";
const ID = "test@tests.mozilla.org";
Components.utils.import("resource://testing-common/httpd.js");
var gServer = new HttpServer();
gServer.start(4444);
// Creates an add-on with a broken signature by changing an existing file
function createBrokenAddonModify(file) {
let brokenFile = gTmpD.clone();
brokenFile.append("broken.xpi");
file.copyTo(brokenFile.parent, brokenFile.leafName);
var stream = AM_Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(AM_Ci.nsIStringInputStream);
stream.setData("FOOBAR", -1);
var zipW = AM_Cc["@mozilla.org/zipwriter;1"].
createInstance(AM_Ci.nsIZipWriter);
zipW.open(brokenFile, FileUtils.MODE_RDWR | FileUtils.MODE_APPEND);
zipW.removeEntry("test.txt", false);
zipW.addEntryStream("test.txt", 0, AM_Ci.nsIZipWriter.COMPRESSION_NONE,
stream, false);
zipW.close();
return brokenFile;
}
// Creates an add-on with a broken signature by adding a new file
function createBrokenAddonAdd(file) {
let brokenFile = gTmpD.clone();
brokenFile.append("broken.xpi");
file.copyTo(brokenFile.parent, brokenFile.leafName);
var stream = AM_Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(AM_Ci.nsIStringInputStream);
stream.setData("FOOBAR", -1);
var zipW = AM_Cc["@mozilla.org/zipwriter;1"].
createInstance(AM_Ci.nsIZipWriter);
zipW.open(brokenFile, FileUtils.MODE_RDWR | FileUtils.MODE_APPEND);
zipW.addEntryStream("test2.txt", 0, AM_Ci.nsIZipWriter.COMPRESSION_NONE,
stream, false);
zipW.close();
return brokenFile;
}
// Creates an add-on with a broken signature by removing an existing file
function createBrokenAddonRemove(file) {
let brokenFile = gTmpD.clone();
brokenFile.append("broken.xpi");
file.copyTo(brokenFile.parent, brokenFile.leafName);
var stream = AM_Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(AM_Ci.nsIStringInputStream);
stream.setData("FOOBAR", -1);
var zipW = AM_Cc["@mozilla.org/zipwriter;1"].
createInstance(AM_Ci.nsIZipWriter);
zipW.open(brokenFile, FileUtils.MODE_RDWR | FileUtils.MODE_APPEND);
zipW.removeEntry("test.txt", false);
zipW.close();
return brokenFile;
}
function createInstall(url) {
return new Promise(resolve => {
AddonManager.getInstallForURL(url, resolve, "application/x-xpinstall");
});
}
function serveUpdateRDF(leafName) {
gServer.registerPathHandler("/update.rdf", function(request, response) {
let updateData = {};
updateData[ID] = [{
version: "2.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "4",
maxVersion: "6",
updateLink: "http://localhost:4444/" + leafName
}]
}];
response.setStatusLine(request.httpVersion, 200, "OK");
response.write(createUpdateRDF(updateData));
});
}
function* test_install_broken(file, expectedError) {
gServer.registerFile("/" + file.leafName, file);
let install = yield createInstall("http://localhost:4444/" + file.leafName);
yield promiseCompleteAllInstalls([install]);
do_check_eq(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
do_check_eq(install.error, expectedError);
do_check_eq(install.addon, null);
gServer.registerFile("/" + file.leafName, null);
}
function* test_install_working(file, expectedSignedState) {
gServer.registerFile("/" + file.leafName, file);
let install = yield createInstall("http://localhost:4444/" + file.leafName);
yield promiseCompleteAllInstalls([install]);
do_check_eq(install.state, AddonManager.STATE_INSTALLED);
do_check_neq(install.addon, null);
do_check_eq(install.addon.signedState, expectedSignedState);
gServer.registerFile("/" + file.leafName, null);
install.addon.uninstall();
}
function* test_update_broken(file, expectedError) {
// First install the older version
yield promiseInstallAllFiles([do_get_file(DATA + WORKING)]);
gServer.registerFile("/" + file.leafName, file);
serveUpdateRDF(file.leafName);
let addon = yield promiseAddonByID(ID);
let install = yield promiseFindAddonUpdates(addon);
yield promiseCompleteAllInstalls([install]);
do_check_eq(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
do_check_eq(install.error, expectedError);
do_check_eq(install.addon, null);
gServer.registerFile("/" + file.leafName, null);
gServer.registerPathHandler("/update.rdf", null);
addon.uninstall();
}
function* test_update_working(file, expectedSignedState) {
// First install the older version
yield promiseInstallAllFiles([do_get_file(DATA + WORKING)]);
gServer.registerFile("/" + file.leafName, file);
serveUpdateRDF(file.leafName);
let addon = yield promiseAddonByID(ID);
let install = yield promiseFindAddonUpdates(addon);
yield promiseCompleteAllInstalls([install]);
do_check_eq(install.state, AddonManager.STATE_INSTALLED);
do_check_neq(install.addon, null);
do_check_eq(install.addon.signedState, expectedSignedState);
gServer.registerFile("/" + file.leafName, null);
gServer.registerPathHandler("/update.rdf", null);
install.addon.uninstall();
}
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "4", "4");
startupManager();
run_next_test();
}
// Try to install a broken add-on
add_task(function*() {
let file = createBrokenAddonModify(do_get_file(DATA + ADDONS.bootstrap.signed));
yield test_install_broken(file, AddonManager.ERROR_CORRUPT_FILE);
file.remove(true);
});
add_task(function*() {
let file = createBrokenAddonAdd(do_get_file(DATA + ADDONS.bootstrap.signed));
yield test_install_broken(file, AddonManager.ERROR_CORRUPT_FILE);
file.remove(true);
});
add_task(function*() {
let file = createBrokenAddonRemove(do_get_file(DATA + ADDONS.bootstrap.signed));
yield test_install_broken(file, AddonManager.ERROR_CORRUPT_FILE);
file.remove(true);
});
// Try to install an add-on with an incorrect ID
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.badid);
yield test_install_broken(file, AddonManager.ERROR_CORRUPT_FILE);
});
// Try to install an unsigned add-on
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.unsigned);
yield test_install_broken(file, AddonManager.ERROR_SIGNEDSTATE_REQUIRED);
});
// Try to install a preliminarily reviewed add-on
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.preliminary);
yield test_install_working(file, AddonManager.SIGNEDSTATE_PRELIMINARY);
});
// Try to install a signed add-on
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.signed);
yield test_install_working(file, AddonManager.SIGNEDSTATE_SIGNED);
});
// Try to update to a broken add-on
add_task(function*() {
let file = createBrokenAddonModify(do_get_file(DATA + ADDONS.bootstrap.signed));
yield test_update_broken(file, AddonManager.ERROR_CORRUPT_FILE);
file.remove(true);
});
add_task(function*() {
let file = createBrokenAddonAdd(do_get_file(DATA + ADDONS.bootstrap.signed));
yield test_update_broken(file, AddonManager.ERROR_CORRUPT_FILE);
file.remove(true);
});
add_task(function*() {
let file = createBrokenAddonRemove(do_get_file(DATA + ADDONS.bootstrap.signed));
yield test_update_broken(file, AddonManager.ERROR_CORRUPT_FILE);
file.remove(true);
});
// Try to update to an add-on with an incorrect ID
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.badid);
yield test_update_broken(file, AddonManager.ERROR_CORRUPT_FILE);
});
// Try to update to an unsigned add-on
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.unsigned);
yield test_update_broken(file, AddonManager.ERROR_SIGNEDSTATE_REQUIRED);
});
// Try to update to a preliminarily reviewed add-on
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.preliminary);
yield test_update_working(file, AddonManager.SIGNEDSTATE_PRELIMINARY);
});
// Try to update to a signed add-on
add_task(function*() {
let file = do_get_file(DATA + ADDONS.bootstrap.signed);
yield test_update_working(file, AddonManager.SIGNEDSTATE_SIGNED);
});

View File

@ -1,164 +0,0 @@
// Enable signature checks for these tests
Services.prefs.setBoolPref(PREF_XPI_SIGNATURES_REQUIRED, 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",
},
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");
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 getActiveVersion() {
return Services.prefs.getIntPref("bootstraptest.active_version");
}
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "4", "4");
// Start and stop the manager to initialise everything in the profile before
// actual testing
startupManager();
shutdownManager();
resetPrefs();
run_next_test();
}
// Removes the signedState field from add-ons in the json database to make it
// look like the database was written with an older version of the application
function stripDB() {
let jData = loadJSON(gExtensionsJSON);
jData.schemaVersion--;
for (let addon of jData.addons)
delete addon.signedState;
saveJSON(jData, gExtensionsJSON);
}
function* test_breaking_migrate(addons, test, expectedSignedState) {
// Startup as the old version
gAppInfo.version = "4";
startupManager(true);
// Install the signed add-on
yield promiseInstallAllFiles([do_get_file(DATA + addons.signed)]);
// Restart to let non-restartless add-ons install fully
yield promiseRestartManager();
yield promiseShutdownManager();
resetPrefs();
stripDB();
// Now replace it with the version to test. Doing this so quickly shouldn't
// trigger the file modification code to detect the change by itself.
manuallyUninstall(profileDir, ID);
manuallyInstall(do_get_file(DATA + addons[test]), profileDir, ID);
// Update the application
gAppInfo.version = "5";
startupManager(true);
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_true(addon.appDisabled);
do_check_false(addon.isActive);
do_check_eq(addon.signedState, expectedSignedState);
// Add-on shouldn't be active
if (addons == ADDONS.bootstrap)
do_check_eq(getActiveVersion(), -1);
else
do_check_false(isExtensionInAddonsList(profileDir, ID));
// Should have flagged the change during startup
let changes = AddonManager.getStartupChanges(AddonManager.STARTUP_CHANGE_DISABLED);
do_check_eq(changes.length, 1);
do_check_eq(changes[0], ID);
addon.uninstall();
// Restart to let non-restartless add-ons uninstall fully
yield promiseRestartManager();
yield shutdownManager();
resetPrefs();
}
function* test_working_migrate(addons, test, expectedSignedState) {
// Startup as the old version
gAppInfo.version = "4";
startupManager(true);
// Install the signed add-on
yield promiseInstallAllFiles([do_get_file(DATA + addons.signed)]);
// Restart to let non-restartless add-ons install fully
yield promiseRestartManager();
yield promiseShutdownManager();
resetPrefs();
stripDB();
// Now replace it with the version to test. Doing this so quickly shouldn't
// trigger the file modification code to detect the change by itself.
manuallyUninstall(profileDir, ID);
manuallyInstall(do_get_file(DATA + addons[test]), profileDir, ID);
// Update the application
gAppInfo.version = "5";
startupManager(true);
let addon = yield promiseAddonByID(ID);
do_check_neq(addon, null);
do_check_false(addon.appDisabled);
do_check_true(addon.isActive);
do_check_eq(addon.signedState, expectedSignedState);
if (addons == ADDONS.bootstrap)
do_check_eq(getActiveVersion(), 2);
else
do_check_true(isExtensionInAddonsList(profileDir, ID));
addon.uninstall();
// Restart to let non-restartless add-ons uninstall fully
yield promiseRestartManager();
yield shutdownManager();
resetPrefs();
}
add_task(function*() {
yield test_breaking_migrate(ADDONS.bootstrap, "unsigned", AddonManager.SIGNEDSTATE_MISSING);
yield test_breaking_migrate(ADDONS.nonbootstrap, "unsigned", AddonManager.SIGNEDSTATE_MISSING);
});
add_task(function*() {
yield test_breaking_migrate(ADDONS.bootstrap, "badid", AddonManager.SIGNEDSTATE_BROKEN);
yield test_breaking_migrate(ADDONS.nonbootstrap, "badid", AddonManager.SIGNEDSTATE_BROKEN);
});
add_task(function*() {
yield test_working_migrate(ADDONS.bootstrap, "signed", AddonManager.SIGNEDSTATE_SIGNED);
yield test_working_migrate(ADDONS.nonbootstrap, "signed", AddonManager.SIGNEDSTATE_SIGNED);
});

View File

@ -22,11 +22,6 @@ skip-if = appname != "firefox"
[test_provider_unsafe_access_shutdown.js]
[test_provider_unsafe_access_startup.js]
[test_shutdown.js]
[test_signed_inject.js]
skip-if = true
[test_signed_install.js]
run-sequentially = Uses hardcoded ports in xpi files.
[test_signed_migrate.js]
[test_XPIcancel.js]
[test_XPIStates.js]