author | Gijs Kruitbosch <gijskruitbosch@gmail.com> |
Mon, 09 Apr 2018 16:00:38 +0100 | |
changeset 413930 | a0a108e7e7b34e2f90a9298d225ae811024615dd |
parent 413929 | 72b3036ce450e15157420a195d86faf7289996cf |
child 413931 | fe275b0fa525753b745dae89c24fa19ad983d206 |
push id | 33853 |
push user | cbrindusan@mozilla.com |
push date | Tue, 17 Apr 2018 09:51:13 +0000 |
treeherder | mozilla-central@8b0ba3f7d099 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | kmag |
bugs | 1452618 |
milestone | 61.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm +++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm @@ -121,17 +121,18 @@ class MockBlocklist { unregister() { MockRegistrar.unregister(this.originalCID); } getAddonBlocklistState(addon, appVersion, toolkitVersion) { return this.addons.get(addon.id, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); } - getAddonBlocklistEntry(addon, appVersion, toolkitVersion) { + async getAddonBlocklistEntry(addon, appVersion, toolkitVersion) { + await Promise.resolve(); let state = this.getAddonBlocklistState(addon, appVersion, toolkitVersion); if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) { return { state, url: "http://example.com/", }; } return null;
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm +++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm @@ -851,17 +851,17 @@ function generateTemporaryInstallID(aFil const sess = TEMP_INSTALL_ID_GEN_SESSION; hasher.update(sess, sess.length); hasher.update(data, data.length); let id = `${getHashStringForCrypto(hasher)}${TEMPORARY_ADDON_SUFFIX}`; logger.info(`Generated temp id ${id} (${sess.join("")}) for ${aFile.path}`); return id; } -var loadManifest = async function(aPackage, aInstallLocation) { +var loadManifest = async function(aPackage, aInstallLocation, aOldAddon) { async function loadFromRDF(aUri) { let manifest = await aPackage.readString("install.rdf"); let addon = await loadManifestFromRDF(aUri, manifest); if (await aPackage.hasResource("icon.png")) { addon.icons[32] = "icon.png"; addon.icons[48] = "icon.png"; } @@ -904,28 +904,28 @@ var loadManifest = async function(aPacka throw new Error(`Webextension is signed with an invalid id (${addon.id})`); } } if (!addon.id && aInstallLocation.name == KEY_APP_TEMPORARY) { addon.id = generateTemporaryInstallID(aPackage.file); } } - addon.updateBlocklistState(); + await addon.updateBlocklistState({oldAddon: aOldAddon}); addon.appDisabled = !isUsableAddon(addon); defineSyncGUID(addon); return addon; }; -var loadManifestFromFile = async function(aFile, aInstallLocation) { +var loadManifestFromFile = async function(aFile, aInstallLocation, aOldAddon) { let pkg = Package.get(aFile); try { - let addon = await loadManifest(pkg, aInstallLocation); + let addon = await loadManifest(pkg, aInstallLocation, aOldAddon); return addon; } finally { pkg.close(); } }; function flushChromeCaches() { // Init this, so it will get the notification. @@ -1425,17 +1425,17 @@ class AddonInstall { try { pkg = Package.get(file); } catch (e) { return Promise.reject([AddonManager.ERROR_CORRUPT_FILE, e]); } try { try { - this.addon = await loadManifest(pkg, this.installLocation); + this.addon = await loadManifest(pkg, this.installLocation, this.existingAddon); } catch (e) { return Promise.reject([AddonManager.ERROR_CORRUPT_FILE, e]); } if (!this.addon.id) { let err = new Error(`Cannot find id for addon ${file.path}`); return Promise.reject([AddonManager.ERROR_CORRUPT_FILE, err]); } @@ -1893,17 +1893,17 @@ var LocalAddonInstall = class extends Ad return; } let addon = await new Promise(resolve => { XPIDatabase.getVisibleAddonForID(this.addon.id, resolve); }); this.existingAddon = addon; - this.addon.updateBlocklistState({oldAddon: this.existingAddon}); + await this.addon.updateBlocklistState({oldAddon: this.existingAddon}); this.addon.updateDate = Date.now(); this.addon.installDate = addon ? addon.installDate : this.addon.updateDate; if (!this.addon.isCompatible) { this.state = AddonManager.STATE_CHECKING; await new Promise(resolve => { new UpdateChecker(this.addon, { @@ -2286,30 +2286,30 @@ var DownloadAddonInstall = class extends logger.debug("downloadFailed: listener changed AddonInstall state for " + this.sourceURI.spec + " to " + this.state); } /** * Notify listeners that the download completed. */ downloadCompleted() { - XPIDatabase.getVisibleAddonForID(this.addon.id, aAddon => { + XPIDatabase.getVisibleAddonForID(this.addon.id, async aAddon => { if (aAddon) this.existingAddon = aAddon; this.state = AddonManager.STATE_DOWNLOADED; this.addon.updateDate = Date.now(); if (this.existingAddon) { this.addon.existingAddonID = this.existingAddon.id; this.addon.installDate = this.existingAddon.installDate; } else { this.addon.installDate = this.addon.updateDate; } - this.addon.updateBlocklistState({oldAddon: this.existingAddon}); + await this.addon.updateBlocklistState({oldAddon: this.existingAddon}); if (AddonManagerPrivate.callInstallListeners("onDownloadEnded", this.listeners, this.wrapper)) { // If a listener changed our state then do not proceed with the install if (this.state != AddonManager.STATE_DOWNLOADED) return;
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -904,21 +904,21 @@ function getAllAliasesForTypes(aTypes) { return [...typeset]; } /** * A synchronous method for loading an add-on's manifest. This should only ever * be used during startup or a sync load of the add-ons DB */ -function syncLoadManifestFromFile(aFile, aInstallLocation) { +function syncLoadManifestFromFile(aFile, aInstallLocation, aOldAddon) { let success = undefined; let result = null; - loadManifestFromFile(aFile, aInstallLocation).then(val => { + loadManifestFromFile(aFile, aInstallLocation, aOldAddon).then(val => { success = true; result = val; }, val => { success = false; result = val; }); Services.tm.spinEventLoopUntil(() => success !== undefined); @@ -4488,40 +4488,40 @@ AddonInternal.prototype = { if (targetApp.id == Services.appinfo.ID) return targetApp; if (targetApp.id == TOOLKIT_ID) app = targetApp; } return app; }, - findBlocklistEntry() { + async findBlocklistEntry() { let staticItem = findMatchingStaticBlocklistItem(this); if (staticItem) { let url = Services.urlFormatter.formatURLPref(PREF_BLOCKLIST_ITEM_URL); return { state: staticItem.level, url: url.replace(/%blockID%/g, staticItem.blockID) }; } return Blocklist.getAddonBlocklistEntry(this.wrapper); }, - updateBlocklistState(options = {}) { + async updateBlocklistState(options = {}) { let {applySoftBlock = true, oldAddon = null, updateDatabase = true} = options; if (oldAddon) { this.userDisabled = oldAddon.userDisabled; this.softDisabled = oldAddon.softDisabled; this.blocklistState = oldAddon.blocklistState; } let oldState = this.blocklistState; - let entry = this.findBlocklistEntry(); + let entry = await this.findBlocklistEntry(); let newState = entry ? entry.state : Blocklist.STATE_NOT_BLOCKED; this.blocklistState = newState; this.blocklistURL = entry && entry.url; let userDisabled, softDisabled; // After a blocklist update, the blocklist service manually applies // new soft blocks after displaying a UI, in which cases we need to @@ -4932,17 +4932,17 @@ AddonWrapper.prototype = { let activeAddon = XPIProvider.activeAddons.get(addon.id); if (activeAddon) return activeAddon.startupPromise || null; return null; }, updateBlocklistState(applySoftBlock = true) { - addonFor(this).updateBlocklistState({applySoftBlock}); + return addonFor(this).updateBlocklistState({applySoftBlock}); }, get userDisabled() { let addon = addonFor(this); return addon.softDisabled || addon.userDisabled; }, set userDisabled(val) { let addon = addonFor(this);
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js +++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js @@ -1220,19 +1220,17 @@ this.XPIDatabaseReconcile = { */ updateMetadata(aInstallLocation, aOldAddon, aAddonState, aNewAddon) { logger.debug("Add-on " + aOldAddon.id + " modified in " + aInstallLocation.name); try { // If there isn't an updated install manifest for this add-on then load it. if (!aNewAddon) { let file = new nsIFile(aAddonState.path); - aNewAddon = syncLoadManifestFromFile(file, aInstallLocation); - - aNewAddon.updateBlocklistState({oldAddon: aOldAddon}); + aNewAddon = syncLoadManifestFromFile(file, aInstallLocation, aOldAddon); } // The ID in the manifest that was loaded must match the ID of the old // add-on. if (aNewAddon.id != aOldAddon.id) throw new Error("Incorrect id in install manifest for existing add-on " + aOldAddon.id); } catch (e) { logger.warn("updateMetadata: Add-on " + aOldAddon.id + " is invalid", e); @@ -1281,29 +1279,22 @@ this.XPIDatabaseReconcile = { * * @param aInstallLocation * The install location containing the add-on * @param aOldAddon * The AddonInternal as it appeared the last time the application * ran * @param aAddonState * The new state of the add-on - * @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 aReloadMetadata * A boolean which indicates whether metadata should be reloaded from * the addon manifests. Default to false. * @return the new addon. */ - updateCompatibility(aInstallLocation, aOldAddon, aAddonState, aOldAppVersion, - aOldPlatformVersion, aReloadMetadata) { + updateCompatibility(aInstallLocation, aOldAddon, aAddonState, aReloadMetadata) { logger.debug("Updating compatibility for add-on " + aOldAddon.id + " in " + aInstallLocation.name); let checkSigning = aOldAddon.signedState === undefined && ADDON_SIGNING && SIGNED_TYPES.has(aOldAddon.type); let manifest = null; if (checkSigning || aReloadMetadata) { try { @@ -1332,17 +1323,16 @@ this.XPIDatabaseReconcile = { let remove = ["syncGUID", "foreignInstall", "visible", "active", "userDisabled", "applyBackgroundUpdates", "sourceURI", "releaseNotesURI", "targetApplications"]; let props = PROP_JSON_FIELDS.filter(a => !remove.includes(a)); copyProperties(manifest, props, aOldAddon); } - aOldAddon.updateBlocklistState({updateDatabase: false}); aOldAddon.appDisabled = !isUsableAddon(aOldAddon); return aOldAddon; }, /** * Compares the add-ons that are currently installed to those that were * known to be installed when the application last ran and applies any @@ -1395,16 +1385,20 @@ this.XPIDatabaseReconcile = { let locationAddonMap = previousAddons.get(a.location); if (!locationAddonMap) { locationAddonMap = new Map(); previousAddons.set(a.location, locationAddonMap); } locationAddonMap.set(a.id, a); } + // Keep track of add-ons whose blocklist status may have changed. We'll check this + // after everything else. + let addonsToCheckAgainstBlocklist = []; + // Build the list of current add-ons into similar maps. When add-ons are still // present we re-use the add-on objects from the database and update their // details directly let currentAddons = new Map(); for (let installLocation of XPIProvider.installLocations) { let locationAddonMap = new Map(); currentAddons.set(installLocation.name, locationAddonMap); @@ -1449,18 +1443,20 @@ this.XPIDatabaseReconcile = { newAddon = this.updateMetadata(installLocation, oldAddon, xpiState, newAddon); } else if (oldPath != xpiState.path) { newAddon = this.updatePath(installLocation, oldAddon, xpiState); } else if (aUpdateCompatibility || aSchemaChange) { // Check compatility when the application version and/or schema // version has changed. A schema change also reloads metadata from // the manifests. newAddon = this.updateCompatibility(installLocation, oldAddon, xpiState, - aOldAppVersion, aOldPlatformVersion, aSchemaChange); + // We need to do a blocklist check later, but the add-on may have changed by then. + // Avoid storing the current copy and just get one when we need one instead. + addonsToCheckAgainstBlocklist.push(newAddon.id); } else { // No change newAddon = oldAddon; } if (newAddon) locationAddonMap.set(newAddon.id, newAddon); } else { @@ -1655,11 +1651,31 @@ this.XPIDatabaseReconcile = { } } XPIStates.save(); // Clear out any cached migration data. XPIDatabase.migrateData = null; XPIDatabase.saveChanges(); + // Do some blocklist checks. These will happen after we've just saved everything, + // because they're async and depend on the blocklist loading. When we're done, save + // the data if any of the add-ons' blocklist state has changed. + AddonManager.shutdown.addBlocker( + "Update add-on blocklist state into add-on DB", + (async () => { + // Avoid querying the AddonManager immediately to give startup a chance + // to complete. + await Promise.resolve(); + let addons = await AddonManager.getAddonsByIDs(addonsToCheckAgainstBlocklist); + await Promise.all(addons.map(addon => { + if (addon) { + return addon.updateBlocklistState({updateDatabase: false}); + } + return null; + })); + XPIDatabase.saveChanges(); + })().catch(Cu.reportError) + ); + return true; }, };
--- a/toolkit/mozapps/extensions/nsBlocklistService.js +++ b/toolkit/mozapps/extensions/nsBlocklistService.js @@ -339,19 +339,18 @@ Blocklist.prototype = { Ci.nsIBlocklistService.STATE_BLOCKED : Ci.nsIBlocklistService.STATE_SOFTBLOCKED), url: blItem.blockID && this._createBlocklistURL(blItem.blockID), }; } } return null; }, - getAddonBlocklistEntry(addon, appVersion, toolkitVersion) { - if (!this.isLoaded) - this._loadBlocklist(); + async getAddonBlocklistEntry(addon, appVersion, toolkitVersion) { + await this.loadBlocklistAsync(); return this._getAddonBlocklistEntry(addon, this._addonEntries, appVersion, toolkitVersion); }, /** * Private version of getAddonBlocklistState that allows the caller to pass in * the add-on blocklist entries to compare against. * @@ -761,19 +760,30 @@ Blocklist.prototype = { return this._addonEntries != null && this._gfxEntries != null && this._pluginEntries != null; }, /* Used for testing */ _clear() { this._addonEntries = null; this._gfxEntries = null; this._pluginEntries = null; + delete this._preloadPromise; }, async loadBlocklistAsync() { + if (this.isLoaded) { + return; + } + if (!this._preloadPromise) { + this._preloadPromise = this._loadBlocklistAsyncInternal(); + } + await this._preloadPromise; + }, + + async _loadBlocklistAsyncInternal() { let profPath = OS.Path.join(OS.Constants.Path.profileDir, FILE_BLOCKLIST); try { await this._preloadBlocklistFile(profPath); return; } catch (e) { LOG("Blocklist::loadBlocklistAsync: Failed to load XML file " + e); } @@ -781,21 +791,25 @@ Blocklist.prototype = { try { await this._preloadBlocklistFile(appFile.path); return; } catch (e) { LOG("Blocklist::loadBlocklistAsync: Failed to load XML file " + e); } LOG("Blocklist::loadBlocklistAsync: no XML File found"); + // Neither file is present, so we just add empty lists, to avoid JS errors fetching + // blocklist information otherwise. + this._addonEntries = []; + this._gfxEntries = []; + this._pluginEntries = []; }, async _preloadBlocklistFile(path) { - if (this._addonEntries) { - // The file has been already loaded. + if (this.isLoaded) { return; } if (!gBlocklistEnabled) { LOG("Blocklist::_preloadBlocklistFile: blocklist is disabled"); return; } @@ -1212,197 +1226,196 @@ Blocklist.prototype = { Services.obs.notifyObservers(null, "blocklist-data-gfxItems", payload); }, _notifyObserversBlocklistUpdated() { Services.obs.notifyObservers(this, "blocklist-updated"); Services.ppmm.broadcastAsyncMessage("Blocklist:blocklistInvalidated", {}); }, - _blocklistUpdated(oldAddonEntries, oldPluginEntries) { + async _blocklistUpdated(oldAddonEntries, oldPluginEntries) { var addonList = []; // A helper function that reverts the prefs passed to default values. function resetPrefs(prefs) { for (let pref of prefs) Services.prefs.clearUserPref(pref); } const types = ["extension", "theme", "locale", "dictionary", "service"]; - AddonManager.getAddonsByTypes(types, addons => { - for (let addon of addons) { - let oldState = addon.blocklistState; - if (addon.updateBlocklistState) { - addon.updateBlocklistState(false); - } else if (oldAddonEntries) { - oldState = this._getAddonBlocklistState(addon, oldAddonEntries); - } else { - oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED; - } - let state = addon.blocklistState; + let addons = await AddonManager.getAddonsByTypes(types); + for (let addon of addons) { + let oldState = addon.blocklistState; + if (addon.updateBlocklistState) { + await addon.updateBlocklistState(false); + } else if (oldAddonEntries) { + oldState = this._getAddonBlocklistState(addon, oldAddonEntries); + } else { + oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED; + } + let state = addon.blocklistState; + + LOG("Blocklist state for " + addon.id + " changed from " + + oldState + " to " + state); + + // We don't want to re-warn about add-ons + if (state == oldState) + continue; + + if (state === Ci.nsIBlocklistService.STATE_BLOCKED) { + // It's a hard block. We must reset certain preferences. + let prefs = this._getAddonPrefs(addon); + resetPrefs(prefs); + } + + // Ensure that softDisabled is false if the add-on is not soft blocked + if (state != Ci.nsIBlocklistService.STATE_SOFTBLOCKED) + addon.softDisabled = false; + + // Don't warn about add-ons becoming unblocked. + if (state == Ci.nsIBlocklistService.STATE_NOT_BLOCKED) + continue; - LOG("Blocklist state for " + addon.id + " changed from " + - oldState + " to " + state); + // If an add-on has dropped from hard to soft blocked just mark it as + // soft disabled and don't warn about it. + if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED && + oldState == Ci.nsIBlocklistService.STATE_BLOCKED) { + addon.softDisabled = true; + continue; + } + + // If the add-on is already disabled for some reason then don't warn + // about it + if (!addon.isActive) { + // But mark it as softblocked if necessary. Note that we avoid setting + // softDisabled at the same time as userDisabled to make it clear + // which was the original cause of the add-on becoming disabled in a + // way that the user can change. + if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED && !addon.userDisabled) + addon.softDisabled = true; + continue; + } + + let entry = this._getAddonBlocklistEntry(addon, this._addonEntries); + addonList.push({ + name: addon.name, + version: addon.version, + icon: addon.iconURL, + disable: false, + blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED, + item: addon, + url: entry && entry.url, + }); + } + + AddonManagerPrivate.updateAddonAppDisabledStates(); - // We don't want to re-warn about add-ons - if (state == oldState) - continue; + var phs = Cc["@mozilla.org/plugin/host;1"]. + getService(Ci.nsIPluginHost); + var plugins = phs.getPluginTags(); + + for (let plugin of plugins) { + let oldState = -1; + if (oldPluginEntries) + oldState = this._getPluginBlocklistState(plugin, oldPluginEntries); + let state = this.getPluginBlocklistState(plugin); + LOG("Blocklist state for " + plugin.name + " changed from " + + oldState + " to " + state); + // We don't want to re-warn about items + if (state == oldState) + continue; - if (state === Ci.nsIBlocklistService.STATE_BLOCKED) { - // It's a hard block. We must reset certain preferences. - let prefs = this._getAddonPrefs(addon); - resetPrefs(prefs); + if (oldState == Ci.nsIBlocklistService.STATE_BLOCKED) { + if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) + plugin.enabledState = Ci.nsIPluginTag.STATE_DISABLED; + } else if (!plugin.disabled && state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) { + if (state != Ci.nsIBlocklistService.STATE_OUTDATED && + state != Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE && + state != Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE) { + addonList.push({ + name: plugin.name, + version: plugin.version, + icon: "chrome://mozapps/skin/plugins/pluginGeneric.svg", + disable: false, + blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED, + item: plugin, + url: this.getPluginBlocklistURL(plugin), + }); } + } + } + + if (addonList.length == 0) { + this._notifyObserversBlocklistUpdated(); + return; + } - // Ensure that softDisabled is false if the add-on is not soft blocked - if (state != Ci.nsIBlocklistService.STATE_SOFTBLOCKED) - addon.softDisabled = false; + if ("@mozilla.org/addons/blocklist-prompt;1" in Cc) { + try { + let blockedPrompter = Cc["@mozilla.org/addons/blocklist-prompt;1"] + .getService(Ci.nsIBlocklistPrompt); + blockedPrompter.prompt(addonList); + } catch (e) { + LOG(e); + } + this._notifyObserversBlocklistUpdated(); + return; + } - // Don't warn about add-ons becoming unblocked. - if (state == Ci.nsIBlocklistService.STATE_NOT_BLOCKED) + var args = { + restart: false, + list: addonList + }; + // This lets the dialog get the raw js object + args.wrappedJSObject = args; + + /* + Some tests run without UI, so the async code listens to a message + that can be sent programatically + */ + let applyBlocklistChanges = () => { + for (let addon of addonList) { + if (!addon.disable) continue; - // If an add-on has dropped from hard to soft blocked just mark it as - // soft disabled and don't warn about it. - if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED && - oldState == Ci.nsIBlocklistService.STATE_BLOCKED) { - addon.softDisabled = true; - continue; - } - - // If the add-on is already disabled for some reason then don't warn - // about it - if (!addon.isActive) { - // But mark it as softblocked if necessary. Note that we avoid setting - // softDisabled at the same time as userDisabled to make it clear - // which was the original cause of the add-on becoming disabled in a - // way that the user can change. - if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED && !addon.userDisabled) - addon.softDisabled = true; - continue; - } - - let entry = this._getAddonBlocklistEntry(addon, this._addonEntries); - addonList.push({ - name: addon.name, - version: addon.version, - icon: addon.iconURL, - disable: false, - blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED, - item: addon, - url: entry && entry.url, - }); - } - - AddonManagerPrivate.updateAddonAppDisabledStates(); - - var phs = Cc["@mozilla.org/plugin/host;1"]. - getService(Ci.nsIPluginHost); - var plugins = phs.getPluginTags(); - - for (let plugin of plugins) { - let oldState = -1; - if (oldPluginEntries) - oldState = this._getPluginBlocklistState(plugin, oldPluginEntries); - let state = this.getPluginBlocklistState(plugin); - LOG("Blocklist state for " + plugin.name + " changed from " + - oldState + " to " + state); - // We don't want to re-warn about items - if (state == oldState) - continue; - - if (oldState == Ci.nsIBlocklistService.STATE_BLOCKED) { - if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) - plugin.enabledState = Ci.nsIPluginTag.STATE_DISABLED; - } else if (!plugin.disabled && state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) { - if (state != Ci.nsIBlocklistService.STATE_OUTDATED && - state != Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE && - state != Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE) { - addonList.push({ - name: plugin.name, - version: plugin.version, - icon: "chrome://mozapps/skin/plugins/pluginGeneric.svg", - disable: false, - blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED, - item: plugin, - url: this.getPluginBlocklistURL(plugin), - }); - } + if (addon.item instanceof Ci.nsIPluginTag) + addon.item.enabledState = Ci.nsIPluginTag.STATE_DISABLED; + else { + // This add-on is softblocked. + addon.item.softDisabled = true; + // We must revert certain prefs. + let prefs = this._getAddonPrefs(addon.item); + resetPrefs(prefs); } } - if (addonList.length == 0) { - this._notifyObserversBlocklistUpdated(); - return; - } + if (args.restart) + restartApp(); - if ("@mozilla.org/addons/blocklist-prompt;1" in Cc) { - try { - let blockedPrompter = Cc["@mozilla.org/addons/blocklist-prompt;1"] - .getService(Ci.nsIBlocklistPrompt); - blockedPrompter.prompt(addonList); - } catch (e) { - LOG(e); - } - this._notifyObserversBlocklistUpdated(); - return; - } + this._notifyObserversBlocklistUpdated(); + Services.obs.removeObserver(applyBlocklistChanges, "addon-blocklist-closed"); + }; - var args = { - restart: false, - list: addonList - }; - // This lets the dialog get the raw js object - args.wrappedJSObject = args; - - /* - Some tests run without UI, so the async code listens to a message - that can be sent programatically - */ - let applyBlocklistChanges = () => { - for (let addon of addonList) { - if (!addon.disable) - continue; + Services.obs.addObserver(applyBlocklistChanges, "addon-blocklist-closed"); - if (addon.item instanceof Ci.nsIPluginTag) - addon.item.enabledState = Ci.nsIPluginTag.STATE_DISABLED; - else { - // This add-on is softblocked. - addon.item.softDisabled = true; - // We must revert certain prefs. - let prefs = this._getAddonPrefs(addon.item); - resetPrefs(prefs); - } - } - - if (args.restart) - restartApp(); - - this._notifyObserversBlocklistUpdated(); - Services.obs.removeObserver(applyBlocklistChanges, "addon-blocklist-closed"); - }; + if (Services.prefs.getBoolPref(PREF_BLOCKLIST_SUPPRESSUI, false)) { + applyBlocklistChanges(); + return; + } - Services.obs.addObserver(applyBlocklistChanges, "addon-blocklist-closed"); - - if (Services.prefs.getBoolPref(PREF_BLOCKLIST_SUPPRESSUI, false)) { + function blocklistUnloadHandler(event) { + if (event.target.location == URI_BLOCKLIST_DIALOG) { applyBlocklistChanges(); - return; + blocklistWindow.removeEventListener("unload", blocklistUnloadHandler); } + } - function blocklistUnloadHandler(event) { - if (event.target.location == URI_BLOCKLIST_DIALOG) { - applyBlocklistChanges(); - blocklistWindow.removeEventListener("unload", blocklistUnloadHandler); - } - } - - let blocklistWindow = Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "", - "chrome,centerscreen,dialog,titlebar", args); - if (blocklistWindow) - blocklistWindow.addEventListener("unload", blocklistUnloadHandler); - }); + let blocklistWindow = Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "", + "chrome,centerscreen,dialog,titlebar", args); + if (blocklistWindow) + blocklistWindow.addEventListener("unload", blocklistUnloadHandler); }, classID: Components.ID("{66354bc9-7ed1-4692-ae1d-8da97d6b205e}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsIBlocklistService, Ci.nsITimerCallback]), };
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_severities.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_severities.js @@ -9,18 +9,18 @@ ChromeUtils.import("resource://testing-c var gTestserver = AddonTestUtils.createHttpServer({hosts: ["example.com"]}); gTestserver.registerDirectory("/data/", do_get_file("data")); // Workaround for Bug 658720 - URL formatter can leak during xpcshell tests const PREF_BLOCKLIST_ITEM_URL = "extensions.blocklist.itemURL"; Services.prefs.setCharPref(PREF_BLOCKLIST_ITEM_URL, "http://example.com/blocklist/%blockID%"); -function getAddonBlocklistURL(addon) { - let entry = Services.blocklist.getAddonBlocklistEntry(addon); +async function getAddonBlocklistURL(addon) { + let entry = await Services.blocklist.getAddonBlocklistEntry(addon); return entry && entry.url; } var ADDONS = [{ // Tests how the blocklist affects a disabled add-on id: "test_bug455906_1@tests.mozilla.org", name: "Bug 455906 Addon Test 1", version: "5", @@ -361,21 +361,21 @@ add_task(async function test_pt3() { equal(check_plugin_state(PLUGINS[2]), "false,true"); equal(check_plugin_state(PLUGINS[3]), "true,true"); equal(check_plugin_state(PLUGINS[4]), "false,true"); // Should have gained the blocklist state but no longer be soft disabled checkAddonState(addons[3], {userDisabled: false, softDisabled: false, appDisabled: true}); // Check blockIDs are correct - equal(getAddonBlocklistURL(addons[0]), create_blocklistURL(addons[0].id)); - equal(getAddonBlocklistURL(addons[1]), create_blocklistURL(addons[1].id)); - equal(getAddonBlocklistURL(addons[2]), create_blocklistURL(addons[2].id)); - equal(getAddonBlocklistURL(addons[3]), create_blocklistURL(addons[3].id)); - equal(getAddonBlocklistURL(addons[4]), create_blocklistURL(addons[4].id)); + equal(await getAddonBlocklistURL(addons[0]), create_blocklistURL(addons[0].id)); + equal(await getAddonBlocklistURL(addons[1]), create_blocklistURL(addons[1].id)); + equal(await getAddonBlocklistURL(addons[2]), create_blocklistURL(addons[2].id)); + equal(await getAddonBlocklistURL(addons[3]), create_blocklistURL(addons[3].id)); + equal(await getAddonBlocklistURL(addons[4]), create_blocklistURL(addons[4].id)); // All plugins have the same blockID on the test equal(Services.blocklist.getPluginBlocklistURL(PLUGINS[0]), create_blocklistURL("test_bug455906_plugin")); equal(Services.blocklist.getPluginBlocklistURL(PLUGINS[1]), create_blocklistURL("test_bug455906_plugin")); equal(Services.blocklist.getPluginBlocklistURL(PLUGINS[2]), create_blocklistURL("test_bug455906_plugin")); equal(Services.blocklist.getPluginBlocklistURL(PLUGINS[3]), create_blocklistURL("test_bug455906_plugin")); equal(Services.blocklist.getPluginBlocklistURL(PLUGINS[4]), create_blocklistURL("test_bug455906_plugin"));
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js @@ -799,17 +799,17 @@ add_task(async function run_app_update_s check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); }); add_task(async function update_schema_2() { await promiseShutdownManager(); await changeXPIDBVersion(100); gAppInfo.version = "2"; - startupManager(true); + await promiseStartupManager(true); let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS); 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(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); @@ -823,17 +823,17 @@ add_task(async function update_schema_2( }); add_task(async function update_schema_3() { await promiseRestartManager(); await promiseShutdownManager(); await changeXPIDBVersion(100); gAppInfo.version = "2.5"; - startupManager(true); + await promiseStartupManager(true); let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS); 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(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); @@ -856,17 +856,17 @@ add_task(async function update_schema_4( check_addon(r, "1.0", false, false, Ci.nsIBlocklistService.STATE_BLOCKED); }); add_task(async function update_schema_5() { await promiseShutdownManager(); await changeXPIDBVersion(100); gAppInfo.version = "1"; - startupManager(true); + await promiseStartupManager(true); let [s1, s2, s3, s4, h, r] = await promiseAddonsByIDs(ADDON_IDS); 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(h, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); @@ -1057,17 +1057,17 @@ add_task(async function run_addon_change 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, hardblock_1.id).remove(true); getFileForAddon(profileDir, regexpblock_1.id).remove(true); - startupManager(false); + await promiseStartupManager(false); await promiseShutdownManager(); writeInstallRDFForExtension(softblock1_2, profileDir); writeInstallRDFForExtension(softblock2_2, profileDir); writeInstallRDFForExtension(softblock3_2, profileDir); writeInstallRDFForExtension(softblock4_2, profileDir); writeInstallRDFForExtension(hardblock_2, profileDir); writeInstallRDFForExtension(regexpblock_2, profileDir); @@ -1183,17 +1183,17 @@ add_task(async function run_background_u 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, hardblock_1.id).remove(true); getFileForAddon(profileDir, regexpblock_1.id).remove(true); - startupManager(false); + await promiseStartupManager(false); await promiseShutdownManager(); writeInstallRDFForExtension(softblock1_3, profileDir); writeInstallRDFForExtension(softblock2_3, profileDir); writeInstallRDFForExtension(softblock3_3, profileDir); writeInstallRDFForExtension(softblock4_3, profileDir); writeInstallRDFForExtension(hardblock_3, profileDir); writeInstallRDFForExtension(regexpblock_3, profileDir); @@ -1289,17 +1289,17 @@ add_task(async function run_manual_updat 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, hardblock_1.id).remove(true); getFileForAddon(profileDir, regexpblock_1.id).remove(true); - startupManager(false); + await promiseStartupManager(false); await promiseShutdownManager(); writeInstallRDFForExtension(softblock1_1, profileDir); writeInstallRDFForExtension(softblock2_1, profileDir); writeInstallRDFForExtension(softblock3_1, profileDir); writeInstallRDFForExtension(softblock4_1, profileDir); writeInstallRDFForExtension(hardblock_1, profileDir); writeInstallRDFForExtension(regexpblock_1, profileDir);
--- a/xpcom/system/nsIBlocklistService.idl +++ b/xpcom/system/nsIBlocklistService.idl @@ -59,19 +59,20 @@ interface nsIBlocklistService : nsISuppo * is used. * @returns The STATE constant. */ unsigned long getPluginBlocklistState(in nsIPluginTag plugin, [optional] in AString appVersion, [optional] in AString toolkitVersion); /** - * Returns the blocklist entry, as an object with `state` and `url` + * Returns a promise that resolves to the blocklist entry. + * The blocklist entry is an object with `state` and `url` * properties, if a blocklist entry for the add-on exists, or null - * othereise. + * otherwise. * @param addon * The addon object to match. * @param appVersion * The version of the application we are checking in the blocklist. * If this parameter is null, the version of the running application * is used. * @param toolkitVersion