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

CLOSED TREE
This commit is contained in:
Sachin Hosmani 2014-01-06 14:16:32 +05:30
parent bde0b0ec9d
commit 069b0b1b39
19 changed files with 778 additions and 146 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 950298 requires clobber because it changes where nsinstall is picked and it was previously installed there with wrong permissions. Also, the directory where js is built changed.
Bug 897735 requires a clobber due to mass mochitest bustage otherwise

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
@ -6212,7 +6210,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() {
@ -6224,7 +6222,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) {
@ -6342,7 +6340,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);