diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd index d8f6db2f3b7..706421f6084 100644 --- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd @@ -99,6 +99,7 @@ + diff --git a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties index 3bbb8b5730b..7a4f9bd9c41 100644 --- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties +++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties @@ -72,6 +72,7 @@ incompatibleThemeName=this Theme incompatibleExtension=Disabled - not compatible with %S %S incompatibleAddonMsg=Not compatible with %S %S blocklistedDisabled=Disabled for your protection +insecureUpdateMessage="%S" will not be installed because it does not provide secure updates invalidGUIDMessage="%S" could not be installed because of an error in its Install Manifest ("%S" is not a valid GUID). Please contact the author of this item about the problem. invalidVersionMessage="%S" could not be installed because of an error in its Install Manifest ("%S" is not a valid Version String). Please contact the author of this item about the problem. @@ -130,6 +131,7 @@ xpinstallDisabledMsgLocked=Software installation has been disabled by your syste xpinstallDisabledMsg=Software installation is currently disabled. Click Enable and try again. safeModeMsg=All add-ons have been disabled by safe mode. disabledCompatMsg=Add-on compatibility checking is disabled. You may have incompatible add-ons. +disabledUpdateSecurityMsg=Add-on update security checking is disabled. You may be compromised by updates. noUpdatesMsg=No updates were found. offlineUpdateMsg=%S is currently in offline mode and is unable to update Add-ons. Click Go Online and try again. offlineInstallMsg=%S is currently in offline mode and is unable to install Add-ons. Click Go Online and try again. diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index 04afcb92f8a..cff71a04806 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -57,6 +57,7 @@ var gDownloadManager = null; var gObserverIndex = -1; var gInSafeMode = false; var gCheckCompat = true; +var gCheckUpdateSecurity = true; var gUpdatesOnly = false; var gAppID = ""; var gPref = null; @@ -66,6 +67,7 @@ var gPlugins = null; var gPluginsDS = null; const PREF_EM_CHECK_COMPATIBILITY = "extensions.checkCompatibility"; +const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; const PREF_EXTENSIONS_GETMORETHEMESURL = "extensions.getMoreThemesURL"; const PREF_EXTENSIONS_GETMOREEXTENSIONSURL = "extensions.getMoreExtensionsURL"; const PREF_EXTENSIONS_DSS_ENABLED = "extensions.dss.enabled"; @@ -267,6 +269,7 @@ function showView(aView) { ["plugin", "?plugin"], ["previewImage", "?previewImage"], ["satisfiesDependencies", "?satisfiesDependencies"], + ["providesUpdatesSecurely", "?providesUpdatesSecurely"], ["type", "?type"], ["updateable", "?updateable"], ["updateURL", "?updateURL"], @@ -316,6 +319,7 @@ function showView(aView) { ["opType", "?opType"], ["previewImage", "?previewImage"], ["satisfiesDependencies", "?satisfiesDependencies"], + ["providesUpdatesSecurely", "?providesUpdatesSecurely"], ["type", "?type"], ["updateURL", "?updateURL"], ["version", "?version"], @@ -654,6 +658,10 @@ function Startup() gCheckCompat = gPref.getBoolPref(PREF_EM_CHECK_COMPATIBILITY); } catch(e) { } + try { + gCheckUpdateSecurity = gPref.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch(e) { } + // Sort on startup and anytime an add-on is installed or upgraded. gExtensionManager.sortTypeByProperty(nsIUpdateItem.TYPE_ADDON, "name", true); // Extension Command Updating is handled by a command controller. @@ -689,6 +697,23 @@ function Startup() msgText, buttonLabel, buttonAccesskey, true, notifyData); } + if (!gCheckUpdateSecurity) { + var defaultCheckSecurity = true; + try { + defaultCheckSecurity = defaultPref.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY); + } catch (e) { } + + // App has update security checking enabled by default so show warning + if (defaultCheckSecurity) { + var msgText = getExtensionString("disabledUpdateSecurityMsg"); + var buttonLabel = getExtensionString("enableButtonLabel"); + var buttonAccesskey = getExtensionString("enableButtonAccesskey"); + var notifyData = "addons-enable-updatesecurity"; + showMessage("chrome://mozapps/skin/extensions/question.png", + msgText, buttonLabel, buttonAccesskey, + true, notifyData); + } + } if (gInSafeMode) { showMessage("chrome://mozapps/skin/extensions/question.png", getExtensionString("safeModeMsg"), @@ -809,7 +834,7 @@ XPInstallDownloadManager.prototype = { var type = isTheme ? nsIUpdateItem.TYPE_THEME : nsIUpdateItem.TYPE_EXTENSION; var item = Components.classes["@mozilla.org/updates/item;1"] .createInstance(Components.interfaces.nsIUpdateItem); - item.init(url, " ", "app-profile", "", "", displayName, url, "", iconURL, "", type, ""); + item.init(url, " ", "app-profile", "", "", displayName, url, "", iconURL, "", "", type, ""); items.push(item); // Advance the enumerator @@ -1368,6 +1393,10 @@ const gAddonsMsgObserver = { gPref.clearUserPref(PREF_EM_CHECK_COMPATIBILITY); gCheckCompat = true; break; + case "addons-enable-updatesecurity": + gPref.clearUserPref(PREF_EM_CHECK_UPDATE_SECURITY); + gCheckUpdateSecurity = true; + break; case "addons-no-updates": var children = gExtensionsView.children; for (var i = 0; i < children.length; ++i) { @@ -1690,6 +1719,7 @@ var gExtensionsViewController = { (!selectedItem.opType || selectedItem.opType == "needs-disable")) && !selectedItem.isBlocklisted && + (!gCheckUpdateSecurity || selectedItem.providesUpdatesSecurely) && (!gCheckCompat || selectedItem.isCompatible) && selectedItem.satisfiesDependencies && !gExtensionsView.hasAttribute("update-operation"); diff --git a/toolkit/mozapps/extensions/content/extensions.xml b/toolkit/mozapps/extensions/content/extensions.xml index 2682e398069..7fe25385dc6 100644 --- a/toolkit/mozapps/extensions/content/extensions.xml +++ b/toolkit/mozapps/extensions/content/extensions.xml @@ -129,6 +129,7 @@ + @@ -239,6 +240,9 @@ + + + diff --git a/toolkit/mozapps/extensions/public/nsIExtensionManager.idl b/toolkit/mozapps/extensions/public/nsIExtensionManager.idl index 8345d97c614..6de6b65130a 100644 --- a/toolkit/mozapps/extensions/public/nsIExtensionManager.idl +++ b/toolkit/mozapps/extensions/public/nsIExtensionManager.idl @@ -478,7 +478,7 @@ interface nsIExtensionManager : nsISupports * XXXben work in progress, the name of this interface will change after the * update system is complete, probably to nsIAddon */ -[scriptable, uuid(a15390e0-2ad6-422c-9596-94f95286c16f)] +[scriptable, uuid(f559f340-5160-420f-abc8-19b251708e7e)] interface nsIUpdateItem : nsISupports { /** @@ -535,6 +535,12 @@ interface nsIUpdateItem : nsISupports */ readonly attribute AString updateRDF; + /** + * The public key to verify updates for this item. This must be the public + * part of the key that was used to sign update manifests for this add-on. + */ + readonly attribute AString updateKey; + const unsigned long TYPE_APP = 0x01; const unsigned long TYPE_EXTENSION = 0x02; const unsigned long TYPE_THEME = 0x04; @@ -564,7 +570,8 @@ interface nsIUpdateItem : nsISupports in AString installLocationKey, in AString minAppVersion, in AString maxAppVersion, in AString name, in AString downloadURL, in AString xpiHash, in AString iconURL, - in AString updateURL, in long type, in AString targetAppID); + in AString updateURL, in AString updateKey, in long type, + in AString targetAppID); /** * Returns a JS Object source representing an nsIUpdateItem. diff --git a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in index 5d0975177b0..e5d693751e0 100644 --- a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in +++ b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in @@ -60,6 +60,7 @@ const nsIURL = Components.interfaces.nsIURL const nsIDirectoryEnumerator = Components.interfaces.nsIDirectoryEnumerator; const PREF_EM_CHECK_COMPATIBILITY = "extensions.checkCompatibility"; +const PREF_EM_CHECK_UPDATE_SECURITY = "extensions.checkUpdateSecurity"; const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion"; const PREF_UPDATE_COUNT = "extensions.update.count"; const PREF_UPDATE_DEFAULT_URL = "extensions.update.url"; @@ -151,6 +152,7 @@ const INSTALLERROR_INCOMPATIBLE_VERSION = -3; const INSTALLERROR_PHONED_HOME = -4; const INSTALLERROR_INCOMPATIBLE_PLATFORM = -5; const INSTALLERROR_BLOCKLISTED = -6; +const INSTALLERROR_INSECURE_UPDATE = -7; const MODE_RDONLY = 0x01; const MODE_WRONLY = 0x02; @@ -173,6 +175,7 @@ var gInstallManifestRoot = null; var gVersionChecker = null; var gLoggingEnabled = null; var gCheckCompatibility = true; +var gCheckUpdateSecurity = true; var gLocale = "en-US"; /** @@ -315,10 +318,12 @@ function getResourceForID(id) { * ... */ function makeItem(id, version, locationKey, minVersion, maxVersion, name, - updateURL, updateHash, iconURL, updateRDF, type, targetAppID) { + updateURL, updateHash, iconURL, updateRDF, updateKey, type, + targetAppID) { var item = new UpdateItem(); item.init(id, version, locationKey, minVersion, maxVersion, name, - updateURL, updateHash, iconURL, updateRDF, type, targetAppID); + updateURL, updateHash, iconURL, updateRDF, updateKey, type, + targetAppID); return item; } @@ -2431,8 +2436,9 @@ ExtensionManager.prototype = { case "nsPref:changed": if (data == PREF_EM_LOGGING_ENABLED) this._loggingToggled(); - else if (data == PREF_EM_CHECK_COMPATIBILITY) - this._checkCompatToggled(); + else if (data == PREF_EM_CHECK_COMPATIBILITY || + data == PREF_EM_CHECK_UPDATE_SECURITY) + this._updateAppDisabledState(); else if ((data == PREF_MATCH_OS_LOCALE) || (data == PREF_SELECTED_LOCALE)) this._updateLocale(); break; @@ -2465,11 +2471,12 @@ ExtensionManager.prototype = { }, /** - * Enables or disables extensions that are incompatible depending upon the pref - * setting for compatibility checking. + * When a preference is toggled that affects whether an item is usable or not + * we must app-enable or app-disable the item based on the new settings. */ - _checkCompatToggled: function() { + _updateAppDisabledState: function() { gCheckCompatibility = getPref("getBoolPref", PREF_EM_CHECK_COMPATIBILITY, true); + gCheckUpdateSecurity = getPref("getBoolPref", PREF_EM_CHECK_UPDATE_SECURITY, true); var ds = this.datasource; // Enumerate all items @@ -2506,6 +2513,7 @@ ExtensionManager.prototype = { } gLoggingEnabled = getPref("getBoolPref", PREF_EM_LOGGING_ENABLED, false); gCheckCompatibility = getPref("getBoolPref", PREF_EM_CHECK_COMPATIBILITY, true); + gCheckUpdateSecurity = getPref("getBoolPref", PREF_EM_CHECK_UPDATE_SECURITY, true); gPref.addObserver("extensions.", this, false); gPref.addObserver(PREF_MATCH_OS_LOCALE, this, false); gPref.addObserver(PREF_SELECTED_LOCALE, this, false); @@ -2751,6 +2759,7 @@ ExtensionManager.prototype = { "", /* XPI Update Hash */ getManifestProperty(installManifest, "iconURL"), getManifestProperty(installManifest, "updateURL"), + getManifestProperty(installManifest, "updateKey"), installData.type, targetAppInfo ? targetAppInfo.appID : gApp.ID); } @@ -2802,6 +2811,11 @@ ExtensionManager.prototype = { callback(installManifest, installData.id, location, installData.type); em._appDisableItem(id); } + else if (installData.error == INSTALLERROR_INSECURE_UPDATE) { + LOG("... success, item installed but does not provide updates securely"); + callback(installManifest, installData.id, location, installData.type); + em._appDisableItem(id); + } else if (installData.error == INSTALLERROR_BLOCKLISTED) { LOG("... success, item installed but is blocklisted"); callback(installManifest, installData.id, location, installData.type); @@ -2820,8 +2834,6 @@ ExtensionManager.prototype = { return "Invalid GUID"; case INSTALLERROR_INVALID_VERSION: return "Invalid Version"; - case INSTALLERROR_INCOMPATIBLE_VERSION: - return "Incompatible Version"; case INSTALLERROR_INCOMPATIBLE_PLATFORM: return "Incompatible Platform"; } @@ -3475,8 +3487,22 @@ ExtensionManager.prototype = { } else if (allAppManaged) allAppManaged = false; - // appDisabled is determined by an item being compatible, - // satisfying its dependencies, and not being blocklisted + + if (ds.getItemProperty(id, "providesUpdatesSecurely") == "false") { + /* It's possible the previous version did not understand updateKeys so + * check if we can import one for this addon from it's manifest. */ + var location = this.getInstallLocation(id); + var installRDF = location.getItemFile(id, FILE_INSTALL_MANIFEST); + if (installRDF.exists()) { + var metadataDS = getInstallManifest(installRDF); + var literal = metadataDS.GetTarget(gInstallManifestRoot, EM_R("updateKey"), true); + if (literal && literal instanceof Components.interfaces.nsIRDFLiteral) + ds.setItemProperty(id, EM_R("updateKey"), literal); + } + } + + // appDisabled is determined by an item being compatible, using secure + // updates, satisfying its dependencies, and not being blocklisted if (this._isUsableItem(id)) { if (ds.getItemProperty(id, "appDisabled")) ds.setItemProperty(id, EM_R("appDisabled"), null); @@ -3853,6 +3879,8 @@ ExtensionManager.prototype = { * INSTALLERROR_INCOMPATIBLE_PLATFORM * error, item is not compatible with the operating * system or ABI the application was built for. + * INSTALLERROR_INSECURE_UPDATE + * error, item has no secure method of providing updates * INSTALLERROR_BLOCKLISTED * error, item is blocklisted */ @@ -3863,6 +3891,8 @@ ExtensionManager.prototype = { type : 0, error : INSTALLERROR_SUCCESS, targetApps : [], + updateURL : "", + updateKey : "", currentApp : null }; // Fetch properties from the Install Manifest @@ -3871,6 +3901,7 @@ ExtensionManager.prototype = { installData.name = getManifestProperty(installManifest, "name"); installData.type = getAddonTypeFromInstallManifest(installManifest); installData.updateURL= getManifestProperty(installManifest, "updateURL"); + installData.updateKey= getManifestProperty(installManifest, "updateKey"); /** * Reads a property off a Target Application resource @@ -3948,12 +3979,23 @@ ExtensionManager.prototype = { installData.error = INSTALLERROR_INVALID_GUID; return installData; } - - // Check the target application range specified by the extension metadata. + + // Check that the add-on provides a secure update method. + if (gCheckUpdateSecurity && + installData.updateURL && + installData.updateURL.substring(0, 6) != "https:" && + !installData.updateKey) { + installData.error = INSTALLERROR_INSECURE_UPDATE; + return installData; + } + + // Check that the target application range allows compatibility with the app if (gCheckCompatibility && - !this.datasource.isCompatible(installManifest, gInstallManifestRoot, undefined)) + !this.datasource.isCompatible(installManifest, gInstallManifestRoot, undefined)) { installData.error = INSTALLERROR_INCOMPATIBLE_VERSION; - + return installData; + } + // Check if the item is blocklisted. if (!gBlocklist) gBlocklist = Components.classes["@mozilla.org/extensions/blocklist;1"] @@ -4192,6 +4234,7 @@ ExtensionManager.prototype = { "", /* XPI Update Hash */ "", /* Icon URL */ installData.updateURL || "", + installData.updateKey || "", installData.type, installData.currentApp.id); em.update([item], 1, nsIExtensionManager.UPDATE_CHECK_COMPATIBILITY, this); @@ -4415,6 +4458,14 @@ ExtensionManager.prototype = { installData.version + " was not installed."); showBlocklistMessage([installData], true); break; + case INSTALLERROR_INSECURE_UPDATE: + LOG("No secure updates: Item: \"" + installData.id + "\" version " + + installData.version + " was not installed."); + var bundle = BundleManager.getBundle(URI_EXTENSIONS_PROPERTIES); + showMessage("incompatibleTitle", + [bundle.GetStringFromName("type-" + installData.type)], + "insecureUpdateMessage", [installData.name]); + break; default: break; } @@ -5064,9 +5115,23 @@ ExtensionManager.prototype = { */ _isUsableItem: function(id) { var ds = this.datasource; - return ((!gCheckCompatibility || ds.getItemProperty(id, "compatible") == "true") && - ds.getItemProperty(id, "blocklisted") == "false" && - ds.getItemProperty(id, "satisfiesDependencies") == "true"); + /* If we're not compatibility checking or if the item is compatible + * and if it isn't blocklisted and has all dependencies satisfied then + * proceed to the security check */ + if ((!gCheckCompatibility || ds.getItemProperty(id, "compatible") == "true") && + ds.getItemProperty(id, "blocklisted") == "false" && + ds.getItemProperty(id, "satisfiesDependencies") == "true") { + + // appManaged items aren't updated so no need to check update security. + if (ds.getItemProperty(id, "appManaged") == "true") + return true; + + /* If we are not ignoring update security then check that the item has + * a secure update mechanism */ + return (!gCheckUpdateSecurity || + ds.getItemProperty(id, "providesUpdatesSecurely") == "true"); + } + return false; }, /** @@ -6164,11 +6229,54 @@ RDFItemUpdater.prototype = { "doesn't give up much in the way of information when the load fails.\r\n" + "\r\nTry checking that: \r\n" + " 1. Your remote RDF file exists at the location.\r\n" + - " 2. Your RDF file is valid XML (starts with \r\n" + + " 2. Your RDF file is valid XML (starts with \r\n" + " and loads in Firefox displaying pretty printed like other XML documents\r\n" + " 3. Your server is sending the data in the correct MIME\r\n" + " type (text/xml)"); + } + + // If we have an update key then the update manifest must be signed + if (aLocalItem.updateKey) { + var extensionRes = gRDF.GetResource(getItemPrefix(aLocalItem.type) + aLocalItem.id); + LOG(extensionRes.Value); + var signature = this._getPropertyFromResource(aDatasource, extensionRes, "signature", null); + if (signature) { + var serializer = new RDFSerializer(); + try { + var updateString = serializer.serializeResource(aDatasource, extensionRes); + var verifier = Components.classes["@mozilla.org/security/datasignatureverifier;1"] + .getService(Components.interfaces.nsIDataSignatureVerifier); + try { + if (!verifier.verifyData(updateString, signature, aLocalItem.updateKey)) { + LOG("RDFItemUpdater:onDatasourceLoaded: Update manifest for " + + aLocalItem.id + " failed signature check."); + this._updater.checkForDone(aLocalItem, nsIAddonUpdateCheckListener.STATUS_FAILURE); + return; + } + } + catch (e) { + LOG("RDFItemUpdater:onDatasourceLoaded: Failed to verify signature for " + + aLocalItem.id + ". This indicates a malformed update key or signature."); + this._updater.checkForDone(aLocalItem, nsIAddonUpdateCheckListener.STATUS_FAILURE); + return; + } + } + catch (e) { + LOG("RDFItemUpdater:onDatasourceLoaded: Failed to generate signature " + + "string for " + aLocalItem.id + ". Serializer threw " + e); + this._updater.checkForDone(aLocalItem, nsIAddonUpdateCheckListener.STATUS_FAILURE); + return; + } + } + else { + LOG("RDFItemUpdater:onDatasourceLoaded: Update manifest for " + + aLocalItem.id + " did not contain a signature."); + this._updater.checkForDone(aLocalItem, nsIAddonUpdateCheckListener.STATUS_FAILURE); + return; + } } + /* If there is no updateKey either the update was over SSL, or it is an old + * addon that we are allowing a grace update. */ // Parse the response RDF var newerItem, sameItem; @@ -6344,16 +6452,37 @@ RDFItemUpdater.prototype = { if (appID != this._updater._appID && appID != TOOLKIT_ID) continue; + var updateLink = this._getPropertyFromResource(aDataSource, targetApp, "updateLink", aLocalItem); + var updateHash = this._getPropertyFromResource(aDataSource, targetApp, "updateHash", aLocalItem); + if (aUpdateCheckType == nsIExtensionManager.UPDATE_CHECK_NEWVERSION) { + // New version information is useless without a link to get it from + if (!updateLink) + continue; + + /* If the update link is non-ssl and we do not have a hash or the hash + * is of an insecure nature then we must ignore this update. Bypass + * this if not checking update security. Currently we only consider + * the sha hashing algorithms as secure. */ + if (gCheckUpdateSecurity && updateLink.substring(0, 6) != "https:" && + (!updateHash || updateHash.substring(0, 3) != "sha")) { + LOG("RDFItemUpdater:_parseV20Update: Update for " + aLocalItem.id + + " at " + updateLink + " ignored because it is insecure. updateLink " + + " must be a https url or an updateHash must be specified."); + continue; + } + } + var updatedItem = makeItem(aLocalItem.id, version, aLocalItem.installLocationKey, this._getPropertyFromResource(aDataSource, targetApp, "minVersion", aLocalItem), this._getPropertyFromResource(aDataSource, targetApp, "maxVersion", aLocalItem), aLocalItem.name, - this._getPropertyFromResource(aDataSource, targetApp, "updateLink", aLocalItem), - this._getPropertyFromResource(aDataSource, targetApp, "updateHash", aLocalItem), + updateLink, + updateHash, "", /* Icon URL */ "", /* RDF Update URL */ + "", /* Update Key */ aLocalItem.type, appID); @@ -6369,6 +6498,158 @@ RDFItemUpdater.prototype = { } }; +/** + * A serialisation method for RDF data that produces an identical string + * provided that the RDF assertions match. + * The serialisation is not complete, only assertions stemming from a given + * resource are included, multiple references to the same resource are not + * permitted, and the RDF prolog and epilog are not included. + * RDF Blob and Date literals are not supported. + */ +function RDFSerializer() +{ + this.cUtils = Components.classes["@mozilla.org/rdf/container-utils;1"] + .getService(Components.interfaces.nsIRDFContainerUtils); + this.resources = []; +} + +RDFSerializer.prototype = { + INDENT: " ", // The indent used for pretty-printing + resources: null, // Array of the resources that have been found + + /** + * Escapes characters from a string that should not appear in XML. + * @param string The string to be escaped + * @returns a string with all characters invalid in XML character data + * converted to entity references. + */ + escapeEntities: function(string) + { + string = string.replace(/&/g, "&"); + string = string.replace(//g, ">"); + string = string.replace(/"/g, """); + return string; + }, + + /** + * Serializes all the elements of an RDF container. + * @param ds The datasource holding the data + * @param container The RDF container to output the child elements of + * @param indent The current level of indent for pretty-printing + * @returns a string containing the serialized elements. + */ + serializeContainerItems: function(ds, container, indent) + { + var result = ""; + var items = container.GetElements(); + while (items.hasMoreElements()) { + var item = items.getNext().QueryInterface(Components.interfaces.nsIRDFResource); + result += indent + "\n" + result += this.serializeResource(ds, item, indent + this.INDENT); + result += indent + "\n" + } + return result; + }, + + /** + * Serializes all em:* (see EM_NS) properties of an RDF resource except for + * the em:signature property. As this serialization is to be compared against + * the manifest signature it cannot contain the em:signature property itself. + * @param ds The datasource holding the data + * @param resource The RDF resource to output the properties of + * @param indent The current level of indent for pretty-printing + * @returns a string containing the serialized properties. + */ + serializeResourceProperties: function(ds, resource, indent) + { + var result = ""; + var items = []; + var arcs = ds.ArcLabelsOut(resource); + while (arcs.hasMoreElements()) { + var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource); + if (arc.ValueUTF8.substring(0, PREFIX_NS_EM.length) != PREFIX_NS_EM) + continue; + var prop = arc.ValueUTF8.substring(PREFIX_NS_EM.length); + if (prop == "signature") + continue; + + var targets = ds.GetTargets(resource, arc, true); + while (targets.hasMoreElements()) { + var target = targets.getNext(); + if (target instanceof Components.interfaces.nsIRDFResource) { + var item = indent + "\n"; + item += this.serializeResource(ds, target, indent + this.INDENT); + item += indent + "\n"; + items.push(item); + } + else if (target instanceof Components.interfaces.nsIRDFLiteral) { + items.push(indent + "" + this.escapeEntities(target.Value) + "\n"); + } + else if (target instanceof Components.interfaces.nsIRDFInt) { + items.push(indent + "" + target.Value + "\n"); + } + else { + throw new Error("Cannot serialize unknown literal type"); + } + } + } + items.sort(); + result += items.join(""); + return result; + }, + + /** + * Recursively serializes an RDF resource and all resources it links to. + * This will only output EM_NS properties and will ignore any em:signature + * property. + * @param ds The datasource holding the data + * @param resource The RDF resource to serialize + * @param indent The current level of indent for pretty-printing. + * Leave undefined for no indent + * @returns a string containing the serialized resource. + * @throws if the RDF data contains multiple references to the same resource. + */ + serializeResource: function(ds, resource, indent) + { + if (this.resources.indexOf(resource) != -1 ) { + // We cannot output multiple references to the same resource. + throw new Error("Cannot serialize multiple references to "+resource.Value); + } + if (indent === undefined) + indent = ""; + + this.resources.push(resource); + var container = null; + var type = "Description"; + if (this.cUtils.IsSeq(ds, resource)) { + type = "Seq"; + container = this.cUtils.MakeSeq(ds, resource); + } + else if (this.cUtils.IsAlt(ds, resource)) { + type = "Alt"; + container = this.cUtils.MakeAlt(ds, resource); + } + else if (this.cUtils.IsBag(ds, resource)) { + type = "Bag"; + container = this.cUtils.MakeBag(ds, resource); + } + + var result = indent + "\n"; + return result; + } +} + /** * A Datasource that holds Extensions. * - Implements nsIRDFDataSource to drive UI @@ -6669,6 +6950,7 @@ ExtensionsDataSource.prototype = { updateHash ? updateHash : "", this.getItemProperty(id, "iconURL"), this.getItemProperty(id, "updateURL"), + this.getItemProperty(id, "updateKey"), this.getItemProperty(id, "type"), targetAppInfo ? targetAppInfo.appID : gApp.ID); }, @@ -7122,7 +7404,7 @@ ExtensionsDataSource.prototype = { // Copy the assertions over from the source datasource. // Assert properties with single values var singleProps = ["version", "updateURL", "updateService", "optionsURL", - "aboutURL", "iconURL", "internalName"]; + "aboutURL", "iconURL", "internalName", "updateKey"]; // Items installed into restricted Install Locations can also be locked // (can't be removed or disabled), and hidden (not shown in the UI) @@ -7737,6 +8019,19 @@ ExtensionsDataSource.prototype = { return EM_L("true"); }, + /** + * Get the providesUpdatesSecurely property (whether or not this item has a + * secure update mechanism) + */ + _rdfGet_providesUpdatesSecurely: function(item, property) { + var id = stripPrefix(item.Value, PREFIX_ITEM_URI); + if (this.getItemProperty(id, "updateKey") || + !this.getItemProperty(id, "updateURL") || + this.getItemProperty(id, "updateURL").substring(0, 6) == "https:") + return EM_L("true"); + return EM_L("false"); + }, + /** * Get the em:blocklisted property (whether or not this item is blocklisted) */ @@ -8192,7 +8487,7 @@ UpdateItem.prototype = { * See nsIUpdateService.idl */ init: function(id, version, installLocationKey, minAppVersion, maxAppVersion, - name, downloadURL, xpiHash, iconURL, updateURL, type, + name, downloadURL, xpiHash, iconURL, updateURL, updateKey, type, targetAppID) { this._id = id; this._version = version; @@ -8204,6 +8499,7 @@ UpdateItem.prototype = { this._xpiHash = xpiHash; this._iconURL = iconURL; this._updateURL = updateURL; + this._updateKey = updateKey; this._type = type; this._targetAppID = targetAppID; }, @@ -8221,6 +8517,7 @@ UpdateItem.prototype = { get xpiHash() { return this._xpiHash; }, get iconURL() { return this._iconURL }, get updateRDF() { return this._updateURL; }, + get updateKey() { return this._updateKey; }, get type() { return this._type; }, get targetAppID() { return this._targetAppID; }, @@ -8238,6 +8535,7 @@ UpdateItem.prototype = { xpiHash : this._xpiHash, iconURL : this._iconURL, updateRDF : this._updateURL, + updateKey : this._updateKey, type : this._type, targetAppID : this._targetAppID }.toSource(); diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_1/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_1/install.rdf new file mode 100644 index 00000000000..e08a66654c4 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_1/install.rdf @@ -0,0 +1,22 @@ + + + + + + test_bug378216_1@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 1 + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_10/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_10/install.rdf new file mode 100644 index 00000000000..1edf1115226 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_10/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_10@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 10 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_11/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_11/install.rdf new file mode 100644 index 00000000000..0bfa2bb05a5 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_11/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_11@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 11 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_12/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_12/install.rdf new file mode 100644 index 00000000000..1741a9852e4 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_12/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_12@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 12 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_13/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_13/install.rdf new file mode 100644 index 00000000000..f2dd65a3c33 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_13/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_13@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 13 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_2/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_2/install.rdf new file mode 100644 index 00000000000..263a226ee8b --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_2/install.rdf @@ -0,0 +1,23 @@ + + + + + + test_bug378216_2@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 2 + http://localhost:4444/test_bug378216.rdf + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_3/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_3/install.rdf new file mode 100644 index 00000000000..d710d901163 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_3/install.rdf @@ -0,0 +1,23 @@ + + + + + + test_bug378216_3@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 3 + https://localhost:4444/test_bug378216_3/update.rdf + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_4/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_4/install.rdf new file mode 100644 index 00000000000..b488f284870 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_4/install.rdf @@ -0,0 +1,26 @@ + + + + + + test_bug378216_4@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 4 + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_5/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_5/install.rdf new file mode 100644 index 00000000000..ccfd5470962 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_5/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_5@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 5 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_6/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_6/install.rdf new file mode 100644 index 00000000000..75a575ebf85 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_6/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_6@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 6 + https://localhost:4444/test_bug378216_6/update.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_7/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_7/install.rdf new file mode 100644 index 00000000000..f754bdcec6d --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_7/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_7@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 7 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_8/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_8/install.rdf new file mode 100644 index 00000000000..264eb3e402d --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_8/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_8@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 8 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_9/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_9/install.rdf new file mode 100644 index 00000000000..db88aa00ca7 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug378216_9/install.rdf @@ -0,0 +1,27 @@ + + + + + + test_bug378216_9@tests.mozilla.org + 1.0 + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + Bug 378216 Test 9 + http://localhost:4444/test_bug378216.rdf + MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK426erD/H3XtsjvaB5+PJqbhj + Zc9EDI5OCJS8R3FIObJ9ZHJK1TXeaE7JWqt9WUmBWTEFvwS+FI9vWu8058N9CHhD + NyeP6i4LuUYjTURnn7Yw/IgzyIJ2oKsYa32RuxAyteqAWqPT/J63wBixIeCxmysf + awB/zH4KaPiY3vnrzQIDAQAB + + + diff --git a/toolkit/mozapps/extensions/test/unit/data/test_bug378216.rdf b/toolkit/mozapps/extensions/test/unit/data/test_bug378216.rdf new file mode 100644 index 00000000000..139ba733161 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/data/test_bug378216.rdf @@ -0,0 +1,197 @@ + + + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 1 + http://localhost:4444/broken.xpi + + + + + + + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 2 + http://localhost:4444/broken.xpi + + + + + + + MIGTMA0GCSqGSIb3DQEBBQUAA4GBAMO1O2gwSCCth1GwYMgscfaNakpN40PJfOWt + ub2HVdg8+OXMciF8d/9eVWm8eH/IxuxyZlmRZTs3O5tv9eWAY5uBCtqDf1WgTsGk + jrgZow1fITkZI7w0//C8eKdMLAtGueGfNs2IlTd5P/0KH/hf1rPc1wUqEqKCd4+L + BcVq13ad + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 1 + http://localhost:4444/broken.xpi + + + + + + + MIGTMA0GCSqGSIb3DQEBBQUAA4GBAMH/33P/bn148mVkAB8i5X8c4LhY52E+MPUT + yKHGpowZnRLgL2O0dfpm+rljOBfKi51322PFrsc6VIFml6x4Lrb5foxSyB0Vs9pb + SEDFWUKquOQvceQ9iEx5Pe0VzrmUZgcQxd8ksSunWL4wJaBZ/evE5amFC6sw3pv/ + fjt8p3GN + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 1 + http://localhost:4444/broken.xpi + sha1:78fc1d2887eda35b4ad2e3a0b60120ca271ce6e6 + + + + + + + MIGTMA0GCSqGSIb3DQEBBQUAA4GBAJ5Dv3Zd7/j5dLchCw9iO/cxPq8oOhOYD2M+ + jUKvmHCyTBRIEaJrE4N7yVbRYk++ERIfyVepLivsVi4pBmF7JTdw0NaKUA0LiOoT + mRL8I7s5NPjCiiNcdqbncWyiZwIj1w1nkbWGTlH/gEjRW/LbvT4JAuec8yNFDa4S + X8mOMf7k + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 1 + https://localhost:4444/broken.xpi + + + + + + + MIGTMA0GCSqGSIb3DQEBBQUAA4GBAGvf7XqqoTl5WofrNq55E7W+UttOEDXLB3Oi + XDiXe0i6njlozilseaUo1hgfQhhzN9gkyetP5tGBVcLRrVyliKpJmD6ABCVGW1lS + qS+SEw7gDHyHkvwKMyWKedpRGChqLYnnf+Y+CX3MWLZLkwPXMKdTYgN3Rx0lEnJk + 37LSEMKE + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 1 + https://localhost:4444/broken.xpi + sha1:78fc1d2887eda35b4ad2e3a0b60120ca271ce6e6 + + + + + + + MIGTMA0GCSqGSIb3DQEBBQUAA4GBACMX/KReOGSJ8CMGRroH1v3Gjv/Qs/pqH+Ow + o+hCKWLUKx7hpJgVJkXXdAHW0U88NXlp1S2H0WqA7I/CdmNXJSPzzV/J4z1dZgXh + JbW6mqNb0pj6nIe7g8OLzSxDgBmO4DUP5DAmnmqciJLWQzN7OdbcwrWz6xPN5kZF + A90eF5zy + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 1 + http://localhost:4444/broken.xpi + md2:78fc1d2887eda35b4ad2e3a0b60120ca271ce6e6 + + + + + + + MIGTMA0GCSqGSIb3DQEBBQUAA4GBAJRfcFvHIWxVyycCw8IjNmEhabc2uqA1zQwp + 5oKh3Y23hwIsQ6xy68Wtjte1NEYFRt5fWkbMXj9YQj6LpVbzBKiGATcrq6MycZKK + o5N22cWbrKKRweJezTyN4eLfQg21pG7r8mdfS0bIA28ZVFtQOmORejoUesEouCGy + eKYk9nS2 + + + + + + + + 2.0 + + + xpcshell@tests.mozilla.org + 1 + 1 + https://localhost:4444/broken.xpi + md2:78fc1d2887eda35b4ad2e3a0b60120ca271ce6e6 + + + + + + + MIGTMA0GCSqGSIb3DQEBBQUAA4GBALQKwzLFr/VOw3gJvv/LCh3/PWDd9FqmFnX+ + hJjBmCaUDtG7CXn1i0h8ed8IeRHpLLT7FCzVwU3bH9BUjdm8wc3ObtlNbd8go01a + CoXz50r3rYPcYz4WS+7/+lvrUqsuWd9Wj+q0NeCPiNaaro6/AolE2Qf5JFRL3lxY + lsKWAnVO + + diff --git a/toolkit/mozapps/extensions/test/unit/test_bug299716.js b/toolkit/mozapps/extensions/test/unit/test_bug299716.js index 1fbc3702311..34162a33dbb 100644 --- a/toolkit/mozapps/extensions/test/unit/test_bug299716.js +++ b/toolkit/mozapps/extensions/test/unit/test_bug299716.js @@ -50,6 +50,9 @@ var env = Components.classes["@mozilla.org/process/environment;1"] .getService(Components.interfaces.nsIEnvironment); env.set("XPCOM_DEBUG_BREAK", "stack"); +// Disables security checking our updates which haven't been signed +gPrefs.setBoolPref("extensions.checkUpdateSecurity", false); + // This allows the EM to attempt to display errors to the user without failing. var promptService = { // nsIPromptService @@ -300,6 +303,7 @@ var next_test = function() {}; function do_check_item(aItem, aVersion, aAddonsEntry) { if (aAddonsEntry.installed) { + do_check_neq(aItem, null); do_check_eq(aItem.version, aVersion); } else { do_check_eq(aItem, null); diff --git a/toolkit/mozapps/extensions/test/unit/test_bug299716_2.js b/toolkit/mozapps/extensions/test/unit/test_bug299716_2.js index 8072b3134ce..2c1c233b39d 100644 --- a/toolkit/mozapps/extensions/test/unit/test_bug299716_2.js +++ b/toolkit/mozapps/extensions/test/unit/test_bug299716_2.js @@ -36,6 +36,9 @@ * ***** END LICENSE BLOCK ***** */ +// Disables security checking our updates which haven't been signed +gPrefs.setBoolPref("extensions.checkUpdateSecurity", false); + // Update check listener. const checkListener = { // nsIAddonUpdateCheckListener diff --git a/toolkit/mozapps/extensions/test/unit/test_bug378216.js b/toolkit/mozapps/extensions/test/unit/test_bug378216.js new file mode 100644 index 00000000000..2befe5babe9 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/test_bug378216.js @@ -0,0 +1,235 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +/** + * Tests for update security restrictions. + * + * Install tests: + * + * Test updateKey updateURL expected + *------------------------------------------- + * 1 absent absent success + * 2 absent http failure + * 3 absent https success + * 4 present absent success + * 5 present http success + * 6 present https success + * + * Update tests: + * + * Test signature updateHash updateLink expected + *-------------------------------------------------------- + * 5 absent absent http fail + * 7 broken absent http fail + * 8 correct absent http no update + * 9 correct sha1 http update + * 10 corrent absent https update + * 11 corrent sha1 https update + * 12 corrent md2 http no update + * 13 corrent md2 https update + */ + +do_import_script("netwerk/test/httpserver/httpd.js"); + +// This allows the EM to attempt to display errors to the user without failing +var promptService = { + alert: function(aParent, aDialogTitle, aText) { + }, + + alertCheck: function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) { + }, + + confirm: function(aParent, aDialogTitle, aText) { + }, + + confirmCheck: function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) { + }, + + confirmEx: function(aParent, aDialogTitle, aText, aButtonFlags, aButton0Title, aButton1Title, aButton2Title, aCheckMsg, aCheckState) { + }, + + prompt: function(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState) { + }, + + promptUsernameAndPassword: function(aParent, aDialogTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState) { + }, + + promptPassword: function(aParent, aDialogTitle, aText, aPassword, aCheckMsg, aCheckState) { + }, + + select: function(aParent, aDialogTitle, aText, aCount, aSelectList, aOutSelection) { + }, + + QueryInterface: function(iid) { + if (iid.equals(Components.interfaces.nsIPromptService) + || iid.equals(Components.interfaces.nsISupports)) + return this; + + throw Components.results.NS_ERROR_NO_INTERFACE; + } +}; + +var PromptServiceFactory = { + createInstance: function (outer, iid) { + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + return promptService.QueryInterface(iid); + } +}; +var registrar = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar); +registrar.registerFactory(Components.ID("{6cc9c9fe-bc0b-432b-a410-253ef8bcc699}"), "PromptService", + "@mozilla.org/embedcomp/prompt-service;1", PromptServiceFactory); + + +var updateListener = { +onUpdateStarted: function() +{ +}, + +onUpdateEnded: function() +{ + do_test_finished(); +}, + +onAddonUpdateStarted: function(addon) +{ +}, + +onAddonUpdateEnded: function(addon, status) +{ + var nsIAddonUpdateCheckListener = Components.interfaces.nsIAddonUpdateCheckListener; + switch (addon.id) + { + case "test_bug378216_5@tests.mozilla.org": + // Update has no signature + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_FAILURE); + break; + case "test_bug378216_7@tests.mozilla.org": + // Update has a signature that does not match + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_FAILURE); + break; + case "test_bug378216_8@tests.mozilla.org": + // Update has a signature but no secure update + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_NO_UPDATE); + break; + case "test_bug378216_9@tests.mozilla.org": + // Update has a signature and a hashed update + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_UPDATE); + do_check_eq(addon.version, "2.0"); + break; + case "test_bug378216_10@tests.mozilla.org": + // Update has a signature and a https update + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_UPDATE); + do_check_eq(addon.version, "2.0"); + break; + case "test_bug378216_11@tests.mozilla.org": + // Update has a signature and a hashed https update + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_UPDATE); + do_check_eq(addon.version, "2.0"); + break; + case "test_bug378216_12@tests.mozilla.org": + // Update has a signature and an insecure hash against the update + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_NO_UPDATE); + break; + case "test_bug378216_13@tests.mozilla.org": + // The insecure hash doesn't matter if we have an https link + do_check_eq(status, nsIAddonUpdateCheckListener.STATUS_UPDATE); + do_check_eq(addon.version, "2.0"); + break; + default: + do_throw("Update check for unknown "+addon.id); + } +} +} + +function run_test() +{ + // Setup for test + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1"); + startupEM(); + gEM.installItemFromFile(do_get_addon("test_bug378216_1"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_2"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_3"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_4"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_5"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_6"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_7"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_8"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_9"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_10"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_11"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_12"), NS_INSTALL_LOCATION_APPPROFILE); + gEM.installItemFromFile(do_get_addon("test_bug378216_13"), NS_INSTALL_LOCATION_APPPROFILE); + + restartEM(); + + do_check_neq(gEM.getItemForID("test_bug378216_1@tests.mozilla.org"), null); + // Test 2 has an insecure updateURL and no updateKey so should fail to install + do_check_eq(gEM.getItemForID("test_bug378216_2@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_3@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_4@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_5@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_6@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_7@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_8@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_9@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_10@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_11@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_12@tests.mozilla.org"), null); + do_check_neq(gEM.getItemForID("test_bug378216_13@tests.mozilla.org"), null); + + server = new nsHttpServer(); + server.registerDirectory("/", do_get_file("toolkit/mozapps/extensions/test/unit/data")); + server.start(4444); + + var updates = [ + gEM.getItemForID("test_bug378216_5@tests.mozilla.org"), + gEM.getItemForID("test_bug378216_7@tests.mozilla.org"), + gEM.getItemForID("test_bug378216_8@tests.mozilla.org"), + gEM.getItemForID("test_bug378216_9@tests.mozilla.org"), + gEM.getItemForID("test_bug378216_10@tests.mozilla.org"), + gEM.getItemForID("test_bug378216_11@tests.mozilla.org"), + gEM.getItemForID("test_bug378216_12@tests.mozilla.org"), + gEM.getItemForID("test_bug378216_13@tests.mozilla.org"), + ]; + + gEM.update(updates, updates.length, + Components.interfaces.nsIExtensionManager.UPDATE_CHECK_NEWVERSION, + updateListener); + do_test_pending(); +} diff --git a/toolkit/mozapps/extensions/test/unit/test_bug384052.js b/toolkit/mozapps/extensions/test/unit/test_bug384052.js index 90e03121e62..e04b8a7c2cf 100644 --- a/toolkit/mozapps/extensions/test/unit/test_bug384052.js +++ b/toolkit/mozapps/extensions/test/unit/test_bug384052.js @@ -80,7 +80,7 @@ function run_test() var item = Cc["@mozilla.org/updates/item;1"].createInstance(Ci.nsIUpdateItem); item.init("test@mozilla.org", "1.0", "app-profile", "0.0", "100.0", "Test extension", - null, null, "", null, item.TYPE_EXTENSION, "xpcshell@tests.mozilla.org"); + null, null, "", null, null, item.TYPE_EXTENSION, "xpcshell@tests.mozilla.org"); gExpectedURL = gTestURL.replace(/%ITEM_ID%/, item.id) .replace(/%CUSTOM1%/, "custom_parameter_1") diff --git a/toolkit/themes/pinstripe/mozapps/extensions/extensions.css b/toolkit/themes/pinstripe/mozapps/extensions/extensions.css index 940f104af34..770482822fa 100644 --- a/toolkit/themes/pinstripe/mozapps/extensions/extensions.css +++ b/toolkit/themes/pinstripe/mozapps/extensions/extensions.css @@ -136,6 +136,7 @@ richlistitem .notifyBadge { richlistitem[availableUpdateURL][updateable="true"] .updateBadge, richlistitem[availableUpdateURL][updateable="true"] .updateAvailableBox, richlistitem[compatible="false"] .notifyBadge, +richlistitem[providesUpdatesSecurely="false"] .notifyBadge, richlistitem[blocklisted="true"] .notifyBadge, richlistitem[satisfiesDependencies="false"] .notifyBadge { display: -moz-box; @@ -205,6 +206,7 @@ richlistitem[type="4"] .disableHide { /* Selected Add-on status messages and images */ richlistitem[compatible="true"] .incompatibleBox, +richlistitem[providesUpdatesSecurely="true"] .insecureUpdateBox, richlistitem[satisfiesDependencies="true"] .needsDependenciesBox, richlistitem[blocklisted="false"] .blocklistedBox, richlistitem[opType="needs-uninstall"] .blocklistedBox, diff --git a/toolkit/themes/winstripe/mozapps/extensions/extensions.css b/toolkit/themes/winstripe/mozapps/extensions/extensions.css index df98c003e56..1867345245f 100644 --- a/toolkit/themes/winstripe/mozapps/extensions/extensions.css +++ b/toolkit/themes/winstripe/mozapps/extensions/extensions.css @@ -205,6 +205,7 @@ richlistitem .notifyBadge { richlistitem[availableUpdateURL][updateable="true"] .updateBadge, richlistitem[availableUpdateURL][updateable="true"] .updateAvailableBox, richlistitem[compatible="false"] .notifyBadge, +richlistitem[providesUpdatesSecurely="false"] .notifyBadge, richlistitem[blocklisted="true"] .notifyBadge, richlistitem[satisfiesDependencies="false"] .notifyBadge { display: -moz-box; @@ -274,6 +275,7 @@ richlistitem[type="4"] .disableHide { /* Selected Add-on status messages and images */ richlistitem[compatible="true"] .incompatibleBox, +richlistitem[providesUpdatesSecurely="true"] .insecureUpdateBox, richlistitem[satisfiesDependencies="true"] .needsDependenciesBox, richlistitem[blocklisted="false"] .blocklistedBox, richlistitem[opType="needs-uninstall"] .blocklistedBox,