From d8f8ca4be5d610abdc43ae17f6beb6a4de0fa4b9 Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Thu, 28 Aug 2008 10:55:43 +0100 Subject: [PATCH] Bug 449027: Support specifying application range for plugins in blocklist.xml. r=robstrong --- browser/app/profile/firefox.js | 2 +- .../extensions/src/nsBlocklistService.js | 210 ++++--- .../test/unit/data/test_bug449027_app.xml | 333 ++++++++++ .../test/unit/data/test_bug449027_toolkit.xml | 208 ++++++ .../extensions/test/unit/test_bug449027.js | 593 ++++++++++++++++++ 5 files changed, 1274 insertions(+), 72 deletions(-) create mode 100644 toolkit/mozapps/extensions/test/unit/data/test_bug449027_app.xml create mode 100644 toolkit/mozapps/extensions/test/unit/data/test_bug449027_toolkit.xml create mode 100644 toolkit/mozapps/extensions/test/unit/test_bug449027.js diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index ca53434173f5..bbd224e89229 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -80,7 +80,7 @@ pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LO // Blocklist preferences pref("extensions.blocklist.enabled", true); pref("extensions.blocklist.interval", 86400); -pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/2/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/"); +pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/"); pref("extensions.blocklist.detailsURL", "http://%LOCALE%.www.mozilla.com/%LOCALE%/blocklist/"); // Dictionary download preference diff --git a/toolkit/mozapps/extensions/src/nsBlocklistService.js b/toolkit/mozapps/extensions/src/nsBlocklistService.js index 766c482aea58..6a35feea3a79 100644 --- a/toolkit/mozapps/extensions/src/nsBlocklistService.js +++ b/toolkit/mozapps/extensions/src/nsBlocklistService.js @@ -23,6 +23,7 @@ # Contributor(s): # Robert Strong # Michael Wu +# Dave Townsend # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or @@ -405,29 +406,8 @@ Blocklist.prototype = { return false; for (var i = 0; i < blItem.length; ++i) { - if (gVersionChecker.compare(version, blItem[i].minVersion) < 0 || - gVersionChecker.compare(version, blItem[i].maxVersion) > 0) - continue; - - var blTargetApp = blItem[i].targetApps[gApp.ID]; - if (blTargetApp) { - for (var x = 0; x < blTargetApp.length; ++x) { - if (gVersionChecker.compare(appVersion, blTargetApp[x].minVersion) < 0 || - gVersionChecker.compare(appVersion, blTargetApp[x].maxVersion) > 0) - continue; - return true; - } - } - - blTargetApp = blItem[i].targetApps[TOOLKIT_ID]; - if (!blTargetApp) - return false; - for (x = 0; x < blTargetApp.length; ++x) { - if (gVersionChecker.compare(toolkitVersion, blTargetApp[x].minVersion) < 0 || - gVersionChecker.compare(toolkitVersion, blTargetApp[x].maxVersion) > 0) - continue; + if (blItem[i].includesItem(version, appVersion, toolkitVersion)) return true; - } } return false; }, @@ -630,7 +610,7 @@ Blocklist.prototype = { var childNodes = doc.documentElement.childNodes; this._addonEntries = this._processItemNodes(childNodes, "em", - this._handleEmItemNode); + this._handleEmItemNode); this._pluginEntries = this._processItemNodes(childNodes, "plugin", this._handlePluginItemNode); } @@ -694,40 +674,52 @@ Blocklist.prototype = { return; var matchNodes = blocklistElement.childNodes; - var matchList; + var blockEntry = { + matches: {}, + versions: [] + }; for (var x = 0; x < matchNodes.length; ++x) { var matchElement = matchNodes.item(x); - if (!(matchElement instanceof Ci.nsIDOMElement) || - matchElement.localName != "match") + if (!(matchElement instanceof Ci.nsIDOMElement)) continue; - - var name = matchElement.getAttribute("name"); - var exp = matchElement.getAttribute("exp"); - if (!matchList) - matchList = { }; - matchList[name] = new RegExp(exp, "m"); + if (matchElement.localName == "match") { + var name = matchElement.getAttribute("name"); + var exp = matchElement.getAttribute("exp"); + blockEntry.matches[name] = new RegExp(exp, "m"); + } + if (matchElement.localName == "versionRange") + blockEntry.versions.push(new BlocklistItemData(matchElement)); } - if (matchList) - result.push(matchList); + result.push(blockEntry); }, - _checkPlugin: function(plugin) { - for each (var matchList in this._pluginEntries) { + _isPluginBlocklisted: function(plugin, appVersion, toolkitVersion) { + for each (var blockEntry in this._pluginEntries) { var matchFailed = false; - for (var name in matchList) { - if (typeof(plugin[name]) != "string" || - !matchList[name].test(plugin[name])) { + for (var name in blockEntry.matches) { + if (!(name in plugin) || + typeof(plugin[name]) != "string" || + !blockEntry.matches[name].test(plugin[name])) { matchFailed = true; break; } } - if (!matchFailed) { - plugin.blocklisted = true; - return; + if (matchFailed) + continue; + + // No version ranges means match any versions + if (blockEntry.versions.length == 0) + return true; + + for (var i = 0; i < blockEntry.versions.length; i++) { + if (blockEntry.versions[i].includesItem(plugin.version, appVersion, + toolkitVersion)) + return true; } } - plugin.blocklisted = false; + + return false; }, _checkPluginsList: function() { @@ -735,7 +727,11 @@ Blocklist.prototype = { this._loadBlocklist(); var phs = Cc["@mozilla.org/plugin/host;1"]. getService(Ci.nsIPluginHost); - phs.getPluginTags({ }).forEach(this._checkPlugin, this); + var plugins = phs.getPluginTags({}); + for (var i = 0; i < plugins.length; i++) + plugins[i].blocklisted = this._isPluginBlocklisted(plugins[i], + gApp.version, + gApp.platformVersion); }, classDescription: "Blocklist Service", @@ -772,25 +768,97 @@ function BlocklistItemData(versionRangeElement) { this.targetApps[appID] = this.getBlocklistAppVersions(targetAppElement); } } - // Default to all versions of the extension and the current application when - // versionRange is not defined. + // Default to all versions of the current application when no targetApplication + // elements were found if (!found) this.targetApps[gApp.ID] = this.getBlocklistAppVersions(null); } BlocklistItemData.prototype = { -/** - * Retrieves a version range (e.g. minVersion and maxVersion) for a - * blocklist item's targetApplication element. - * @param targetAppElement - * A targetApplication blocklist element. - * @returns An array of JS objects with the following properties: - * "minVersion" The minimum version in a version range (default = 0). - * "maxVersion" The maximum version in a version range (default = *). - */ + /** + * Tests if a version of an item is included in the version range and target + * application information represented by this BlocklistItemData using the + * provided application and toolkit versions. + * @param version + * The version of the item being tested. + * @param appVersion + * The application version to test with. + * @param toolkitVersion + * The toolkit version to test with. + * @returns True if the version range covers the item version and application + * or toolkit version. + */ + includesItem: function(version, appVersion, toolkitVersion) { + // Some platforms have no version for plugins, these don't match if there + // was a min/maxVersion provided + if (!version && (this.minVersion || this.maxVersion)) + return false; + + // Check if the item version matches + if (!this.matchesRange(version, this.minVersion, this.maxVersion)) + return false; + + // Check if the application version matches + if (this.matchesTargetRange(gApp.ID, appVersion)) + return true; + + // Check if the toolkit version matches + return this.matchesTargetRange(TOOLKIT_ID, toolkitVersion); + }, + + /** + * Checks if a version is higher than or equal to the minVersion (if provided) + * and lower than or equal to the maxVersion (if provided). + * @param version + * The version to test. + * @param minVersion + * The minimum version. If null it is assumed that version is always + * larger. + * @param maxVersion + * The maximum version. If null it is assumed that version is always + * smaller. + */ + matchesRange: function(version, minVersion, maxVersion) { + if (minVersion && gVersionChecker.compare(version, minVersion) < 0) + return false; + if (maxVersion && gVersionChecker.compare(version, maxVersion) > 0) + return false; + return true; + }, + + /** + * Tests if there is a matching range for the given target application id and + * version. + * @param appID + * The application ID to test for, may be for an application or toolkit + * @param appVersion + * The version of the application to test for. + * @returns True if this version range covers the application version given. + */ + matchesTargetRange: function(appID, appVersion) { + var blTargetApp = this.targetApps[appID]; + if (!blTargetApp) + return false; + + for (var x = 0; x < blTargetApp.length; ++x) { + if (this.matchesRange(appVersion, blTargetApp[x].minVersion, blTargetApp[x].maxVersion)) + return true; + } + + return false; + }, + + /** + * Retrieves a version range (e.g. minVersion and maxVersion) for a + * blocklist item's targetApplication element. + * @param targetAppElement + * A targetApplication blocklist element. + * @returns An array of JS objects with the following properties: + * "minVersion" The minimum version in a version range (default = null). + * "maxVersion" The maximum version in a version range (default = null). + */ getBlocklistAppVersions: function(targetAppElement) { var appVersions = [ ]; - var found = false; if (targetAppElement) { for (var i = 0; i < targetAppElement.childNodes.length; ++i) { @@ -798,28 +866,28 @@ BlocklistItemData.prototype = { if (!(versionRangeElement instanceof Ci.nsIDOMElement) || versionRangeElement.localName != "versionRange") continue; - found = true; appVersions.push(this.getBlocklistVersionRange(versionRangeElement)); } } - // return minVersion = 0 and maxVersion = * if not available - if (!found) - return [ this.getBlocklistVersionRange(null) ]; + // return minVersion = null and maxVersion = null if no specific versionRange + // elements were found + if (appVersions.length == 0) + appVersions.push(this.getBlocklistVersionRange(null)); return appVersions; }, -/** - * Retrieves a version range (e.g. minVersion and maxVersion) for a blocklist - * versionRange element. - * @param versionRangeElement - * The versionRange blocklist element. - * @returns A JS object with the following properties: - * "minVersion" The minimum version in a version range (default = 0). - * "maxVersion" The maximum version in a version range (default = *). - */ + /** + * Retrieves a version range (e.g. minVersion and maxVersion) for a blocklist + * versionRange element. + * @param versionRangeElement + * The versionRange blocklist element. + * @returns A JS object with the following properties: + * "minVersion" The minimum version in a version range (default = null). + * "maxVersion" The maximum version in a version range (default = null). + */ getBlocklistVersionRange: function(versionRangeElement) { - var minVersion = "0"; - var maxVersion = "*"; + var minVersion = null; + var maxVersion = null; if (!versionRangeElement) return { minVersion: minVersion, maxVersion: maxVersion }; diff --git a/toolkit/mozapps/extensions/test/unit/data/test_bug449027_app.xml b/toolkit/mozapps/extensions/test/unit/data/test_bug449027_app.xml new file mode 100644 index 000000000000..f12ca1fa6d56 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/data/test_bug449027_app.xml @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/unit/data/test_bug449027_toolkit.xml b/toolkit/mozapps/extensions/test/unit/data/test_bug449027_toolkit.xml new file mode 100644 index 000000000000..ad8ec5ed9df4 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/data/test_bug449027_toolkit.xml @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/mozapps/extensions/test/unit/test_bug449027.js b/toolkit/mozapps/extensions/test/unit/test_bug449027.js new file mode 100644 index 000000000000..00d8dd573718 --- /dev/null +++ b/toolkit/mozapps/extensions/test/unit/test_bug449027.js @@ -0,0 +1,593 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Dave Townsend . + * + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL + * + * ***** END LICENSE BLOCK ***** + */ +const URI_EXTENSION_LIST_DIALOG = "chrome://mozapps/content/extensions/list.xul"; + +do_import_script("netwerk/test/httpserver/httpd.js"); + +var ADDONS = [{ + id: "test_bug449027_1@tests.mozilla.org", + name: "Bug 449027 Addon Test 1", + version: "5", + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + id: "test_bug449027_2@tests.mozilla.org", + name: "Bug 449027 Addon Test 2", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_3@tests.mozilla.org", + name: "Bug 449027 Addon Test 3", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_4@tests.mozilla.org", + name: "Bug 449027 Addon Test 4", + version: "5", + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + id: "test_bug449027_5@tests.mozilla.org", + name: "Bug 449027 Addon Test 5", + version: "5", + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + id: "test_bug449027_6@tests.mozilla.org", + name: "Bug 449027 Addon Test 6", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_7@tests.mozilla.org", + name: "Bug 449027 Addon Test 7", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_8@tests.mozilla.org", + name: "Bug 449027 Addon Test 8", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_9@tests.mozilla.org", + name: "Bug 449027 Addon Test 9", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_10@tests.mozilla.org", + name: "Bug 449027 Addon Test 10", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_11@tests.mozilla.org", + name: "Bug 449027 Addon Test 11", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_12@tests.mozilla.org", + name: "Bug 449027 Addon Test 12", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_13@tests.mozilla.org", + name: "Bug 449027 Addon Test 13", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + id: "test_bug449027_14@tests.mozilla.org", + name: "Bug 449027 Addon Test 14", + version: "5", + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + id: "test_bug449027_15@tests.mozilla.org", + name: "Bug 449027 Addon Test 15", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_16@tests.mozilla.org", + name: "Bug 449027 Addon Test 16", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_17@tests.mozilla.org", + name: "Bug 449027 Addon Test 17", + version: "5", + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + id: "test_bug449027_18@tests.mozilla.org", + name: "Bug 449027 Addon Test 18", + version: "5", + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + id: "test_bug449027_19@tests.mozilla.org", + name: "Bug 449027 Addon Test 19", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_20@tests.mozilla.org", + name: "Bug 449027 Addon Test 20", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_21@tests.mozilla.org", + name: "Bug 449027 Addon Test 21", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_22@tests.mozilla.org", + name: "Bug 449027 Addon Test 22", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_23@tests.mozilla.org", + name: "Bug 449027 Addon Test 23", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_24@tests.mozilla.org", + name: "Bug 449027 Addon Test 24", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + id: "test_bug449027_25@tests.mozilla.org", + name: "Bug 449027 Addon Test 25", + version: "5", + start: false, + appBlocks: true, + toolkitBlocks: true +}]; + +var PLUGINS = [{ + name: "test_bug449027_1", + version: "5", + blocklisted: false, + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + name: "test_bug449027_2", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_3", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_4", + version: "5", + blocklisted: false, + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + name: "test_bug449027_5", + version: "5", + blocklisted: false, + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + name: "test_bug449027_6", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_7", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_8", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_9", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_10", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_11", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_12", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_13", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: false +}, { + name: "test_bug449027_14", + version: "5", + blocklisted: false, + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + name: "test_bug449027_15", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_16", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_17", + version: "5", + blocklisted: false, + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + name: "test_bug449027_18", + version: "5", + blocklisted: false, + start: false, + appBlocks: false, + toolkitBlocks: false +}, { + name: "test_bug449027_19", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_20", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_21", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_22", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_23", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_24", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}, { + name: "test_bug449027_25", + version: "5", + blocklisted: false, + start: false, + appBlocks: true, + toolkitBlocks: true +}]; + +var gCallback = null; +var gTestserver = null; +var gNewBlocks = []; + +// A fake plugin host for the blocklist service to use +var PluginHost = { + getPluginTags: function(countRef) { + countRef.value = PLUGINS.length; + return PLUGINS; + }, + + QueryInterface: function(iid) { + if (iid.equals(Components.interfaces.nsIPluginHost) + || iid.equals(Components.interfaces.nsISupports)) + return this; + + throw Components.results.NS_ERROR_NO_INTERFACE; + } +} + +var PluginHostFactory = { + createInstance: function (outer, iid) { + if (outer != null) + throw Components.results.NS_ERROR_NO_AGGREGATION; + return PluginHost.QueryInterface(iid); + } +}; + +// 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_LIST_DIALOG); + do_check_neq(gCallback, null); + do_check_true(arguments instanceof Components.interfaces.nsIDialogParamBlock); + + gNewBlocks = []; + var count = arguments.GetInt(1); + for (var i = 0; i < count; i++) + gNewBlocks.push(arguments.GetString(i)); + + // Call the callback after the blocklist has finished up + do_timeout(0, "gCallback()"); + }, + + QueryInterface: function(iid) { + if (iid.equals(Components.interfaces.nsIWindowWatcher) + || iid.equals(Components.interfaces.nsISupports)) + return this; + + throw Components.results.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 registrar = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar); +registrar.registerFactory(Components.ID("{721c3e73-969e-474b-a6dc-059fd288c428}"), + "Fake Plugin Host", + "@mozilla.org/plugin/host;1", PluginHostFactory); +registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), + "Fake Window Watcher", + "@mozilla.org/embedcomp/window-watcher;1", WindowWatcherFactory); + +function create_addon(addon) { + var installrdf = "\n" + + "\n" + + "\n" + + " \n" + + " " + addon.id + "\n" + + " " + addon.version + "\n" + + " \n" + + " \n" + + " xpcshell@tests.mozilla.org\n" + + " 3\n" + + " 3\n" + + " \n" + + " \n" + + " " + addon.name + "\n" + + " \n" + + "\n"; + var target = gProfD.clone(); + target.append("extensions"); + target.append(addon.id); + target.append("install.rdf"); + target.create(target.NORMAL_FILE_TYPE, 0644); + var stream = Components.classes["@mozilla.org/network/file-output-stream;1"] + .createInstance(Components.interfaces.nsIFileOutputStream); + stream.init(target, 0x04 | 0x08 | 0x20, 0664, 0); // write, create, truncate + stream.write(installrdf, installrdf.length); + stream.close(); +} + +/** + * Checks that items are blocklisted correctly according to the current test. + * If a lastTest is provided checks that the notification dialog got passed + * the newly blocked items compared to the previous test. + */ +function check_state(test, lastTest) { + for (var i = 0; i < ADDONS.length; i++) { + var blocked = getManifestProperty(ADDONS[i].id, "blocklisted") == "true"; + if (blocked != ADDONS[i][test]) + do_throw("Blocklist state did not match expected for extension " + (i + 1) + ", test " + test); + } + for (i = 0; i < PLUGINS.length; i++) { + if (PLUGINS[i].blocklisted != PLUGINS[i][test]) + do_throw("Blocklist state did not match expected for plugin " + (i + 1) + ", test " + test); + } + + if (lastTest) { + var expected = 0; + for (i = 0; i < ADDONS.length; i++) { + if (ADDONS[i][test] && !ADDONS[i][lastTest]) { + if (gNewBlocks.indexOf(ADDONS[i].name + " " + ADDONS[i].version) < 0) + do_throw("Addon " + (i + 1) + " should have been listed in the blocklist notification for test " + test); + expected++; + } + } + + do_check_eq(expected, gNewBlocks.length); + } +} + +function load_blocklist(file) { + gPrefs.setCharPref("extensions.blocklist.url", "http://localhost:4444/data/" + file); + var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"] + .getService(Components.interfaces.nsITimerCallback); + blocklist.notify(null); +} + +function run_test() { + // Setup for test + dump("Setting up tests\n"); + // Rather than keeping lots of identical add-ons in version control, just + // write them into the profile. + for (var i = 0; i < ADDONS.length; i++) + create_addon(ADDONS[i]); + + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "3", "8"); + startupEM(); + gTestserver = new nsHttpServer(); + gTestserver.registerDirectory("/data/", do_get_file("toolkit/mozapps/extensions/test/unit/data")); + gTestserver.start(4444); + + do_test_pending(); + check_test_pt1(); +} + +/** + * Checks the initial state is correct + */ +function check_test_pt1() { + dump("Checking pt 1\n"); + for (var i = 0; i < ADDONS.length; i++) { + if (!gEM.getItemForID(ADDONS[i].id)) + do_throw("Addon " + (i + 1) + " did not get installed correctly"); + } + check_state("start", null); + run_test_pt2(); +} + +/** + * Load the toolkit based blocks + */ +function run_test_pt2() { + dump("Running test pt 2\n"); + gCallback = check_test_pt2; + load_blocklist("test_bug449027_toolkit.xml"); +} + +function check_test_pt2() { + dump("Checking pt 2\n"); + check_state("toolkitBlocks", "start"); + run_test_pt3(); +} + +/** + * Load the application based blocks + */ +function run_test_pt3() { + dump("Running test pt 3\n"); + gCallback = check_test_pt3; + load_blocklist("test_bug449027_app.xml"); +} + +function check_test_pt3() { + dump("Checking pt 3\n"); + check_state("appBlocks", "toolkitBlocks"); + gTestserver.stop(); + do_test_finished(); +}