Backed out changeset f99621542727 (bug 1038068) for test failures in test_corrupt.js etc on a CLOSED TREE

This commit is contained in:
Carsten "Tomcat" Book 2015-04-23 09:09:30 +02:00
parent 27540c68d6
commit 8faa6c90eb
41 changed files with 330 additions and 1304 deletions

View File

@ -22,7 +22,8 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1038068: Check add-on signatures and refuse to install unsigned or broken add-ons
Bug 1155718: Merge Bluetooth v1/v2 files for all simple cases
Not sure why this needs a clobber but tests perma-failed when they don't on
try.
This patch set renames source files. This requires updating the
build system's dependency information from scratch. The issue has
been reported in bug 1154232.

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

@ -4108,8 +4108,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

@ -39,7 +39,7 @@ interface nsIVerifySignedManifestCallback : nsISupports
* This represents a service to access and manipulate
* X.509 certificates stored in a database.
*/
[scriptable, uuid(560bc9ac-3e71-472e-9b08-2270d0c71878)]
[scriptable, uuid(8b01c2af-3a44-44d3-8ea5-51c2455e6c4b)]
interface nsIX509CertDB : nsISupports {
/**
@ -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]