mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
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:
parent
7167becd52
commit
9adc1fecb8
@ -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/");
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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.
@ -35,8 +35,6 @@ array_names = [
|
||||
'trustedAppPublicRoot',
|
||||
'trustedAppTestRoot',
|
||||
'xpcshellRoot',
|
||||
'addonsPublicRoot',
|
||||
'addonsStageRoot',
|
||||
]
|
||||
|
||||
for n in array_names:
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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']:
|
||||
|
@ -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);
|
||||
}
|
@ -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>
|
@ -1 +0,0 @@
|
||||
This test file can be altered to break signing checks.
|
@ -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);
|
||||
}
|
@ -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>
|
@ -1 +0,0 @@
|
||||
This test file can be altered to break signing checks.
|
@ -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>
|
@ -1 +0,0 @@
|
||||
This test file can be altered to break signing checks.
|
@ -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>
|
@ -1 +0,0 @@
|
||||
This test file can be altered to break signing checks.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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.
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
@ -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);
|
||||
});
|
@ -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);
|
||||
});
|
@ -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]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user