diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-07-18 08:24:24 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-07-18 08:24:24 +0200 |
commit | fc61780b35af913801d72086456f493f63197da6 (patch) | |
tree | f85891288a7bd988da9f0f15ae64e5c63f00d493 /toolkit/mozapps/extensions/internal | |
parent | 69f7f9e5f1475891ce11cc4f431692f965b0cd30 (diff) | |
parent | 50d3e596bbe89c95615f96eb71f6bc5be737a1db (diff) | |
download | UXP-2018.07.18.tar UXP-2018.07.18.tar.gz UXP-2018.07.18.tar.lz UXP-2018.07.18.tar.xz UXP-2018.07.18.zip |
Merge commit '50d3e596bbe89c95615f96eb71f6bc5be737a1db' into Basilisk-releasev2018.07.18
# Conflicts:
# browser/app/profile/firefox.js
# browser/components/preferences/jar.mn
Diffstat (limited to 'toolkit/mozapps/extensions/internal')
5 files changed, 348 insertions, 134 deletions
diff --git a/toolkit/mozapps/extensions/internal/AddonLogging.jsm b/toolkit/mozapps/extensions/internal/AddonLogging.jsm index 362439bae..f05a6fe6c 100644 --- a/toolkit/mozapps/extensions/internal/AddonLogging.jsm +++ b/toolkit/mozapps/extensions/internal/AddonLogging.jsm @@ -81,7 +81,7 @@ function AddonLogger(aName) { AddonLogger.prototype = { name: null, - error: function AddonLogger_error(aStr, aException) { + error: function(aStr, aException) { let message = formatLogMessage("error", this.name, aStr, aException); let stack = getStackDetails(aException); @@ -95,6 +95,18 @@ AddonLogger.prototype = { // Always dump errors, in case the Console Service isn't listening yet dump("*** " + message + "\n"); + function formatTimestamp(date) { + // Format timestamp as: "%Y-%m-%d %H:%M:%S" + let year = String(date.getFullYear()); + let month = String(date.getMonth() + 1).padStart(2, "0"); + let day = String(date.getDate()).padStart(2, "0"); + let hours = String(date.getHours()).padStart(2, "0"); + let minutes = String(date.getMinutes()).padStart(2, "0"); + let seconds = String(date.getSeconds()).padStart(2, "0"); + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; + } + try { var tstamp = new Date(); var logfile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_EXTENSIONS_LOG]); @@ -104,7 +116,7 @@ AddonLogger.prototype = { var writer = Cc["@mozilla.org/intl/converter-output-stream;1"]. createInstance(Ci.nsIConverterOutputStream); writer.init(stream, "UTF-8", 0, 0x0000); - writer.writeString(tstamp.toLocaleFormat("%Y-%m-%d %H:%M:%S ") + + writer.writeString(formatTimestamp(tstamp) + " " + message + " at " + stack.sourceName + ":" + stack.lineNumber + "\n"); writer.close(); @@ -112,7 +124,7 @@ AddonLogger.prototype = { catch (e) { } }, - warn: function AddonLogger_warn(aStr, aException) { + warn: function(aStr, aException) { let message = formatLogMessage("warn", this.name, aStr, aException); let stack = getStackDetails(aException); @@ -127,7 +139,7 @@ AddonLogger.prototype = { dump("*** " + message + "\n"); }, - log: function AddonLogger_log(aStr, aException) { + log: function(aStr, aException) { if (gDebugLogEnabled) { let message = formatLogMessage("log", this.name, aStr, aException); dump("*** " + message + "\n"); @@ -137,14 +149,14 @@ AddonLogger.prototype = { }; this.LogManager = { - getLogger: function LogManager_getLogger(aName, aTarget) { + getLogger: function(aName, aTarget) { let logger = new AddonLogger(aName); if (aTarget) { ["error", "warn", "log"].forEach(function(name) { let fname = name.toUpperCase(); delete aTarget[fname]; - aTarget[fname] = function LogManager_targetName(aStr, aException) { + aTarget[fname] = function(aStr, aException) { logger[name](aStr, aException); }; }); @@ -155,13 +167,13 @@ this.LogManager = { }; var PrefObserver = { - init: function PrefObserver_init() { + init: function() { Services.prefs.addObserver(PREF_LOGGING_ENABLED, this, false); Services.obs.addObserver(this, "xpcom-shutdown", false); this.observe(null, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, PREF_LOGGING_ENABLED); }, - observe: function PrefObserver_observe(aSubject, aTopic, aData) { + observe: function(aSubject, aTopic, aData) { if (aTopic == "xpcom-shutdown") { Services.prefs.removeObserver(PREF_LOGGING_ENABLED, this); Services.obs.removeObserver(this, "xpcom-shutdown"); diff --git a/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm b/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm index 8d742ea42..f927bc745 100644 --- a/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm +++ b/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm @@ -15,30 +15,36 @@ const Cu = Components.utils; this.EXPORTED_SYMBOLS = [ "AddonUpdateChecker" ]; -const TIMEOUT = 60 * 1000; -const PREFIX_NS_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; -const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#"; -const PREFIX_ITEM = "urn:mozilla:item:"; -const PREFIX_EXTENSION = "urn:mozilla:extension:"; -const PREFIX_THEME = "urn:mozilla:theme:"; -const TOOLKIT_ID = "toolkit@mozilla.org" -#ifdef MOZ_PHOENIX_EXTENSIONS -const FIREFOX_ID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}" -#endif -const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml" +const TIMEOUT = 60 * 1000; +const PREFIX_NS_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; +const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#"; +const PREFIX_ITEM = "urn:mozilla:item:"; +const PREFIX_EXTENSION = "urn:mozilla:extension:"; +const PREFIX_THEME = "urn:mozilla:theme:"; +const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml"; + +const TOOLKIT_ID = "toolkit@mozilla.org"; +const FIREFOX_ID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; +const FIREFOX_APPCOMPATVERSION = "56.9" const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts"; +const PREF_EM_MIN_COMPAT_APP_VERSION = "extensions.minCompatibleAppVersion"; Components.utils.import("resource://gre/modules/Services.jsm"); 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"); +XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest", + "resource://gre/modules/ServiceRequest.jsm"); + // Shared code for suppressing bad cert dialogs. -XPCOMUtils.defineLazyGetter(this, "CertUtils", function certUtilsLazyGetter() { +XPCOMUtils.defineLazyGetter(this, "CertUtils", function() { let certUtils = {}; Components.utils.import("resource://gre/modules/CertUtils.jsm", certUtils); return certUtils; @@ -80,7 +86,7 @@ RDFSerializer.prototype = { * @return a string with all characters invalid in XML character data * converted to entity references. */ - escapeEntities: function RDFS_escapeEntities(aString) { + escapeEntities: function(aString) { aString = aString.replace(/&/g, "&"); aString = aString.replace(/</g, "<"); aString = aString.replace(/>/g, ">"); @@ -98,8 +104,7 @@ RDFSerializer.prototype = { * The current level of indent for pretty-printing * @return a string containing the serialized elements. */ - serializeContainerItems: function RDFS_serializeContainerItems(aDs, aContainer, - aIndent) { + serializeContainerItems: function(aDs, aContainer, aIndent) { var result = ""; var items = aContainer.GetElements(); while (items.hasMoreElements()) { @@ -125,9 +130,7 @@ RDFSerializer.prototype = { * @return a string containing the serialized properties. * @throws if the resource contains a property that cannot be serialized */ - serializeResourceProperties: function RDFS_serializeResourceProperties(aDs, - aResource, - aIndent) { + serializeResourceProperties: function(aDs, aResource, aIndent) { var result = ""; var items = []; var arcs = aDs.ArcLabelsOut(aResource); @@ -181,7 +184,7 @@ RDFSerializer.prototype = { * @return a string containing the serialized resource. * @throws if the RDF data contains multiple references to the same resource. */ - serializeResource: function RDFS_serializeResource(aDs, aResource, aIndent) { + serializeResource: function(aDs, aResource, aIndent) { if (this.resources.indexOf(aResource) != -1 ) { // We cannot output multiple references to the same resource. throw Components.Exception("Cannot serialize multiple references to " + aResource.Value); @@ -221,6 +224,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. * * @param aId @@ -229,10 +274,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.rdf: Update manifest had an unrecognised namespace: " + + aManifestData.documentElement.namespaceURI); + } + function EM_R(aProp) { return gRDF.GetResource(PREFIX_NS_EM + aProp); } @@ -261,7 +313,7 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { function getRequiredProperty(aDs, aSource, aProperty) { let value = getProperty(aDs, aSource, aProperty); if (!value) - throw Components.Exception("Update manifest is missing a required " + aProperty + " property."); + throw Components.Exception("update.rdf: Update manifest is missing a required " + aProperty + " property."); return value; } @@ -275,15 +327,19 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { let extensionRes = gRDF.GetResource(PREFIX_EXTENSION + aId); let themeRes = gRDF.GetResource(PREFIX_THEME + aId); let itemRes = gRDF.GetResource(PREFIX_ITEM + aId); - let addonRes = ds.ArcLabelsOut(extensionRes).hasMoreElements() ? extensionRes - : ds.ArcLabelsOut(themeRes).hasMoreElements() ? themeRes - : itemRes; + let addonRes; + if (ds.ArcLabelsOut(extensionRes).hasMoreElements()) + addonRes = extensionRes; + else if (ds.ArcLabelsOut(themeRes).hasMoreElements()) + addonRes = themeRes; + else + addonRes = itemRes; // If we have an update key then the update manifest must be signed if (aUpdateKey) { let signature = getProperty(ds, addonRes, "signature"); if (!signature) - throw Components.Exception("Update manifest for " + aId + " does not contain a required signature"); + throw Components.Exception("update.rdf: Update manifest for " + aId + " does not contain a required signature"); let serializer = new RDFSerializer(); let updateString = null; @@ -291,7 +347,7 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { updateString = serializer.serializeResource(ds, addonRes); } catch (e) { - throw Components.Exception("Failed to generate signed string for " + aId + ". Serializer threw " + e, + throw Components.Exception("update.rdf: Failed to generate signed string for " + aId + ". Serializer threw " + e, e.result); } @@ -303,7 +359,7 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { result = verifier.verifyData(updateString, signature, aUpdateKey); } catch (e) { - throw Components.Exception("The signature or updateKey for " + aId + " is malformed." + + throw Components.Exception("update.rdf: The signature or updateKey for " + aId + " is malformed." + "Verifier threw " + e, e.result); } @@ -316,7 +372,7 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { // A missing updates property doesn't count as a failure, just as no avialable // update information if (!updates) { - logger.warn("Update manifest for " + aId + " did not contain an updates property"); + logger.warn("update.rdf: Update manifest for " + aId + " did not contain an updates property"); return []; } @@ -326,7 +382,7 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { let cu = Cc["@mozilla.org/rdf/container-utils;1"]. getService(Ci.nsIRDFContainerUtils); if (!cu.IsContainer(ds, updates)) - throw Components.Exception("Updates property was not an RDF container"); + throw Components.Exception("update.rdf: Updates property was not an RDF container"); let results = []; let ctr = Cc["@mozilla.org/rdf/container;1"]. @@ -337,11 +393,11 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { let item = items.getNext().QueryInterface(Ci.nsIRDFResource); let version = getProperty(ds, item, "version"); if (!version) { - logger.warn("Update manifest is missing a required version property."); + logger.warn("update.rdf: Update manifest is missing a required version property."); continue; } - logger.debug("Found an update entry for " + aId + " version " + version); + logger.debug("update.rdf: Found an update entry for " + aId + " version " + version); let targetApps = ds.GetTargets(item, EM_R("targetApplication"), true); while (targetApps.hasMoreElements()) { @@ -369,14 +425,10 @@ 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); } } @@ -384,6 +436,160 @@ function parseRDFManifest(aId, aUpdateKey, aRequest) { } /** + * 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.json: 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.json: 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.json: Update manifest is missing a required ${aProperty} property.`); + return value; + } + + let manifest = aManifestData; + + if (!TYPE_CHECK["object"](manifest)) + throw Components.Exception("update.json: 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.json: Update manifest did not contain an entry for " + aId); + return []; + } + + let appID = Services.appinfo.ID; + let platformVersion = Services.appinfo.platformVersion; + + // 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(`update.json: Found an update entry for ${aId} version ${version}`); + + let applications = getRequiredProperty(update, "applications", "object"); + + let app; + let appEntry; + + if (appID in applications) { + logger.debug("update.json: Native targetApplication"); + app = getProperty(applications, appID, "object"); + + appEntry = { + id: appID, + minVersion: getRequiredProperty(app, "min_version", "string"), + maxVersion: getRequiredProperty(app, "max_version", "string"), + } + } +#ifdef MOZ_PHOENIX_EXTENSIONS + else if (FIREFOX_ID in applications) { + logger.debug("update.json: Dual-GUID targetApplication"); + app = getProperty(applications, FIREFOX_ID, "object"); + + appEntry = { + id: FIREFOX_ID, + minVersion: getRequiredProperty(app, "min_version", "string"), + maxVersion: getRequiredProperty(app, "max_version", "string"), + } + } +#endif + else if (TOOLKIT_ID in applications) { + logger.debug("update.json: Toolkit targetApplication"); + app = getProperty(applications, TOOLKIT_ID, "object"); + + appEntry = { + id: TOOLKIT_ID, + minVersion: getRequiredProperty(app, "min_version", "string"), + maxVersion: getRequiredProperty(app, "max_version", "string"), + } + } + else if ("gecko" in applications) { + logger.debug("update.json: Mozilla Compatiblity Mode"); + app = getProperty(applications, "gecko", "object"); + + appEntry = { +#ifdef MOZ_PHOENIX + id: FIREFOX_ID, + minVersion: getProperty(app, "strict_min_version", "string", + Services.prefs.getCharPref(PREF_EM_MIN_COMPAT_APP_VERSION)), +#else + id: TOOLKIT_ID, + minVersion: platformVersion, +#endif +#if defined(MOZ_PHOENIX) && defined(MOZ_PHOENIX_EXTENSIONS) + maxVersion: FIREFOX_APPCOMPATVERSION, +#else + maxVersion: '*', +#endif + }; + } + else { + continue; + } + + let result = { + id: aId, + version: version, + multiprocessCompatible: getProperty(update, "multiprocess_compatible", "boolean", false), + updateURL: getProperty(update, "update_link", "string"), + updateHash: getProperty(update, "update_hash", "string"), + updateInfoURL: getProperty(update, "update_info_url", "string"), + strictCompatibility: getProperty(app, "strict_compatibility", "boolean", false), + targetApplications: [appEntry], + }; + + // 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 * @@ -411,20 +617,18 @@ function UpdateParser(aId, aUpdateKey, aUrl, aObserver) { logger.debug("Requesting " + aUrl); try { - this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. - createInstance(Ci.nsIXMLHttpRequest); + this.request = new ServiceRequest(); this.request.open("GET", this.url, true); this.request.channel.notificationCallbacks = new CertUtils.BadCertHandler(!requireBuiltIn); 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; - this.request.addEventListener("load", function loadEventListener(event) { self.onLoad() }, false); - this.request.addEventListener("error", function errorEventListener(event) { self.onError() }, false); - this.request.addEventListener("timeout", function timeoutEventListener(event) { self.onTimeout() }, false); + this.request.addEventListener("load", () => this.onLoad(), false); + this.request.addEventListener("error", () => this.onError(), false); + this.request.addEventListener("timeout", () => this.onTimeout(), false); this.request.send(null); } catch (e) { @@ -442,7 +646,7 @@ UpdateParser.prototype = { /** * Called when the manifest has been successfully loaded. */ - onLoad: function UP_onLoad() { + onLoad: function() { let request = this.request; this.request = null; this._doneAt = new Error("place holder"); @@ -458,6 +662,7 @@ UpdateParser.prototype = { CertUtils.checkCert(request.channel, !requireBuiltIn); } catch (e) { + logger.warn("Request failed: " + this.url + " - " + e); this.notifyError(AddonUpdateChecker.ERROR_DOWNLOAD_ERROR); return; } @@ -476,41 +681,52 @@ UpdateParser.prototype = { return; } - let xml = request.responseXML; - if (!xml || xml.documentElement.namespaceURI == XMLURI_PARSE_ERROR) { - logger.warn("Update manifest was not valid XML"); - this.notifyError(AddonUpdateChecker.ERROR_PARSE_ERROR); + // 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)) + throw e; + 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; } - // We currently only know about RDF update manifests - if (xml.documentElement.namespaceURI == PREFIX_NS_RDF) { - let results = null; + let results; + try { + results = parser(); + } + catch (e) { + logger.warn("onUpdateCheckComplete failed to parse update manifest", e); + this.notifyError(AddonUpdateChecker.ERROR_PARSE_ERROR); + return; + } + 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; - } - if ("onUpdateCheckComplete" in this.observer) { - try { - this.observer.onUpdateCheckComplete(results); - } - catch (e) { - logger.warn("onUpdateCheckComplete notification failed", 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")); + } }, /** @@ -526,7 +742,7 @@ UpdateParser.prototype = { /** * Called when the manifest failed to load. */ - onError: function UP_onError() { + onError: function() { if (!Components.isSuccessCode(this.request.status)) { logger.warn("Request failed: " + this.url + " - " + this.request.status); } @@ -555,7 +771,7 @@ UpdateParser.prototype = { /** * Helper method to notify the observer that an error occured. */ - notifyError: function UP_notifyError(aStatus) { + notifyError: function(aStatus) { if ("onUpdateCheckError" in this.observer) { try { this.observer.onUpdateCheckError(aStatus); @@ -569,7 +785,7 @@ UpdateParser.prototype = { /** * Called to cancel an in-progress update check. */ - cancel: function UP_cancel() { + cancel: function() { if (!this.request) { logger.error("Trying to cancel already-complete request", this._doneAt); return; @@ -669,12 +885,9 @@ this.AddonUpdateChecker = { * Ignore strictCompatibility when testing if an update matches. Optional. * @return an update object if one matches or null if not */ - getCompatibilityUpdate: function AUC_getCompatibilityUpdate(aUpdates, aVersion, - aIgnoreCompatibility, - aAppVersion, - aPlatformVersion, - aIgnoreMaxVersion, - aIgnoreStrictCompat) { + getCompatibilityUpdate: function(aUpdates, aVersion, aIgnoreCompatibility, + aAppVersion, aPlatformVersion, + aIgnoreMaxVersion, aIgnoreStrictCompat) { if (!aAppVersion) aAppVersion = Services.appinfo.version; if (!aPlatformVersion) @@ -686,8 +899,8 @@ this.AddonUpdateChecker = { for (let targetApp of update.targetApplications) { let id = targetApp.id; #ifdef MOZ_PHOENIX_EXTENSIONS - if (id == Services.appinfo.ID || id == FIREFOX_ID || - id == TOOLKIT_ID) + if (id == Services.appinfo.ID || id == FIREFOX_ID || + id == TOOLKIT_ID) #else if (id == Services.appinfo.ID || id == TOOLKIT_ID) #endif @@ -720,12 +933,9 @@ this.AddonUpdateChecker = { * Array of AddonCompatibilityOverride to take into account. Optional. * @return an update object if one matches or null if not */ - getNewestCompatibleUpdate: function AUC_getNewestCompatibleUpdate(aUpdates, - aAppVersion, - aPlatformVersion, - aIgnoreMaxVersion, - aIgnoreStrictCompat, - aCompatOverrides) { + getNewestCompatibleUpdate: function(aUpdates, aAppVersion, aPlatformVersion, + aIgnoreMaxVersion, aIgnoreStrictCompat, + aCompatOverrides) { if (!aAppVersion) aAppVersion = Services.appinfo.version; if (!aPlatformVersion) @@ -765,10 +975,10 @@ this.AddonUpdateChecker = { * @return UpdateParser so that the caller can use UpdateParser.cancel() to shut * down in-progress update requests */ - checkForUpdates: function AUC_checkForUpdates(aId, aUpdateKey, aUrl, aObserver) { + checkForUpdates: function(aId, aUpdateKey, aUrl, aObserver) { // Define an array of internally used IDs to NOT send to AUS such as the // Default Theme. Please keep this list in sync with: - // toolkit/mozapps/webextensions/AddonUpdateChecker.jsm + // toolkit/mozapps/extensions/AddonUpdateChecker.jsm let internalIDS = [ '{972ce4c6-7e08-4474-a285-3208198ce6fd}', 'modern@themes.mozilla.org' diff --git a/toolkit/mozapps/extensions/internal/Content.js b/toolkit/mozapps/extensions/internal/Content.js index 9ab3b9ad6..9f366ba32 100644 --- a/toolkit/mozapps/extensions/internal/Content.js +++ b/toolkit/mozapps/extensions/internal/Content.js @@ -2,6 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* globals addMessageListener*/ + "use strict"; (function() { @@ -14,17 +16,22 @@ var nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile", "initWithPath"); const MSG_JAR_FLUSH = "AddonJarFlush"; +const MSG_MESSAGE_MANAGER_CACHES_FLUSH = "AddonMessageManagerCachesFlush"; try { if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) { - // Propagate JAR cache flush notifications across process boundaries. - addMessageListener(MSG_JAR_FLUSH, function jar_flushMessageListener(message) { + // Propagate JAR cache flush notifications across process boundaries. + addMessageListener(MSG_JAR_FLUSH, function(message) { let file = new nsIFile(message.data); Services.obs.notifyObservers(file, "flush-cache-entry", null); }); + // Propagate message manager caches flush notifications across processes. + addMessageListener(MSG_MESSAGE_MANAGER_CACHES_FLUSH, function() { + Services.obs.notifyObservers(null, "message-manager-flush-caches", null); + }); } -} catch(e) { +} catch (e) { Cu.reportError(e); } diff --git a/toolkit/mozapps/extensions/internal/LightweightThemeImageOptimizer.jsm b/toolkit/mozapps/extensions/internal/LightweightThemeImageOptimizer.jsm index 1e7d6b0d8..a9201c3da 100644 --- a/toolkit/mozapps/extensions/internal/LightweightThemeImageOptimizer.jsm +++ b/toolkit/mozapps/extensions/internal/LightweightThemeImageOptimizer.jsm @@ -59,10 +59,14 @@ var ImageCropper = { return aImageURL; } - if (Services.prefs.getBoolPref("lightweightThemes.animation.enabled")) { - //Don't crop if animated - return aImageURL; - } + try { + if (Services.prefs.getBoolPref("lightweightThemes.animation.enabled")) { + //Don't crop if animated + return aImageURL; + } + } catch(e) { + // Continue of pref doesn't exist. + } // Generate the cropped image's file name using its // base name and the current screen size. @@ -120,22 +124,19 @@ var ImageCropper = { }; var ImageFile = { - read: function ImageFile_read(aURI, aCallback) { - this._netUtil.asyncFetch2( - aURI, - function read_asyncFetch(aInputStream, aStatus, aRequest) { + read: function(aURI, aCallback) { + this._netUtil.asyncFetch({ + uri: aURI, + loadUsingSystemPrincipal: true, + contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE + }, function(aInputStream, aStatus, aRequest) { if (Components.isSuccessCode(aStatus) && aRequest instanceof Ci.nsIChannel) { let channel = aRequest.QueryInterface(Ci.nsIChannel); aCallback(aInputStream, channel.contentType); } else { aCallback(); } - }, - null, // aLoadingNode - Services.scriptSecurityManager.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_NORMAL, - Ci.nsIContentPolicy.TYPE_IMAGE); + }); }, write: function ImageFile_write(aFile, aInputStream, aCallback) { diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index b522bd3ae..9ea876f6c 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -96,8 +96,6 @@ const PREF_INTERPOSITION_ENABLED = "extensions.interposition.enabled"; const PREF_EM_MIN_COMPAT_APP_VERSION = "extensions.minCompatibleAppVersion"; const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion"; -const PREF_CHECKCOMAT_THEMEOVERRIDE = "extensions.checkCompatibility.temporaryThemeOverride_minAppVersion"; - const URI_EXTENSION_SELECT_DIALOG = "chrome://mozapps/content/extensions/selectAddons.xul"; const URI_EXTENSION_UPDATE_DIALOG = "chrome://mozapps/content/extensions/update.xul"; const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties"; @@ -662,22 +660,8 @@ function isUsableAddon(aAddon) { return false; } else { - let app = aAddon.matchingTargetApplication; - if (!app) + if (!aAddon.matchingTargetApplication) return false; - - // XXX Temporary solution to let applications opt-in to make themes safer - // following significant UI changes even if checkCompatibility=false has - // been set, until we get bug 962001. - if (aAddon.type == "theme" && app.id == Services.appinfo.ID) { - try { - let minCompatVersion = Services.prefs.getCharPref(PREF_CHECKCOMAT_THEMEOVERRIDE); - if (minCompatVersion && - Services.vc.compare(minCompatVersion, app.maxVersion) > 0) { - return false; - } - } catch (e) {} - } } return true; |