mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1214058: Part 1 - Add a simplified JSON-based add-on update protocol. r=Mossop
This commit is contained in:
parent
984587207a
commit
0ca0a616cf
@ -4402,6 +4402,7 @@ pref("xpinstall.whitelist.required", true);
|
||||
pref("xpinstall.signatures.required", false);
|
||||
pref("extensions.alwaysUnpack", false);
|
||||
pref("extensions.minCompatiblePlatformVersion", "2.0");
|
||||
pref("extensions.webExtensionsMinPlatformVersion", "42.0a1");
|
||||
|
||||
pref("network.buffer.cache.count", 24);
|
||||
pref("network.buffer.cache.size", 32768);
|
||||
|
@ -42,6 +42,8 @@ const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
|
||||
const PREF_SELECTED_LOCALE = "general.useragent.locale";
|
||||
const UNKNOWN_XPCOM_ABI = "unknownABI";
|
||||
|
||||
const PREF_MIN_WEBEXT_PLATFORM_VERSION = "extensions.webExtensionsMinPlatformVersion";
|
||||
|
||||
const UPDATE_REQUEST_VERSION = 2;
|
||||
const CATEGORY_UPDATE_PARAMS = "extension-update-params";
|
||||
|
||||
@ -663,6 +665,7 @@ var gCheckUpdateSecurity = gCheckUpdateSecurityDefault;
|
||||
var gUpdateEnabled = true;
|
||||
var gAutoUpdateDefault = true;
|
||||
var gHotfixID = null;
|
||||
var gWebExtensionsMinPlatformVersion = null;
|
||||
var gShutdownBarrier = null;
|
||||
var gRepoShutdownState = "";
|
||||
var gShutdownInProgress = false;
|
||||
@ -947,6 +950,11 @@ var AddonManagerInternal = {
|
||||
} catch (e) {}
|
||||
Services.prefs.addObserver(PREF_EM_HOTFIX_ID, this, false);
|
||||
|
||||
try {
|
||||
gWebExtensionsMinPlatformVersion = Services.prefs.getCharPref(PREF_MIN_WEBEXT_PLATFORM_VERSION);
|
||||
} catch (e) {}
|
||||
Services.prefs.addObserver(PREF_MIN_WEBEXT_PLATFORM_VERSION, this, false);
|
||||
|
||||
let defaultProvidersEnabled = true;
|
||||
try {
|
||||
defaultProvidersEnabled = Services.prefs.getBoolPref(PREF_DEFAULT_PROVIDERS_ENABLED);
|
||||
@ -1377,6 +1385,10 @@ var AddonManagerInternal = {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PREF_MIN_WEBEXT_PLATFORM_VERSION: {
|
||||
gWebExtensionsMinPlatformVersion = Services.prefs.getCharPref(PREF_MIN_WEBEXT_PLATFORM_VERSION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -2894,6 +2906,10 @@ this.AddonManagerPrivate = {
|
||||
safeCall(listener.onUpdateFinished.bind(listener), addon);
|
||||
}
|
||||
},
|
||||
|
||||
get webExtensionsMinPlatformVersion() {
|
||||
return gWebExtensionsMinPlatformVersion;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,8 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
|
||||
"resource://gre/modules/AddonManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
|
||||
"resource://gre/modules/addons/AddonRepository.jsm");
|
||||
|
||||
@ -217,6 +219,48 @@ RDFSerializer.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the update URL in an update item, as returned by
|
||||
* parseRDFManifest and parseJSONManifest. Ensures that:
|
||||
*
|
||||
* - The URL is secure, or secured by a strong enough hash.
|
||||
* - The security principal of the update manifest has permission to
|
||||
* load the URL.
|
||||
*
|
||||
* @param aUpdate
|
||||
* The update item to sanitize.
|
||||
* @param aRequest
|
||||
* The XMLHttpRequest used to load the manifest.
|
||||
* @param aHashPattern
|
||||
* The regular expression used to validate the update hash.
|
||||
* @param aHashString
|
||||
* The human-readable string specifying which hash functions
|
||||
* are accepted.
|
||||
*/
|
||||
function sanitizeUpdateURL(aUpdate, aRequest, aHashPattern, aHashString) {
|
||||
if (aUpdate.updateURL) {
|
||||
let scriptSecurity = Services.scriptSecurityManager;
|
||||
let principal = scriptSecurity.getChannelURIPrincipal(aRequest.channel);
|
||||
try {
|
||||
// This logs an error on failure, so no need to log it a second time
|
||||
scriptSecurity.checkLoadURIStrWithPrincipal(principal, aUpdate.updateURL,
|
||||
scriptSecurity.DISALLOW_SCRIPT);
|
||||
} catch (e) {
|
||||
delete aUpdate.updateURL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (AddonManager.checkUpdateSecurity &&
|
||||
!aUpdate.updateURL.startsWith("https:") &&
|
||||
!aHashPattern.test(aUpdate.updateHash)) {
|
||||
logger.warn(`Update link ${aUpdate.updateURL} is not secure and is not verified ` +
|
||||
`by a strong enough hash (needs to be ${aHashString}).`);
|
||||
delete aUpdate.updateURL;
|
||||
delete aUpdate.updateHash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an RDF style update manifest into an array of update objects.
|
||||
*
|
||||
@ -226,10 +270,17 @@ RDFSerializer.prototype = {
|
||||
* An optional update key for the add-on
|
||||
* @param aRequest
|
||||
* The XMLHttpRequest that has retrieved the update manifest
|
||||
* @param aManifestData
|
||||
* The pre-parsed manifest, as a bare XML DOM document
|
||||
* @return an array of update objects
|
||||
* @throws if the update manifest is invalid in any way
|
||||
*/
|
||||
function parseRDFManifest(aId, aUpdateKey, aRequest) {
|
||||
function parseRDFManifest(aId, aUpdateKey, aRequest, aManifestData) {
|
||||
if (aManifestData.documentElement.namespaceURI != PREFIX_NS_RDF) {
|
||||
throw Components.Exception("Update manifest had an unrecognised namespace: " + xml.documentElement.namespaceURI);
|
||||
return;
|
||||
}
|
||||
|
||||
function EM_R(aProp) {
|
||||
return gRDF.GetResource(PREFIX_NS_EM + aProp);
|
||||
}
|
||||
@ -366,20 +417,136 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) {
|
||||
targetApplications: [appEntry]
|
||||
};
|
||||
|
||||
if (result.updateURL && AddonManager.checkUpdateSecurity &&
|
||||
result.updateURL.substring(0, 6) != "https:" &&
|
||||
(!result.updateHash || result.updateHash.substring(0, 3) != "sha")) {
|
||||
logger.warn("updateLink " + result.updateURL + " is not secure and is not verified" +
|
||||
" by a strong enough hash (needs to be sha1 or stronger).");
|
||||
delete result.updateURL;
|
||||
delete result.updateHash;
|
||||
}
|
||||
// The JSON update protocol requires an SHA-2 hash. RDF still
|
||||
// supports SHA-1, for compatibility reasons.
|
||||
sanitizeUpdateURL(result, aRequest, /^sha/, "sha1 or stronger");
|
||||
|
||||
results.push(result);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an JSON update manifest into an array of update objects.
|
||||
*
|
||||
* @param aId
|
||||
* The ID of the add-on being checked for updates
|
||||
* @param aUpdateKey
|
||||
* An optional update key for the add-on
|
||||
* @param aRequest
|
||||
* The XMLHttpRequest that has retrieved the update manifest
|
||||
* @param aManifestData
|
||||
* The pre-parsed manifest, as a JSON object tree
|
||||
* @return an array of update objects
|
||||
* @throws if the update manifest is invalid in any way
|
||||
*/
|
||||
function parseJSONManifest(aId, aUpdateKey, aRequest, aManifestData) {
|
||||
if (aUpdateKey)
|
||||
throw Components.Exception("Update keys are not supported for JSON update manifests");
|
||||
|
||||
let TYPE_CHECK = {
|
||||
"array": val => Array.isArray(val),
|
||||
"object": val => val && typeof val == "object" && !Array.isArray(val),
|
||||
};
|
||||
|
||||
function getProperty(aObj, aProperty, aType, aDefault = undefined) {
|
||||
if (!(aProperty in aObj))
|
||||
return aDefault;
|
||||
|
||||
let value = aObj[aProperty];
|
||||
|
||||
let matchesType = aType in TYPE_CHECK ? TYPE_CHECK[aType](value) : typeof value == aType;
|
||||
if (!matchesType)
|
||||
throw Components.Exception(`Update manifest property '${aProperty}' has incorrect type (expected ${aType})`);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function getRequiredProperty(aObj, aProperty, aType) {
|
||||
let value = getProperty(aObj, aProperty, aType);
|
||||
if (value === undefined)
|
||||
throw Components.Exception(`Update manifest is missing a required ${aProperty} property.`);
|
||||
return value;
|
||||
}
|
||||
|
||||
let manifest = aManifestData;
|
||||
|
||||
if (!TYPE_CHECK["object"](manifest))
|
||||
throw Components.Exception("Root element of update manifest must be a JSON object literal");
|
||||
|
||||
// The set of add-ons this manifest has updates for
|
||||
let addons = getRequiredProperty(manifest, "addons", "object");
|
||||
|
||||
// The entry for this particular add-on
|
||||
let addon = getProperty(addons, aId, "object");
|
||||
|
||||
// A missing entry doesn't count as a failure, just as no avialable update
|
||||
// information
|
||||
if (!addon) {
|
||||
logger.warn("Update manifest did not contain an entry for " + aId);
|
||||
return [];
|
||||
}
|
||||
|
||||
// The list of available updates
|
||||
let updates = getProperty(addon, "updates", "array", []);
|
||||
|
||||
let results = [];
|
||||
|
||||
for (let update of updates) {
|
||||
let version = getRequiredProperty(update, "version", "string");
|
||||
|
||||
logger.debug(`Found an update entry for ${aId} version ${version}`);
|
||||
|
||||
let applications = getProperty(update, "applications", "object",
|
||||
{ gecko: {} });
|
||||
|
||||
// "gecko" is currently the only supported application entry. If
|
||||
// it's missing, skip this update.
|
||||
if (!("gecko" in applications))
|
||||
continue;
|
||||
|
||||
let app = getProperty(applications, "gecko", "object");
|
||||
|
||||
let appEntry = {
|
||||
id: TOOLKIT_ID,
|
||||
minVersion: getProperty(app, "strict_min_version", "string",
|
||||
AddonManagerPrivate.webExtensionsMinPlatformVersion),
|
||||
maxVersion: "*",
|
||||
};
|
||||
|
||||
let result = {
|
||||
id: aId,
|
||||
version: version,
|
||||
multiprocessCompatible: getProperty(update, "multiprocess_compatible", "boolean", true),
|
||||
updateURL: getProperty(update, "update_link", "string"),
|
||||
updateHash: getProperty(update, "update_hash", "string"),
|
||||
updateInfoURL: getProperty(update, "update_info_url", "string"),
|
||||
strictCompatibility: false,
|
||||
targetApplications: [appEntry],
|
||||
};
|
||||
|
||||
if ("strict_max_version" in app) {
|
||||
if ("advisory_max_version" in app) {
|
||||
logger.warn("Ignoring 'advisory_max_version' update manifest property for " +
|
||||
aId + " property since 'strict_max_version' also present");
|
||||
}
|
||||
|
||||
appEntry.maxVersion = getProperty(app, "strict_max_version", "string");
|
||||
result.strictCompatibility = appEntry.maxVersion != "*";
|
||||
} else if ("advisory_max_version" in app) {
|
||||
appEntry.maxVersion = getProperty(app, "advisory_max_version", "string");
|
||||
}
|
||||
|
||||
// The JSON update protocol requires an SHA-2 hash. RDF still
|
||||
// supports SHA-1, for compatibility reasons.
|
||||
sanitizeUpdateURL(result, aRequest, /^sha(256|512):/, "sha256 or sha512");
|
||||
|
||||
results.push(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts downloading an update manifest and then passes it to an appropriate
|
||||
* parser to convert to an array of update objects
|
||||
@ -415,7 +582,7 @@ function UpdateParser(aId, aUpdateKey, aUrl, aObserver) {
|
||||
this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
|
||||
// Prevent the request from writing to cache.
|
||||
this.request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
|
||||
this.request.overrideMimeType("text/xml");
|
||||
this.request.overrideMimeType("text/plain");
|
||||
this.request.setRequestHeader("Moz-XPI-Update", "1", true);
|
||||
this.request.timeout = TIMEOUT;
|
||||
var self = this;
|
||||
@ -474,41 +641,50 @@ UpdateParser.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let xml = request.responseXML;
|
||||
if (!xml || xml.documentElement.namespaceURI == XMLURI_PARSE_ERROR) {
|
||||
logger.warn("Update manifest was not valid XML");
|
||||
// Detect the manifest type by first attempting to parse it as
|
||||
// JSON, and falling back to parsing it as XML if that fails.
|
||||
let parser;
|
||||
try {
|
||||
try {
|
||||
let json = JSON.parse(request.responseText);
|
||||
|
||||
parser = () => parseJSONManifest(this.id, this.updateKey, request, json);
|
||||
} catch (e if e instanceof SyntaxError) {
|
||||
let domParser = Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
|
||||
let xml = domParser.parseFromString(request.responseText, "text/xml");
|
||||
|
||||
if (xml.documentElement.namespaceURI == XMLURI_PARSE_ERROR)
|
||||
throw new Error("Update manifest was not valid XML or JSON");
|
||||
|
||||
parser = () => parseRDFManifest(this.id, this.updateKey, request, xml);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn("onUpdateCheckComplete failed to determine manifest type");
|
||||
this.notifyError(AddonUpdateChecker.ERROR_UNKNOWN_FORMAT);
|
||||
return;
|
||||
}
|
||||
|
||||
let results;
|
||||
try {
|
||||
results = parser();
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("onUpdateCheckComplete failed to parse update manifest", e);
|
||||
this.notifyError(AddonUpdateChecker.ERROR_PARSE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// We currently only know about RDF update manifests
|
||||
if (xml.documentElement.namespaceURI == PREFIX_NS_RDF) {
|
||||
let results = null;
|
||||
|
||||
if ("onUpdateCheckComplete" in this.observer) {
|
||||
try {
|
||||
results = parseRDFManifest(this.id, this.updateKey, request);
|
||||
this.observer.onUpdateCheckComplete(results);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("onUpdateCheckComplete failed to parse RDF manifest", e);
|
||||
this.notifyError(AddonUpdateChecker.ERROR_PARSE_ERROR);
|
||||
return;
|
||||
logger.warn("onUpdateCheckComplete notification failed", e);
|
||||
}
|
||||
if ("onUpdateCheckComplete" in this.observer) {
|
||||
try {
|
||||
this.observer.onUpdateCheckComplete(results);
|
||||
}
|
||||
catch (e) {
|
||||
logger.warn("onUpdateCheckComplete notification failed", e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.warn("onUpdateCheckComplete may not properly cancel", new Error("stack marker"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
logger.warn("Update manifest had an unrecognised namespace: " + xml.documentElement.namespaceURI);
|
||||
this.notifyError(AddonUpdateChecker.ERROR_UNKNOWN_FORMAT);
|
||||
else {
|
||||
logger.warn("onUpdateCheckComplete may not properly cancel", new Error("stack marker"));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -906,7 +906,7 @@ function loadManifestFromWebManifest(aStream) {
|
||||
|
||||
addon.targetApplications = [{
|
||||
id: TOOLKIT_ID,
|
||||
minVersion: "42a1",
|
||||
minVersion: AddonManagerPrivate.webExtensionsMinPlatformVersion,
|
||||
maxVersion: "*",
|
||||
}];
|
||||
|
||||
|
@ -0,0 +1,327 @@
|
||||
{
|
||||
"addons": {
|
||||
"updatecheck1@tests.mozilla.org": {
|
||||
"updates": [
|
||||
{
|
||||
"version": "1.0",
|
||||
"update_link": "https://localhost:4444/addons/test1.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"_comment_": "This update is incompatible and so should not be considered a valid update",
|
||||
"version": "2.0",
|
||||
"update_link": "https://localhost:4444/addons/test2.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "2",
|
||||
"strict_max_version": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "3.0",
|
||||
"update_link": "https://localhost:4444/addons/test3.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "https://localhost:4444/addons/test2.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"_comment_": "This update is incompatible and so should not be considered a valid update",
|
||||
"version": "4.0",
|
||||
"update_link": "https://localhost:4444/addons/test4.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "2",
|
||||
"strict_max_version": "2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_5@tests.mozilla.org": {
|
||||
"_comment_": "An update which expects a signature. It will fail since signatures are ",
|
||||
"_comment_": "supported in this format.",
|
||||
"_comment_": "The updateLink will also be ignored since it is not secure and there ",
|
||||
"_comment_": "is no updateHash.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "http://localhost:4444/broken.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_5@tests.mozilla.org": {
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "http://localhost:4444/broken.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_7@tests.mozilla.org": {
|
||||
"_comment_": "An update which expects a signature. It will fail since signatures are ",
|
||||
"_comment_": "supported in this format.",
|
||||
"_comment_": "The updateLink will also be ignored since it is not secure ",
|
||||
"_comment_": "and there is no updateHash.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "http://localhost:4444/broken.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_8@tests.mozilla.org": {
|
||||
"_comment_": "The updateLink will be ignored since it is not secure and ",
|
||||
"_comment_": "there is no updateHash.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "http://localhost:4444/broken.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_9@tests.mozilla.org": {
|
||||
"_comment_": "The updateLink will used since there is an updateHash to verify it.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "http://localhost:4444/broken.xpi",
|
||||
"update_hash": "sha256:78fc1d2887eda35b4ad2e3a0b60120ca271ce6e6",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_10@tests.mozilla.org": {
|
||||
"_comment_": "The updateLink will used since it is a secure URL.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "https://localhost:4444/broken.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_11@tests.mozilla.org": {
|
||||
"_comment_": "The updateLink will used since it is a secure URL.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "https://localhost:4444/broken.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_12@tests.mozilla.org": {
|
||||
"_comment_": "The updateLink will not be used since the updateHash ",
|
||||
"_comment_": "verifying it is not strong enough.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "http://localhost:4444/broken.xpi",
|
||||
"update_hash": "sha1:78fc1d2887eda35b4ad2e3a0b60120ca271ce6e6",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"test_bug378216_13@tests.mozilla.org": {
|
||||
"_comment_": "An update with a weak hash. The updateLink will used since it is ",
|
||||
"_comment_": "a secure URL.",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "https://localhost:4444/broken.xpi",
|
||||
"update_hash": "sha1:78fc1d2887eda35b4ad2e3a0b60120ca271ce6e6",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "1",
|
||||
"strict_max_version": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"_comment_": "There should be no information present for test_bug378216_14",
|
||||
|
||||
"test_bug378216_15@tests.mozilla.org": {
|
||||
"_comment_": "Invalid update JSON",
|
||||
|
||||
"updates": "foo"
|
||||
},
|
||||
|
||||
"ignore-compat@tests.mozilla.org": {
|
||||
"_comment_": "Various updates available - one is not compatible, but compatibility checking is disabled",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "1.0",
|
||||
"update_link": "https://localhost:4444/addons/test1.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "0.1",
|
||||
"advisory_max_version": "0.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"version": "2.0",
|
||||
"update_link": "https://localhost:4444/addons/test2.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "0.5",
|
||||
"advisory_max_version": "0.6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"_comment_": "Update for future app versions - should never be compatible",
|
||||
"version": "3.0",
|
||||
"update_link": "https://localhost:4444/addons/test3.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "2",
|
||||
"advisory_max_version": "3"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"compat-override@tests.mozilla.org": {
|
||||
"_comment_": "Various updates available - one is not compatible, but compatibility checking is disabled",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"_comment_": "Has compatibility override, but it doesn't match this app version",
|
||||
"version": "1.0",
|
||||
"update_link": "https://localhost:4444/addons/test1.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "0.1",
|
||||
"advisory_max_version": "0.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"_comment_": "Has compatibility override, so is incompaible",
|
||||
"version": "2.0",
|
||||
"update_link": "https://localhost:4444/addons/test2.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "0.5",
|
||||
"advisory_max_version": "0.6"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"_comment_": "Update for future app versions - should never be compatible",
|
||||
"version": "3.0",
|
||||
"update_link": "https://localhost:4444/addons/test3.xpi",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "2",
|
||||
"advisory_max_version": "3"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"compat-strict-optin@tests.mozilla.org": {
|
||||
"_comment_": "Opt-in to strict compatibility checking",
|
||||
|
||||
"updates": [
|
||||
{
|
||||
"version": "1.0",
|
||||
"update_link": "https://localhost:4444/addons/test1.xpi",
|
||||
"_comment_": "strictCompatibility: true",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"strict_min_version": "0.1",
|
||||
"strict_max_version": "0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -236,7 +236,7 @@
|
||||
A90eF5zy</em:signature>
|
||||
</RDF:Description>
|
||||
|
||||
<!-- An update with a valid signature. The updateLink will used since the
|
||||
<!-- An update with a valid signature. The updateLink will not be used since the
|
||||
updateHash verifying it is not strong enough. -->
|
||||
<RDF:Description about="urn:mozilla:extension:test_bug378216_12@tests.mozilla.org">
|
||||
<em:updates>
|
||||
|
@ -1542,7 +1542,7 @@ if ("nsIWindowsRegKey" in AM_Ci) {
|
||||
* This is a mock nsIWindowsRegistry implementation. It only implements the
|
||||
* methods that the extension manager requires.
|
||||
*/
|
||||
function MockWindowsRegKey() {
|
||||
var MockWindowsRegKey = function MockWindowsRegKey() {
|
||||
}
|
||||
|
||||
MockWindowsRegKey.prototype = {
|
||||
@ -1723,6 +1723,30 @@ do_register_cleanup(function addon_cleanup() {
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a new HttpServer for testing, and begins listening on the
|
||||
* specified port. Automatically shuts down the server when the test
|
||||
* unit ends.
|
||||
*
|
||||
* @param port
|
||||
* The port to listen on. If omitted, listen on a random
|
||||
* port. The latter is the preferred behavior.
|
||||
*
|
||||
* @return HttpServer
|
||||
*/
|
||||
function createHttpServer(port = -1) {
|
||||
let server = new HttpServer();
|
||||
server.start(port);
|
||||
|
||||
do_register_cleanup(() => {
|
||||
return new Promise(resolve => {
|
||||
server.stop(resolve);
|
||||
});
|
||||
});
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler function that responds with the interpolated
|
||||
* static file associated to the URL specified by request.path.
|
||||
@ -1912,3 +1936,43 @@ function promiseFindAddonUpdates(addon, reason = AddonManager.UPDATE_WHEN_PERIOD
|
||||
}, reason);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors console output for the duration of a task, and returns a promise
|
||||
* which resolves to a tuple containing a list of all console messages
|
||||
* generated during the task's execution, and the result of the task itself.
|
||||
*
|
||||
* @param {function} aTask
|
||||
* The task to run while monitoring console output. May be
|
||||
* either a generator function, per Task.jsm, or an ordinary
|
||||
* function which returns promose.
|
||||
* @return {Promise<[Array<nsIConsoleMessage>, *]>}
|
||||
*/
|
||||
var promiseConsoleOutput = Task.async(function*(aTask) {
|
||||
const DONE = "=== xpcshell test console listener done ===";
|
||||
|
||||
let listener, messages = [];
|
||||
let awaitListener = new Promise(resolve => {
|
||||
listener = msg => {
|
||||
if (msg == DONE) {
|
||||
resolve();
|
||||
} else {
|
||||
msg instanceof Components.interfaces.nsIScriptError;
|
||||
messages.push(msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Services.console.registerListener(listener);
|
||||
try {
|
||||
let result = yield aTask();
|
||||
|
||||
Services.console.logStringMessage(DONE);
|
||||
yield awaitListener;
|
||||
|
||||
return { messages, result };
|
||||
}
|
||||
finally {
|
||||
Services.console.unregisterListener(listener);
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,373 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
// This verifies that AddonUpdateChecker works correctly for JSON
|
||||
// update manifests, particularly for behavior which does not
|
||||
// cleanly overlap with RDF manifests.
|
||||
|
||||
const TOOLKIT_ID = "toolkit@mozilla.org";
|
||||
const TOOLKIT_MINVERSION = "42.0a1";
|
||||
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "42.0a2", "42.0a2");
|
||||
|
||||
Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm");
|
||||
Components.utils.import("resource://testing-common/httpd.js");
|
||||
|
||||
let testserver = createHttpServer();
|
||||
gPort = testserver.identity.primaryPort;
|
||||
|
||||
let gUpdateManifests = {};
|
||||
|
||||
function mapManifest(aPath, aManifestData) {
|
||||
gUpdateManifests[aPath] = aManifestData;
|
||||
testserver.registerPathHandler(aPath, serveManifest);
|
||||
}
|
||||
|
||||
function serveManifest(request, response) {
|
||||
let manifest = gUpdateManifests[request.path];
|
||||
|
||||
response.setHeader("Content-Type", manifest.contentType, false);
|
||||
response.write(manifest.data);
|
||||
}
|
||||
|
||||
const extensionsDir = gProfD.clone();
|
||||
extensionsDir.append("extensions");
|
||||
|
||||
|
||||
function checkUpdates(aData) {
|
||||
// Registers JSON update manifest for it with the testing server,
|
||||
// checks for updates, and yields the list of updates on
|
||||
// success.
|
||||
|
||||
let extension = aData.manifestExtension || "json";
|
||||
|
||||
let path = `/updates/${aData.id}.${extension}`;
|
||||
let updateUrl = `http://localhost:${gPort}${path}`
|
||||
|
||||
let addonData = {};
|
||||
if ("updates" in aData)
|
||||
addonData.updates = aData.updates;
|
||||
|
||||
let manifestJSON = {
|
||||
"addons": {
|
||||
[aData.id]: addonData
|
||||
}
|
||||
};
|
||||
|
||||
mapManifest(path.replace(/\?.*/, ""),
|
||||
{ data: JSON.stringify(manifestJSON),
|
||||
contentType: aData.contentType || "application/json" });
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
AddonUpdateChecker.checkForUpdates(aData.id, aData.updateKey, updateUrl, {
|
||||
onUpdateCheckComplete: resolve,
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
reject(new Error("Update check failed with status " + status));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
add_task(function* test_default_values() {
|
||||
// Checks that the appropriate defaults are used for omitted values.
|
||||
|
||||
startupManager();
|
||||
|
||||
let updates = yield checkUpdates({
|
||||
id: "updatecheck-defaults@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
updates: [{
|
||||
version: "0.2"
|
||||
}]
|
||||
});
|
||||
|
||||
equal(updates.length, 1);
|
||||
let update = updates[0];
|
||||
|
||||
equal(update.targetApplications.length, 1);
|
||||
let targetApp = update.targetApplications[0];
|
||||
|
||||
equal(targetApp.id, TOOLKIT_ID);
|
||||
equal(targetApp.minVersion, TOOLKIT_MINVERSION);
|
||||
equal(targetApp.maxVersion, "*");
|
||||
|
||||
equal(update.version, "0.2");
|
||||
equal(update.multiprocessCompatible, true, "multiprocess_compatible flag");
|
||||
equal(update.strictCompatibility, false, "inferred strictConpatibility flag");
|
||||
equal(update.updateURL, null, "updateURL");
|
||||
equal(update.updateHash, null, "updateHash");
|
||||
equal(update.updateInfoURL, null, "updateInfoURL");
|
||||
|
||||
// If there's no applications property, we default to using one
|
||||
// containing "gecko". If there is an applications property, but
|
||||
// it doesn't contain "gecko", the update is skipped.
|
||||
updates = yield checkUpdates({
|
||||
id: "updatecheck-defaults@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
updates: [{
|
||||
version: "0.2",
|
||||
applications: { "foo": {} }
|
||||
}]
|
||||
});
|
||||
|
||||
equal(updates.length, 0);
|
||||
|
||||
// Updates property is also optional. No updates, but also no error.
|
||||
updates = yield checkUpdates({
|
||||
id: "updatecheck-defaults@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
});
|
||||
|
||||
equal(updates.length, 0);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_explicit_values() {
|
||||
// Checks that the appropriate explicit values are used when
|
||||
// provided.
|
||||
|
||||
let updates = yield checkUpdates({
|
||||
id: "updatecheck-explicit@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
updates: [{
|
||||
version: "0.2",
|
||||
update_link: "https://example.com/foo.xpi",
|
||||
update_hash: "sha256:0",
|
||||
update_info_url: "https://example.com/update_info.html",
|
||||
multiprocess_compatible: false,
|
||||
applications: {
|
||||
gecko: {
|
||||
strict_min_version: "42.0a2.xpcshell",
|
||||
strict_max_version: "43.xpcshell"
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
equal(updates.length, 1);
|
||||
let update = updates[0];
|
||||
|
||||
equal(update.targetApplications.length, 1);
|
||||
let targetApp = update.targetApplications[0];
|
||||
|
||||
equal(targetApp.id, TOOLKIT_ID);
|
||||
equal(targetApp.minVersion, "42.0a2.xpcshell");
|
||||
equal(targetApp.maxVersion, "43.xpcshell");
|
||||
|
||||
equal(update.version, "0.2");
|
||||
equal(update.multiprocessCompatible, false, "multiprocess_compatible flag");
|
||||
equal(update.strictCompatibility, true, "inferred strictCompatibility flag");
|
||||
equal(update.updateURL, "https://example.com/foo.xpi", "updateURL");
|
||||
equal(update.updateHash, "sha256:0", "updateHash");
|
||||
equal(update.updateInfoURL, "https://example.com/update_info.html", "updateInfoURL");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_secure_hashes() {
|
||||
// Checks that only secure hash functions are accepted for
|
||||
// non-secure update URLs.
|
||||
|
||||
let hashFunctions = ["sha512",
|
||||
"sha256",
|
||||
"sha1",
|
||||
"md5",
|
||||
"md4",
|
||||
"xxx"];
|
||||
|
||||
let updateItems = hashFunctions.map((hash, idx) => ({
|
||||
version: `0.${idx}`,
|
||||
update_link: `http://localhost:${gPort}/updates/${idx}-${hash}.xpi`,
|
||||
update_hash: `${hash}:08ac852190ecd81f40a514ea9299fe9143d9ab5e296b97e73fb2a314de49648a`,
|
||||
}));
|
||||
|
||||
let { messages, result: updates } = yield promiseConsoleOutput(() => {
|
||||
return checkUpdates({
|
||||
id: "updatecheck-hashes@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
updates: updateItems
|
||||
});
|
||||
});
|
||||
|
||||
equal(updates.length, hashFunctions.length);
|
||||
|
||||
updates = updates.filter(update => update.updateHash || update.updateURL);
|
||||
equal(updates.length, 2, "expected number of update hashes were accepted");
|
||||
|
||||
ok(updates[0].updateHash.startsWith("sha512:"), "sha512 hash is present");
|
||||
ok(updates[0].updateURL);
|
||||
|
||||
ok(updates[1].updateHash.startsWith("sha256:"), "sha256 hash is present");
|
||||
ok(updates[1].updateURL);
|
||||
|
||||
messages = messages.filter(msg => /Update link.*not secure.*strong enough hash \(needs to be sha256 or sha512\)/.test(msg.message));
|
||||
equal(messages.length, hashFunctions.length - 2, "insecure hashes generated the expected warning");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_strict_compat() {
|
||||
// Checks that strict compatibility is enabled for strict max
|
||||
// versions other than "*", but not for advisory max versions.
|
||||
// Also, ensure that strict max versions take precedence over
|
||||
// advisory versions.
|
||||
|
||||
let { messages, result: updates } = yield promiseConsoleOutput(() => {
|
||||
return checkUpdates({
|
||||
id: "updatecheck-strict@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
updates: [
|
||||
{ version: "0.2",
|
||||
applications: { gecko: { strict_max_version: "*" } } },
|
||||
{ version: "0.3",
|
||||
applications: { gecko: { strict_max_version: "43" } } },
|
||||
{ version: "0.4",
|
||||
applications: { gecko: { advisory_max_version: "43" } } },
|
||||
{ version: "0.5",
|
||||
applications: { gecko: { advisory_max_version: "43",
|
||||
strict_max_version: "44" } } },
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
equal(updates.length, 4, "all update items accepted");
|
||||
|
||||
equal(updates[0].targetApplications[0].maxVersion, "*");
|
||||
equal(updates[0].strictCompatibility, false);
|
||||
|
||||
equal(updates[1].targetApplications[0].maxVersion, "43");
|
||||
equal(updates[1].strictCompatibility, true);
|
||||
|
||||
equal(updates[2].targetApplications[0].maxVersion, "43");
|
||||
equal(updates[2].strictCompatibility, false);
|
||||
|
||||
equal(updates[3].targetApplications[0].maxVersion, "44");
|
||||
equal(updates[3].strictCompatibility, true);
|
||||
|
||||
messages = messages.filter(msg => /Ignoring 'advisory_max_version'.*'strict_max_version' also present/.test(msg.message));
|
||||
equal(messages.length, 1, "mix of advisory_max_version and strict_max_version generated the expected warning");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_update_url_security() {
|
||||
// Checks that update links to privileged URLs are not accepted.
|
||||
|
||||
let { messages, result: updates } = yield promiseConsoleOutput(() => {
|
||||
return checkUpdates({
|
||||
id: "updatecheck-security@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
updates: [
|
||||
{ version: "0.2",
|
||||
update_link: "chrome://browser/content/browser.xul",
|
||||
update_hash: "sha256:08ac852190ecd81f40a514ea9299fe9143d9ab5e296b97e73fb2a314de49648a" },
|
||||
{ version: "0.3",
|
||||
update_link: "http://example.com/update.xpi",
|
||||
update_hash: "sha256:18ac852190ecd81f40a514ea9299fe9143d9ab5e296b97e73fb2a314de49648a" },
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
equal(updates.length, 2, "both updates were processed");
|
||||
equal(updates[0].updateURL, null, "privileged update URL was removed");
|
||||
equal(updates[1].updateURL, "http://example.com/update.xpi", "safe update URL was accepted");
|
||||
|
||||
messages = messages.filter(msg => /http:\/\/localhost.*\/updates\/.*may not load or link to chrome:/.test(msg.message));
|
||||
equal(messages.length, 1, "privileged upate URL generated the expected console message");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_no_update_key() {
|
||||
// Checks that updates fail when an update key has been specified.
|
||||
|
||||
let { messages } = yield promiseConsoleOutput(function* () {
|
||||
yield Assert.rejects(
|
||||
checkUpdates({
|
||||
id: "updatecheck-updatekey@tests.mozilla.org",
|
||||
version: "0.1",
|
||||
updateKey: "ayzzx=",
|
||||
updates: [
|
||||
{ version: "0.2" },
|
||||
{ version: "0.3" },
|
||||
]
|
||||
}),
|
||||
null, "updated expected to fail");
|
||||
});
|
||||
|
||||
messages = messages.filter(msg => /Update keys are not supported for JSON update manifests/.test(msg.message));
|
||||
equal(messages.length, 1, "got expected update-key-unsupported error");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_type_detection() {
|
||||
// Checks that JSON update manifests are detected correctly
|
||||
// regardless of extension or MIME type.
|
||||
|
||||
let tests = [
|
||||
{ contentType: "application/json",
|
||||
extension: "json",
|
||||
valid: true },
|
||||
{ contentType: "application/json",
|
||||
extension: "php",
|
||||
valid: true },
|
||||
{ contentType: "text/plain",
|
||||
extension: "json",
|
||||
valid: true },
|
||||
{ contentType: "application/octet-stream",
|
||||
extension: "json",
|
||||
valid: true },
|
||||
{ contentType: "text/plain",
|
||||
extension: "json?foo=bar",
|
||||
valid: true },
|
||||
{ contentType: "text/plain",
|
||||
extension: "php",
|
||||
valid: true },
|
||||
{ contentType: "text/plain",
|
||||
extension: "rdf",
|
||||
valid: true },
|
||||
{ contentType: "application/json",
|
||||
extension: "rdf",
|
||||
valid: true },
|
||||
{ contentType: "text/xml",
|
||||
extension: "json",
|
||||
valid: true },
|
||||
{ contentType: "application/rdf+xml",
|
||||
extension: "json",
|
||||
valid: true },
|
||||
];
|
||||
|
||||
for (let [i, test] of tests.entries()) {
|
||||
let { messages } = yield promiseConsoleOutput(function *() {
|
||||
let id = `updatecheck-typedetection-${i}@tests.mozilla.org`;
|
||||
let updates;
|
||||
try {
|
||||
updates = yield checkUpdates({
|
||||
id: id,
|
||||
version: "0.1",
|
||||
contentType: test.contentType,
|
||||
manifestExtension: test.extension,
|
||||
updates: [{ version: "0.2" }]
|
||||
});
|
||||
} catch (e) {
|
||||
ok(!test.valid, "update manifest correctly detected as RDF");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(test.valid, "update manifest correctly detected as JSON");
|
||||
equal(updates.length, 1, "correct number of updates");
|
||||
equal(updates[0].id, id, "update is for correct extension");
|
||||
});
|
||||
|
||||
if (test.valid) {
|
||||
// Make sure we don't get any XML parsing errors from the
|
||||
// XMLHttpRequest machinery.
|
||||
ok(!messages.some(msg => /not well-formed/.test(msg.message)),
|
||||
"expect XMLHttpRequest not to attempt XML parsing");
|
||||
}
|
||||
|
||||
messages = messages.filter(msg => /Update manifest was not valid XML/.test(msg.message));
|
||||
equal(messages.length, !test.valid, "expected number of XML parsing errors");
|
||||
}
|
||||
});
|
@ -7,52 +7,47 @@
|
||||
Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm");
|
||||
|
||||
Components.utils.import("resource://testing-common/httpd.js");
|
||||
var testserver;
|
||||
|
||||
function run_test() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
var testserver = createHttpServer(4444);
|
||||
testserver.registerDirectory("/data/", do_get_file("data"));
|
||||
|
||||
// Create and configure the HTTP server.
|
||||
testserver = new HttpServer();
|
||||
testserver.registerDirectory("/data/", do_get_file("data"));
|
||||
testserver.start(4444);
|
||||
function checkUpdates(aId, aUpdateKey, aUpdateFile) {
|
||||
return new Promise((resolve, reject) => {
|
||||
AddonUpdateChecker.checkForUpdates(aId, aUpdateKey, `http://localhost:4444/data/${aUpdateFile}`, {
|
||||
onUpdateCheckComplete: resolve,
|
||||
|
||||
do_test_pending();
|
||||
run_test_1();
|
||||
}
|
||||
|
||||
function end_test() {
|
||||
testserver.stop(do_test_finished);
|
||||
}
|
||||
|
||||
// Test that a basic update check returns the expected available updates
|
||||
function run_test_1() {
|
||||
AddonUpdateChecker.checkForUpdates("updatecheck1@tests.mozilla.org", null,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
check_test_1(updates);
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
onUpdateCheckError: function(status) {
|
||||
let error = new Error("Update check failed with status " + status);
|
||||
error.status = status;
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function check_test_1(updates) {
|
||||
do_check_eq(updates.length, 5);
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates);
|
||||
do_check_neq(update, null);
|
||||
do_check_eq(update.version, 3);
|
||||
update = AddonUpdateChecker.getCompatibilityUpdate(updates, "2");
|
||||
do_check_neq(update, null);
|
||||
do_check_eq(update.version, 2);
|
||||
do_check_eq(update.targetApplications[0].minVersion, 1);
|
||||
do_check_eq(update.targetApplications[0].maxVersion, 2);
|
||||
function run_test() {
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
|
||||
|
||||
run_test_2();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Test that a basic update check returns the expected available updates
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
let updates = yield checkUpdates("updatecheck1@tests.mozilla.org", null, file);
|
||||
|
||||
equal(updates.length, 5);
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates);
|
||||
notEqual(update, null);
|
||||
equal(update.version, "3.0");
|
||||
update = AddonUpdateChecker.getCompatibilityUpdate(updates, "2");
|
||||
notEqual(update, null);
|
||||
equal(update.version, "2.0");
|
||||
equal(update.targetApplications[0].minVersion, "1");
|
||||
equal(update.targetApplications[0].maxVersion, "2");
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Tests that the security checks are applied correctly
|
||||
*
|
||||
@ -73,240 +68,169 @@ var updateKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbh
|
||||
"NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf" +
|
||||
"awB/zH4KaPiY3vnrzQIDAQAB";
|
||||
|
||||
function run_test_2() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_5@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_throw("Expected the update check to fail");
|
||||
},
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
try {
|
||||
yield checkUpdates("test_bug378216_5@tests.mozilla.org",
|
||||
updateKey, file);
|
||||
throw "Expected the update check to fail";
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
run_test_3();
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
try {
|
||||
yield checkUpdates("test_bug378216_7@tests.mozilla.org",
|
||||
updateKey, file);
|
||||
|
||||
throw "Expected the update check to fail";
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
// Make sure that the JSON manifest is rejected when an update key is
|
||||
// required, but perform the remaining tests which aren't expected to fail
|
||||
// because of the update key, without requiring one for the JSON variant.
|
||||
|
||||
try {
|
||||
let updates = yield checkUpdates("test_bug378216_8@tests.mozilla.org",
|
||||
updateKey, "test_updatecheck.json");
|
||||
|
||||
throw "Expected the update check to fail";
|
||||
} catch(e) {}
|
||||
|
||||
for (let [file, key] of [["test_updatecheck.rdf", updateKey],
|
||||
["test_updatecheck.json", null]]) {
|
||||
let updates = yield checkUpdates("test_bug378216_8@tests.mozilla.org",
|
||||
key, file);
|
||||
equal(updates.length, 1);
|
||||
ok(!("updateURL" in updates[0]));
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let [file, key] of [["test_updatecheck.rdf", updateKey],
|
||||
["test_updatecheck.json", null]]) {
|
||||
let updates = yield checkUpdates("test_bug378216_9@tests.mozilla.org",
|
||||
key, file);
|
||||
equal(updates.length, 1);
|
||||
equal(updates[0].version, "2.0");
|
||||
ok("updateURL" in updates[0]);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let [file, key] of [["test_updatecheck.rdf", updateKey],
|
||||
["test_updatecheck.json", null]]) {
|
||||
let updates = yield checkUpdates("test_bug378216_10@tests.mozilla.org",
|
||||
key, file);
|
||||
equal(updates.length, 1);
|
||||
equal(updates[0].version, "2.0");
|
||||
ok("updateURL" in updates[0]);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let [file, key] of [["test_updatecheck.rdf", updateKey],
|
||||
["test_updatecheck.json", null]]) {
|
||||
let updates = yield checkUpdates("test_bug378216_11@tests.mozilla.org",
|
||||
key, file);
|
||||
equal(updates.length, 1);
|
||||
equal(updates[0].version, "2.0");
|
||||
ok("updateURL" in updates[0]);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let [file, key] of [["test_updatecheck.rdf", updateKey],
|
||||
["test_updatecheck.json", null]]) {
|
||||
let updates = yield checkUpdates("test_bug378216_12@tests.mozilla.org",
|
||||
key, file);
|
||||
equal(updates.length, 1);
|
||||
do_check_false("updateURL" in updates[0]);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let [file, key] of [["test_updatecheck.rdf", updateKey],
|
||||
["test_updatecheck.json", null]]) {
|
||||
let updates = yield checkUpdates("test_bug378216_13@tests.mozilla.org",
|
||||
key, file);
|
||||
equal(updates.length, 1);
|
||||
equal(updates[0].version, "2.0");
|
||||
ok("updateURL" in updates[0]);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
let updates = yield checkUpdates("test_bug378216_14@tests.mozilla.org",
|
||||
null, file);
|
||||
equal(updates.length, 0);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
try {
|
||||
yield checkUpdates("test_bug378216_15@tests.mozilla.org",
|
||||
null, file);
|
||||
|
||||
throw "Update check should have failed";
|
||||
} catch (e) {
|
||||
equal(e.status, AddonUpdateChecker.ERROR_PARSE_ERROR);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function run_test_3() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_7@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_throw("Expected the update check to fail");
|
||||
},
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
let updates = yield checkUpdates("ignore-compat@tests.mozilla.org",
|
||||
null, file);
|
||||
equal(updates.length, 3);
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(
|
||||
updates, null, null, true);
|
||||
notEqual(update, null);
|
||||
equal(update.version, 2);
|
||||
}
|
||||
});
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
run_test_4();
|
||||
}
|
||||
});
|
||||
}
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
let updates = yield checkUpdates("compat-override@tests.mozilla.org",
|
||||
null, file);
|
||||
equal(updates.length, 3);
|
||||
let overrides = [{
|
||||
type: "incompatible",
|
||||
minVersion: 1,
|
||||
maxVersion: 2,
|
||||
appID: "xpcshell@tests.mozilla.org",
|
||||
appMinVersion: 0.1,
|
||||
appMaxVersion: 0.2
|
||||
}, {
|
||||
type: "incompatible",
|
||||
minVersion: 2,
|
||||
maxVersion: 2,
|
||||
appID: "xpcshell@tests.mozilla.org",
|
||||
appMinVersion: 1,
|
||||
appMaxVersion: 2
|
||||
}];
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(
|
||||
updates, null, null, true, false, overrides);
|
||||
notEqual(update, null);
|
||||
equal(update.version, 1);
|
||||
}
|
||||
});
|
||||
|
||||
function run_test_4() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_8@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 1);
|
||||
do_check_false("updateURL" in updates[0]);
|
||||
run_test_5();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_5() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_9@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 1);
|
||||
do_check_eq(updates[0].version, "2.0");
|
||||
do_check_true("updateURL" in updates[0]);
|
||||
run_test_6();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_6() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_10@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 1);
|
||||
do_check_eq(updates[0].version, "2.0");
|
||||
do_check_true("updateURL" in updates[0]);
|
||||
run_test_7();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_7() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_11@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 1);
|
||||
do_check_eq(updates[0].version, "2.0");
|
||||
do_check_true("updateURL" in updates[0]);
|
||||
run_test_8();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_8() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_12@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 1);
|
||||
do_check_false("updateURL" in updates[0]);
|
||||
run_test_9();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_9() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_13@tests.mozilla.org",
|
||||
updateKey,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 1);
|
||||
do_check_eq(updates[0].version, "2.0");
|
||||
do_check_true("updateURL" in updates[0]);
|
||||
run_test_10();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_10() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_14@tests.mozilla.org",
|
||||
null,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 0);
|
||||
run_test_11();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_11() {
|
||||
AddonUpdateChecker.checkForUpdates("test_bug378216_15@tests.mozilla.org",
|
||||
null,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_throw("Update check should have failed");
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_check_eq(status, AddonUpdateChecker.ERROR_PARSE_ERROR);
|
||||
run_test_12();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_12() {
|
||||
AddonUpdateChecker.checkForUpdates("ignore-compat@tests.mozilla.org",
|
||||
null,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 3);
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates,
|
||||
null,
|
||||
null,
|
||||
true);
|
||||
do_check_neq(update, null);
|
||||
do_check_eq(update.version, 2);
|
||||
run_test_13();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_13() {
|
||||
AddonUpdateChecker.checkForUpdates("compat-override@tests.mozilla.org",
|
||||
null,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 3);
|
||||
let overrides = [{
|
||||
type: "incompatible",
|
||||
minVersion: 1,
|
||||
maxVersion: 2,
|
||||
appID: "xpcshell@tests.mozilla.org",
|
||||
appMinVersion: 0.1,
|
||||
appMaxVersion: 0.2
|
||||
}, {
|
||||
type: "incompatible",
|
||||
minVersion: 2,
|
||||
maxVersion: 2,
|
||||
appID: "xpcshell@tests.mozilla.org",
|
||||
appMinVersion: 1,
|
||||
appMaxVersion: 2
|
||||
}];
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
false,
|
||||
overrides);
|
||||
do_check_neq(update, null);
|
||||
do_check_eq(update.version, 1);
|
||||
run_test_14();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test_14() {
|
||||
AddonUpdateChecker.checkForUpdates("compat-strict-optin@tests.mozilla.org",
|
||||
null,
|
||||
"http://localhost:4444/data/test_updatecheck.rdf", {
|
||||
onUpdateCheckComplete: function(updates) {
|
||||
do_check_eq(updates.length, 1);
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(updates,
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
do_check_eq(update, null);
|
||||
end_test();
|
||||
},
|
||||
|
||||
onUpdateCheckError: function(status) {
|
||||
do_throw("Update check failed with status " + status);
|
||||
}
|
||||
});
|
||||
}
|
||||
add_task(function* () {
|
||||
for (let file of ["test_updatecheck.rdf", "test_updatecheck.json"]) {
|
||||
let updates = yield checkUpdates("compat-strict-optin@tests.mozilla.org",
|
||||
null, file);
|
||||
equal(updates.length, 1);
|
||||
let update = AddonUpdateChecker.getNewestCompatibleUpdate(
|
||||
updates, null, null, true, false);
|
||||
equal(update, null);
|
||||
}
|
||||
});
|
||||
|
@ -279,6 +279,7 @@ skip-if = os == "android"
|
||||
# Bug 676992: test consistently hangs on Android
|
||||
skip-if = os == "android"
|
||||
run-sequentially = Uses hardcoded ports in xpi files.
|
||||
[test_json_updatecheck.js]
|
||||
[test_updateid.js]
|
||||
# Bug 676992: test consistently hangs on Android
|
||||
skip-if = os == "android"
|
||||
|
Loading…
Reference in New Issue
Block a user