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";
+
+ if (container)
+ result += this.serializeContainerItems(ds, container, indent + this.INDENT);
+
+ result += this.serializeResourceProperties(ds, resource, indent + this.INDENT);
+
+ 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,