Bug 897735 - Support regular expression filters for name and creator in extension blocks. r=Unfocused

This commit is contained in:
Sachin Hosmani 2014-01-06 14:16:32 +05:30
parent 5826abf08c
commit ac557339b2
18 changed files with 777 additions and 145 deletions

View File

@ -463,7 +463,7 @@ appUpdater.prototype =
* See XPIProvider.jsm
*/
onUpdateAvailable: function(aAddon, aInstall) {
if (!Services.blocklist.isAddonBlocklisted(aAddon.id, aInstall.version,
if (!Services.blocklist.isAddonBlocklisted(aAddon,
this.update.appVersion,
this.update.platformVersion)) {
// Compatibility or new version updates mean the same thing here.

View File

@ -36,10 +36,10 @@ var tests = {
testSimpleBlocklist: function(next) {
// this really just tests adding and clearing our blocklist for later tests
setAndUpdateBlocklist(blocklistURL, function() {
ok(Services.blocklist.isAddonBlocklisted("test1.example.com@services.mozilla.org", "0", "0", "0"), "blocking 'blocked'");
ok(!Services.blocklist.isAddonBlocklisted("example.com@services.mozilla.org", "0", "0", "0"), "not blocking 'good'");
ok(Services.blocklist.isAddonBlocklisted(SocialService.createWrapper(manifest_bad)), "blocking 'blocked'");
ok(!Services.blocklist.isAddonBlocklisted(SocialService.createWrapper(manifest)), "not blocking 'good'");
resetBlocklist(function() {
ok(!Services.blocklist.isAddonBlocklisted("test1.example.com@services.mozilla.org", "0", "0", "0"), "blocklist cleared");
ok(!Services.blocklist.isAddonBlocklisted(SocialService.createWrapper(manifest_bad)), "blocklist cleared");
next();
});
});

View File

@ -454,7 +454,7 @@ appUpdater.prototype =
* See XPIProvider.jsm
*/
onUpdateAvailable: function(aAddon, aInstall) {
if (!Services.blocklist.isAddonBlocklisted(aAddon.id, aInstall.version,
if (!Services.blocklist.isAddonBlocklisted(aAddon,
this.update.appVersion,
this.update.platformVersion)) {
// Compatibility or new version updates mean the same thing here.

View File

@ -585,21 +585,30 @@ this.SocialService = {
},
installProvider: function(aDOMDocument, data, installCallback) {
let manifest;
let installOrigin = aDOMDocument.nodePrincipal.origin;
let id = getAddonIDFromOrigin(installOrigin);
let version = data && data.version ? data.version : "0";
if (Services.blocklist.getAddonBlocklistState(id, version) == Ci.nsIBlocklistService.STATE_BLOCKED)
throw new Error("installProvider: provider with origin [" +
installOrigin + "] is blocklisted");
if (data) {
let installType = getOriginActivationType(installOrigin);
// if we get data, we MUST have a valid manifest generated from the data
manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
if (!manifest)
throw new Error("SocialService.installProvider: service configuration is invalid from " + aDOMDocument.location.href);
let addon = new AddonWrapper(manifest);
if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
throw new Error("installProvider: provider with origin [" +
installOrigin + "] is blocklisted");
}
let id = getAddonIDFromOrigin(installOrigin);
AddonManager.getAddonByID(id, function(aAddon) {
if (aAddon && aAddon.userDisabled) {
aAddon.cancelUninstall();
aAddon.userDisabled = false;
}
schedule(function () {
this._installProvider(aDOMDocument, data, aManifest => {
this._installProvider(aDOMDocument, manifest, aManifest => {
this._notifyProviderListeners("provider-installed", aManifest.origin);
installCallback(aManifest);
});
@ -607,18 +616,11 @@ this.SocialService = {
}.bind(this));
},
_installProvider: function(aDOMDocument, data, installCallback) {
_installProvider: function(aDOMDocument, manifest, installCallback) {
let sourceURI = aDOMDocument.location.href;
let installOrigin = aDOMDocument.nodePrincipal.origin;
let installType = getOriginActivationType(installOrigin);
let manifest;
if (data) {
// if we get data, we MUST have a valid manifest generated from the data
manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
if (!manifest)
throw new Error("SocialService.installProvider: service configuration is invalid from " + sourceURI);
}
let installer;
switch(installType) {
case "foreign":
@ -662,6 +664,10 @@ this.SocialService = {
}
},
createWrapper: function(manifest) {
return new AddonWrapper(manifest);
},
/**
* updateProvider is used from the worker to self-update. Since we do not
* have knowledge of the currently selected provider here, we will notify
@ -716,8 +722,8 @@ function SocialProvider(input) {
if (!input.origin)
throw new Error("SocialProvider must be passed an origin");
let id = getAddonIDFromOrigin(input.origin);
if (Services.blocklist.getAddonBlocklistState(id, input.version || "0") == Ci.nsIBlocklistService.STATE_BLOCKED)
let addon = new AddonWrapper(input);
if (addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
throw new Error("SocialProvider: provider with origin [" +
input.origin + "] is blocklisted");
@ -1011,8 +1017,8 @@ var SocialAddonProvider = {
for (let manifest of SocialServiceInternal.manifests) {
try {
if (ActiveProviders.has(manifest.origin)) {
let id = getAddonIDFromOrigin(manifest.origin);
if (Services.blocklist.getAddonBlocklistState(id, manifest.version || "0") != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
let addon = new AddonWrapper(manifest);
if (addon.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
SocialService.removeProvider(manifest.origin);
}
}
@ -1100,11 +1106,11 @@ AddonWrapper.prototype = {
},
get blocklistState() {
return Services.blocklist.getAddonBlocklistState(this.id, this.version || "0");
return Services.blocklist.getAddonBlocklistState(this);
},
get blocklistURL() {
return Services.blocklist.getAddonBlocklistURL(this.id, this.version || "0");
return Services.blocklist.getAddonBlocklistURL(this);
},
get screenshots() {

View File

@ -721,8 +721,7 @@ this.AddonUpdateChecker = {
for (let update of aUpdates) {
if (!update.updateURL)
continue;
let state = blocklist.getAddonBlocklistState(update.id, update.version,
aAppVersion, aPlatformVersion);
let state = blocklist.getAddonBlocklistState(update, aAppVersion, aPlatformVersion);
if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED)
continue;
if ((newest == null || (Services.vc.compare(newest.version, update.version) < 0)) &&

View File

@ -550,12 +550,10 @@ function applyBlocklistChanges(aOldAddon, aNewAddon, aOldAppVersion,
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
let oldBlocklistState = bs.getAddonBlocklistState(aOldAddon.id,
aOldAddon.version,
let oldBlocklistState = bs.getAddonBlocklistState(createWrapper(aOldAddon),
aOldAppVersion,
aOldPlatformVersion);
let newBlocklistState = bs.getAddonBlocklistState(aNewAddon.id,
aNewAddon.version);
let newBlocklistState = bs.getAddonBlocklistState(createWrapper(aNewAddon));
// If the blocklist state hasn't changed then the properties don't need to
// change
@ -6213,7 +6211,7 @@ AddonInternal.prototype = {
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
return bs.getAddonBlocklistState(this.id, this.version);
return bs.getAddonBlocklistState(createWrapper(this));
},
get blocklistURL() {
@ -6225,7 +6223,7 @@ AddonInternal.prototype = {
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
return bs.getAddonBlocklistURL(this.id, this.version);
return bs.getAddonBlocklistURL(createWrapper(this));
},
applyCompatibilityUpdate: function AddonInternal_applyCompatibilityUpdate(aUpdate, aSyncCompatibility) {
@ -6343,7 +6341,7 @@ function AddonWrapper(aAddon) {
["id", "syncGUID", "version", "type", "isCompatible", "isPlatformCompatible",
"providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled",
"softDisabled", "skinnable", "size", "foreignInstall", "hasBinaryComponents",
"strictCompatibility", "compatibilityOverrides"].forEach(function(aProp) {
"strictCompatibility", "compatibilityOverrides", "updateURL"].forEach(function(aProp) {
this.__defineGetter__(aProp, function AddonWrapper_propertyGetter() aAddon[aProp]);
}, this);

View File

@ -49,6 +49,8 @@ const VULNERABILITYSTATUS_NONE = 0;
const VULNERABILITYSTATUS_UPDATE_AVAILABLE = 1;
const VULNERABILITYSTATUS_NO_UPDATE = 2;
const EXTENSION_BLOCK_FILTERS = ["id", "name", "creator", "homepageURL", "updateURL"];
var gLoggingEnabled = null;
var gBlocklistEnabled = true;
var gBlocklistLevel = DEFAULT_LEVEL;
@ -317,16 +319,16 @@ Blocklist.prototype = {
},
/* See nsIBlocklistService */
isAddonBlocklisted: function Blocklist_isAddonBlocklisted(id, version, appVersion, toolkitVersion) {
return this.getAddonBlocklistState(id, version, appVersion, toolkitVersion) ==
isAddonBlocklisted: function Blocklist_isAddonBlocklisted(addon, appVersion, toolkitVersion) {
return this.getAddonBlocklistState(addon, appVersion, toolkitVersion) ==
Ci.nsIBlocklistService.STATE_BLOCKED;
},
/* See nsIBlocklistService */
getAddonBlocklistState: function Blocklist_getAddonBlocklistState(id, version, appVersion, toolkitVersion) {
getAddonBlocklistState: function Blocklist_getAddonBlocklistState(addon, appVersion, toolkitVersion) {
if (!this._addonEntries)
this._loadBlocklist();
return this._getAddonBlocklistState(id, version, this._addonEntries,
return this._getAddonBlocklistState(addon, this._addonEntries,
appVersion, toolkitVersion);
},
@ -349,8 +351,8 @@ Blocklist.prototype = {
* @returns The blocklist state for the item, one of the STATE constants as
* defined in nsIBlocklistService.
*/
_getAddonBlocklistState: function Blocklist_getAddonBlocklistStateCall(id,
version, addonEntries, appVersion, toolkitVersion) {
_getAddonBlocklistState: function Blocklist_getAddonBlocklistStateCall(addon,
addonEntries, appVersion, toolkitVersion) {
if (!gBlocklistEnabled)
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
@ -359,12 +361,12 @@ Blocklist.prototype = {
if (!toolkitVersion)
toolkitVersion = gApp.platformVersion;
var blItem = this._findMatchingAddonEntry(addonEntries, id);
var blItem = this._findMatchingAddonEntry(addonEntries, addon);
if (!blItem)
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
for (let currentblItem of blItem.versions) {
if (currentblItem.includesItem(version, appVersion, toolkitVersion))
if (currentblItem.includesItem(addon.version, appVersion, toolkitVersion))
return currentblItem.severity >= gBlocklistLevel ? Ci.nsIBlocklistService.STATE_BLOCKED :
Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
}
@ -374,36 +376,63 @@ Blocklist.prototype = {
/**
* Returns the set of prefs of the add-on stored in the blocklist file
* (probably to revert them on disabling).
* @param id
* ID of the add-on.
* @param addon
* The add-on whose to-be-reset prefs are to be found.
*/
_getAddonPrefs: function Blocklist_getAddonPrefs(id) {
let entry = this._findMatchingAddonEntry(this._addonEntries, id);
_getAddonPrefs: function Blocklist_getAddonPrefs(addon) {
let entry = this._findMatchingAddonEntry(this._addonEntries, addon);
return entry.prefs.slice(0);
},
_findMatchingAddonEntry: function Blocklist_findMatchingAddonEntry(aAddonEntries,
aId) {
for (let entry of aAddonEntries) {
if (entry.id instanceof RegExp) {
if (entry.id.test(aId))
return entry;
} else if (entry.id == aId) {
return entry;
aAddon) {
if (!aAddon)
return null;
// Returns true if the params object passes the constraints set by entry.
// (For every non-null property in entry, the same key must exist in
// params and value must be the same)
function checkEntry(entry, params) {
for (let [key, value] of entry) {
if (value === null || value === undefined)
continue;
if (params[key]) {
if (value instanceof RegExp) {
if (!value.test(params[key])) {
return false;
}
} else if (value !== params[key]) {
return false;
}
} else {
return false;
}
}
return true;
}
return null;
let params = {};
for (let filter of EXTENSION_BLOCK_FILTERS) {
params[filter] = aAddon[filter];
}
if (params.creator)
params.creator = params.creator.name;
for (let entry of aAddonEntries) {
if (checkEntry(entry.attributes, params)) {
return entry;
}
}
return null;
},
/* See nsIBlocklistService */
getAddonBlocklistURL: function Blocklist_getAddonBlocklistURL(id, version, appVersion, toolkitVersion) {
getAddonBlocklistURL: function Blocklist_getAddonBlocklistURL(addon, appVersion, toolkitVersion) {
if (!gBlocklistEnabled)
return "";
if (!this._addonEntries)
this._loadBlocklist();
let blItem = this._findMatchingAddonEntry(this._addonEntries, id);
let blItem = this._findMatchingAddonEntry(this._addonEntries, addon);
if (!blItem || !blItem.blockID)
return null;
@ -734,18 +763,26 @@ Blocklist.prototype = {
return;
let blockEntry = {
id: null,
versions: [],
prefs: [],
blockID: null
blockID: null,
attributes: new Map()
// Atleast one of EXTENSION_BLOCK_FILTERS must get added to attributes
};
// Any filter starting with '/' is interpreted as a regex. So if an attribute
// starts with a '/' it must be checked via a regex.
function regExpCheck(attr) {
return attr.startsWith("/") ? parseRegExp(attr) : attr;
}
for (let filter of EXTENSION_BLOCK_FILTERS) {
let attr = blocklistElement.getAttribute(filter);
if (attr)
blockEntry.attributes.set(filter, regExpCheck(attr));
}
var childNodes = blocklistElement.childNodes;
var id = blocklistElement.getAttribute("id");
// Add-on IDs cannot contain '/', so an ID starting with '/' must be a regex
if (id.startsWith("/"))
id = parseRegExp(id);
blockEntry.id = id;
for (let x = 0; x < childNodes.length; x++) {
var childElement = childNodes.item(x);
@ -928,9 +965,8 @@ Blocklist.prototype = {
for (let addon of addons) {
let oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED;
if (oldAddonEntries)
oldState = self._getAddonBlocklistState(addon.id, addon.version,
oldAddonEntries);
let state = self.getAddonBlocklistState(addon.id, addon.version);
oldState = self._getAddonBlocklistState(addon, oldAddonEntries);
let state = self.getAddonBlocklistState(addon);
LOG("Blocklist state for " + addon.id + " changed from " +
oldState + " to " + state);
@ -941,7 +977,7 @@ Blocklist.prototype = {
if (state === Ci.nsIBlocklistService.STATE_BLOCKED) {
// It's a hard block. We must reset certain preferences.
let prefs = self._getAddonPrefs(addon.id);
let prefs = self._getAddonPrefs(addon);
resetPrefs(prefs);
}
@ -973,7 +1009,7 @@ Blocklist.prototype = {
disable: false,
blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED,
item: addon,
url: self.getAddonBlocklistURL(addon.id),
url: self.getAddonBlocklistURL(addon),
});
}
@ -1056,7 +1092,7 @@ Blocklist.prototype = {
// This add-on is softblocked.
addon.item.softDisabled = true;
// We must revert certain prefs.
let prefs = self._getAddonPrefs(addon.item.id);
let prefs = self._getAddonPrefs(addon.item);
resetPrefs(prefs);
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem name="/^Mozilla Corp\.$/">
<versionRange severity="1">
<targetApplication id="xpcshell@tests.mozilla.org">
<versionRange minVersion="1" maxVersion="2.*"/>
</targetApplication>
</versionRange>
</emItem>
<emItem id="/block2/" name="/^Moz/" creator="Dangerous"
homepageURL="/\.dangerous\.com/" updateURL="/\.dangerous\.com/">
<versionRange severity="3">
<targetApplication id="xpcshell@tests.mozilla.org">
<versionRange minVersion="1" maxVersion="2.*"/>
</targetApplication>
</versionRange>
</emItem>
</emItems>
</blocklist>

View File

@ -3,7 +3,10 @@
<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
<emItems>
<emItem id="test_bug393285_2@tests.mozilla.org"/>
<emItem id="test_bug393285_3@tests.mozilla.org">
<emItem id="test_bug393285_3a@tests.mozilla.org">
<versionRange minVersion="1.0" maxVersion="1.0"/>
</emItem>
<emItem id="test_bug393285_3b@tests.mozilla.org">
<versionRange minVersion="1.0" maxVersion="1.0"/>
</emItem>
<emItem id="test_bug393285_4@tests.mozilla.org">

View File

@ -0,0 +1,159 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests blocking of extensions by ID, name, creator, homepageURL, updateURL
// and RegExps for each. See bug 897735.
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
Cu.import("resource://testing-common/httpd.js");
var testserver = new HttpServer();
testserver.start(-1);
gPort = testserver.identity.primaryPort;
// register static files with server and interpolate port numbers in them
mapFile("/data/test_blocklist_metadata_filters_1.xml", testserver);
const profileDir = gProfD.clone();
profileDir.append("extensions");
// 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;
});
//run the code after the blocklist is closed
Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
},
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 Cr.NS_ERROR_NO_AGGREGATION;
return WindowWatcher.QueryInterface(iid);
}
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
"Fake Window Watcher",
"@mozilla.org/embedcomp/window-watcher;1",
WindowWatcherFactory);
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:" +
gPort + "/data/" + aFile);
var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsITimerCallback);
blocklist.notify(null);
}
function end_test() {
testserver.stop(do_test_finished);
}
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
// Should get blocked by name
writeInstallRDFForExtension({
id: "block1@tests.mozilla.org",
version: "1.0",
name: "Mozilla Corp.",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Should get blocked by all the attributes.
writeInstallRDFForExtension({
id: "block2@tests.mozilla.org",
version: "1.0",
name: "Moz-addon",
creator: "Dangerous",
homepageURL: "www.extension.dangerous.com",
updateURL: "www.extension.dangerous.com/update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Fails to get blocked because of a different ID even though other
// attributes match against a blocklist entry.
writeInstallRDFForExtension({
id: "block3@tests.mozilla.org",
version: "1.0",
name: "Moz-addon",
creator: "Dangerous",
homepageURL: "www.extensions.dangerous.com",
updateURL: "www.extension.dangerous.com/update.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
startupManager();
AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
"block2@tests.mozilla.org",
"block3@tests.mozilla.org"], function([a1, a2, a3]) {
do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(a2.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
do_check_eq(a3.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
run_test_1();
});
}
function run_test_1() {
load_blocklist("test_blocklist_metadata_filters_1.xml", function() {
restartManager();
AddonManager.getAddonsByIDs(["block1@tests.mozilla.org",
"block2@tests.mozilla.org",
"block3@tests.mozilla.org"], function([a1, a2, a3]) {
do_check_eq(a1.blocklistState, Ci.nsIBlocklistService.STATE_SOFTBLOCKED);
do_check_eq(a2.blocklistState, Ci.nsIBlocklistService.STATE_BLOCKED);
do_check_eq(a3.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
end_test();
});
});
}

View File

@ -79,10 +79,10 @@ var ADDONS = [
// This is a replacement for the blocklist service
var BlocklistService = {
getAddonBlocklistState: function(aId, aVersion, aAppVersion, aToolkitVersion) {
if (aId == "bug335238_3@tests.mozilla.org")
getAddonBlocklistState: function(aAddon, aAppVersion, aToolkitVersion) {
if (aAddon.id == "bug335238_3@tests.mozilla.org")
return Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
if (aId == "bug335238_4@tests.mozilla.org")
if (aAddon.id == "bug335238_4@tests.mozilla.org")
return Ci.nsIBlocklistService.STATE_BLOCKED;
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
},
@ -91,8 +91,8 @@ var BlocklistService = {
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
},
isAddonBlocklisted: function(aId, aVersion, aAppVersion, aToolkitVersion) {
return this.getAddonBlocklistState(aId, aVersion, aAppVersion, aToolkitVersion) ==
isAddonBlocklisted: function(aAddon, aAppVersion, aToolkitVersion) {
return this.getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion) ==
Ci.nsIBlocklistService.STATE_BLOCKED;
},

View File

@ -3,53 +3,325 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
Cu.import("resource://testing-common/httpd.js");
var testserver = new HttpServer();
testserver.start(-1);
gPort = testserver.identity.primaryPort;
// register static files with server and interpolate port numbers in them
mapFile("/data/test_bug393285.xml", testserver);
const profileDir = gProfD.clone();
profileDir.append("extensions");
let addonIDs = ["test_bug393285_1@tests.mozilla.org",
"test_bug393285_2@tests.mozilla.org",
"test_bug393285_3a@tests.mozilla.org",
"test_bug393285_3b@tests.mozilla.org",
"test_bug393285_4@tests.mozilla.org",
"test_bug393285_5@tests.mozilla.org",
"test_bug393285_6@tests.mozilla.org",
"test_bug393285_7@tests.mozilla.org",
"test_bug393285_8@tests.mozilla.org",
"test_bug393285_9@tests.mozilla.org",
"test_bug393285_10@tests.mozilla.org",
"test_bug393285_11@tests.mozilla.org",
"test_bug393285_12@tests.mozilla.org",
"test_bug393285_13@tests.mozilla.org",
"test_bug393285_14@tests.mozilla.org"];
// A window watcher to deal with the blocklist UI dialog.
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;
});
//run the code after the blocklist is closed
Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
},
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 Cr.NS_ERROR_NO_AGGREGATION;
return WindowWatcher.QueryInterface(iid);
}
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
"Fake Window Watcher",
"@mozilla.org/embedcomp/window-watcher;1",
WindowWatcherFactory);
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:" +
gPort + "/data/" + aFile);
var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsITimerCallback);
blocklist.notify(null);
}
function end_test() {
testserver.stop(do_test_finished);
}
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
// We cannot force the blocklist to update so just copy our test list to the profile
var blocklistFile = gProfD.clone();
blocklistFile.append("blocklist.xml");
if (blocklistFile.exists())
blocklistFile.remove(false);
var source = do_get_file("data/test_bug393285.xml");
source.copyTo(gProfD, "blocklist.xml");
writeInstallRDFForExtension({
id: "test_bug393285_1@tests.mozilla.org",
name: "extension 1",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
.getService(Components.interfaces.nsIBlocklistService);
// No info in blocklist, shouldn't be blocked
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_1@tests.mozilla.org", "1", "1", "1.9"));
// Should always be blocked
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_2@tests.mozilla.org", "1", "1", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_2@tests.mozilla.org",
name: "extension 2",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Only version 1 should be blocked
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_3@tests.mozilla.org", "1", "1", "1.9"));
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_3@tests.mozilla.org", "2", "1", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_3a@tests.mozilla.org",
name: "extension 3a",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Should be blocked for app version 1
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_4@tests.mozilla.org", "1", "1", "1.9"));
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_4@tests.mozilla.org", "1", "2", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_3b@tests.mozilla.org",
name: "extension 3b",
version: "2.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Not blocklisted because we are a different OS
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_5@tests.mozilla.org", "1", "2", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_4@tests.mozilla.org",
name: "extension 4",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Blocklisted based on OS
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_6@tests.mozilla.org", "1", "2", "1.9"));
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_7@tests.mozilla.org", "1", "2", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_5@tests.mozilla.org",
name: "extension 5",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Not blocklisted because we are a different ABI
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_8@tests.mozilla.org", "1", "2", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_6@tests.mozilla.org",
name: "extension 6",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Blocklisted based on ABI
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_9@tests.mozilla.org", "1", "2", "1.9"));
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_10@tests.mozilla.org", "1", "2", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_7@tests.mozilla.org",
name: "extension 7",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Doesnt match both os and abi so not blocked
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_11@tests.mozilla.org", "1", "2", "1.9"));
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_12@tests.mozilla.org", "1", "2", "1.9"));
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_13@tests.mozilla.org", "1", "2", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_8@tests.mozilla.org",
name: "extension 8",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
// Matches both os and abi so blocked
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_14@tests.mozilla.org", "1", "2", "1.9"));
writeInstallRDFForExtension({
id: "test_bug393285_9@tests.mozilla.org",
name: "extension 9",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
writeInstallRDFForExtension({
id: "test_bug393285_10@tests.mozilla.org",
name: "extension 10",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
writeInstallRDFForExtension({
id: "test_bug393285_11@tests.mozilla.org",
name: "extension 11",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
writeInstallRDFForExtension({
id: "test_bug393285_12@tests.mozilla.org",
name: "extension 12",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
writeInstallRDFForExtension({
id: "test_bug393285_13@tests.mozilla.org",
name: "extension 13",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
writeInstallRDFForExtension({
id: "test_bug393285_14@tests.mozilla.org",
name: "extension 14",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
startupManager();
AddonManager.getAddonsByIDs(addonIDs, function(addons) {
for (addon of addons) {
do_check_eq(addon.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
}
run_test_1();
});
}
function run_test_1() {
load_blocklist("test_bug393285.xml", function() {
restartManager();
var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
.getService(Ci.nsIBlocklistService);
AddonManager.getAddonsByIDs(addonIDs,
function([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
a11, a12, a13, a14, a15]) {
// No info in blocklist, shouldn't be blocked
do_check_false(blocklist.isAddonBlocklisted(a1, "1", "1.9"));
// Should always be blocked
do_check_true(blocklist.isAddonBlocklisted(a2, "1", "1.9"));
// Only version 1 should be blocked
do_check_true(blocklist.isAddonBlocklisted(a3, "1", "1.9"));
do_check_false(blocklist.isAddonBlocklisted(a4, "1", "1.9"));
// Should be blocked for app version 1
do_check_true(blocklist.isAddonBlocklisted(a5, "1", "1.9"));
do_check_false(blocklist.isAddonBlocklisted(a5, "2", "1.9"));
// Not blocklisted because we are a different OS
do_check_false(blocklist.isAddonBlocklisted(a6, "2", "1.9"));
// Blocklisted based on OS
do_check_true(blocklist.isAddonBlocklisted(a7, "2", "1.9"));
do_check_true(blocklist.isAddonBlocklisted(a8, "2", "1.9"));
// Not blocklisted because we are a different ABI
do_check_false(blocklist.isAddonBlocklisted(a9, "2", "1.9"));
// Blocklisted based on ABI
do_check_true(blocklist.isAddonBlocklisted(a10, "2", "1.9"));
do_check_true(blocklist.isAddonBlocklisted(a11, "2", "1.9"));
// Doesnt match both os and abi so not blocked
do_check_false(blocklist.isAddonBlocklisted(a12, "2", "1.9"));
do_check_false(blocklist.isAddonBlocklisted(a13, "2", "1.9"));
do_check_false(blocklist.isAddonBlocklisted(a14, "2", "1.9"));
// Matches both os and abi so blocked
do_check_true(blocklist.isAddonBlocklisted(a15, "2", "1.9"));
end_test();
});
});
}

View File

@ -3,24 +3,165 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
let addonIDs = ["test_bug393285_1@tests.mozilla.org",
"test_bug393285_2@tests.mozilla.org",
"test_bug393285_3a@tests.mozilla.org",
"test_bug393285_4@tests.mozilla.org"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
const URI_EXTENSION_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
Cu.import("resource://testing-common/httpd.js");
var testserver = new HttpServer();
testserver.start(-1);
gPort = testserver.identity.primaryPort;
// register static files with server and interpolate port numbers in them
mapFile("/data/test_bug393285.xml", testserver);
const profileDir = gProfD.clone();
profileDir.append("extensions");
// A window watcher to deal with the blocklist UI dialog.
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;
});
//run the code after the blocklist is closed
Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
},
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 Cr.NS_ERROR_NO_AGGREGATION;
return WindowWatcher.QueryInterface(iid);
}
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),
"Fake Window Watcher",
"@mozilla.org/embedcomp/window-watcher;1",
WindowWatcherFactory);
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:" +
gPort + "/data/" + aFile);
var blocklist = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsITimerCallback);
blocklist.notify(null);
}
function end_test() {
testserver.stop(do_test_finished);
}
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
// We cannot force the blocklist to update so just copy our test list to the profile
var blocklistFile = gProfD.clone();
blocklistFile.append("blocklist.xml");
if (blocklistFile.exists())
blocklistFile.remove(false);
var source = do_get_file("data/test_bug393285.xml");
source.copyTo(gProfD, "blocklist.xml");
writeInstallRDFForExtension({
id: "test_bug393285_1@tests.mozilla.org",
name: "extension 1",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
.getService(Components.interfaces.nsIBlocklistService);
// All these should be blocklisted for the current app.
do_check_false(blocklist.isAddonBlocklisted("test_bug393285_1@tests.mozilla.org", "1", null, null));
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_2@tests.mozilla.org", "1", null, null));
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_3@tests.mozilla.org", "1", null, null));
do_check_true(blocklist.isAddonBlocklisted("test_bug393285_4@tests.mozilla.org", "1", null, null));
writeInstallRDFForExtension({
id: "test_bug393285_2@tests.mozilla.org",
name: "extension 2",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
writeInstallRDFForExtension({
id: "test_bug393285_3a@tests.mozilla.org",
name: "extension 3a",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
writeInstallRDFForExtension({
id: "test_bug393285_4@tests.mozilla.org",
name: "extension 4",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "3"
}]
}, profileDir);
startupManager();
AddonManager.getAddonsByIDs(addonIDs, function(addons) {
for (addon of addons) {
do_check_eq(addon.blocklistState, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
}
run_test_1();
});
}
function run_test_1() {
load_blocklist("test_bug393285.xml", function() {
restartManager();
var blocklist = Cc["@mozilla.org/extensions/blocklist;1"]
.getService(Ci.nsIBlocklistService);
AddonManager.getAddonsByIDs(addonIDs,
function([a1, a2, a3, a4]) {
// No info in blocklist, shouldn't be blocked
do_check_false(blocklist.isAddonBlocklisted(a1, null, null));
// All these should be blocklisted for the current app.
do_check_true(blocklist.isAddonBlocklisted(a2, null, null));
do_check_true(blocklist.isAddonBlocklisted(a3, null, null));
do_check_true(blocklist.isAddonBlocklisted(a4, null, null));
end_test();
});
});
}

View File

@ -461,11 +461,11 @@ function check_test_pt3() {
do_check_eq(check_addon_state(addons[3]), "false,false,true");
// Check blockIDs are correct
do_check_eq(blocklist.getAddonBlocklistURL(addons[0].id,''),create_blocklistURL(addons[0].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[1].id,''),create_blocklistURL(addons[1].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[2].id,''),create_blocklistURL(addons[2].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[3].id,''),create_blocklistURL(addons[3].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[4].id,''),create_blocklistURL(addons[4].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[0]),create_blocklistURL(addons[0].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[1]),create_blocklistURL(addons[1].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[2]),create_blocklistURL(addons[2].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[3]),create_blocklistURL(addons[3].id));
do_check_eq(blocklist.getAddonBlocklistURL(addons[4]),create_blocklistURL(addons[4].id));
// All plugins have the same blockID on the test
do_check_eq(blocklist.getPluginBlocklistURL(PLUGINS[0]), create_blocklistURL('test_bug455906_plugin'));

View File

@ -17,6 +17,7 @@ skip-if = os == "android"
[test_badschema.js]
[test_blocklistchange.js]
[test_blocklist_prefs.js]
[test_blocklist_metadata_filters.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_blocklist_regexp.js]

View File

@ -869,7 +869,7 @@ var gIncompatibleCheckPage = {
// the add-on will become incompatible.
let bs = CoC["@mozilla.org/extensions/blocklist;1"].
getService(CoI.nsIBlocklistService);
if (bs.isAddonBlocklisted(addon.id, install.version,
if (bs.isAddonBlocklisted(addon,
gUpdates.update.appVersion,
gUpdates.update.platformVersion))
return;

View File

@ -2957,7 +2957,7 @@ UpdateService.prototype = {
// the add-on will become incompatible.
let bs = Cc["@mozilla.org/extensions/blocklist;1"].
getService(Ci.nsIBlocklistService);
if (bs.isAddonBlocklisted(addon.id, install.version,
if (bs.isAddonBlocklisted(addon,
gUpdates.update.appVersion,
gUpdates.update.platformVersion))
return;

View File

@ -29,10 +29,8 @@ interface nsIBlocklistService : nsISupports
/**
* Determine if an item is blocklisted
* @param id
* The ID of the item.
* @param version
* The item's version.
* @param addon
* The addon item to be checked.
* @param appVersion
* The version of the application we are checking in the blocklist.
* If this parameter is null, the version of the running application
@ -44,16 +42,14 @@ interface nsIBlocklistService : nsISupports
* @returns true if the item is compatible with this version of the
* application or this version of the toolkit, false, otherwise.
*/
boolean isAddonBlocklisted(in AString id, in AString version,
boolean isAddonBlocklisted(in jsval addon,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
/**
* Determine the blocklist state of an add-on
* @param id
* The ID of the item.
* @param version
* The item's version.
* The addon item to be checked.
* @param appVersion
* The version of the application we are checking in the blocklist.
* If this parameter is null, the version of the running application
@ -64,7 +60,7 @@ interface nsIBlocklistService : nsISupports
* is used.
* @returns The STATE constant.
*/
unsigned long getAddonBlocklistState(in AString id, in AString version,
unsigned long getAddonBlocklistState(in jsval addon,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);
@ -88,11 +84,11 @@ interface nsIBlocklistService : nsISupports
/**
* Determine the blocklist web page of an add-on.
* @param id
* The ID of the blocked add-on.
* @param addon
* The addon item whose url is required.
* @returns The URL of the description page.
*/
AString getAddonBlocklistURL(in AString id, in AString version,
AString getAddonBlocklistURL(in jsval addon,
[optional] in AString appVersion,
[optional] in AString toolkitVersion);