diff --git a/toolkit/mozapps/extensions/AddonManager.jsm b/toolkit/mozapps/extensions/AddonManager.jsm index eb63fde7b485..929e4c4bf126 100644 --- a/toolkit/mozapps/extensions/AddonManager.jsm +++ b/toolkit/mozapps/extensions/AddonManager.jsm @@ -42,9 +42,10 @@ const Ci = Components.interfaces; const Cr = Components.results; const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion"; -const PREF_EM_UPDATE_ENABLED = "extensions.update.enabled"; -const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion"; -const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"; +const PREF_EM_UPDATE_ENABLED = "extensions.update.enabled"; +const PREF_EM_LAST_APP_VERSION = "extensions.lastAppVersion"; +const PREF_EM_LAST_PLATFORM_VERSION = "extensions.lastPlatformVersion"; +const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault"; Components.utils.import("resource://gre/modules/Services.jsm"); @@ -231,9 +232,16 @@ var AddonManagerInternal = { let appChanged = undefined; + let oldAppVersion = null; try { - appChanged = Services.appinfo.version != - Services.prefs.getCharPref(PREF_EM_LAST_APP_VERSION); + oldAppVersion = Services.prefs.getCharPref(PREF_EM_LAST_APP_VERSION); + appChanged = Services.appinfo.version != oldAppVersion; + } + catch (e) { } + + let oldPlatformVersion = null; + try { + oldPlatformVersion = Services.prefs.getCharPref(PREF_EM_LAST_PLATFORM_VERSION); } catch (e) { } @@ -241,6 +249,8 @@ var AddonManagerInternal = { LOG("Application has been upgraded"); Services.prefs.setCharPref(PREF_EM_LAST_APP_VERSION, Services.appinfo.version); + Services.prefs.setCharPref(PREF_EM_LAST_PLATFORM_VERSION, + Services.appinfo.platformVersion); Services.prefs.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION, (appChanged === undefined ? 0 : -1)); } @@ -273,7 +283,8 @@ var AddonManagerInternal = { } this.providers.forEach(function(provider) { - callProvider(provider, "startup", null, appChanged); + callProvider(provider, "startup", null, appChanged, oldAppVersion, + oldPlatformVersion); }); gStarted = true; }, diff --git a/toolkit/mozapps/extensions/AddonUpdateChecker.jsm b/toolkit/mozapps/extensions/AddonUpdateChecker.jsm index ae2e2b71f83d..7496ce0c8ca9 100644 --- a/toolkit/mozapps/extensions/AddonUpdateChecker.jsm +++ b/toolkit/mozapps/extensions/AddonUpdateChecker.jsm @@ -386,6 +386,7 @@ function parseRDFManifest(aId, aType, aUpdateKey, aRequest) { } let result = { + id: aId, version: version, updateURL: getProperty(ds, targetApp, "updateLink"), updateHash: getProperty(ds, targetApp, "updateHash"), @@ -684,10 +685,17 @@ var AddonUpdateChecker = { if (!aPlatformVersion) aPlatformVersion = Services.appinfo.platformVersion; + let blocklist = Cc["@mozilla.org/extensions/blocklist;1"]. + getService(Ci.nsIBlocklistService); + let newest = null; for (let i = 0; i < aUpdates.length; i++) { if (!aUpdates[i].updateURL) continue; + let state = blocklist.getAddonBlocklistState(aUpdates[i].id, aUpdates[i].version, + aAppVersion, aPlatformVersion); + if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) + continue; if ((newest == null || (Services.vc.compare(newest.version, aUpdates[i].version) < 0)) && matchesVersions(aUpdates[i], aAppVersion, aPlatformVersion)) newest = aUpdates[i]; diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index 84ad6a2cf97b..5dacd6d59802 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -115,7 +115,7 @@ const TOOLKIT_ID = "toolkit@mozilla.org"; const BRANCH_REGEXP = /^([^\.]+\.[0-9]+[a-z]*).*/gi; -const DB_SCHEMA = 3; +const DB_SCHEMA = 4; const REQ_VERSION = 2; // Properties that exist in the install manifest @@ -130,7 +130,8 @@ const PROP_TARGETAPP = ["id", "minVersion", "maxVersion"]; const DB_METADATA = ["installDate", "updateDate", "size", "sourceURI", "releaseNotesURI", "applyBackgroundUpdates"]; const DB_BOOL_METADATA = ["visible", "active", "userDisabled", "appDisabled", - "pendingUninstall", "bootstrap", "skinnable"]; + "pendingUninstall", "bootstrap", "skinnable", + "softDisabled"]; const BOOTSTRAP_REASONS = { APP_STARTUP : 1, @@ -412,6 +413,61 @@ function findClosestLocale(aLocales) { return null; } +/** + * Sets the userDisabled and softDisabled properties of an add-on based on what + * values those properties had for a previous instance of the add-on. The + * previous instance may be a previous install or in the case of an application + * version change the same add-on. + * + * @param aOldAddon + * The previous instance of the add-on + * @param aNewAddon + * The new instance of the add-on + * @param aAppVersion + * The optional application version to use when checking the blocklist + * or undefined to use the current application + * @param aPlatformVersion + * The optional platform version to use when checking the blocklist or + * undefined to use the current platform + */ +function applyBlocklistChanges(aOldAddon, aNewAddon, aOldAppVersion, + aOldPlatformVersion) { + // Copy the properties by default + aNewAddon.userDisabled = aOldAddon.userDisabled; + aNewAddon.softDisabled = aOldAddon.softDisabled; + + let bs = Cc["@mozilla.org/extensions/blocklist;1"]. + getService(Ci.nsIBlocklistService); + + let oldBlocklistState = bs.getAddonBlocklistState(aOldAddon.id, + aOldAddon.version, + aOldAppVersion, + aOldPlatformVersion); + let newBlocklistState = bs.getAddonBlocklistState(aNewAddon.id, + aNewAddon.version); + + // If the blocklist state hasn't changed then the properties don't need to + // change + if (newBlocklistState == oldBlocklistState) + return; + + if (newBlocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) { + if (aNewAddon.type != "theme") { + // The add-on has become softblocked, set softDisabled if it isn't already + // userDisabled + aNewAddon.softDisabled = !aNewAddon.userDisabled; + } + else { + // Themes just get userDisabled to switch back to the default theme + aNewAddon.userDisabled = true; + } + } + else { + // If the new add-on is not softblocked then it cannot be softDisabled + aNewAddon.softDisabled = false; + } +} + /** * Calculates whether an add-on should be appDisabled or not. * @@ -445,6 +501,10 @@ function isUsableAddon(aAddon) { return true; } +function isAddonDisabled(aAddon) { + return aAddon.appDisabled || aAddon.softDisabled || aAddon.userDisabled; +} + this.__defineGetter__("gRDF", function() { delete this.gRDF; return this.gRDF = Cc["@mozilla.org/rdf/rdf-service;1"]. @@ -704,7 +764,8 @@ function loadManifestFromRDF(aUri, aStream) { addon.internalName != XPIProvider.selectedSkin; } else { - addon.userDisabled = addon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED; + addon.userDisabled = false; + addon.softDisabled = addon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED; } addon.appDisabled = !isUsableAddon(addon); @@ -957,7 +1018,8 @@ function verifyZipSigning(aZip, aPrincipal) { */ function escapeAddonURI(aAddon, aUri, aUpdateType, aAppVersion) { - var addonStatus = aAddon.userDisabled ? "userDisabled" : "userEnabled"; + var addonStatus = aAddon.userDisabled || aAddon.softDisabled ? "userDisabled" + : "userEnabled"; if (!aAddon.isCompatible) addonStatus += ",incompatible"; @@ -1272,6 +1334,17 @@ var Prefs = { catch (e) { } return defaultValue; + }, + + /** + * Clears a preference if it has a user value + * + * @param aName + * The name of the preference + */ + clearUserPref: function(aName) { + if (Services.prefs.prefHasUserValue(aName)) + Services.prefs.clearUserPref(aName); } } @@ -1329,8 +1402,14 @@ var XPIProvider = { * last used with an application with a different version number, * false means that the profile was last used by this version of the * application. + * @param aOldAppVersion + * The version of the application last run with this profile or null + * if it is a new profile or the version is unknown + * @param aOldPlatformVersion + * The version of the platform last run with this profile or null + * if it is a new profile or the version is unknown */ - startup: function XPI_startup(aAppChanged) { + startup: function XPI_startup(aAppChanged, aOldAppVersion, aOldPlatformVersion) { LOG("startup"); this.installs = []; this.installLocations = []; @@ -1431,7 +1510,8 @@ var XPIProvider = { Services.prefs.addObserver(this.checkCompatibilityPref, this, false); Services.prefs.addObserver(PREF_EM_CHECK_UPDATE_SECURITY, this, false); - let flushCaches = this.checkForChanges(aAppChanged); + let flushCaches = this.checkForChanges(aAppChanged, aOldAppVersion, + aOldPlatformVersion); // Changes to installed extensions may have changed which theme is selected this.applyThemeChange(); @@ -2059,6 +2139,12 @@ var XPIProvider = { * @param aUpdateCompatibility * true to update add-ons appDisabled property when the application * version has changed + * @param aOldAppVersion + * The version of the application last run with this profile or null + * if it is a new profile or the version is unknown + * @param aOldPlatformVersion + * The version of the platform last run with this profile or null + * if it is a new profile or the version is unknown * @param aMigrateData * an object generated from a previous version of the database * holding information about what add-ons were previously userDisabled @@ -2071,6 +2157,8 @@ var XPIProvider = { */ processFileChanges: function XPI_processFileChanges(aState, aManifests, aUpdateCompatibility, + aOldAppVersion, + aOldPlatformVersion, aMigrateData, aActiveBundles) { let visibleAddons = {}; @@ -2103,8 +2191,7 @@ var XPIProvider = { if (!newAddon) { let file = aInstallLocation.getLocationForID(aOldAddon.id); newAddon = loadManifestFromFile(file); - // Carry over the userDisabled setting for add-ons that just appeared - newAddon.userDisabled = aOldAddon.userDisabled; + applyBlocklistChanges(aOldAddon, newAddon); } // The ID in the manifest that was loaded must match the ID of the old @@ -2136,6 +2223,11 @@ var XPIProvider = { if (newAddon.visible) { visibleAddons[newAddon.id] = newAddon; + // If this was the active theme and it is now disabled then enable the + // default theme + if (aOldAddon.active && isAddonDisabled(newAddon)) + XPIProvider.enableDefaultTheme(); + // If the new add-on is bootstrapped and active then call its install method if (newAddon.active && newAddon.bootstrap) { let installReason = Services.vc.compare(aOldAddon.version, newAddon.version) < 0 ? @@ -2193,7 +2285,7 @@ var XPIProvider = { // If it should be active then mark it as active otherwise unload // its scope - if (!aOldAddon.appDisabled && !aOldAddon.userDisabled) { + if (!isAddonDisabled(aOldAddon)) { aOldAddon.active = true; XPIDatabase.updateAddonActive(aOldAddon); } @@ -2210,26 +2302,40 @@ var XPIProvider = { // App version changed, we may need to update the appDisabled property. if (aUpdateCompatibility) { - let appDisabled = !isUsableAddon(aOldAddon); - let userDisabled = aOldAddon.userDisabled; + // Create a basic add-on object for the new state to save reproducing + // the applyBlocklistChanges code + let newAddon = new AddonInternal(); + newAddon.id = aOldAddon.id; + newAddon.version = aOldAddon.version; + newAddon.type = aOldAddon.type; + newAddon.appDisabled = !isUsableAddon(aOldAddon); + // Sync the userDisabled flag to the selectedSkin if (aOldAddon.type == "theme") - userDisabled = aOldAddon.internalName != XPIProvider.selectedSkin; - let wasDisabled = aOldAddon.appDisabled || aOldAddon.userDisabled; - let isDisabled = appDisabled || userDisabled; + newAddon.userDisabled = aOldAddon.internalName != XPIProvider.selectedSkin; + + applyBlocklistChanges(aOldAddon, newAddon, aOldAppVersion, + aOldPlatformVersion); + + let wasDisabled = isAddonDisabled(aOldAddon); + let isDisabled = isAddonDisabled(newAddon); // Remember add-ons that became appDisabled by the application change - if (aOldAddon.visible && appDisabled && !aOldAddon.appDisabled) + if (aOldAddon.visible && newAddon.appDisabled && !aOldAddon.appDisabled) XPIProvider.startupChanges.appDisabled.push(aOldAddon.id); // If either property has changed update the database. - if (appDisabled != aOldAddon.appDisabled || - userDisabled != aOldAddon.userDisabled) { + if (newAddon.appDisabled != aOldAddon.appDisabled || + newAddon.userDisabled != aOldAddon.userDisabled || + newAddon.softDisabled != aOldAddon.softDisabled) { LOG("Add-on " + aOldAddon.id + " changed appDisabled state to " + - appDisabled + " and userDisabled state to " + userDisabled); + newAddon.appDisabled + ", userDisabled state to " + + newAddon.userDisabled + " and softDisabled state to " + + newAddon.softDisabled); XPIDatabase.setAddonProperties(aOldAddon, { - appDisabled: appDisabled, - userDisabled: userDisabled + appDisabled: newAddon.appDisabled, + userDisabled: newAddon.userDisabled, + softDisabled: newAddon.softDisabled }); } @@ -2347,6 +2453,8 @@ var XPIProvider = { newAddon.userDisabled = aMigrateData.userDisabled; if ("installDate" in aMigrateData) newAddon.installDate = aMigrateData.installDate; + if ("softDisabled" in aMigrateData) + newAddon.softDisabled = aMigrateData.softDisabled; // Some properties should only be migrated if the add-on hasn't changed. // The version property isn't a perfect check for this but covers the @@ -2355,24 +2463,33 @@ var XPIProvider = { if ("targetApplications" in aMigrateData) newAddon.applyCompatibilityUpdate(aMigrateData, true); } + + // Since the DB schema has changed make sure softDisabled is correct + applyBlocklistChanges(newAddon, newAddon, aOldAppVersion, + aOldPlatformVersion); } - // If we have a list of what add-ons should be marked as active then use it if (aActiveBundles) { + // If we have a list of what add-ons should be marked as active then use + // it to guess at migration data // For themes we know which is active by the current skin setting if (newAddon.type == "theme") newAddon.active = newAddon.internalName == XPIProvider.currentSkin; else newAddon.active = aActiveBundles.indexOf(aAddonState.descriptor) != -1; - // If the add-on isn't active and it isn't appDisabled then it is - // probably userDisabled - if (!newAddon.active && newAddon.visible && !newAddon.appDisabled) - newAddon.userDisabled = true; + // If the add-on wasn't active and it isn't already disabled in some way + // then it was probably either softDisabled or userDisabled + if (!newAddon.active && newAddon.visible && !isAddonDisabled(newAddon)) { + // If the add-on is softblocked then assume it is softDisabled + if (newAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) + newAddon.softDisabled = true; + else + newAddon.userDisabled = true; + } } else { - newAddon.active = (newAddon.visible && !newAddon.userDisabled && - !newAddon.appDisabled) + newAddon.active = (newAddon.visible && !isAddonDisabled(newAddon)) } try { @@ -2553,9 +2670,16 @@ var XPIProvider = { * last used with an application with a different version number, * false means that the profile was last used by this version of the * application. + * @param aOldAppVersion + * The version of the application last run with this profile or null + * if it is a new profile or the version is unknown + * @param aOldPlatformVersion + * The version of the platform last run with this profile or null + * if it is a new profile or the version is unknown * @return true if a change requiring a restart was detected */ - checkForChanges: function XPI_checkForChanges(aAppChanged) { + checkForChanges: function XPI_checkForChanges(aAppChanged, aOldAppVersion, + aOldPlatformVersion) { LOG("checkForChanges"); // Import the website installation permissions if the application has changed @@ -2632,6 +2756,8 @@ var XPIProvider = { try { extensionListChanged = this.processFileChanges(state, manifests, aAppChanged, + aOldAppVersion, + aOldPlatformVersion, migrateData, null); } catch (e) { @@ -2644,7 +2770,7 @@ var XPIProvider = { // compatible otherwise switch back the default if (this.currentSkin != this.defaultSkin) { let oldSkin = XPIDatabase.getVisibleAddonForInternalName(this.currentSkin); - if (!oldSkin || oldSkin.appDisabled) + if (!oldSkin || isAddonDisabled(oldSkin)) this.enableDefaultTheme(); } @@ -2946,10 +3072,27 @@ var XPIProvider = { enableDefaultTheme: function XPI_enableDefaultTheme() { LOG("Activating default theme"); let addon = XPIDatabase.getVisibleAddonForInternalName(this.defaultSkin); - if (addon) - this.updateAddonDisabledState(addon, false); - else + if (addon) { + if (addon.userDisabled) { + this.updateAddonDisabledState(addon, false); + } + else if (!this.extensionsActive) { + // During startup we may end up trying to enable the default theme when + // the database thinks it is already enabled (see f.e. bug 638847). In + // this case just force the theme preferences to be correct + Services.prefs.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, + addon.internalName); + this.currentSkin = this.selectedSkin = addon.internalName; + Prefs.clearUserPref(PREF_DSS_SKIN_TO_SELECT); + Prefs.clearUserPref(PREF_DSS_SWITCHPENDING); + } + else { + WARN("Attempting to activate an already active default theme"); + } + } + else { WARN("Unable to activate the default theme"); + } }, /** @@ -3091,7 +3234,7 @@ var XPIProvider = { // If the add-on is not going to be active after installation then it // doesn't require a restart to install. - if (aAddon.userDisabled || aAddon.appDisabled) + if (isAddonDisabled(aAddon)) return false; // Themes will require a restart (even if dynamic switching is enabled due @@ -3272,29 +3415,49 @@ var XPIProvider = { * @param aUserDisabled * Value for the userDisabled property. If undefined the value will * not change + * @param aSoftDisabled + * Value for the softDisabled property. If undefined the value will + * not change. If true this will force userDisabled to be true * @throws if addon is not a DBAddonInternal */ updateAddonDisabledState: function XPI_updateAddonDisabledState(aAddon, - aUserDisabled) { + aUserDisabled, + aSoftDisabled) { if (!(aAddon instanceof DBAddonInternal)) throw new Error("Can only update addon states for installed addons."); + if (aUserDisabled !== undefined && aSoftDisabled !== undefined) { + throw new Error("Cannot change userDisabled and softDisabled at the " + + "same time"); + } - if (aUserDisabled === undefined) + if (aUserDisabled === undefined) { aUserDisabled = aAddon.userDisabled; + } + else if (!aUserDisabled) { + // If enabling the add-on then remove softDisabled + aSoftDisabled = false; + } + + // If not changing softDisabled or the add-on is already userDisabled then + // use the existing value for softDisabled + if (aSoftDisabled === undefined || aUserDisabled) + aSoftDisabled = aAddon.softDisabled; let appDisabled = !isUsableAddon(aAddon); // No change means nothing to do here if (aAddon.userDisabled == aUserDisabled && - aAddon.appDisabled == appDisabled) + aAddon.appDisabled == appDisabled && + aAddon.softDisabled == aSoftDisabled) return; - let wasDisabled = aAddon.userDisabled || aAddon.appDisabled; - let isDisabled = aUserDisabled || appDisabled; + let wasDisabled = isAddonDisabled(aAddon); + let isDisabled = aUserDisabled || aSoftDisabled || appDisabled; // Update the properties in the database XPIDatabase.setAddonProperties(aAddon, { userDisabled: aUserDisabled, - appDisabled: appDisabled + appDisabled: appDisabled, + softDisabled: aSoftDisabled }); // If the add-on is not visible or the add-on is not changing state then @@ -3413,8 +3576,7 @@ var XPIProvider = { let wrappedAddon = createWrapper(aAddon); AddonManagerPrivate.callAddonListeners("onInstalling", wrappedAddon, false); - if (!aAddon.userDisabled && !aAddon.appDisabled && - !XPIProvider.enableRequiresRestart(aAddon)) { + if (!isAddonDisabled(aAddon) && !XPIProvider.enableRequiresRestart(aAddon)) { aAddon.active = true; XPIDatabase.updateAddonActive(aAddon); } @@ -3495,7 +3657,7 @@ const FIELDS_ADDON = "internal_id, id, location, version, type, internalName, " "icon64URL, defaultLocale, visible, active, userDisabled, " + "appDisabled, pendingUninstall, descriptor, installDate, " + "updateDate, applyBackgroundUpdates, bootstrap, skinnable, " + - "size, sourceURI, releaseNotesURI"; + "size, sourceURI, releaseNotesURI, softDisabled"; /** * A helper function to log an SQL error. @@ -3640,7 +3802,7 @@ var XPIDatabase = { ":userDisabled, :appDisabled, :pendingUninstall, " + ":descriptor, :installDate, :updateDate, " + ":applyBackgroundUpdates, :bootstrap, :skinnable, " + - ":size, :sourceURI, :releaseNotesURI)", + ":size, :sourceURI, :releaseNotesURI, :softDisabled)", addAddonMetadata_addon_locale: "INSERT INTO addon_locale VALUES " + "(:internal_id, :name, :locale)", addAddonMetadata_locale: "INSERT INTO locale (name, description, creator, " + @@ -3683,11 +3845,12 @@ var XPIDatabase = { makeAddonVisible: "UPDATE addon SET visible=1 WHERE internal_id=:internal_id", removeAddonMetadata: "DELETE FROM addon WHERE internal_id=:internal_id", - // Equates to active = visible && !userDisabled && !appDisabled + // Equates to active = visible && !userDisabled && !softDisabled && !appDisabled setActiveAddons: "UPDATE addon SET active=MIN(visible, 1 - userDisabled, " + - "1 - appDisabled)", + "1 - softDisabled, 1 - appDisabled)", setAddonProperties: "UPDATE addon SET userDisabled=:userDisabled, " + "appDisabled=:appDisabled, " + + "softDisabled=:softDisabled, " + "pendingUninstall=:pendingUninstall, " + "applyBackgroundUpdates=:applyBackgroundUpdates WHERE " + "internal_id=:internal_id", @@ -3850,7 +4013,8 @@ var XPIDatabase = { this.beginTransaction(); try { let state = XPIProvider.getInstallLocationStates(); - XPIProvider.processFileChanges(state, {}, false, migrateData, activeBundles) + XPIProvider.processFileChanges(state, {}, false, undefined, undefined, + migrateData, activeBundles) // Make sure to update the active add-ons and add-ons list on shutdown Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, true); this.commitTransaction(); @@ -3998,10 +4162,28 @@ var XPIDatabase = { // Attempt to migrate data from a different (even future!) version of the // database try { - var stmt = this.connection.createStatement("SELECT internal_id, id, " + - "location, userDisabled, " + - "installDate, version " + - "FROM addon"); + // Build a list of sql statements that might recover useful data from this + // and future versions of the schema + var sql = []; + sql.push("SELECT internal_id, id, location, userDisabled, " + + "softDisabled, installDate, version FROM addon"); + sql.push("SELECT internal_id, id, location, userDisabled, installDate, " + + "version FROM addon"); + + var stmt = null; + if (!sql.some(function(aSql) { + try { + stmt = this.connection.createStatement(aSql); + return true; + } + catch (e) { + return false; + } + }, this)) { + ERROR("Unable to read anything useful from the database"); + return migrateData; + } + for (let row in resultRows(stmt)) { if (!(row.location in migrateData)) migrateData[row.location] = {}; @@ -4012,6 +4194,9 @@ var XPIDatabase = { userDisabled: row.userDisabled == 1, targetApplications: [] }; + + if ("softDisabled" in row) + migrateData[row.location][row.id].softDisabled = row.softDisabled == 1; } var taStmt = this.connection.createStatement("SELECT id, minVersion, " + @@ -4131,7 +4316,8 @@ var XPIDatabase = { "applyBackgroundUpdates INTEGER, " + "bootstrap INTEGER, skinnable INTEGER, " + "size INTEGER, sourceURI TEXT, " + - "releaseNotesURI TEXT, UNIQUE (id, location)"); + "releaseNotesURI TEXT, softDisabled INTEGER, " + + "UNIQUE (id, location)"); this.connection.createTable("targetApplication", "addon_internal_id INTEGER, " + "id TEXT, minVersion TEXT, maxVersion TEXT, " + @@ -4892,7 +5078,7 @@ var XPIDatabase = { let stmt = this.getStatement("setAddonProperties"); stmt.params.internal_id = aAddon._internal_id; - ["userDisabled", "appDisabled", + ["userDisabled", "appDisabled", "softDisabled", "pendingUninstall"].forEach(function(aProp) { if (aProp in aProperties) { stmt.params[aProp] = convertBoolean(aProperties[aProp]); @@ -5103,7 +5289,7 @@ function AddonInstall(aCallback, aInstallLocation, aUrl, aHash, aName, aType, XPIDatabase.getVisibleAddonForID(self.addon.id, function(aAddon) { self.existingAddon = aAddon; if (aAddon) - self.addon.userDisabled = aAddon.userDisabled; + applyBlocklistChanges(aAddon, self.addon); self.addon.updateDate = Date.now(); self.addon.installDate = aAddon ? aAddon.installDate : self.addon.updateDate; @@ -5808,8 +5994,8 @@ AddonInstall.prototype = { if (self.existingAddon) { self.addon.existingAddonID = self.existingAddon.id; - self.addon.userDisabled = self.existingAddon.userDisabled; self.addon.installDate = self.existingAddon.installDate; + applyBlocklistChanges(self.existingAddon, self.addon); } else { self.addon.installDate = self.addon.updateDate; @@ -5979,8 +6165,7 @@ AddonInstall.prototype = { } else { this.addon.installDate = this.addon.updateDate; - this.addon.active = (this.addon.visible && !this.addon.userDisabled && - !this.addon.appDisabled) + this.addon.active = (this.addon.visible && !isAddonDisabled(this.addon)) XPIDatabase.addAddonMetadata(this.addon, file.persistentDescriptor); } @@ -6330,6 +6515,7 @@ AddonInternal.prototype = { visible: false, userDisabled: false, appDisabled: false, + softDisabled: false, sourceURI: null, releaseNotesURI: null, @@ -6576,7 +6762,7 @@ function AddonWrapper(aAddon) { ["id", "version", "type", "isCompatible", "isPlatformCompatible", "providesUpdatesSecurely", "blocklistState", "appDisabled", - "userDisabled", "skinnable", "size"].forEach(function(aProp) { + "softDisabled", "skinnable", "size"].forEach(function(aProp) { this.__defineGetter__(aProp, function() aAddon[aProp]); }, this); @@ -6763,9 +6949,9 @@ function AddonWrapper(aAddon) { pending |= AddonManager.PENDING_UNINSTALL; } - if (aAddon.active && (aAddon.userDisabled || aAddon.appDisabled)) + if (aAddon.active && isAddonDisabled(aAddon)) pending |= AddonManager.PENDING_DISABLE; - else if (!aAddon.active && (!aAddon.userDisabled && !aAddon.appDisabled)) + else if (!aAddon.active && !isAddonDisabled(aAddon)) pending |= AddonManager.PENDING_ENABLE; if (aAddon.pendingUpgrade) @@ -6796,7 +6982,7 @@ function AddonWrapper(aAddon) { return permissions; if (!aAddon.appDisabled) { - if (aAddon.userDisabled) + if (this.userDisabled) permissions |= AddonManager.PERM_CAN_ENABLE; else if (aAddon.type != "theme") permissions |= AddonManager.PERM_CAN_DISABLE; @@ -6820,8 +7006,11 @@ function AddonWrapper(aAddon) { return aAddon.active; }); + this.__defineGetter__("userDisabled", function() { + return aAddon.softDisabled || aAddon.userDisabled; + }); this.__defineSetter__("userDisabled", function(val) { - if (val == aAddon.userDisabled) + if (val == this.userDisabled) return val; if (aAddon instanceof DBAddonInternal) { @@ -6836,6 +7025,33 @@ function AddonWrapper(aAddon) { } else { aAddon.userDisabled = val; + // When enabling remove the softDisabled flag + if (!val) + aAddon.softDisabled = false; + } + + return val; + }); + + this.__defineSetter__("softDisabled", function(val) { + if (val == aAddon.softDisabled) + return val; + + if (aAddon instanceof DBAddonInternal) { + // When softDisabling a theme just enable the active theme + if (aAddon.type == "theme" && val && !aAddon.userDisabled) { + if (aAddon.internalName == XPIProvider.defaultSkin) + throw new Error("Cannot disable the default theme"); + XPIProvider.enableDefaultTheme(); + } + else { + XPIProvider.updateAddonDisabledState(aAddon, undefined, val); + } + } + else { + // Only set softDisabled if not already disabled + if (!aAddon.userDisabled) + aAddon.softDisabled = val; } return val; diff --git a/toolkit/mozapps/extensions/nsBlocklistService.js b/toolkit/mozapps/extensions/nsBlocklistService.js index ec6d30e13aef..dcfb88cd6fc3 100644 --- a/toolkit/mozapps/extensions/nsBlocklistService.js +++ b/toolkit/mozapps/extensions/nsBlocklistService.js @@ -511,6 +511,7 @@ Blocklist.prototype = { return; } + LOG("Blocklist::notify: Requesting " + uri.spec); var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. createInstance(Ci.nsIXMLHttpRequest); request.open("GET", uri.spec, true); @@ -859,19 +860,23 @@ Blocklist.prototype = { LOG("Blocklist state for " + addons[i].id + " changed from " + oldState + " to " + state); - // Don't warn about add-ons becoming unblocked. - if (state == 0) - continue; - // We don't want to re-warn about add-ons if (state == oldState) continue; + // Ensure that softDisabled is false if the add-on is not soft blocked + if (state != Ci.nsIBlocklistService.STATE_SOFTBLOCKED) + addons[i].softDisabled = false; + + // Don't warn about add-ons becoming unblocked. + if (state == Ci.nsIBlocklistService.STATE_NOT_BLOCKED) + continue; + // If an add-on has dropped from hard to soft blocked just mark it as - // user disabled and don't warn about it. + // soft disabled and don't warn about it. if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED && oldState == Ci.nsIBlocklistService.STATE_BLOCKED) { - addons[i].userDisabled = true; + addons[i].softDisabled = true; continue; } @@ -929,8 +934,10 @@ Blocklist.prototype = { plugins[i].blocklisted = state == Ci.nsIBlocklistService.STATE_BLOCKED; } - if (addonList.length == 0) + if (addonList.length == 0) { + Services.obs.notifyObservers(self, "blocklist-updated", ""); return; + } if ("@mozilla.org/addons/blocklist-prompt;1" in Cc) { try { @@ -940,6 +947,7 @@ Blocklist.prototype = { } catch (e) { LOG(e); } + Services.obs.notifyObservers(self, "blocklist-updated", ""); return; } @@ -962,11 +970,13 @@ Blocklist.prototype = { if (addonList[i].item instanceof Ci.nsIPluginTag) addonList[i].item.disabled = true; else - addonList[i].item.userDisabled = true; + addonList[i].item.softDisabled = true; } if (args.restart) restartApp(); + + Services.obs.notifyObservers(self, "blocklist-updated", ""); }); }, diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_hard1_1/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_hard1_1/install.rdf new file mode 100644 index 000000000000..76cb372c67f8 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_hard1_1/install.rdf @@ -0,0 +1,19 @@ + + + + + + hardblock@tests.mozilla.org + 1.0 + Hardblocked add-on + http://localhost:4444/data/addon_update1.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_hard1_2/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_hard1_2/install.rdf new file mode 100644 index 000000000000..ebfbb4050544 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_hard1_2/install.rdf @@ -0,0 +1,19 @@ + + + + + + hardblock@tests.mozilla.org + 2.0 + Hardblocked add-on + http://localhost:4444/data/addon_update2.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_hard1_3/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_hard1_3/install.rdf new file mode 100644 index 000000000000..a7978e1c8dd6 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_hard1_3/install.rdf @@ -0,0 +1,19 @@ + + + + + + hardblock@tests.mozilla.org + 3.0 + Hardblocked add-on + http://localhost:4444/data/addon_update3.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft1_1/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft1_1/install.rdf new file mode 100644 index 000000000000..e2d910be6103 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft1_1/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock1@tests.mozilla.org + 1.0 + Softblocked add-on + http://localhost:4444/data/addon_update1.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft1_2/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft1_2/install.rdf new file mode 100644 index 000000000000..1d58dbb962c0 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft1_2/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock1@tests.mozilla.org + 2.0 + Softblocked add-on + http://localhost:4444/data/addon_update2.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft1_3/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft1_3/install.rdf new file mode 100644 index 000000000000..e9094cc9738d --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft1_3/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock1@tests.mozilla.org + 3.0 + Softblocked add-on + http://localhost:4444/data/addon_update3.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft2_1/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft2_1/install.rdf new file mode 100644 index 000000000000..3026fa2d0ba3 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft2_1/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock2@tests.mozilla.org + 1.0 + Softblocked add-on + http://localhost:4444/data/addon_update1.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft2_2/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft2_2/install.rdf new file mode 100644 index 000000000000..4075277861f3 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft2_2/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock2@tests.mozilla.org + 2.0 + Softblocked add-on + http://localhost:4444/data/addon_update2.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft2_3/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft2_3/install.rdf new file mode 100644 index 000000000000..efa90afd70c3 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft2_3/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock2@tests.mozilla.org + 3.0 + Softblocked add-on + http://localhost:4444/data/addon_update3.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft3_1/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft3_1/install.rdf new file mode 100644 index 000000000000..3d45fb20f7a3 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft3_1/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock3@tests.mozilla.org + 1.0 + Softblocked add-on + http://localhost:4444/data/addon_update1.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft3_2/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft3_2/install.rdf new file mode 100644 index 000000000000..a2fcb99ba474 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft3_2/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock3@tests.mozilla.org + 2.0 + Softblocked add-on + http://localhost:4444/data/addon_update2.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft3_3/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft3_3/install.rdf new file mode 100644 index 000000000000..17efb24fa8f8 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft3_3/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock3@tests.mozilla.org + 3.0 + Softblocked add-on + http://localhost:4444/data/addon_update3.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft4_1/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft4_1/install.rdf new file mode 100644 index 000000000000..02c240e26d0c --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft4_1/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock4@tests.mozilla.org + 1.0 + Softblocked add-on + http://localhost:4444/data/addon_update1.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft4_2/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft4_2/install.rdf new file mode 100644 index 000000000000..728698cb0efd --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft4_2/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock4@tests.mozilla.org + 2.0 + Softblocked add-on + http://localhost:4444/data/addon_update2.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft4_3/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft4_3/install.rdf new file mode 100644 index 000000000000..c155342e751d --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft4_3/install.rdf @@ -0,0 +1,19 @@ + + + + + + softblock4@tests.mozilla.org + 3.0 + Softblocked add-on + http://localhost:4444/data/addon_update3.rdf + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft5_1/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft5_1/install.rdf new file mode 100644 index 000000000000..b434512e868c --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft5_1/install.rdf @@ -0,0 +1,20 @@ + + + + + + softblock5@tests.mozilla.org + 1.0 + Softblocked add-on + http://localhost:4444/data/addon_update1.rdf + test/1.0 + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft5_2/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft5_2/install.rdf new file mode 100644 index 000000000000..0f9cdea1e750 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft5_2/install.rdf @@ -0,0 +1,20 @@ + + + + + + softblock5@tests.mozilla.org + 2.0 + Softblocked add-on + http://localhost:4444/data/addon_update2.rdf + test/1.0 + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/addons/blocklist_soft5_3/install.rdf b/toolkit/mozapps/extensions/test/addons/blocklist_soft5_3/install.rdf new file mode 100644 index 000000000000..e345d5035f4b --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/blocklist_soft5_3/install.rdf @@ -0,0 +1,20 @@ + + + + + + softblock5@tests.mozilla.org + 3.0 + Softblocked add-on + http://localhost:4444/data/addon_update3.rdf + test/1.0 + + + xpcshell@tests.mozilla.org + 1 + 3 + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml new file mode 100644 index 000000000000..374c353183e6 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_change.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf new file mode 100644 index 000000000000..55f510e16bb2 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update1.rdf @@ -0,0 +1,124 @@ + + + + + + + + + 2 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft1_2.xpi + + + + + + + + + + + + + + 2 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft2_2.xpi + + + + + + + + + + + + + + 2 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft3_2.xpi + + + + + + + + + + + + + + 2 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft4_2.xpi + + + + + + + + + + + + + + 2 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft5_2.xpi + + + + + + + + + + + + + + 2 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_hard1_2.xpi + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf new file mode 100644 index 000000000000..0722a49bdc64 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update2.rdf @@ -0,0 +1,124 @@ + + + + + + + + + 3 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft1_3.xpi + + + + + + + + + + + + + + 3 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft2_3.xpi + + + + + + + + + + + + + + 3 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft3_3.xpi + + + + + + + + + + + + + + 3 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft4_3.xpi + + + + + + + + + + + + + + 3 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft5_3.xpi + + + + + + + + + + + + + + 3 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_hard1_3.xpi + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf new file mode 100644 index 000000000000..a13e47a470de --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/addon_update3.rdf @@ -0,0 +1,124 @@ + + + + + + + + + 4 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft1_1.xpi + + + + + + + + + + + + + + 4 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft2_1.xpi + + + + + + + + + + + + + + 4 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft3_1.xpi + + + + + + + + + + + + + + 4 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft4_1.xpi + + + + + + + + + + + + + + 4 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_soft5_1.xpi + + + + + + + + + + + + + + 4 + + + toolkit@mozilla.org + 0 + * + http://localhost:4444/addons/blocklist_hard1_1.xpi + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml new file mode 100644 index 000000000000..43fea570d091 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/app_update.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update1.xml b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update1.xml new file mode 100644 index 000000000000..87011cd39883 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update1.xml @@ -0,0 +1,3 @@ + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml new file mode 100644 index 000000000000..8b1a0f676bbf --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/blocklist_update2.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml new file mode 100644 index 000000000000..dd82aaf144a1 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/blocklistchange/manual_update.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js index d4b77160c263..8f1f2c6705d4 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js +++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js @@ -27,7 +27,7 @@ function createAppInfo(id, name, version, platformVersion) { ID: id, version: version, appBuildID: "2007010101", - platformVersion: platformVersion, + platformVersion: platformVersion ? platformVersion : "1.0", platformBuildID: "2007010101", // nsIXULRuntime @@ -613,6 +613,22 @@ function setExtensionModifiedTime(aExt, aTime) { } } +/** + * Gets the nsIFile for where an add-on is installed. It may point to a file or + * a directory depending on whether add-ons are being installed unpacked or not. + * + * @param aDir + * The nsIFile for the install location + * @param aId + * The ID of the add-on + * @return an nsIFile + */ +function getFileForAddon(aDir, aId) { + var dir = aDir.clone(); + dir.append(do_get_expected_addon_name(aId)); + return dir; +} + function registerDirectory(aKey, aDir) { var dirProvider = { getFile: function(aProp, aPersistent) { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js new file mode 100644 index 000000000000..402f3b206b09 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js @@ -0,0 +1,1260 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Checks that changes that cause an add-on to become unblocked or blocked have +// the right effect + +// The tests follow a mostly common pattern. First they start with the add-ons +// unblocked, then they make a change that causes the add-ons to become blocked +// then they make a similar change that keeps the add-ons blocked then they make +// a change that unblocks the add-ons. Some tests skip the initial part and +// start with add-ons detected as blocked. + +// softblock1 is enabled/disabled by the blocklist changes so its softDisabled +// property should always match its userDisabled property + +// softblock2 gets manually enabled then disabled after it becomes blocked so +// its softDisabled property should never become true after that + +// softblock3 does the same as softblock2 however it remains disabled + +// softblock4 is disabled while unblocked and so should never have softDisabled +// set to true and stay userDisabled. This add-on is not used in tests that +// start with add-ons blocked as it would be identical to softblock3 + +// softblock5 is a theme. Currently themes just get disabled when they become +// softblocked and have to be manually re-enabled if they become completely +// unblocked (bug 657520) + +const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul"; + +Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +// Allow insecure updates +Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false) + +do_load_httpd_js(); +var testserver; + +var default_theme = { + id: "default@tests.mozilla.org", + version: "1.0", + name: "Softblocked add-on", + internalName: "classic/1.0", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock1_1 = { + id: "softblock1@tests.mozilla.org", + version: "1.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update1.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock1_2 = { + id: "softblock1@tests.mozilla.org", + version: "2.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update2.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock1_3 = { + id: "softblock1@tests.mozilla.org", + version: "3.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update3.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock2_1 = { + id: "softblock2@tests.mozilla.org", + version: "1.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update1.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock2_2 = { + id: "softblock2@tests.mozilla.org", + version: "2.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update2.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock2_3 = { + id: "softblock2@tests.mozilla.org", + version: "3.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update3.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock3_1 = { + id: "softblock3@tests.mozilla.org", + version: "1.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update1.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock3_2 = { + id: "softblock3@tests.mozilla.org", + version: "2.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update2.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock3_3 = { + id: "softblock3@tests.mozilla.org", + version: "3.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update3.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock4_1 = { + id: "softblock4@tests.mozilla.org", + version: "1.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update1.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock4_2 = { + id: "softblock4@tests.mozilla.org", + version: "2.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update2.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock4_3 = { + id: "softblock4@tests.mozilla.org", + version: "3.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update3.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock5_1 = { + id: "softblock5@tests.mozilla.org", + version: "1.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update1.rdf", + internalName: "test/1.0", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock5_2 = { + id: "softblock5@tests.mozilla.org", + version: "2.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update2.rdf", + internalName: "test/1.0", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var softblock5_3 = { + id: "softblock5@tests.mozilla.org", + version: "3.0", + name: "Softblocked add-on", + updateURL: "http://localhost:4444/data/addon_update3.rdf", + internalName: "test/1.0", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var hardblock_1 = { + id: "hardblock@tests.mozilla.org", + version: "1.0", + name: "Hardblocked add-on", + updateURL: "http://localhost:4444/data/addon_update1.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var hardblock_2 = { + id: "hardblock@tests.mozilla.org", + version: "2.0", + name: "Hardblocked add-on", + updateURL: "http://localhost:4444/data/addon_update2.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +var hardblock_3 = { + id: "hardblock@tests.mozilla.org", + version: "3.0", + name: "Hardblocked add-on", + updateURL: "http://localhost:4444/data/addon_update3.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "3" + }] +}; + +const ADDON_IDS = ["softblock1@tests.mozilla.org", + "softblock2@tests.mozilla.org", + "softblock3@tests.mozilla.org", + "softblock4@tests.mozilla.org", + "softblock5@tests.mozilla.org", + "hardblock@tests.mozilla.org"]; + +// Don't need the full interface, attempts to call other methods will just +// throw which is just fine +var WindowWatcher = { + openWindow: function(parent, url, name, features, arguments) { + // Should be called to list the newly blocklisted items + do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG); + + // Simulate auto-disabling any softblocks + var list = arguments.wrappedJSObject.list; + list.forEach(function(aItem) { + if (!aItem.blocked) + aItem.disable = true; + }); + }, + + 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 InstallConfirm = { + confirm: function(aWindow, aUrl, aInstalls, aInstallCount) { + aInstalls.forEach(function(aInstall) { + aInstall.install(); + }); + }, + + QueryInterface: function(iid) { + if (iid.equals(Ci.amIWebInstallPrompt) + || iid.equals(Ci.nsISupports)) + return this; + + throw Cr.NS_ERROR_NO_INTERFACE; + } +}; + +var InstallConfirmFactory = { + createInstance: function createInstance(outer, iid) { + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + return InstallConfirm.QueryInterface(iid); + } +}; + +var registrar = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar); +registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), + "Fake Window Watcher", + "@mozilla.org/embedcomp/window-watcher;1", WindowWatcherFactory); +registrar.registerFactory(Components.ID("{f0863905-4dde-42e2-991c-2dc8209bc9ca}"), + "Fake Install Prompt", + "@mozilla.org/addons/web-install-prompt;1", InstallConfirmFactory); + +const profileDir = gProfD.clone(); +profileDir.append("extensions"); + +function load_blocklist(aFile, aCallback) { + Services.obs.addObserver(function() { + Services.obs.removeObserver(arguments.callee, "blocklist-updated"); + + do_execute_soon(aCallback); + }, "blocklist-updated", false); + + Services.prefs.setCharPref("extensions.blocklist.url", "http://localhost:4444/data/" + aFile); + var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]. + getService(Ci.nsITimerCallback); + blocklist.notify(null); +} + +// Does a background update check for add-ons and waits for any started installs +// to complete +function background_update(aCallback) { + var installCount = 0; + + AddonManager.addInstallListener({ + onNewInstall: function(aInstall) { + installCount++; + }, + + onInstallEnded: function(aInstall) { + installCount--; + if (installCount) + return; + + AddonManager.removeInstallListener(this); + + do_execute_soon(aCallback); + } + }); + + Services.obs.addObserver(function() { + Services.obs.removeObserver(arguments.callee, "addons-background-update-complete"); + + if (!installCount) + do_execute_soon(aCallback); + }, "addons-background-update-complete", false); + + AddonManagerPrivate.backgroundUpdateCheck(); +} + +// Manually updates the test add-ons to the given version +function manual_update(aVersion, aCallback) { + var installs = []; + AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_soft1_" + aVersion + ".xpi", + function(aInstall) { + installs.push(aInstall); + AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_soft2_" + aVersion + ".xpi", + function(aInstall) { + installs.push(aInstall); + AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_soft3_" + aVersion + ".xpi", + function(aInstall) { + installs.push(aInstall); + AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_soft4_" + aVersion + ".xpi", + function(aInstall) { + installs.push(aInstall); + AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_soft5_" + aVersion + ".xpi", + function(aInstall) { + installs.push(aInstall); + AddonManager.getInstallForURL("http://localhost:4444/addons/blocklist_hard1_" + aVersion + ".xpi", + function(aInstall) { + installs.push(aInstall); + + Services.obs.addObserver(function(aSubject, aTopic, aData) { + Services.obs.removeObserver(arguments.callee, "addon-install-blocked"); + + aSubject.QueryInterface(Ci.amIWebInstallInfo); + + var installCount = aSubject.installs.length; + + var listener = { + installComplete: function() { + installCount--; + if (installCount) + return; + + do_execute_soon(aCallback); + }, + + onDownloadCancelled: function(aInstall) { + this.installComplete(); + }, + + onInstallEnded: function(aInstall) { + this.installComplete(); + } + }; + + aSubject.installs.forEach(function(aInstall) { + aInstall.addListener(listener); + }); + + aSubject.install(); + }, "addon-install-blocked", false); + + AddonManager.installAddonsFromWebpage("application/x-xpinstall", null, + NetUtil.newURI("http://localhost:4444/"), + installs); + }, "application/x-xpinstall"); + }, "application/x-xpinstall"); + }, "application/x-xpinstall"); + }, "application/x-xpinstall"); + }, "application/x-xpinstall"); + }, "application/x-xpinstall"); +} + +// Checks that an add-ons properties match expected values +function check_addon(aAddon, aExpectedVersion, aExpectedUserDisabled, + aExpectedSoftDisabled, aExpectedState) { + dump("Testing " + aAddon.id + " version " + aAddon.version + "\n"); + dump(aAddon.userDisabled + " " + aAddon.softDisabled + "\n"); + + do_check_neq(aAddon, null); + do_check_eq(aAddon.version, aExpectedVersion); + do_check_eq(aAddon.userDisabled, aExpectedUserDisabled); + do_check_eq(aAddon.softDisabled, aExpectedSoftDisabled); + if (aAddon.softDisabled) + do_check_true(aAddon.userDisabled); + + if (aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED) { + do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE)); + do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE)); + } + else if (aAddon.userDisabled) { + do_check_true(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE)); + do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE)); + } + else { + do_check_false(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_ENABLE)); + if (aAddon.type != "theme") + do_check_true(hasFlag(aAddon.permissions, AddonManager.PERM_CAN_DISABLE)); + } + do_check_eq(aAddon.appDisabled, aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(aAddon.blocklistState, aExpectedState); + + let willBeActive = aAddon.isActive; + if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_DISABLE)) + willBeActive = false; + else if (hasFlag(aAddon.pendingOperations, AddonManager.PENDING_ENABLE)) + willBeActive = true; + + if (aExpectedUserDisabled || aExpectedState == Ci.nsIBlocklistService.STATE_BLOCKED) { + do_check_false(willBeActive); + } + else { + do_check_true(willBeActive); + } +} + +function run_test() { + // Create and configure the HTTP server. + testserver = new nsHttpServer(); + testserver.registerDirectory("/data/", do_get_file("data/blocklistchange")); + testserver.registerDirectory("/addons/", do_get_file("addons")); + testserver.start(4444); + + do_test_pending(); + + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1"); + writeInstallRDFForExtension(default_theme, profileDir); + writeInstallRDFForExtension(softblock1_1, profileDir); + writeInstallRDFForExtension(softblock2_1, profileDir); + writeInstallRDFForExtension(softblock3_1, profileDir); + writeInstallRDFForExtension(softblock4_1, profileDir); + writeInstallRDFForExtension(softblock5_1, profileDir); + writeInstallRDFForExtension(hardblock_1, profileDir); + startupManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + s4.userDisabled = true; + s5.userDisabled = false; + restartManager(); + + run_app_update_test(); + }); +} + +function end_test() { + testserver.stop(do_test_finished); +} + +// Starts with add-ons unblocked and then switches application versions to +// change add-ons to blocked and back +function run_app_update_test() { + dump(arguments.callee.name + "\n"); + load_blocklist("app_update.xml", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0"); + + restartManager("2"); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + restartManager("2.5"); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + restartManager("1"); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s1.userDisabled = false; + s2.userDisabled = false; + s5.userDisabled = false; + run_app_update_schema_test(); + }); + }); + }); + }); + }); +} + +// Starts with add-ons unblocked and then switches application versions to +// change add-ons to blocked and back. A DB schema change is faked to force a +// rebuild when the application version changes +function run_app_update_schema_test() { + dump(arguments.callee.name + "\n"); + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0"); + + shutdownManager(); + var dbfile = gProfD.clone(); + dbfile.append("extensions.sqlite"); + var db = Services.storage.openDatabase(dbfile); + db.schemaVersion = 100; + db.close(); + gAppInfo.version = "2"; + startupManager(true); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + shutdownManager(); + var dbfile = gProfD.clone(); + dbfile.append("extensions.sqlite"); + var db = Services.storage.openDatabase(dbfile); + db.schemaVersion = 100; + db.close(); + gAppInfo.version = "2.5"; + startupManager(true); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + shutdownManager(); + var dbfile = gProfD.clone(); + dbfile.append("extensions.sqlite"); + var db = Services.storage.openDatabase(dbfile); + db.schemaVersion = 100; + db.close(); + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + shutdownManager(); + var dbfile = gProfD.clone(); + dbfile.append("extensions.sqlite"); + var db = Services.storage.openDatabase(dbfile); + db.schemaVersion = 100; + db.close(); + gAppInfo.version = "1"; + startupManager(true); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s1.userDisabled = false; + s2.userDisabled = false; + s5.userDisabled = false; + run_blocklist_update_test(); + }); + }); + }); + }); + }); +} + +// Starts with add-ons unblocked and then loads new blocklists to change add-ons +// to blocked and back again. +function run_blocklist_update_test() { + dump(arguments.callee.name + "\n"); + load_blocklist("blocklist_update1.xml", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0"); + + load_blocklist("blocklist_update2.xml", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + load_blocklist("blocklist_update2.xml", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + load_blocklist("blocklist_update1.xml", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s1.userDisabled = false; + s2.userDisabled = false; + s5.userDisabled = false; + run_addon_change_test(); + }); + }); + }); + }); + }); + }); + }); + }); +} + +// Starts with add-ons unblocked and then new versions are installed outside of +// the app to change them to blocked and back again. +function run_addon_change_test() { + dump(arguments.callee.name + "\n"); + load_blocklist("addon_change.xml", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "test/1.0"); + + shutdownManager(); + + writeInstallRDFForExtension(softblock1_2, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_2.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock2_2, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_2.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock3_2, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_2.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock4_2, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_2.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock5_2, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_2.id), Date.now() + 10000); + writeInstallRDFForExtension(hardblock_2, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_2.id), Date.now() + 10000); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + shutdownManager(); + + writeInstallRDFForExtension(softblock1_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_3.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock2_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_3.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock3_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_3.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock4_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_3.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock5_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_3.id), Date.now() + 20000); + writeInstallRDFForExtension(hardblock_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 20000); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + shutdownManager(); + + writeInstallRDFForExtension(softblock1_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_1.id), Date.now() + 30000); + writeInstallRDFForExtension(softblock2_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_1.id), Date.now() + 30000); + writeInstallRDFForExtension(softblock3_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_1.id), Date.now() + 30000); + writeInstallRDFForExtension(softblock4_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_1.id), Date.now() + 30000); + writeInstallRDFForExtension(softblock5_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_1.id), Date.now() + 30000); + writeInstallRDFForExtension(hardblock_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 30000); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + do_check_eq(Services.prefs.getCharPref("general.skins.selectedSkin"), "classic/1.0"); + + s1.userDisabled = false; + s2.userDisabled = false; + s5.userDisabled = false; + run_addon_change_2_test(); + }); + }); + }); + }); + }); +} + +// Starts with add-ons blocked and then new versions are installed outside of +// the app to change them to unblocked. +function run_addon_change_2_test() { + dump(arguments.callee.name + "\n"); + shutdownManager(); + + getFileForAddon(profileDir, softblock1_1.id).remove(true); + getFileForAddon(profileDir, softblock2_1.id).remove(true); + getFileForAddon(profileDir, softblock3_1.id).remove(true); + getFileForAddon(profileDir, softblock4_1.id).remove(true); + getFileForAddon(profileDir, softblock5_1.id).remove(true); + getFileForAddon(profileDir, hardblock_1.id).remove(true); + + startupManager(false); + shutdownManager(); + + writeInstallRDFForExtension(softblock1_2, profileDir); + writeInstallRDFForExtension(softblock2_2, profileDir); + writeInstallRDFForExtension(softblock3_2, profileDir); + writeInstallRDFForExtension(softblock4_2, profileDir); + writeInstallRDFForExtension(softblock5_2, profileDir); + writeInstallRDFForExtension(hardblock_2, profileDir); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "2.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + shutdownManager(); + + writeInstallRDFForExtension(softblock1_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_3.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock2_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_3.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock3_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_3.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock4_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_3.id), Date.now() + 10000); + writeInstallRDFForExtension(softblock5_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_3.id), Date.now() + 10000); + writeInstallRDFForExtension(hardblock_3, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_3.id), Date.now() + 10000); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + shutdownManager(); + + writeInstallRDFForExtension(softblock1_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock1_1.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock2_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock2_1.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock3_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock3_1.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock4_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock4_1.id), Date.now() + 20000); + writeInstallRDFForExtension(softblock5_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, softblock5_1.id), Date.now() + 20000); + writeInstallRDFForExtension(hardblock_1, profileDir); + setExtensionModifiedTime(getFileForAddon(profileDir, hardblock_1.id), Date.now() + 20000); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + + s1.userDisabled = false; + s2.userDisabled = false; + s4.userDisabled = true; + s5.userDisabled = false; + run_background_update_test(); + }); + }); + }); +} + +// Add-ons are initially unblocked then attempts to upgrade to blocked versions +// in the background which should fail +function run_background_update_test() { + dump(arguments.callee.name + "\n"); + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + + background_update(function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + + run_background_update_2_test(); + }); + }); + }); +} + +// Starts with add-ons blocked and then new versions are detected and installed +// automatically for unblocked versions. +function run_background_update_2_test() { + dump(arguments.callee.name + "\n"); + shutdownManager(); + + getFileForAddon(profileDir, softblock1_1.id).remove(true); + getFileForAddon(profileDir, softblock2_1.id).remove(true); + getFileForAddon(profileDir, softblock3_1.id).remove(true); + getFileForAddon(profileDir, softblock4_1.id).remove(true); + getFileForAddon(profileDir, softblock5_1.id).remove(true); + getFileForAddon(profileDir, hardblock_1.id).remove(true); + + startupManager(false); + shutdownManager(); + + writeInstallRDFForExtension(softblock1_3, profileDir); + writeInstallRDFForExtension(softblock2_3, profileDir); + writeInstallRDFForExtension(softblock3_3, profileDir); + writeInstallRDFForExtension(softblock4_3, profileDir); + writeInstallRDFForExtension(softblock5_3, profileDir); + writeInstallRDFForExtension(hardblock_3, profileDir); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "3.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + background_update(function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + + s1.userDisabled = false; + s2.userDisabled = false; + s4.userDisabled = true; + s5.userDisabled = true; + run_manual_update_test(); + }); + }); + }); +} + +// Starts with add-ons blocked and then simulates the user upgrading them to +// unblocked versions. +function run_manual_update_test() { + dump(arguments.callee.name + "\n"); + restartManager(); + load_blocklist("manual_update.xml", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + manual_update("2", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s4, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s5, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + // Can't manually update to a hardblocked add-on + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + manual_update("3", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s4, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s5, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + + run_manual_update_2_test(); + }); + }); + }); + }); + }); + }); +} + +// Starts with add-ons blocked and then new versions are installed outside of +// the app to change them to unblocked. +function run_manual_update_2_test() { + dump(arguments.callee.name + "\n"); + shutdownManager(); + + getFileForAddon(profileDir, softblock1_1.id).remove(true); + getFileForAddon(profileDir, softblock2_1.id).remove(true); + getFileForAddon(profileDir, softblock3_1.id).remove(true); + getFileForAddon(profileDir, softblock4_1.id).remove(true); + getFileForAddon(profileDir, softblock5_1.id).remove(true); + getFileForAddon(profileDir, hardblock_1.id).remove(true); + + startupManager(false); + shutdownManager(); + + writeInstallRDFForExtension(softblock1_1, profileDir); + writeInstallRDFForExtension(softblock2_1, profileDir); + writeInstallRDFForExtension(softblock3_1, profileDir); + writeInstallRDFForExtension(softblock4_1, profileDir); + writeInstallRDFForExtension(softblock5_1, profileDir); + writeInstallRDFForExtension(hardblock_1, profileDir); + + startupManager(false); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + s2.userDisabled = false; + s2.userDisabled = true; + check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + s3.userDisabled = false; + check_addon(s3, "1.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + restartManager(); + + manual_update("2", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "2.0", false, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + // Can't manually update to a hardblocked add-on + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + restartManager(); + + manual_update("3", function() { + restartManager(); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(s3, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + check_addon(h, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); + + s1.userDisabled = false; + s2.userDisabled = false; + s4.userDisabled = true; + run_local_install_test(); + }); + }); + }); + }); + }); +} + +// Uses the API to install blocked add-ons from the local filesystem +function run_local_install_test() { + dump(arguments.callee.name + "\n"); + shutdownManager(); + + getFileForAddon(profileDir, softblock1_1.id).remove(true); + getFileForAddon(profileDir, softblock2_1.id).remove(true); + getFileForAddon(profileDir, softblock3_1.id).remove(true); + getFileForAddon(profileDir, softblock4_1.id).remove(true); + getFileForAddon(profileDir, softblock5_1.id).remove(true); + getFileForAddon(profileDir, hardblock_1.id).remove(true); + + startupManager(false); + + installAllFiles([ + do_get_file("addons/blocklist_soft1_1.xpi"), + do_get_file("addons/blocklist_soft2_1.xpi"), + do_get_file("addons/blocklist_soft3_1.xpi"), + do_get_file("addons/blocklist_soft4_1.xpi"), + do_get_file("addons/blocklist_soft5_1.xpi"), + do_get_file("addons/blocklist_hard1_1.xpi") + ], function() { + AddonManager.getAllInstalls(function(aInstalls) { + // Should have finished all installs without needing to restart + do_check_eq(aInstalls.length, 0); + + AddonManager.getAddonsByIDs(ADDON_IDS, function([s1, s2, s3, s4, s5, h]) { + + check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(s3, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); + check_addon(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); + + end_test(); + }); + }); + }); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js b/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js index 56a8d110c980..767c5437f114 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js @@ -239,7 +239,7 @@ function load_blocklist(file) { } function check_addon_state(addon) { - return addon.userDisabled + "," + addon.appDisabled; + return addon.userDisabled + "," + addon.softDisabled + "," + addon.appDisabled; } function check_plugin_state(plugin) { @@ -278,13 +278,13 @@ function run_test() { // Before every main test this is the state the add-ons are meant to be in function check_initial_state(callback) { AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], function(addons) { - do_check_eq(check_addon_state(addons[0]), "true,false"); - do_check_eq(check_addon_state(addons[1]), "false,false"); - do_check_eq(check_addon_state(addons[2]), "false,false"); - do_check_eq(check_addon_state(addons[3]), "true,false"); - do_check_eq(check_addon_state(addons[4]), "false,false"); - do_check_eq(check_addon_state(addons[5]), "false,true"); - do_check_eq(check_addon_state(addons[6]), "false,true"); + do_check_eq(check_addon_state(addons[0]), "true,false,false"); + do_check_eq(check_addon_state(addons[1]), "false,false,false"); + do_check_eq(check_addon_state(addons[2]), "false,false,false"); + do_check_eq(check_addon_state(addons[3]), "true,true,false"); + do_check_eq(check_addon_state(addons[4]), "false,false,false"); + do_check_eq(check_addon_state(addons[5]), "false,false,true"); + do_check_eq(check_addon_state(addons[6]), "false,false,true"); do_check_eq(check_plugin_state(PLUGINS[0]), "true,false"); do_check_eq(check_plugin_state(PLUGINS[1]), "false,false"); @@ -307,17 +307,17 @@ function check_test_pt1() { do_throw("Addon " + (i + 1) + " did not get installed correctly"); } - do_check_eq(check_addon_state(addons[0]), "false,false"); - do_check_eq(check_addon_state(addons[1]), "false,false"); - do_check_eq(check_addon_state(addons[2]), "false,false"); + do_check_eq(check_addon_state(addons[0]), "false,false,false"); + do_check_eq(check_addon_state(addons[1]), "false,false,false"); + do_check_eq(check_addon_state(addons[2]), "false,false,false"); - // Warn add-ons should be user disabled automatically - do_check_eq(check_addon_state(addons[3]), "true,false"); - do_check_eq(check_addon_state(addons[4]), "true,false"); + // Warn add-ons should be soft disabled automatically + do_check_eq(check_addon_state(addons[3]), "true,true,false"); + do_check_eq(check_addon_state(addons[4]), "true,true,false"); // Blocked and incompatible should be app disabled only - do_check_eq(check_addon_state(addons[5]), "false,true"); - do_check_eq(check_addon_state(addons[6]), "false,true"); + do_check_eq(check_addon_state(addons[5]), "false,false,true"); + do_check_eq(check_addon_state(addons[6]), "false,false,true"); // We've overridden the plugin host so we cannot tell what that would have // initialised the plugins as @@ -376,19 +376,19 @@ function check_test_pt2() { AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], function(addons) { // Should have disabled this add-on as requested - do_check_eq(check_addon_state(addons[2]), "true,false"); + do_check_eq(check_addon_state(addons[2]), "true,true,false"); do_check_eq(check_plugin_state(PLUGINS[2]), "true,false"); - // The blocked add-on should have changed to user disabled - do_check_eq(check_addon_state(addons[5]), "true,false"); + // The blocked add-on should have changed to soft disabled + do_check_eq(check_addon_state(addons[5]), "true,true,false"); do_check_eq(check_plugin_state(PLUGINS[5]), "true,false"); // These should have been unchanged - do_check_eq(check_addon_state(addons[0]), "true,false"); - do_check_eq(check_addon_state(addons[1]), "false,false"); - do_check_eq(check_addon_state(addons[3]), "true,false"); - do_check_eq(check_addon_state(addons[4]), "false,false"); - do_check_eq(check_addon_state(addons[6]), "false,true"); + do_check_eq(check_addon_state(addons[0]), "true,false,false"); + do_check_eq(check_addon_state(addons[1]), "false,false,false"); + do_check_eq(check_addon_state(addons[3]), "true,true,false"); + do_check_eq(check_addon_state(addons[4]), "false,false,false"); + do_check_eq(check_addon_state(addons[6]), "false,false,true"); do_check_eq(check_plugin_state(PLUGINS[0]), "true,false"); do_check_eq(check_plugin_state(PLUGINS[1]), "false,false"); do_check_eq(check_plugin_state(PLUGINS[3]), "true,false"); @@ -460,20 +460,22 @@ function check_test_pt3() { AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], function(addons) { // All should have gained the blocklist state, user disabled as previously - do_check_eq(check_addon_state(addons[0]), "true,true"); - do_check_eq(check_addon_state(addons[1]), "false,true"); - do_check_eq(check_addon_state(addons[2]), "false,true"); - do_check_eq(check_addon_state(addons[3]), "true,true"); - do_check_eq(check_addon_state(addons[4]), "false,true"); + do_check_eq(check_addon_state(addons[0]), "true,false,true"); + do_check_eq(check_addon_state(addons[1]), "false,false,true"); + do_check_eq(check_addon_state(addons[2]), "false,false,true"); + do_check_eq(check_addon_state(addons[4]), "false,false,true"); do_check_eq(check_plugin_state(PLUGINS[0]), "true,true"); do_check_eq(check_plugin_state(PLUGINS[1]), "false,true"); do_check_eq(check_plugin_state(PLUGINS[2]), "false,true"); do_check_eq(check_plugin_state(PLUGINS[3]), "true,true"); do_check_eq(check_plugin_state(PLUGINS[4]), "false,true"); + // Should have gained the blocklist state but no longer be soft disabled + do_check_eq(check_addon_state(addons[3]), "false,false,true"); + // Shouldn't be changed - do_check_eq(check_addon_state(addons[5]), "false,true"); - do_check_eq(check_addon_state(addons[6]), "false,true"); + do_check_eq(check_addon_state(addons[5]), "false,false,true"); + do_check_eq(check_addon_state(addons[6]), "false,false,true"); do_check_eq(check_plugin_state(PLUGINS[5]), "false,true"); // Back to starting state @@ -511,16 +513,18 @@ function check_test_pt4() { AddonManager.getAddonsByIDs([a.id for each (a in ADDONS)], function(addons) { // This should have become unblocked - do_check_eq(check_addon_state(addons[5]), "false,false"); + do_check_eq(check_addon_state(addons[5]), "false,false,false"); do_check_eq(check_plugin_state(PLUGINS[5]), "false,false"); + // Should get re-enabled + do_check_eq(check_addon_state(addons[3]), "false,false,false"); + // No change for anything else - do_check_eq(check_addon_state(addons[0]), "true,false"); - do_check_eq(check_addon_state(addons[1]), "false,false"); - do_check_eq(check_addon_state(addons[2]), "false,false"); - do_check_eq(check_addon_state(addons[3]), "true,false"); - do_check_eq(check_addon_state(addons[4]), "false,false"); - do_check_eq(check_addon_state(addons[6]), "false,true"); + do_check_eq(check_addon_state(addons[0]), "true,false,false"); + do_check_eq(check_addon_state(addons[1]), "false,false,false"); + do_check_eq(check_addon_state(addons[2]), "false,false,false"); + do_check_eq(check_addon_state(addons[4]), "false,false,false"); + do_check_eq(check_addon_state(addons[6]), "false,false,true"); do_check_eq(check_plugin_state(PLUGINS[0]), "true,false"); do_check_eq(check_plugin_state(PLUGINS[1]), "false,false"); do_check_eq(check_plugin_state(PLUGINS[2]), "false,false");