diff --git a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in index 7c89c8db4150..298f04402563 100644 --- a/toolkit/mozapps/extensions/src/nsExtensionManager.js.in +++ b/toolkit/mozapps/extensions/src/nsExtensionManager.js.in @@ -146,7 +146,7 @@ const INSTALLERROR_SUCCESS = 0; const INSTALLERROR_INVALID_VERSION = -1; const INSTALLERROR_INVALID_GUID = -2; const INSTALLERROR_INCOMPATIBLE_VERSION = -3; -const INSTALLERROR_PHONED_HOME = -4; +const INSTALLERROR_PHONING_HOME = -4; const INSTALLERROR_INCOMPATIBLE_PLATFORM = -5; const INSTALLERROR_BLOCKLISTED = -6; const INSTALLERROR_INSECURE_UPDATE = -7; @@ -4302,6 +4302,9 @@ ExtensionManager.prototype = { * An updated Install Manifest from the Version Update check. * Can be null when invoked from callers other than the Version * Update check. + * @returns The install result code. If this is INSTALLERROR_PHONING_HOME + * then a remote update check has been started to attempt to resolve + * compatibility problems. */ installItemFromFileInternal: function EM_installItemFromFileInternal(aXPIFile, aInstallLocationKey, @@ -4550,25 +4553,29 @@ ExtensionManager.prototype = { // Try and install again, but use the updated compatibility DB. // This will send out an apropriate onInstallEnded notification for us. - em.installItemFromFileInternal(this._xpi, aInstallLocationKey, - this._installManifest); + var status = em.installItemFromFileInternal(this._xpi, + aInstallLocationKey, + this._installManifest); - // Add the updated compatibility info to the datasource if done - if (StartupCache.entries[aInstallLocationKey][addon.id].op == OP_NONE) { - em.datasource.setTargetApplicationInfo(addon.id, - addon.targetAppID, - addon.minAppVersion, - addon.maxAppVersion, - null); - } - else { // needs a restart - // Add updatedMinVersion and updatedMaxVersion so it can be used - // to update the datasource during the installation or upgrade. - em.datasource.setUpdatedTargetAppInfo(addon.id, - addon.targetAppID, - addon.minAppVersion, - addon.maxAppVersion, - null); + // The install may still have failed at this point due to the blocklist + if (status == INSTALLERROR_SUCCESS) { + // Add the updated compatibility info to the datasource if done + if (StartupCache.entries[aInstallLocationKey][addon.id].op == OP_NONE) { + em.datasource.setTargetApplicationInfo(addon.id, + addon.targetAppID, + addon.minAppVersion, + addon.maxAppVersion, + null); + } + else { // needs a restart + // Add updatedMinVersion and updatedMaxVersion so it can be used + // to update the datasource during the installation or upgrade. + em.datasource.setUpdatedTargetAppInfo(addon.id, + addon.targetAppID, + addon.minAppVersion, + addon.maxAppVersion, + null); + } } } else { @@ -4626,7 +4633,7 @@ ExtensionManager.prototype = { "Installation will not proceed."); for (var i = 0; i < this._installListeners.length; ++i) this._installListeners[i].onInstallEnded(addon, INSTALLERROR_INVALID_MANIFEST); - return; + return INSTALLERROR_INVALID_MANIFEST; } } else @@ -4656,12 +4663,12 @@ ExtensionManager.prototype = { if (shouldPhoneHomeIfNecessary && installData.currentApp) { var installLocation = getInstallLocation(installData.id, aInstallLocationKey); if (!installLocation) - return; + return INSTALLERROR_INCOMPATIBLE_VERSION; var stagedFile = installLocation.stageFile(aXPIFile, installData.id); (new IncompatibleObserver(this)).checkForUpdates(addon, installManifest, stagedFile); // Return early to prevent deletion of the install manifest file. - return; + return INSTALLERROR_PHONING_HOME; } else { // XXXben Look up XULRunnerSettingsThingy to see if there is a registered @@ -4676,6 +4683,7 @@ ExtensionManager.prototype = { case INSTALLERROR_SOFTBLOCKED: if (!showBlocklistMessage(installData, true)) break; + installData.error = INSTALLERROR_SUCCESS; // Fall through to continue the install case INSTALLERROR_SUCCESS: // Installation of multiple extensions / themes contained within a single xpi. @@ -4694,7 +4702,7 @@ ExtensionManager.prototype = { // but that's an edge case I don't care about. for (var i = 0; i < this._installListeners.length; ++i) this._installListeners[i].onInstallEnded(addon, INSTALLERROR_RESTRICTED); - return; + return INSTALLERROR_RESTRICTED; } // Stage a copy of the XPI/JAR file for our own evil purposes... @@ -4791,6 +4799,8 @@ ExtensionManager.prototype = { // The install of this item is complete, notify observers for (var i = 0; i < this._installListeners.length; ++i) this._installListeners[i].onInstallEnded(addon, installData.error); + + return installData.error; }, /** @@ -6312,11 +6322,13 @@ ExtensionItemUpdater.prototype = { * The already installed nsIUpdateItem that the update is for * @param aRemoteItem * The nsIUpdateItem we are trying to update to + * @param aUpdateCheckType + * The type of update check being performed * * @returns true if the item is compatible and is not blocklisted. * false if the item is not compatible or is blocklisted. */ - _isValidUpdate: function _isValidUpdate(aLocalItem, aRemoteItem) { + _isValidUpdate: function _isValidUpdate(aLocalItem, aRemoteItem, aUpdateCheckType) { var appExtensionsVersion = (aRemoteItem.targetAppID != TOOLKIT_ID) ? this._appVersion : this._platformVersion; @@ -6331,14 +6343,17 @@ ExtensionItemUpdater.prototype = { if (!max || gVersionChecker.compare(appExtensionsVersion, max) > 0) return false; - if (!gBlocklist) - gBlocklist = Cc["@mozilla.org/extensions/blocklist;1"]. - getService(Ci.nsIBlocklistService); - // Denies updates that are hard blocked, soft blocked items will be warned - // about during the install. - if (gBlocklist.isAddonBlocklisted(aLocalItem.id, aRemoteItem.version, - this._appVersion, this._platformVersion)) - return false; + // Ignore the blocklist for compatibility only checks. + if (aUpdateCheckType != Ci.nsIExtensionManager.UPDATE_CHECK_COMPATIBILITY) { + if (!gBlocklist) + gBlocklist = Cc["@mozilla.org/extensions/blocklist;1"]. + getService(Ci.nsIBlocklistService); + // Denies updates that are hard blocked, soft blocked items will be warned + // about during the install. + if (gBlocklist.isAddonBlocklisted(aLocalItem.id, aRemoteItem.version, + this._appVersion, this._platformVersion)) + return false; + } return true; }, @@ -6920,7 +6935,7 @@ RDFItemUpdater.prototype = { aLocalItem.type, appID); - if (this._updater._isValidUpdate(aLocalItem, updatedItem)) { + if (this._updater._isValidUpdate(aLocalItem, updatedItem, aUpdateCheckType)) { if (aUpdateCheckType == Ci.nsIExtensionManager.UPDATE_CHECK_NEWVERSION) { var infourl = this._getPropertyFromResource(aDataSource, targetApp, "updateInfoURL"); diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_1/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_1/install.rdf new file mode 100644 index 000000000000..52e516cf0cf3 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_1/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_1@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 2 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_2/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_2/install.rdf new file mode 100644 index 000000000000..e0cf1a7a3f98 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_2/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_2@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 1 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_3/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_3/install.rdf new file mode 100644 index 000000000000..da9500a221ac --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_3/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_3@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 1 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_4/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_4/install.rdf new file mode 100644 index 000000000000..0e7a677ed133 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_4/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_4@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 2 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_5/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_5/install.rdf new file mode 100644 index 000000000000..26f295e38650 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_5/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_5@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 1 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_6/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_6/install.rdf new file mode 100644 index 000000000000..05bedeae3780 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_6/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_6@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 1 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_7/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_7/install.rdf new file mode 100644 index 000000000000..5e0f408a068c --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_7/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_7@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 2 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_8/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_8/install.rdf new file mode 100644 index 000000000000..be316b531adf --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_8/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_8@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 1 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_9/install.rdf b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_9/install.rdf new file mode 100644 index 000000000000..eead04acd377 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/addons/test_bug463819_9/install.rdf @@ -0,0 +1,18 @@ + + + + + test_bug463819_9@tests.mozilla.org + 1 + + + xpcshell@tests.mozilla.org + 1 + 1 + + + Test for Bug 463819 + http://localhost:4444/test_bug463819.rdf + + diff --git a/toolkit/mozapps/extensions/test/unit/data/test_bug463819.rdf b/toolkit/mozapps/extensions/test/unit/data/test_bug463819.rdf new file mode 100644 index 000000000000..cd5e336e9896 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/data/test_bug463819.rdf @@ -0,0 +1,63 @@ + + + + + + + + + + 1.0 + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + + + + + + + + + + 1.0 + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + + + + + + + + + + 1.0 + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/unit/data/test_bug463819.xml b/toolkit/mozapps/extensions/test/unit/data/test_bug463819.xml new file mode 100644 index 000000000000..52a7cb5583e5 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/data/test_bug463819.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/unit/test_bug463819.js b/toolkit/mozapps/extensions/test/unit/test_bug463819.js new file mode 100644 index 000000000000..0407748e72f0 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/test_bug463819.js @@ -0,0 +1,262 @@ +/* ***** 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) 2008 + * 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 ***** + */ + +const INSTALLERROR_SUCCESS = 0; +const INSTALLERROR_INCOMPATIBLE_VERSION = -3; +const INSTALLERROR_BLOCKLISTED = -6; +const INSTALLERROR_SOFTBLOCKED = -10; + +// Disables security checking our updates which haven't been signed +gPrefs.setBoolPref("extensions.checkUpdateSecurity", false); + +// Get the HTTP server. +do_import_script("netwerk/test/httpserver/httpd.js"); +var testserver; + +// 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; + } +}; + +// This will be called to show the blocklist message, we just make it look like +// it was dismissed. +var WindowWatcher = { + openWindow: function(parent, url, name, features, arguments) { + }, + + QueryInterface: function(iid) { + if (iid.equals(Ci.nsIWindowWatcher) + || iid.equals(Ci.nsISupports)) + return this; + + throw Cr.NS_ERROR_NO_INTERFACE; + } +} + +var WindowWatcherFactory = { + createInstance: function createInstance(outer, iid) { + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + return WindowWatcher.QueryInterface(iid); + } +}; + +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); +registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), + "Fake Window Watcher", + "@mozilla.org/embedcomp/window-watcher;1", WindowWatcherFactory); + +var gNextTest, gLastStatus; + +// nsIAddonInstallListener +var installListener = { + onDownloadStarted: function(aAddon) { + }, + + onDownloadEnded: function(aAddon) { + }, + + onInstallStarted: function(aAddon) { + }, + + onCompatibilityCheckStarted: function(aAddon) { + }, + + onCompatibilityCheckEnded: function(aAddon, aStatus) { + }, + + onInstallEnded: function(aAddon, aStatus) { + gLastStatus = aStatus; + }, + + onInstallsCompleted: function() { + gNextTest(); + }, + + onDownloadProgress: function onProgress(aAddon, aValue, aMaxValue) { + } +} + +function run_test() { + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2", "1.9"); + + // Install the blocklist + var blocklist = do_get_file("toolkit/mozapps/extensions/test/unit/data/test_bug463819.xml"); + blocklist.copyTo(gProfD, "blocklist.xml"); + + // Create and configure the HTTP server. + testserver = new nsHttpServer(); + testserver.registerDirectory("/", do_get_file("toolkit/mozapps/extensions/test/unit/data")); + testserver.start(4444); + + startupEM(); + gEM.addInstallListener(installListener); + + // These add-ons require no update check so will complete installation immediately + dump("Installing add-on 1\n"); + gNextTest = test_addon_1; + gEM.installItemFromFile(do_get_addon("test_bug463819_1"), NS_INSTALL_LOCATION_APPPROFILE); + dump("Installing add-on 4\n"); + gNextTest = test_addon_4; + gEM.installItemFromFile(do_get_addon("test_bug463819_4"), NS_INSTALL_LOCATION_APPPROFILE); + dump("Installing add-on 7\n"); + gNextTest = test_addon_7; + gEM.installItemFromFile(do_get_addon("test_bug463819_7"), NS_INSTALL_LOCATION_APPPROFILE); + + do_test_pending(); + + // These add-ons will perform a compatibility check before responding. + dump("Installing add-on 2\n"); + gNextTest = test_addon_2; + gEM.installItemFromFile(do_get_addon("test_bug463819_2"), NS_INSTALL_LOCATION_APPPROFILE); +} + +// Compatible in install.rdf and not in blocklist +function test_addon_1() { + do_check_eq(gLastStatus, INSTALLERROR_SUCCESS); +} + +// Compatible in install.rdf and low severity in blocklist +function test_addon_4() { + do_check_eq(gLastStatus, INSTALLERROR_SOFTBLOCKED); +} + +// Compatible in install.rdf and high severity in blocklist +function test_addon_7() { + do_check_eq(gLastStatus, INSTALLERROR_BLOCKLISTED); +} + +// Incompatible in install.rdf, compatible in update.rdf, not in blocklist +function test_addon_2() { + do_check_eq(gLastStatus, INSTALLERROR_SUCCESS); + + dump("Installing add-on 3\n"); + gNextTest = test_addon_3; + gEM.installItemFromFile(do_get_addon("test_bug463819_3"), NS_INSTALL_LOCATION_APPPROFILE); +} + +// Incompatible in install.rdf, incompatible in update.rdf, not in blocklist +function test_addon_3() { + do_check_eq(gLastStatus, INSTALLERROR_INCOMPATIBLE_VERSION); + + dump("Installing add-on 5\n"); + gNextTest = test_addon_5; + gEM.installItemFromFile(do_get_addon("test_bug463819_5"), NS_INSTALL_LOCATION_APPPROFILE); +} + +// Incompatible in install.rdf, compatible in update.rdf, low severity in blocklist +function test_addon_5() { + do_check_eq(gLastStatus, INSTALLERROR_SOFTBLOCKED); + + dump("Installing add-on 6\n"); + gNextTest = test_addon_6; + gEM.installItemFromFile(do_get_addon("test_bug463819_6"), NS_INSTALL_LOCATION_APPPROFILE); +} + +// Incompatible in install.rdf, incompatible in update.rdf, low severity in blocklist +function test_addon_6() { + do_check_eq(gLastStatus, INSTALLERROR_INCOMPATIBLE_VERSION); + + dump("Installing add-on 8\n"); + gNextTest = test_addon_8; + gEM.installItemFromFile(do_get_addon("test_bug463819_8"), NS_INSTALL_LOCATION_APPPROFILE); +} + +// Incompatible in install.rdf, compatible in update.rdf, high severity in blocklist +function test_addon_8() { + do_check_eq(gLastStatus, INSTALLERROR_BLOCKLISTED); + + dump("Installing add-on 9\n"); + gNextTest = test_addon_9; + gEM.installItemFromFile(do_get_addon("test_bug463819_9"), NS_INSTALL_LOCATION_APPPROFILE); +} + +// Incompatible in install.rdf, incompatible in update.rdf, high severity in blocklist +function test_addon_9() { + do_check_eq(gLastStatus, INSTALLERROR_INCOMPATIBLE_VERSION); + + finish_test(); +} + +function finish_test() { + testserver.stop(); + do_test_finished(); +}