2007-08-16 00:43:12 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/*
|
2007-08-16 21:17:45 +00:00
|
|
|
# ***** 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 the Blocklist Service.
|
|
|
|
#
|
|
|
|
# The Initial Developer of the Original Code is
|
|
|
|
# Mozilla Corporation.
|
|
|
|
# Portions created by the Initial Developer are Copyright (C) 2007
|
|
|
|
# the Initial Developer. All Rights Reserved.
|
|
|
|
#
|
|
|
|
# Contributor(s):
|
|
|
|
# Robert Strong <robert.bugzilla@gmail.com>
|
|
|
|
# Michael Wu <flamingice@sourmilk.net>
|
2008-09-02 11:53:34 +00:00
|
|
|
# Dave Townsend <dtownsend@oxymoronical.com>
|
2007-08-16 21:17:45 +00:00
|
|
|
#
|
|
|
|
# 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 *****
|
|
|
|
*/
|
2007-08-16 00:43:12 +00:00
|
|
|
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
const Cr = Components.results;
|
|
|
|
|
2007-08-25 06:12:05 +00:00
|
|
|
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
const TOOLKIT_ID = "toolkit@mozilla.org"
|
|
|
|
const KEY_PROFILEDIR = "ProfD";
|
2008-03-19 22:35:03 +00:00
|
|
|
const KEY_APPDIR = "XCurProcD";
|
2007-08-16 00:43:12 +00:00
|
|
|
const FILE_BLOCKLIST = "blocklist.xml";
|
|
|
|
const PREF_BLOCKLIST_URL = "extensions.blocklist.url";
|
|
|
|
const PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
|
|
|
|
const PREF_BLOCKLIST_INTERVAL = "extensions.blocklist.interval";
|
2008-11-02 12:13:48 +00:00
|
|
|
const PREF_BLOCKLIST_LEVEL = "extensions.blocklist.level";
|
2008-04-25 17:10:02 +00:00
|
|
|
const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale";
|
|
|
|
const PREF_PARTNER_BRANCH = "app.partner.";
|
|
|
|
const PREF_APP_DISTRIBUTION = "distribution.id";
|
|
|
|
const PREF_APP_DISTRIBUTION_VERSION = "distribution.version";
|
|
|
|
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
|
2007-08-16 00:43:12 +00:00
|
|
|
const PREF_EM_LOGGING_ENABLED = "extensions.logging.enabled";
|
|
|
|
const XMLURI_BLOCKLIST = "http://www.mozilla.org/2006/addons-blocklist";
|
|
|
|
const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
|
2008-04-25 17:10:02 +00:00
|
|
|
const UNKNOWN_XPCOM_ABI = "unknownABI";
|
2008-11-02 12:13:48 +00:00
|
|
|
const URI_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul"
|
|
|
|
const DEFAULT_SEVERITY = 3;
|
|
|
|
const DEFAULT_LEVEL = 2;
|
|
|
|
const MAX_BLOCK_LEVEL = 3;
|
2007-08-16 00:43:12 +00:00
|
|
|
|
|
|
|
const MODE_RDONLY = 0x01;
|
|
|
|
const MODE_WRONLY = 0x02;
|
|
|
|
const MODE_CREATE = 0x08;
|
|
|
|
const MODE_APPEND = 0x10;
|
|
|
|
const MODE_TRUNCATE = 0x20;
|
|
|
|
|
|
|
|
const PERMS_FILE = 0644;
|
|
|
|
const PERMS_DIRECTORY = 0755;
|
|
|
|
|
|
|
|
var gApp = null;
|
|
|
|
var gPref = null;
|
|
|
|
var gOS = null;
|
|
|
|
var gConsole = null;
|
|
|
|
var gVersionChecker = null;
|
|
|
|
var gLoggingEnabled = null;
|
2008-04-25 17:10:02 +00:00
|
|
|
var gABI = null;
|
|
|
|
var gOSVersion = null;
|
2008-11-02 12:13:48 +00:00
|
|
|
var gBlocklistEnabled = true;
|
|
|
|
var gBlocklistLevel = DEFAULT_LEVEL;
|
2007-08-16 00:43:12 +00:00
|
|
|
|
|
|
|
// shared code for suppressing bad cert dialogs
|
|
|
|
#include ../../shared/src/badCertHandler.js
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Logs a string to the error console.
|
|
|
|
* @param string
|
|
|
|
* The string to write to the error console..
|
|
|
|
*/
|
|
|
|
function LOG(string) {
|
|
|
|
if (gLoggingEnabled) {
|
|
|
|
dump("*** " + string + "\n");
|
2007-08-31 00:43:24 +00:00
|
|
|
if (gConsole)
|
|
|
|
gConsole.logStringMessage(string);
|
2007-08-16 00:43:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a preference value, handling the case where there is no default.
|
|
|
|
* @param func
|
|
|
|
* The name of the preference function to call, on nsIPrefBranch
|
|
|
|
* @param preference
|
|
|
|
* The name of the preference
|
|
|
|
* @param defaultValue
|
|
|
|
* The default value to return in the event the preference has
|
|
|
|
* no setting
|
|
|
|
* @returns The value of the preference, or undefined if there was no
|
|
|
|
* user or default value.
|
|
|
|
*/
|
|
|
|
function getPref(func, preference, defaultValue) {
|
|
|
|
try {
|
|
|
|
return gPref[func](preference);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
}
|
|
|
|
return defaultValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the file at the specified hierarchy under a Directory Service key.
|
|
|
|
* @param key
|
|
|
|
* The Directory Service Key to start from
|
|
|
|
* @param pathArray
|
|
|
|
* An array of path components to locate beneath the directory
|
|
|
|
* specified by |key|. The last item in this array must be the
|
|
|
|
* leaf name of a file.
|
|
|
|
* @return nsIFile object for the file specified. The file is NOT created
|
|
|
|
* if it does not exist, however all required directories along
|
|
|
|
* the way are.
|
|
|
|
*/
|
|
|
|
function getFile(key, pathArray) {
|
|
|
|
var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
|
|
|
|
getService(Ci.nsIProperties);
|
|
|
|
var file = fileLocator.get(key, Ci.nsILocalFile);
|
|
|
|
for (var i = 0; i < pathArray.length - 1; ++i) {
|
|
|
|
file.append(pathArray[i]);
|
|
|
|
if (!file.exists())
|
|
|
|
file.create(Ci.nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
|
|
|
|
}
|
|
|
|
file.followLinks = false;
|
|
|
|
file.append(pathArray[pathArray.length - 1]);
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-08-29 08:16:15 +00:00
|
|
|
* Opens a safe file output stream for writing.
|
2007-08-16 00:43:12 +00:00
|
|
|
* @param file
|
|
|
|
* The file to write to.
|
|
|
|
* @param modeFlags
|
2007-08-29 08:16:15 +00:00
|
|
|
* (optional) File open flags. Can be undefined.
|
2007-08-16 00:43:12 +00:00
|
|
|
* @returns nsIFileOutputStream to write to.
|
|
|
|
*/
|
|
|
|
function openSafeFileOutputStream(file, modeFlags) {
|
|
|
|
var fos = Cc["@mozilla.org/network/safe-file-output-stream;1"].
|
|
|
|
createInstance(Ci.nsIFileOutputStream);
|
|
|
|
if (modeFlags === undefined)
|
|
|
|
modeFlags = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE;
|
2007-08-29 08:16:15 +00:00
|
|
|
if (!file.exists())
|
2007-08-16 00:43:12 +00:00
|
|
|
file.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
|
|
|
|
fos.init(file, modeFlags, PERMS_FILE, 0);
|
|
|
|
return fos;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Closes a safe file output stream.
|
|
|
|
* @param stream
|
|
|
|
* The stream to close.
|
|
|
|
*/
|
|
|
|
function closeSafeFileOutputStream(stream) {
|
|
|
|
if (stream instanceof Ci.nsISafeOutputStream)
|
|
|
|
stream.finish();
|
|
|
|
else
|
|
|
|
stream.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructs a URI to a spec.
|
|
|
|
* @param spec
|
|
|
|
* The spec to construct a URI to
|
|
|
|
* @returns The nsIURI constructed.
|
|
|
|
*/
|
|
|
|
function newURI(spec) {
|
|
|
|
var ioServ = Cc["@mozilla.org/network/io-service;1"].
|
|
|
|
getService(Ci.nsIIOService);
|
|
|
|
return ioServ.newURI(spec, null, null);
|
|
|
|
}
|
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
// Restarts the application checking in with observers first
|
|
|
|
function restartApp() {
|
|
|
|
// Notify all windows that an application quit has been requested.
|
|
|
|
var os = Cc["@mozilla.org/observer-service;1"].
|
|
|
|
getService(Ci.nsIObserverService);
|
|
|
|
var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
|
|
|
|
createInstance(Ci.nsISupportsPRBool);
|
|
|
|
os.notifyObservers(cancelQuit, "quit-application-requested", null);
|
|
|
|
|
|
|
|
// Something aborted the quit process.
|
|
|
|
if (cancelQuit.data)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var as = Cc["@mozilla.org/toolkit/app-startup;1"].
|
|
|
|
getService(Ci.nsIAppStartup);
|
|
|
|
as.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
|
|
|
|
}
|
|
|
|
|
2007-11-07 08:56:29 +00:00
|
|
|
/**
|
|
|
|
* Checks whether this blocklist element is valid for the current OS and ABI.
|
|
|
|
* If the element has an "os" attribute then the current OS must appear in
|
2008-10-02 06:49:45 +00:00
|
|
|
* its comma separated list for the element to be valid. Similarly for the
|
2007-11-07 08:56:29 +00:00
|
|
|
* xpcomabi attribute.
|
|
|
|
*/
|
|
|
|
function matchesOSABI(blocklistElement) {
|
|
|
|
if (blocklistElement.hasAttribute("os")) {
|
|
|
|
var choices = blocklistElement.getAttribute("os").split(",");
|
|
|
|
if (choices.length > 0 && choices.indexOf(gApp.OS) < 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blocklistElement.hasAttribute("xpcomabi")) {
|
|
|
|
choices = blocklistElement.getAttribute("xpcomabi").split(",");
|
|
|
|
if (choices.length > 0 && choices.indexOf(gApp.XPCOMABI) < 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-04-25 17:10:02 +00:00
|
|
|
/**
|
|
|
|
* Gets the current value of the locale. It's possible for this preference to
|
|
|
|
* be localized, so we have to do a little extra work here. Similar code
|
|
|
|
* exists in nsHttpHandler.cpp when building the UA string.
|
|
|
|
*/
|
|
|
|
function getLocale() {
|
|
|
|
try {
|
|
|
|
// Get the default branch
|
2008-11-02 12:13:48 +00:00
|
|
|
var defaultPrefs = gPref.getDefaultBranch(null);
|
2008-04-25 17:10:02 +00:00
|
|
|
return defaultPrefs.getCharPref(PREF_GENERAL_USERAGENT_LOCALE);
|
|
|
|
} catch (e) {}
|
|
|
|
|
|
|
|
return gPref.getCharPref(PREF_GENERAL_USERAGENT_LOCALE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read the update channel from defaults only. We do this to ensure that
|
|
|
|
* the channel is tightly coupled with the application and does not apply
|
|
|
|
* to other installations of the application that may use the same profile.
|
|
|
|
*/
|
|
|
|
function getUpdateChannel() {
|
|
|
|
var channel = "default";
|
|
|
|
var prefName;
|
|
|
|
var prefValue;
|
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
var defaults = gPref.getDefaultBranch(null);
|
2008-04-25 17:10:02 +00:00
|
|
|
try {
|
|
|
|
channel = defaults.getCharPref(PREF_APP_UPDATE_CHANNEL);
|
|
|
|
} catch (e) {
|
|
|
|
// use default when pref not found
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
var partners = gPref.getChildList(PREF_PARTNER_BRANCH, { });
|
|
|
|
if (partners.length) {
|
|
|
|
channel += "-cck";
|
|
|
|
partners.sort();
|
|
|
|
|
|
|
|
for each (prefName in partners) {
|
|
|
|
prefValue = gPref.getCharPref(prefName);
|
|
|
|
channel += "-" + prefValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
Components.utils.reportError(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
return channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the distribution pref values, from defaults only */
|
|
|
|
function getDistributionPrefValue(aPrefName) {
|
|
|
|
var prefValue = "default";
|
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
var defaults = gPref.getDefaultBranch(null);
|
2008-04-25 17:10:02 +00:00
|
|
|
try {
|
|
|
|
prefValue = defaults.getCharPref(aPrefName);
|
|
|
|
} catch (e) {
|
|
|
|
// use default when pref not found
|
|
|
|
}
|
|
|
|
|
|
|
|
return prefValue;
|
|
|
|
}
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
/**
|
|
|
|
* Manages the Blocklist. The Blocklist is a representation of the contents of
|
|
|
|
* blocklist.xml and allows us to remotely disable / re-enable blocklisted
|
|
|
|
* items managed by the Extension Manager with an item's appDisabled property.
|
|
|
|
* It also blocklists plugins with data from blocklist.xml.
|
|
|
|
*/
|
|
|
|
|
|
|
|
function Blocklist() {
|
|
|
|
gApp = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
|
|
|
|
gApp.QueryInterface(Ci.nsIXULRuntime);
|
|
|
|
gPref = Cc["@mozilla.org/preferences-service;1"].
|
2008-11-02 12:13:48 +00:00
|
|
|
getService(Ci.nsIPrefService).
|
|
|
|
QueryInterface(Ci.nsIPrefBranch2);
|
2007-08-16 00:43:12 +00:00
|
|
|
gVersionChecker = Cc["@mozilla.org/xpcom/version-comparator;1"].
|
|
|
|
getService(Ci.nsIVersionComparator);
|
|
|
|
gConsole = Cc["@mozilla.org/consoleservice;1"].
|
2007-08-29 08:16:15 +00:00
|
|
|
getService(Ci.nsIConsoleService);
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
gOS = Cc["@mozilla.org/observer-service;1"].
|
|
|
|
getService(Ci.nsIObserverService);
|
|
|
|
gOS.addObserver(this, "xpcom-shutdown", false);
|
2008-04-25 17:10:02 +00:00
|
|
|
|
|
|
|
// Not all builds have a known ABI
|
|
|
|
try {
|
|
|
|
gABI = gApp.XPCOMABI;
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
LOG("Blocklist: XPCOM ABI unknown.");
|
|
|
|
gABI = UNKNOWN_XPCOM_ABI;
|
|
|
|
}
|
|
|
|
|
|
|
|
var osVersion;
|
|
|
|
var sysInfo = Components.classes["@mozilla.org/system-info;1"]
|
|
|
|
.getService(Components.interfaces.nsIPropertyBag2);
|
|
|
|
try {
|
|
|
|
osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version");
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
LOG("Blocklist: OS Version unknown.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (osVersion) {
|
|
|
|
try {
|
|
|
|
osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")";
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
// Not all platforms have a secondary widget library, so an error is nothing to worry about.
|
|
|
|
}
|
|
|
|
gOSVersion = encodeURIComponent(osVersion);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
// Mac universal build should report a different ABI than either macppc
|
|
|
|
// or mactel.
|
|
|
|
var macutils = Components.classes["@mozilla.org/xpcom/mac-utils;1"]
|
|
|
|
.getService(Components.interfaces.nsIMacUtils);
|
|
|
|
|
|
|
|
if (macutils.isUniversalBinary)
|
|
|
|
gABI = "Universal-gcc3";
|
|
|
|
#endif
|
2007-08-16 00:43:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Blocklist.prototype = {
|
|
|
|
/**
|
|
|
|
* Extension ID -> array of Version Ranges
|
|
|
|
* Each value in the version range array is a JS Object that has the
|
|
|
|
* following properties:
|
|
|
|
* "minVersion" The minimum version in a version range (default = 0)
|
|
|
|
* "maxVersion" The maximum version in a version range (default = *)
|
|
|
|
* "targetApps" Application ID -> array of Version Ranges
|
|
|
|
* (default = current application ID)
|
|
|
|
* Each value in the version range array is a JS Object that
|
|
|
|
* has the following properties:
|
|
|
|
* "minVersion" The minimum version in a version range
|
|
|
|
* (default = 0)
|
|
|
|
* "maxVersion" The maximum version in a version range
|
|
|
|
* (default = *)
|
|
|
|
*/
|
|
|
|
_addonEntries: null,
|
|
|
|
_pluginEntries: null,
|
|
|
|
|
|
|
|
observe: function (aSubject, aTopic, aData) {
|
|
|
|
switch (aTopic) {
|
|
|
|
case "profile-after-change":
|
|
|
|
gLoggingEnabled = getPref("getBoolPref", PREF_EM_LOGGING_ENABLED, false);
|
2008-11-02 12:13:48 +00:00
|
|
|
gBlocklistEnabled = getPref("getBoolPref", PREF_BLOCKLIST_ENABLED, true);
|
|
|
|
gBlocklistLevel = Math.min(getPref("getIntPref", PREF_BLOCKLIST_LEVEL, DEFAULT_LEVEL),
|
|
|
|
MAX_BLOCK_LEVEL);
|
|
|
|
gPref.addObserver("extensions.blocklist.", this, false);
|
2007-08-16 00:43:12 +00:00
|
|
|
var tm = Cc["@mozilla.org/updates/timer-manager;1"].
|
|
|
|
getService(Ci.nsIUpdateTimerManager);
|
|
|
|
var interval = getPref("getIntPref", PREF_BLOCKLIST_INTERVAL, 86400);
|
|
|
|
tm.registerTimer("blocklist-background-update-timer", this, interval);
|
|
|
|
break;
|
|
|
|
case "xpcom-shutdown":
|
|
|
|
gOS.removeObserver(this, "xpcom-shutdown");
|
|
|
|
gOS = null;
|
2008-11-28 20:49:48 +00:00
|
|
|
gPref.removeObserver("extensions.blocklist.", this);
|
2007-08-16 00:43:12 +00:00
|
|
|
gPref = null;
|
|
|
|
gConsole = null;
|
|
|
|
gVersionChecker = null;
|
|
|
|
gApp = null;
|
|
|
|
break;
|
2008-11-02 12:13:48 +00:00
|
|
|
case "nsPref:changed":
|
|
|
|
switch (aData) {
|
|
|
|
case PREF_BLOCKLIST_ENABLED:
|
|
|
|
gBlocklistEnabled = getPref("getBoolPref", PREF_BLOCKLIST_ENABLED, true);
|
|
|
|
this._loadBlocklist();
|
|
|
|
this._blocklistUpdated(null, null);
|
|
|
|
break;
|
|
|
|
case PREF_BLOCKLIST_LEVEL:
|
|
|
|
gBlocklistLevel = Math.min(getPref("getIntPref", PREF_BLOCKLIST_LEVEL, DEFAULT_LEVEL),
|
|
|
|
MAX_BLOCK_LEVEL);
|
|
|
|
this._blocklistUpdated(null, null);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2007-08-16 00:43:12 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
/* See nsIBlocklistService */
|
2007-08-16 00:43:12 +00:00
|
|
|
isAddonBlocklisted: function(id, version, appVersion, toolkitVersion) {
|
2008-11-02 12:13:48 +00:00
|
|
|
return this.getAddonBlocklistState(id, version, appVersion, toolkitVersion) ==
|
|
|
|
Ci.nsIBlocklistService.STATE_BLOCKED;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* See nsIBlocklistService */
|
|
|
|
getAddonBlocklistState: function(id, version, appVersion, toolkitVersion) {
|
2007-08-16 00:43:12 +00:00
|
|
|
if (!this._addonEntries)
|
2008-03-19 22:35:03 +00:00
|
|
|
this._loadBlocklist();
|
2008-11-02 12:13:48 +00:00
|
|
|
return this._getAddonBlocklistState(id, version, this._addonEntries,
|
|
|
|
appVersion, toolkitVersion);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private version of getAddonBlocklistState that allows the caller to pass in
|
|
|
|
* the add-on blocklist entries to compare against.
|
|
|
|
*
|
|
|
|
* @param id
|
|
|
|
* The ID of the item to get the blocklist state for.
|
|
|
|
* @param version
|
|
|
|
* The version of the item to get the blocklist state for.
|
|
|
|
* @param addonEntries
|
|
|
|
* The add-on blocklist entries to compare against.
|
|
|
|
* @param appVersion
|
|
|
|
* The application version to compare to, will use the current
|
|
|
|
* version if null.
|
|
|
|
* @param toolkitVersion
|
|
|
|
* The toolkit version to compare to, will use the current version if
|
|
|
|
* null.
|
|
|
|
* @returns The blocklist state for the item, one of the STATE constants as
|
|
|
|
* defined in nsIBlocklistService.
|
|
|
|
*/
|
|
|
|
_getAddonBlocklistState: function(id, version, addonEntries, appVersion, toolkitVersion) {
|
|
|
|
if (!gBlocklistEnabled)
|
|
|
|
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
|
|
|
|
2008-02-29 19:06:29 +00:00
|
|
|
if (!appVersion)
|
2007-08-16 00:43:12 +00:00
|
|
|
appVersion = gApp.version;
|
2008-02-29 19:06:29 +00:00
|
|
|
if (!toolkitVersion)
|
2007-08-16 00:43:12 +00:00
|
|
|
toolkitVersion = gApp.platformVersion;
|
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
var blItem = addonEntries[id];
|
2007-08-16 00:43:12 +00:00
|
|
|
if (!blItem)
|
2008-11-02 12:13:48 +00:00
|
|
|
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
2007-08-16 00:43:12 +00:00
|
|
|
|
|
|
|
for (var i = 0; i < blItem.length; ++i) {
|
2008-09-02 11:53:34 +00:00
|
|
|
if (blItem[i].includesItem(version, appVersion, toolkitVersion))
|
2008-11-02 12:13:48 +00:00
|
|
|
return blItem[i].severity >= gBlocklistLevel ? Ci.nsIBlocklistService.STATE_BLOCKED :
|
|
|
|
Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
|
2007-08-16 00:43:12 +00:00
|
|
|
}
|
2008-11-02 12:13:48 +00:00
|
|
|
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
2007-08-16 00:43:12 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
notify: function(aTimer) {
|
2008-11-02 12:13:48 +00:00
|
|
|
if (!gBlocklistEnabled)
|
2007-08-16 00:43:12 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
try {
|
|
|
|
var dsURI = gPref.getCharPref(PREF_BLOCKLIST_URL);
|
|
|
|
}
|
|
|
|
catch (e) {
|
2007-08-29 08:16:15 +00:00
|
|
|
LOG("Blocklist::notify: The " + PREF_BLOCKLIST_URL + " preference" +
|
2007-08-16 00:43:12 +00:00
|
|
|
" is missing!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dsURI = dsURI.replace(/%APP_ID%/g, gApp.ID);
|
|
|
|
dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version);
|
2008-04-25 17:10:02 +00:00
|
|
|
dsURI = dsURI.replace(/%PRODUCT%/g, gApp.name);
|
|
|
|
dsURI = dsURI.replace(/%VERSION%/g, gApp.version);
|
|
|
|
dsURI = dsURI.replace(/%BUILD_ID%/g, gApp.appBuildID);
|
|
|
|
dsURI = dsURI.replace(/%BUILD_TARGET%/g, gApp.OS + "_" + gABI);
|
|
|
|
dsURI = dsURI.replace(/%OS_VERSION%/g, gOSVersion);
|
|
|
|
dsURI = dsURI.replace(/%LOCALE%/g, getLocale());
|
|
|
|
dsURI = dsURI.replace(/%CHANNEL%/g, getUpdateChannel());
|
|
|
|
dsURI = dsURI.replace(/%PLATFORM_VERSION%/g, gApp.platformVersion);
|
|
|
|
dsURI = dsURI.replace(/%DISTRIBUTION%/g,
|
|
|
|
getDistributionPrefValue(PREF_APP_DISTRIBUTION));
|
|
|
|
dsURI = dsURI.replace(/%DISTRIBUTION_VERSION%/g,
|
|
|
|
getDistributionPrefValue(PREF_APP_DISTRIBUTION_VERSION));
|
|
|
|
dsURI = dsURI.replace(/\+/g, "%2B");
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
// Verify that the URI is valid
|
|
|
|
try {
|
|
|
|
var uri = newURI(dsURI);
|
|
|
|
}
|
|
|
|
catch (e) {
|
2007-08-29 08:16:15 +00:00
|
|
|
LOG("Blocklist::notify: There was an error creating the blocklist URI\r\n" +
|
2007-08-16 00:43:12 +00:00
|
|
|
"for: " + dsURI + ", error: " + e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
|
|
|
createInstance(Ci.nsIXMLHttpRequest);
|
|
|
|
request.open("GET", uri.spec, true);
|
|
|
|
request.channel.notificationCallbacks = new BadCertHandler();
|
|
|
|
request.overrideMimeType("text/xml");
|
|
|
|
request.setRequestHeader("Cache-Control", "no-cache");
|
|
|
|
request.QueryInterface(Components.interfaces.nsIJSXMLHttpRequest);
|
|
|
|
|
|
|
|
var self = this;
|
|
|
|
request.onerror = function(event) { self.onXMLError(event); };
|
|
|
|
request.onload = function(event) { self.onXMLLoad(event); };
|
|
|
|
request.send(null);
|
2008-11-02 12:13:48 +00:00
|
|
|
|
|
|
|
// When the blocklist loads we need to compare it to the current copy so
|
|
|
|
// make sure we have loaded it.
|
|
|
|
if (!this._addonEntries)
|
|
|
|
this._loadBlocklist();
|
2007-08-16 00:43:12 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
onXMLLoad: function(aEvent) {
|
|
|
|
var request = aEvent.target;
|
|
|
|
try {
|
|
|
|
checkCert(request.channel);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
LOG("Blocklist::onXMLLoad: " + e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var responseXML = request.responseXML;
|
|
|
|
if (!responseXML || responseXML.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
|
|
|
|
(request.status != 200 && request.status != 0)) {
|
|
|
|
LOG("Blocklist::onXMLLoad: there was an error during load");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var blocklistFile = getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
|
|
|
|
if (blocklistFile.exists())
|
|
|
|
blocklistFile.remove(false);
|
|
|
|
var fos = openSafeFileOutputStream(blocklistFile);
|
|
|
|
fos.write(request.responseText, request.responseText.length);
|
|
|
|
closeSafeFileOutputStream(fos);
|
2008-11-02 12:13:48 +00:00
|
|
|
|
|
|
|
var oldAddonEntries = this._addonEntries;
|
|
|
|
var oldPluginEntries = this._pluginEntries;
|
|
|
|
this._addonEntries = { };
|
|
|
|
this._pluginEntries = { };
|
2007-08-16 00:43:12 +00:00
|
|
|
this._loadBlocklistFromFile(getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]));
|
2008-11-02 12:13:48 +00:00
|
|
|
|
|
|
|
this._blocklistUpdated(oldAddonEntries, oldPluginEntries);
|
2007-08-16 00:43:12 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
onXMLError: function(aEvent) {
|
|
|
|
try {
|
|
|
|
var request = aEvent.target;
|
|
|
|
// the following may throw (e.g. a local file or timeout)
|
|
|
|
var status = request.status;
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
request = aEvent.target.channel.QueryInterface(Ci.nsIRequest);
|
|
|
|
status = request.status;
|
|
|
|
}
|
|
|
|
var statusText = request.statusText;
|
|
|
|
// When status is 0 we don't have a valid channel.
|
|
|
|
if (status == 0)
|
|
|
|
statusText = "nsIXMLHttpRequest channel unavailable";
|
|
|
|
LOG("Blocklist:onError: There was an error loading the blocklist file\r\n" +
|
|
|
|
statusText);
|
|
|
|
},
|
|
|
|
|
2008-03-19 22:35:03 +00:00
|
|
|
/**
|
|
|
|
* Finds the newest blocklist file from the application and the profile and
|
|
|
|
* load it or does nothing if neither exist.
|
|
|
|
*/
|
|
|
|
_loadBlocklist: function() {
|
2008-03-20 06:31:20 +00:00
|
|
|
this._addonEntries = { };
|
|
|
|
this._pluginEntries = { };
|
2008-03-19 22:35:03 +00:00
|
|
|
var profFile = getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
|
|
|
|
if (profFile.exists()) {
|
|
|
|
this._loadBlocklistFromFile(profFile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var appFile = getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
|
2008-03-20 06:31:20 +00:00
|
|
|
if (appFile.exists()) {
|
2008-03-19 22:35:03 +00:00
|
|
|
this._loadBlocklistFromFile(appFile);
|
2008-03-20 06:31:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
LOG("Blocklist::_loadBlocklist: no XML File found");
|
2008-03-19 22:35:03 +00:00
|
|
|
},
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
/**
|
2007-08-16 21:17:45 +00:00
|
|
|
# The blocklist XML file looks something like this:
|
|
|
|
#
|
|
|
|
# <blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
|
|
|
# <emItems>
|
|
|
|
# <emItem id="item_1@domain">
|
|
|
|
# <versionRange minVersion="1.0" maxVersion="2.0.*">
|
|
|
|
# <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
|
|
|
# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
|
|
|
|
# <versionRange minVersion="1.7" maxVersion="1.7.*"/>
|
|
|
|
# </targetApplication>
|
|
|
|
# <targetApplication id="toolkit@mozilla.org">
|
2007-08-29 08:16:15 +00:00
|
|
|
# <versionRange minVersion="1.9" maxVersion="1.9.*"/>
|
2007-08-16 21:17:45 +00:00
|
|
|
# </targetApplication>
|
|
|
|
# </versionRange>
|
|
|
|
# <versionRange minVersion="3.0" maxVersion="3.0.*">
|
|
|
|
# <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
|
|
|
# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
|
|
|
|
# </targetApplication>
|
|
|
|
# <targetApplication id="toolkit@mozilla.org">
|
2007-08-29 08:16:15 +00:00
|
|
|
# <versionRange minVersion="1.9" maxVersion="1.9.*"/>
|
2007-08-16 21:17:45 +00:00
|
|
|
# </targetApplication>
|
|
|
|
# </versionRange>
|
|
|
|
# </emItem>
|
|
|
|
# <emItem id="item_2@domain">
|
|
|
|
# <versionRange minVersion="3.1" maxVersion="4.*"/>
|
|
|
|
# </emItem>
|
|
|
|
# <emItem id="item_3@domain">
|
|
|
|
# <versionRange>
|
|
|
|
# <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
|
|
|
|
# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
|
|
|
|
# </targetApplication>
|
|
|
|
# </versionRange>
|
|
|
|
# </emItem>
|
|
|
|
# <emItem id="item_4@domain">
|
|
|
|
# <versionRange>
|
|
|
|
# <targetApplication>
|
|
|
|
# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
|
|
|
|
# </targetApplication>
|
|
|
|
# </versionRange>
|
|
|
|
# <emItem id="item_5@domain"/>
|
|
|
|
# </emItems>
|
|
|
|
# <pluginItems>
|
|
|
|
# <pluginItem>
|
|
|
|
# <!-- All match tags must match a plugin to blocklist a plugin -->
|
|
|
|
# <match name="name" exp="some plugin"/>
|
|
|
|
# <match name="description" exp="1[.]2[.]3"/>
|
|
|
|
# </pluginItem>
|
|
|
|
# </pluginItems>
|
2007-08-29 08:16:15 +00:00
|
|
|
# </blocklist>
|
2007-08-16 00:43:12 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
_loadBlocklistFromFile: function(file) {
|
2008-11-02 12:13:48 +00:00
|
|
|
if (!gBlocklistEnabled) {
|
2007-08-16 00:43:12 +00:00
|
|
|
LOG("Blocklist::_loadBlocklistFromFile: blocklist is disabled");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file.exists()) {
|
|
|
|
LOG("Blocklist::_loadBlocklistFromFile: XML File does not exist");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
|
|
|
.createInstance(Components.interfaces.nsIFileInputStream);
|
|
|
|
fileStream.init(file, MODE_RDONLY, PERMS_FILE, 0);
|
|
|
|
try {
|
|
|
|
var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
|
|
|
|
createInstance(Ci.nsIDOMParser);
|
|
|
|
var doc = parser.parseFromStream(fileStream, "UTF-8", file.fileSize, "text/xml");
|
|
|
|
if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) {
|
|
|
|
LOG("Blocklist::_loadBlocklistFromFile: aborting due to incorrect " +
|
|
|
|
"XML Namespace.\r\nExpected: " + XMLURI_BLOCKLIST + "\r\n" +
|
|
|
|
"Received: " + doc.documentElement.namespaceURI);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var childNodes = doc.documentElement.childNodes;
|
|
|
|
this._addonEntries = this._processItemNodes(childNodes, "em",
|
2008-09-02 11:53:34 +00:00
|
|
|
this._handleEmItemNode);
|
2007-08-16 00:43:12 +00:00
|
|
|
this._pluginEntries = this._processItemNodes(childNodes, "plugin",
|
|
|
|
this._handlePluginItemNode);
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
LOG("Blocklist::_loadBlocklistFromFile: Error constructing blocklist " + e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
fileStream.close();
|
|
|
|
},
|
|
|
|
|
|
|
|
_processItemNodes: function(deChildNodes, prefix, handler) {
|
|
|
|
var result = [];
|
|
|
|
var itemNodes;
|
|
|
|
var containerName = prefix + "Items";
|
|
|
|
for (var i = 0; i < deChildNodes.length; ++i) {
|
2007-11-07 08:57:19 +00:00
|
|
|
var emItemsElement = deChildNodes.item(i);
|
|
|
|
if (emItemsElement instanceof Ci.nsIDOMElement &&
|
2007-08-16 00:43:12 +00:00
|
|
|
emItemsElement.localName == containerName) {
|
|
|
|
itemNodes = emItemsElement.childNodes;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!itemNodes)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
var itemName = prefix + "Item";
|
|
|
|
for (var i = 0; i < itemNodes.length; ++i) {
|
2007-11-07 08:57:19 +00:00
|
|
|
var blocklistElement = itemNodes.item(i);
|
|
|
|
if (!(blocklistElement instanceof Ci.nsIDOMElement) ||
|
2007-08-16 00:43:12 +00:00
|
|
|
blocklistElement.localName != itemName)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
handler(blocklistElement, result);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
},
|
|
|
|
|
|
|
|
_handleEmItemNode: function(blocklistElement, result) {
|
2007-11-07 08:56:29 +00:00
|
|
|
if (!matchesOSABI(blocklistElement))
|
|
|
|
return;
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
var versionNodes = blocklistElement.childNodes;
|
|
|
|
var id = blocklistElement.getAttribute("id");
|
|
|
|
result[id] = [];
|
|
|
|
for (var x = 0; x < versionNodes.length; ++x) {
|
2007-11-07 08:57:19 +00:00
|
|
|
var versionRangeElement = versionNodes.item(x);
|
|
|
|
if (!(versionRangeElement instanceof Ci.nsIDOMElement) ||
|
2007-08-16 00:43:12 +00:00
|
|
|
versionRangeElement.localName != "versionRange")
|
|
|
|
continue;
|
|
|
|
|
|
|
|
result[id].push(new BlocklistItemData(versionRangeElement));
|
|
|
|
}
|
|
|
|
// if only the extension ID is specified block all versions of the
|
|
|
|
// extension for the current application.
|
|
|
|
if (result[id].length == 0)
|
|
|
|
result[id].push(new BlocklistItemData(null));
|
|
|
|
},
|
|
|
|
|
|
|
|
_handlePluginItemNode: function(blocklistElement, result) {
|
2007-11-07 08:56:29 +00:00
|
|
|
if (!matchesOSABI(blocklistElement))
|
|
|
|
return;
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
var matchNodes = blocklistElement.childNodes;
|
2008-09-02 11:53:34 +00:00
|
|
|
var blockEntry = {
|
|
|
|
matches: {},
|
|
|
|
versions: []
|
|
|
|
};
|
2009-08-21 15:52:57 +00:00
|
|
|
var hasMatch = false;
|
2007-08-16 00:43:12 +00:00
|
|
|
for (var x = 0; x < matchNodes.length; ++x) {
|
2007-11-07 08:57:19 +00:00
|
|
|
var matchElement = matchNodes.item(x);
|
2008-09-02 11:53:34 +00:00
|
|
|
if (!(matchElement instanceof Ci.nsIDOMElement))
|
2007-08-16 00:43:12 +00:00
|
|
|
continue;
|
2008-09-02 11:53:34 +00:00
|
|
|
if (matchElement.localName == "match") {
|
|
|
|
var name = matchElement.getAttribute("name");
|
|
|
|
var exp = matchElement.getAttribute("exp");
|
2009-08-21 15:52:57 +00:00
|
|
|
try {
|
|
|
|
blockEntry.matches[name] = new RegExp(exp, "m");
|
|
|
|
hasMatch = true;
|
|
|
|
} catch (e) {
|
|
|
|
// Ignore invalid regular expressions
|
|
|
|
}
|
2008-09-02 11:53:34 +00:00
|
|
|
}
|
|
|
|
if (matchElement.localName == "versionRange")
|
|
|
|
blockEntry.versions.push(new BlocklistItemData(matchElement));
|
2007-08-16 00:43:12 +00:00
|
|
|
}
|
2009-08-21 15:52:57 +00:00
|
|
|
// Plugin entries require *something* to match to an actual plugin
|
|
|
|
if (!hasMatch)
|
|
|
|
return;
|
2008-11-02 12:13:48 +00:00
|
|
|
// Add a default versionRange if there wasn't one specified
|
|
|
|
if (blockEntry.versions.length == 0)
|
|
|
|
blockEntry.versions.push(new BlocklistItemData(null));
|
2008-09-02 11:53:34 +00:00
|
|
|
result.push(blockEntry);
|
2007-08-16 00:43:12 +00:00
|
|
|
},
|
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
/* See nsIBlocklistService */
|
|
|
|
getPluginBlocklistState: function(plugin, appVersion, toolkitVersion) {
|
|
|
|
if (!this._pluginEntries)
|
|
|
|
this._loadBlocklist();
|
|
|
|
return this._getPluginBlocklistState(plugin, this._pluginEntries,
|
|
|
|
appVersion, toolkitVersion);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Private version of getPluginBlocklistState that allows the caller to pass in
|
|
|
|
* the plugin blocklist entries.
|
|
|
|
*
|
|
|
|
* @param plugin
|
|
|
|
* The nsIPluginTag to get the blocklist state for.
|
|
|
|
* @param pluginEntries
|
|
|
|
* The plugin blocklist entries to compare against.
|
|
|
|
* @param appVersion
|
|
|
|
* The application version to compare to, will use the current
|
|
|
|
* version if null.
|
|
|
|
* @param toolkitVersion
|
|
|
|
* The toolkit version to compare to, will use the current version if
|
|
|
|
* null.
|
|
|
|
* @returns The blocklist state for the item, one of the STATE constants as
|
|
|
|
* defined in nsIBlocklistService.
|
|
|
|
*/
|
|
|
|
_getPluginBlocklistState: function(plugin, pluginEntries, appVersion, toolkitVersion) {
|
|
|
|
if (!gBlocklistEnabled)
|
|
|
|
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
|
|
|
|
|
|
|
if (!appVersion)
|
|
|
|
appVersion = gApp.version;
|
|
|
|
if (!toolkitVersion)
|
|
|
|
toolkitVersion = gApp.platformVersion;
|
|
|
|
|
|
|
|
for each (var blockEntry in pluginEntries) {
|
2007-08-16 00:43:12 +00:00
|
|
|
var matchFailed = false;
|
2008-09-02 11:53:34 +00:00
|
|
|
for (var name in blockEntry.matches) {
|
|
|
|
if (!(name in plugin) ||
|
|
|
|
typeof(plugin[name]) != "string" ||
|
|
|
|
!blockEntry.matches[name].test(plugin[name])) {
|
2007-08-16 00:43:12 +00:00
|
|
|
matchFailed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-02 11:53:34 +00:00
|
|
|
if (matchFailed)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (var i = 0; i < blockEntry.versions.length; i++) {
|
|
|
|
if (blockEntry.versions[i].includesItem(plugin.version, appVersion,
|
|
|
|
toolkitVersion))
|
2008-11-02 12:13:48 +00:00
|
|
|
return blockEntry.versions[i].severity >= gBlocklistLevel ?
|
|
|
|
Ci.nsIBlocklistService.STATE_BLOCKED :
|
|
|
|
Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
|
2007-08-16 00:43:12 +00:00
|
|
|
}
|
|
|
|
}
|
2008-09-02 11:53:34 +00:00
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
2007-08-16 00:43:12 +00:00
|
|
|
},
|
|
|
|
|
2008-11-02 12:13:48 +00:00
|
|
|
_blocklistUpdated: function(oldAddonEntries, oldPluginEntries) {
|
|
|
|
var addonList = [];
|
|
|
|
|
|
|
|
var em = Cc["@mozilla.org/extensions/manager;1"].
|
|
|
|
getService(Ci.nsIExtensionManager);
|
|
|
|
var addons = em.updateAndGetNewBlocklistedItems({});
|
|
|
|
|
|
|
|
for (let i = 0; i < addons.length; i++) {
|
|
|
|
let oldState = -1;
|
|
|
|
if (oldAddonEntries)
|
|
|
|
oldState = this._getAddonBlocklistState(addons[i].id, addons[i].version,
|
|
|
|
oldAddonEntries);
|
|
|
|
let state = this.getAddonBlocklistState(addons[i].id, addons[i].version);
|
|
|
|
// We don't want to re-warn about items
|
|
|
|
if (state == oldState)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
addonList.push({
|
|
|
|
name: addons[i].name,
|
|
|
|
version: addons[i].version,
|
|
|
|
icon: addons[i].iconURL,
|
|
|
|
disable: false,
|
|
|
|
blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED,
|
|
|
|
item: addons[i]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2007-08-16 00:43:12 +00:00
|
|
|
var phs = Cc["@mozilla.org/plugin/host;1"].
|
|
|
|
getService(Ci.nsIPluginHost);
|
2008-09-02 11:53:34 +00:00
|
|
|
var plugins = phs.getPluginTags({});
|
2008-11-02 12:13:48 +00:00
|
|
|
|
|
|
|
for (let i = 0; i < plugins.length; i++) {
|
|
|
|
let oldState = -1;
|
|
|
|
if (oldPluginEntries)
|
|
|
|
oldState = this._getPluginBlocklistState(plugins[i], oldPluginEntries);
|
|
|
|
let state = this.getPluginBlocklistState(plugins[i]);
|
|
|
|
// We don't want to re-warn about items
|
|
|
|
if (state == oldState)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (plugins[i].blocklisted) {
|
|
|
|
if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED)
|
|
|
|
plugins[i].disabled = true;
|
|
|
|
}
|
|
|
|
else if (!plugins[i].disabled && state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
|
|
|
|
addonList.push({
|
|
|
|
name: plugins[i].name,
|
|
|
|
version: plugins[i].version,
|
|
|
|
icon: "chrome://mozapps/skin/plugins/pluginGeneric.png",
|
|
|
|
disable: false,
|
|
|
|
blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED,
|
|
|
|
item: plugins[i]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
plugins[i].blocklisted = state == Ci.nsIBlocklistService.STATE_BLOCKED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addonList.length == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var args = {
|
|
|
|
restart: false,
|
|
|
|
list: addonList
|
|
|
|
};
|
|
|
|
// This lets the dialog get the raw js object
|
|
|
|
args.wrappedJSObject = args;
|
|
|
|
|
|
|
|
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
|
|
|
|
getService(Ci.nsIWindowWatcher);
|
|
|
|
ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
|
|
|
|
"chrome,centerscreen,dialog,modal,titlebar", args);
|
|
|
|
|
|
|
|
for (let i = 0; i < addonList.length; i++) {
|
|
|
|
if (!addonList[i].disable)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (addonList[i].item instanceof Ci.nsIUpdateItem)
|
|
|
|
em.disableItem(addonList[i].item.id);
|
|
|
|
else if (addonList[i].item instanceof Ci.nsIPluginTag)
|
|
|
|
addonList[i].item.disabled = true;
|
|
|
|
else
|
|
|
|
LOG("Unknown add-on type: " + addonList[i].item);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args.restart)
|
|
|
|
restartApp();
|
2007-08-16 00:43:12 +00:00
|
|
|
},
|
|
|
|
|
2007-08-25 06:12:05 +00:00
|
|
|
classDescription: "Blocklist Service",
|
|
|
|
contractID: "@mozilla.org/extensions/blocklist;1",
|
|
|
|
classID: Components.ID("{66354bc9-7ed1-4692-ae1d-8da97d6b205e}"),
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
|
|
|
Ci.nsIBlocklistService,
|
|
|
|
Ci.nsITimerCallback]),
|
2008-11-28 20:49:48 +00:00
|
|
|
_xpcom_categories: [{ category: "profile-after-change" }]
|
2007-08-16 00:43:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper for constructing a blocklist.
|
|
|
|
*/
|
|
|
|
function BlocklistItemData(versionRangeElement) {
|
|
|
|
var versionRange = this.getBlocklistVersionRange(versionRangeElement);
|
|
|
|
this.minVersion = versionRange.minVersion;
|
|
|
|
this.maxVersion = versionRange.maxVersion;
|
2008-11-02 12:13:48 +00:00
|
|
|
if (versionRangeElement && versionRangeElement.hasAttribute("severity"))
|
|
|
|
this.severity = versionRangeElement.getAttribute("severity");
|
|
|
|
else
|
|
|
|
this.severity = DEFAULT_SEVERITY;
|
2007-08-16 00:43:12 +00:00
|
|
|
this.targetApps = { };
|
|
|
|
var found = false;
|
|
|
|
|
|
|
|
if (versionRangeElement) {
|
|
|
|
for (var i = 0; i < versionRangeElement.childNodes.length; ++i) {
|
2007-11-07 08:57:19 +00:00
|
|
|
var targetAppElement = versionRangeElement.childNodes.item(i);
|
|
|
|
if (!(targetAppElement instanceof Ci.nsIDOMElement) ||
|
2007-08-16 00:43:12 +00:00
|
|
|
targetAppElement.localName != "targetApplication")
|
|
|
|
continue;
|
|
|
|
found = true;
|
|
|
|
// default to the current application if id is not provided.
|
|
|
|
var appID = targetAppElement.hasAttribute("id") ? targetAppElement.getAttribute("id") : gApp.ID;
|
|
|
|
this.targetApps[appID] = this.getBlocklistAppVersions(targetAppElement);
|
|
|
|
}
|
|
|
|
}
|
2008-09-02 11:53:34 +00:00
|
|
|
// Default to all versions of the current application when no targetApplication
|
|
|
|
// elements were found
|
2007-08-16 00:43:12 +00:00
|
|
|
if (!found)
|
|
|
|
this.targetApps[gApp.ID] = this.getBlocklistAppVersions(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
BlocklistItemData.prototype = {
|
2008-09-02 11:53:34 +00:00
|
|
|
/**
|
|
|
|
* 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).
|
|
|
|
*/
|
2007-08-16 00:43:12 +00:00
|
|
|
getBlocklistAppVersions: function(targetAppElement) {
|
|
|
|
var appVersions = [ ];
|
|
|
|
|
|
|
|
if (targetAppElement) {
|
|
|
|
for (var i = 0; i < targetAppElement.childNodes.length; ++i) {
|
2007-11-07 08:57:19 +00:00
|
|
|
var versionRangeElement = targetAppElement.childNodes.item(i);
|
|
|
|
if (!(versionRangeElement instanceof Ci.nsIDOMElement) ||
|
2007-08-16 00:43:12 +00:00
|
|
|
versionRangeElement.localName != "versionRange")
|
|
|
|
continue;
|
|
|
|
appVersions.push(this.getBlocklistVersionRange(versionRangeElement));
|
|
|
|
}
|
|
|
|
}
|
2008-09-02 11:53:34 +00:00
|
|
|
// return minVersion = null and maxVersion = null if no specific versionRange
|
|
|
|
// elements were found
|
|
|
|
if (appVersions.length == 0)
|
|
|
|
appVersions.push(this.getBlocklistVersionRange(null));
|
2007-08-16 00:43:12 +00:00
|
|
|
return appVersions;
|
|
|
|
},
|
|
|
|
|
2008-09-02 11:53:34 +00:00
|
|
|
/**
|
|
|
|
* 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).
|
|
|
|
*/
|
2007-08-16 00:43:12 +00:00
|
|
|
getBlocklistVersionRange: function(versionRangeElement) {
|
2008-09-02 11:53:34 +00:00
|
|
|
var minVersion = null;
|
|
|
|
var maxVersion = null;
|
2007-08-16 00:43:12 +00:00
|
|
|
if (!versionRangeElement)
|
|
|
|
return { minVersion: minVersion, maxVersion: maxVersion };
|
|
|
|
|
|
|
|
if (versionRangeElement.hasAttribute("minVersion"))
|
|
|
|
minVersion = versionRangeElement.getAttribute("minVersion");
|
|
|
|
if (versionRangeElement.hasAttribute("maxVersion"))
|
|
|
|
maxVersion = versionRangeElement.getAttribute("maxVersion");
|
|
|
|
|
|
|
|
return { minVersion: minVersion, maxVersion: maxVersion };
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
function NSGetModule(aCompMgr, aFileSpec) {
|
2007-08-25 06:12:05 +00:00
|
|
|
return XPCOMUtils.generateModule([Blocklist]);
|
2007-08-16 00:43:12 +00:00
|
|
|
}
|