summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions')
-rw-r--r--toolkit/mozapps/extensions/content/extensions.js8
-rw-r--r--toolkit/mozapps/extensions/content/newaddon.js6
-rw-r--r--toolkit/mozapps/extensions/content/selectAddons.js4
-rw-r--r--toolkit/mozapps/extensions/extensions.manifest4
-rw-r--r--toolkit/mozapps/extensions/internal/Content.js2
-rw-r--r--toolkit/mozapps/extensions/internal/GMPProvider.jsm7
-rw-r--r--toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm467
-rw-r--r--toolkit/mozapps/extensions/internal/XPIProvider.jsm1
-rw-r--r--toolkit/mozapps/extensions/internal/XPIProviderUtils.js8
-rw-r--r--toolkit/mozapps/extensions/internal/moz.build2
-rw-r--r--toolkit/mozapps/extensions/moz.build1
-rw-r--r--toolkit/mozapps/extensions/nsBlocklistService.js1478
12 files changed, 487 insertions, 1501 deletions
diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js
index fc4392231..1e185f879 100644
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -4,10 +4,10 @@
"use strict";
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cr = Components.results;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+var Cr = Components.results;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
diff --git a/toolkit/mozapps/extensions/content/newaddon.js b/toolkit/mozapps/extensions/content/newaddon.js
index 2b2a54af5..e45b3c1cc 100644
--- a/toolkit/mozapps/extensions/content/newaddon.js
+++ b/toolkit/mozapps/extensions/content/newaddon.js
@@ -2,9 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
diff --git a/toolkit/mozapps/extensions/content/selectAddons.js b/toolkit/mozapps/extensions/content/selectAddons.js
index f80932b3f..01b9030ee 100644
--- a/toolkit/mozapps/extensions/content/selectAddons.js
+++ b/toolkit/mozapps/extensions/content/selectAddons.js
@@ -10,8 +10,8 @@ Components.utils.import("resource://gre/modules/AddonManager.jsm");
Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
-const Cc = Components.classes;
-const Ci = Components.interfaces;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
var gView = null;
diff --git a/toolkit/mozapps/extensions/extensions.manifest b/toolkit/mozapps/extensions/extensions.manifest
index 14aca3ff6..7efb74a9d 100644
--- a/toolkit/mozapps/extensions/extensions.manifest
+++ b/toolkit/mozapps/extensions/extensions.manifest
@@ -1,7 +1,3 @@
-component {66354bc9-7ed1-4692-ae1d-8da97d6b205e} nsBlocklistService.js
-contract @mozilla.org/extensions/blocklist;1 {66354bc9-7ed1-4692-ae1d-8da97d6b205e}
-category profile-after-change nsBlocklistService @mozilla.org/extensions/blocklist;1
-category update-timer nsBlocklistService @mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400
component {4399533d-08d1-458c-a87a-235f74451cfa} addonManager.js
contract @mozilla.org/addons/integration;1 {4399533d-08d1-458c-a87a-235f74451cfa}
category update-timer addonManager @mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400
diff --git a/toolkit/mozapps/extensions/internal/Content.js b/toolkit/mozapps/extensions/internal/Content.js
index 61a8b0323..9ab3b9ad6 100644
--- a/toolkit/mozapps/extensions/internal/Content.js
+++ b/toolkit/mozapps/extensions/internal/Content.js
@@ -6,7 +6,7 @@
(function() {
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
var {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
diff --git a/toolkit/mozapps/extensions/internal/GMPProvider.jsm b/toolkit/mozapps/extensions/internal/GMPProvider.jsm
index 52affa9ba..25651f1b8 100644
--- a/toolkit/mozapps/extensions/internal/GMPProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/GMPProvider.jsm
@@ -4,9 +4,9 @@
"use strict";
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
this.EXPORTED_SYMBOLS = [];
@@ -58,6 +58,7 @@ const GMP_PLUGINS = [
optionsURL: "chrome://mozapps/content/extensions/gmpPrefs.xul",
isEME: true
}];
+XPCOMUtils.defineConstant(this, "GMP_PLUGINS", GMP_PLUGINS);
XPCOMUtils.defineLazyGetter(this, "pluginsBundle",
() => Services.strings.createBundle("chrome://global/locale/plugins.properties"));
diff --git a/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm b/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm
new file mode 100644
index 000000000..f98dd2a94
--- /dev/null
+++ b/toolkit/mozapps/extensions/internal/ProductAddonChecker.jsm
@@ -0,0 +1,467 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+const LOCAL_EME_SOURCES = [{
+ "id": "gmp-eme-adobe",
+ "src": "chrome://global/content/gmp-sources/eme-adobe.json"
+}, {
+ "id": "gmp-gmpopenh264",
+ "src": "chrome://global/content/gmp-sources/openh264.json"
+}, {
+ "id": "gmp-widevinecdm",
+ "src": "chrome://global/content/gmp-sources/widevinecdm.json"
+}];
+
+this.EXPORTED_SYMBOLS = [ "ProductAddonChecker" ];
+
+Cu.importGlobalProperties(["XMLHttpRequest"]);
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://gre/modules/CertUtils.jsm");
+/* globals checkCert, BadCertHandler*/
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+
+/* globals GMPPrefs */
+XPCOMUtils.defineLazyModuleGetter(this, "GMPPrefs",
+ "resource://gre/modules/GMPUtils.jsm");
+
+/* globals OS */
+
+XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
+ "resource://gre/modules/UpdateUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "ServiceRequest",
+ "resource://gre/modules/ServiceRequest.jsm");
+
+// This exists so that tests can override the XHR behaviour for downloading
+// the addon update XML file.
+var CreateXHR = function() {
+ return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
+ createInstance(Ci.nsISupports);
+}
+
+var logger = Log.repository.getLogger("addons.productaddons");
+
+/**
+ * Number of milliseconds after which we need to cancel `downloadXML`.
+ *
+ * Bug 1087674 suggests that the XHR we use in `downloadXML` may
+ * never terminate in presence of network nuisances (e.g. strange
+ * antivirus behavior). This timeout is a defensive measure to ensure
+ * that we fail cleanly in such case.
+ */
+const TIMEOUT_DELAY_MS = 20000;
+// Chunk size for the incremental downloader
+const DOWNLOAD_CHUNK_BYTES_SIZE = 300000;
+// Incremental downloader interval
+const DOWNLOAD_INTERVAL = 0;
+// How much of a file to read into memory at a time for hashing
+const HASH_CHUNK_SIZE = 8192;
+
+/**
+ * Gets the status of an XMLHttpRequest either directly or from its underlying
+ * channel.
+ *
+ * @param request
+ * The XMLHttpRequest.
+ * @return an integer status value.
+ */
+function getRequestStatus(request) {
+ let status = null;
+ try {
+ status = request.status;
+ }
+ catch (e) {
+ }
+
+ if (status != null) {
+ return status;
+ }
+
+ return request.channel.QueryInterface(Ci.nsIRequest).status;
+}
+
+/**
+ * Downloads an XML document from a URL optionally testing the SSL certificate
+ * for certain attributes.
+ *
+ * @param url
+ * The url to download from.
+ * @param allowNonBuiltIn
+ * Whether to trust SSL certificates without a built-in CA issuer.
+ * @param allowedCerts
+ * The list of certificate attributes to match the SSL certificate
+ * against or null to skip checks.
+ * @return a promise that resolves to the DOM document downloaded or rejects
+ * with a JS exception in case of error.
+ */
+function downloadXML(url, allowNonBuiltIn = false, allowedCerts = null) {
+ return new Promise((resolve, reject) => {
+ let request = CreateXHR();
+ // This is here to let unit test code override XHR
+ if (request.wrappedJSObject) {
+ request = request.wrappedJSObject;
+ }
+ request.open("GET", url, true);
+ request.channel.notificationCallbacks = new BadCertHandler(allowNonBuiltIn);
+ // Prevent the request from reading from the cache.
+ request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
+ // Prevent the request from writing to the cache.
+ request.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
+ // Use conservative TLS settings. See bug 1325501.
+ // TODO move to ServiceRequest.
+ if (request.channel instanceof Ci.nsIHttpChannelInternal) {
+ request.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true;
+ }
+ request.timeout = TIMEOUT_DELAY_MS;
+
+ request.overrideMimeType("text/xml");
+ // The Cache-Control header is only interpreted by proxies and the
+ // final destination. It does not help if a resource is already
+ // cached locally.
+ request.setRequestHeader("Cache-Control", "no-cache");
+ // HTTP/1.0 servers might not implement Cache-Control and
+ // might only implement Pragma: no-cache
+ request.setRequestHeader("Pragma", "no-cache");
+
+ let fail = (event) => {
+ let request = event.target;
+ let status = getRequestStatus(request);
+ let message = "Failed downloading XML, status: " + status + ", reason: " + event.type;
+ logger.warn(message);
+ let ex = new Error(message);
+ ex.status = status;
+ reject(ex);
+ };
+
+ let success = (event) => {
+ logger.info("Completed downloading document");
+ let request = event.target;
+
+ try {
+ checkCert(request.channel, allowNonBuiltIn, allowedCerts);
+ } catch (ex) {
+ logger.error("Request failed certificate checks: " + ex);
+ ex.status = getRequestStatus(request);
+ reject(ex);
+ return;
+ }
+
+ resolve(request.responseXML);
+ };
+
+ request.addEventListener("error", fail, false);
+ request.addEventListener("abort", fail, false);
+ request.addEventListener("timeout", fail, false);
+ request.addEventListener("load", success, false);
+
+ logger.info("sending request to: " + url);
+ request.send(null);
+ });
+}
+
+function downloadJSON(uri) {
+ logger.info("fetching config from: " + uri);
+ return new Promise((resolve, reject) => {
+ let xmlHttp = new ServiceRequest({mozAnon: true});
+
+ xmlHttp.onload = function(aResponse) {
+ resolve(JSON.parse(this.responseText));
+ };
+
+ xmlHttp.onerror = function(e) {
+ reject("Fetching " + uri + " results in error code: " + e.target.status);
+ };
+
+ xmlHttp.open("GET", uri);
+ xmlHttp.overrideMimeType("application/json");
+ xmlHttp.send();
+ });
+}
+
+
+/**
+ * Parses a list of add-ons from a DOM document.
+ *
+ * @param document
+ * The DOM document to parse.
+ * @return null if there is no <addons> element otherwise an object containing
+ * an array of the addons listed and a field notifying whether the
+ * fallback was used.
+ */
+function parseXML(document) {
+ // Check that the root element is correct
+ if (document.documentElement.localName != "updates") {
+ throw new Error("got node name: " + document.documentElement.localName +
+ ", expected: updates");
+ }
+
+ // Check if there are any addons elements in the updates element
+ let addons = document.querySelector("updates:root > addons");
+ if (!addons) {
+ return null;
+ }
+
+ let results = [];
+ let addonList = document.querySelectorAll("updates:root > addons > addon");
+ for (let addonElement of addonList) {
+ let addon = {};
+
+ for (let name of ["id", "URL", "hashFunction", "hashValue", "version", "size"]) {
+ if (addonElement.hasAttribute(name)) {
+ addon[name] = addonElement.getAttribute(name);
+ }
+ }
+ addon.size = Number(addon.size) || undefined;
+
+ results.push(addon);
+ }
+
+ return {
+ usedFallback: false,
+ gmpAddons: results
+ };
+}
+
+/**
+ * If downloading from the network fails (AUS server is down),
+ * load the sources from local build configuration.
+ */
+function downloadLocalConfig() {
+
+ if (!GMPPrefs.get(GMPPrefs.KEY_UPDATE_ENABLED, true)) {
+ logger.info("Updates are disabled via media.gmp-manager.updateEnabled");
+ return Promise.resolve({usedFallback: true, gmpAddons: []});
+ }
+
+ return Promise.all(LOCAL_EME_SOURCES.map(conf => {
+ return downloadJSON(conf.src).then(addons => {
+
+ let platforms = addons.vendors[conf.id].platforms;
+ let target = Services.appinfo.OS + "_" + UpdateUtils.ABI;
+ let details = null;
+
+ while (!details) {
+ if (!(target in platforms)) {
+ // There was no matching platform so return false, this addon
+ // will be filtered from the results below
+ logger.info("no details found for: " + target);
+ return false;
+ }
+ // Field either has the details of the binary or is an alias
+ // to another build target key that does
+ if (platforms[target].alias) {
+ target = platforms[target].alias;
+ } else {
+ details = platforms[target];
+ }
+ }
+
+ logger.info("found plugin: " + conf.id);
+ return {
+ "id": conf.id,
+ "URL": details.fileUrl,
+ "hashFunction": addons.hashFunction,
+ "hashValue": details.hashValue,
+ "version": addons.vendors[conf.id].version,
+ "size": details.filesize
+ };
+ });
+ })).then(addons => {
+
+ // Some filters may not match this platform so
+ // filter those out
+ addons = addons.filter(x => x !== false);
+
+ return {
+ usedFallback: true,
+ gmpAddons: addons
+ };
+ });
+}
+
+/**
+ * Downloads file from a URL using XHR.
+ *
+ * @param url
+ * The url to download from.
+ * @return a promise that resolves to the path of a temporary file or rejects
+ * with a JS exception in case of error.
+ */
+function downloadFile(url) {
+ return new Promise((resolve, reject) => {
+ let xhr = new XMLHttpRequest();
+ xhr.onload = function(response) {
+ logger.info("downloadXHR File download. status=" + xhr.status);
+ if (xhr.status != 200 && xhr.status != 206) {
+ reject(Components.Exception("File download failed", xhr.status));
+ return;
+ }
+ Task.spawn(function* () {
+ let f = yield OS.File.openUnique(OS.Path.join(OS.Constants.Path.tmpDir, "tmpaddon"));
+ let path = f.path;
+ logger.info(`Downloaded file will be saved to ${path}`);
+ yield f.file.close();
+ yield OS.File.writeAtomic(path, new Uint8Array(xhr.response));
+ return path;
+ }).then(resolve, reject);
+ };
+
+ let fail = (event) => {
+ let request = event.target;
+ let status = getRequestStatus(request);
+ let message = "Failed downloading via XHR, status: " + status + ", reason: " + event.type;
+ logger.warn(message);
+ let ex = new Error(message);
+ ex.status = status;
+ reject(ex);
+ };
+ xhr.addEventListener("error", fail);
+ xhr.addEventListener("abort", fail);
+
+ xhr.responseType = "arraybuffer";
+ try {
+ xhr.open("GET", url);
+ // Use conservative TLS settings. See bug 1325501.
+ // TODO move to ServiceRequest.
+ if (xhr.channel instanceof Ci.nsIHttpChannelInternal) {
+ xhr.channel.QueryInterface(Ci.nsIHttpChannelInternal).beConservative = true;
+ }
+ xhr.send(null);
+ } catch (ex) {
+ reject(ex);
+ }
+ });
+}
+
+/**
+ * Convert a string containing binary values to hex.
+ */
+function binaryToHex(input) {
+ let result = "";
+ for (let i = 0; i < input.length; ++i) {
+ let hex = input.charCodeAt(i).toString(16);
+ if (hex.length == 1) {
+ hex = "0" + hex;
+ }
+ result += hex;
+ }
+ return result;
+}
+
+/**
+ * Calculates the hash of a file.
+ *
+ * @param hashFunction
+ * The type of hash function to use, must be supported by nsICryptoHash.
+ * @param path
+ * The path of the file to hash.
+ * @return a promise that resolves to hash of the file or rejects with a JS
+ * exception in case of error.
+ */
+var computeHash = Task.async(function*(hashFunction, path) {
+ let file = yield OS.File.open(path, { existing: true, read: true });
+ try {
+ let hasher = Cc["@mozilla.org/security/hash;1"].
+ createInstance(Ci.nsICryptoHash);
+ hasher.initWithString(hashFunction);
+
+ let bytes;
+ do {
+ bytes = yield file.read(HASH_CHUNK_SIZE);
+ hasher.update(bytes, bytes.length);
+ } while (bytes.length == HASH_CHUNK_SIZE);
+
+ return binaryToHex(hasher.finish(false));
+ }
+ finally {
+ yield file.close();
+ }
+});
+
+/**
+ * Verifies that a downloaded file matches what was expected.
+ *
+ * @param properties
+ * The properties to check, `size` and `hashFunction` with `hashValue`
+ * are supported. Any properties missing won't be checked.
+ * @param path
+ * The path of the file to check.
+ * @return a promise that resolves if the file matched or rejects with a JS
+ * exception in case of error.
+ */
+var verifyFile = Task.async(function*(properties, path) {
+ if (properties.size !== undefined) {
+ let stat = yield OS.File.stat(path);
+ if (stat.size != properties.size) {
+ throw new Error("Downloaded file was " + stat.size + " bytes but expected " + properties.size + " bytes.");
+ }
+ }
+
+ if (properties.hashFunction !== undefined) {
+ let expectedDigest = properties.hashValue.toLowerCase();
+ let digest = yield computeHash(properties.hashFunction, path);
+ if (digest != expectedDigest) {
+ throw new Error("Hash was `" + digest + "` but expected `" + expectedDigest + "`.");
+ }
+ }
+});
+
+const ProductAddonChecker = {
+ /**
+ * Downloads a list of add-ons from a URL optionally testing the SSL
+ * certificate for certain attributes.
+ *
+ * @param url
+ * The url to download from.
+ * @param allowNonBuiltIn
+ * Whether to trust SSL certificates without a built-in CA issuer.
+ * @param allowedCerts
+ * The list of certificate attributes to match the SSL certificate
+ * against or null to skip checks.
+ * @return a promise that resolves to an object containing the list of add-ons
+ * and whether the local fallback was used, or rejects with a JS
+ * exception in case of error.
+ */
+ getProductAddonList: function(url, allowNonBuiltIn = false, allowedCerts = null) {
+ if (!GMPPrefs.get(GMPPrefs.KEY_UPDATE_ENABLED, true)) {
+ logger.info("Updates are disabled via media.gmp-manager.updateEnabled");
+ return Promise.resolve({usedFallback: true, gmpAddons: []});
+ }
+
+ return downloadXML(url, allowNonBuiltIn, allowedCerts)
+ .then(parseXML)
+ .catch(downloadLocalConfig);
+ },
+
+ /**
+ * Downloads an add-on to a local file and checks that it matches the expected
+ * file. The caller is responsible for deleting the temporary file returned.
+ *
+ * @param addon
+ * The addon to download.
+ * @return a promise that resolves to the temporary file downloaded or rejects
+ * with a JS exception in case of error.
+ */
+ downloadAddon: Task.async(function*(addon) {
+ let path = yield downloadFile(addon.URL);
+ try {
+ yield verifyFile(addon, path);
+ return path;
+ }
+ catch (e) {
+ yield OS.File.remove(path);
+ throw e;
+ }
+ })
+}
diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
index 5b3585cd8..b522bd3ae 100644
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -144,6 +144,7 @@ const FIREFOX_APPCOMPATVERSION = "56.9"
// The value for this is in Makefile.in
#expand const DB_SCHEMA = __MOZ_EXTENSIONS_DB_SCHEMA__;
+XPCOMUtils.defineConstant(this, "DB_SCHEMA", DB_SCHEMA);
#ifdef MOZ_DEVTOOLS
const NOTIFICATION_TOOLBOXPROCESS_LOADED = "ToolboxProcessLoaded";
#endif
diff --git a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
index 6b37ed640..f2420bd1a 100644
--- a/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
+++ b/toolkit/mozapps/extensions/internal/XPIProviderUtils.js
@@ -4,10 +4,10 @@
"use strict";
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+var Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
diff --git a/toolkit/mozapps/extensions/internal/moz.build b/toolkit/mozapps/extensions/internal/moz.build
index efcd2af21..337df3104 100644
--- a/toolkit/mozapps/extensions/internal/moz.build
+++ b/toolkit/mozapps/extensions/internal/moz.build
@@ -5,12 +5,12 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXTRA_JS_MODULES.addons += [
- '../../webextensions/internal/ProductAddonChecker.jsm',
'AddonLogging.jsm',
'AddonRepository_SQLiteMigrator.jsm',
'Content.js',
'GMPProvider.jsm',
'LightweightThemeImageOptimizer.jsm',
+ 'ProductAddonChecker.jsm',
'SpellCheckDictionaryBootstrap.js',
]
diff --git a/toolkit/mozapps/extensions/moz.build b/toolkit/mozapps/extensions/moz.build
index 19f449210..ca04d74a0 100644
--- a/toolkit/mozapps/extensions/moz.build
+++ b/toolkit/mozapps/extensions/moz.build
@@ -25,7 +25,6 @@ EXTRA_COMPONENTS += [
EXTRA_PP_COMPONENTS += [
'extensions.manifest',
- 'nsBlocklistService.js',
]
EXTRA_JS_MODULES += [
diff --git a/toolkit/mozapps/extensions/nsBlocklistService.js b/toolkit/mozapps/extensions/nsBlocklistService.js
deleted file mode 100644
index 487dae8e5..000000000
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ /dev/null
@@ -1,1478 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/Services.jsm");
-
-try {
- // AddonManager.jsm doesn't allow itself to be imported in the child
- // process. We're used in the child process (for now), so guard against
- // this.
- Components.utils.import("resource://gre/modules/AddonManager.jsm");
-} catch (e) {
-}
-
-XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
- "resource://gre/modules/FileUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
- "resource://gre/modules/UpdateChannel.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS",
- "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Task",
- "resource://gre/modules/Task.jsm");
-
-const TOOLKIT_ID = "toolkit@mozilla.org"
-const KEY_PROFILEDIR = "ProfD";
-const KEY_APPDIR = "XCurProcD";
-const FILE_BLOCKLIST = "blocklist.xml";
-const PREF_BLOCKLIST_LASTUPDATETIME = "app.update.lastUpdateTime.blocklist-background-update-timer";
-const PREF_BLOCKLIST_URL = "extensions.blocklist.url";
-const PREF_BLOCKLIST_ITEM_URL = "extensions.blocklist.itemURL";
-const PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
-const PREF_BLOCKLIST_INTERVAL = "extensions.blocklist.interval";
-const PREF_BLOCKLIST_LEVEL = "extensions.blocklist.level";
-const PREF_BLOCKLIST_PINGCOUNTTOTAL = "extensions.blocklist.pingCountTotal";
-const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
-const PREF_BLOCKLIST_SUPPRESSUI = "extensions.blocklist.suppressUI";
-const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
-const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale";
-const PREF_APP_DISTRIBUTION = "distribution.id";
-const PREF_APP_DISTRIBUTION_VERSION = "distribution.version";
-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"
-const UNKNOWN_XPCOM_ABI = "unknownABI";
-const URI_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul"
-const DEFAULT_SEVERITY = 3;
-const DEFAULT_LEVEL = 2;
-const MAX_BLOCK_LEVEL = 3;
-const SEVERITY_OUTDATED = 0;
-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;
-
-XPCOMUtils.defineLazyServiceGetter(this, "gConsole",
- "@mozilla.org/consoleservice;1",
- "nsIConsoleService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gVersionChecker",
- "@mozilla.org/xpcom/version-comparator;1",
- "nsIVersionComparator");
-
-XPCOMUtils.defineLazyServiceGetter(this, "gCertBlocklistService",
- "@mozilla.org/security/certblocklist;1",
- "nsICertBlocklist");
-
-XPCOMUtils.defineLazyGetter(this, "gPref", function bls_gPref() {
- return Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).
- QueryInterface(Ci.nsIPrefBranch);
-});
-
-XPCOMUtils.defineLazyGetter(this, "gApp", function bls_gApp() {
- return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).
- QueryInterface(Ci.nsIXULRuntime);
-});
-
-XPCOMUtils.defineLazyGetter(this, "gABI", function bls_gABI() {
- let abi = null;
- try {
- abi = gApp.XPCOMABI;
- }
- catch (e) {
- LOG("BlockList Global gABI: XPCOM ABI unknown.");
- }
-#ifdef XP_MACOSX
- // Mac universal build should report a different ABI than either macppc
- // or mactel.
- let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
- getService(Ci.nsIMacUtils);
-
- if (macutils.isUniversalBinary)
- abi += "-u-" + macutils.architecturesInBinary;
-#endif
- return abi;
-});
-
-XPCOMUtils.defineLazyGetter(this, "gOSVersion", function bls_gOSVersion() {
- let osVersion;
- let sysInfo = Cc["@mozilla.org/system-info;1"].
- getService(Ci.nsIPropertyBag2);
- try {
- osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version");
- }
- catch (e) {
- LOG("BlockList Global gOSVersion: 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.
- }
- osVersion = encodeURIComponent(osVersion);
- }
- return osVersion;
-});
-
-// shared code for suppressing bad cert dialogs
-XPCOMUtils.defineLazyGetter(this, "gCertUtils", function bls_gCertUtils() {
- let temp = { };
- Components.utils.import("resource://gre/modules/CertUtils.jsm", temp);
- return temp;
-});
-
-/**
- * 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");
- gConsole.logStringMessage(string);
- }
-}
-
-/**
- * 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;
-}
-
-/**
- * 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);
-}
-
-// 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);
-}
-
-/**
- * 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
- * its comma separated list for the element to be valid. Similarly for the
- * 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;
-}
-
-/**
- * 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
- var defaultPrefs = gPref.getDefaultBranch(null);
- return defaultPrefs.getComplexValue(PREF_GENERAL_USERAGENT_LOCALE,
- Ci.nsIPrefLocalizedString).data;
- } catch (e) {}
-
- return gPref.getCharPref(PREF_GENERAL_USERAGENT_LOCALE);
-}
-
-/* Get the distribution pref values, from defaults only */
-function getDistributionPrefValue(aPrefName) {
- var prefValue = "default";
-
- var defaults = gPref.getDefaultBranch(null);
- try {
- prefValue = defaults.getCharPref(aPrefName);
- } catch (e) {
- // use default when pref not found
- }
-
- return prefValue;
-}
-
-/**
- * Parse a string representation of a regular expression. Needed because we
- * use the /pattern/flags form (because it's detectable), which is only
- * supported as a literal in JS.
- *
- * @param aStr
- * String representation of regexp
- * @return RegExp instance
- */
-function parseRegExp(aStr) {
- let lastSlash = aStr.lastIndexOf("/");
- let pattern = aStr.slice(1, lastSlash);
- let flags = aStr.slice(lastSlash + 1);
- return new RegExp(pattern, flags);
-}
-
-/**
- * Helper function to test if the blockEntry matches with the plugin.
- *
- * @param blockEntry
- * The plugin blocklist entries to compare against.
- * @param plugin
- * The nsIPluginTag to get the blocklist state for.
- * @returns True if the blockEntry matches the plugin, false otherwise.
- */
-function matchesAllPluginNames(blockEntry, plugin) {
- for (let name in blockEntry.matches) {
- if (!(name in plugin) ||
- typeof(plugin[name]) != "string" ||
- !blockEntry.matches[name].test(plugin[name])) {
- return false;
- }
- }
- return true;
-}
-
-/**
- * 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() {
- Services.obs.addObserver(this, "xpcom-shutdown", false);
- Services.obs.addObserver(this, "sessionstore-windows-restored", false);
- gLoggingEnabled = getPref("getBoolPref", PREF_EM_LOGGING_ENABLED, false);
- 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);
- gPref.addObserver(PREF_EM_LOGGING_ENABLED, this, false);
- this.wrappedJSObject = this;
-}
-
-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 Blocklist_observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "xpcom-shutdown":
- Services.obs.removeObserver(this, "xpcom-shutdown");
- gPref.removeObserver("extensions.blocklist.", this);
- gPref.removeObserver(PREF_EM_LOGGING_ENABLED, this);
- break;
- case "nsPref:changed":
- switch (aData) {
- case PREF_EM_LOGGING_ENABLED:
- gLoggingEnabled = getPref("getBoolPref", PREF_EM_LOGGING_ENABLED, false);
- break;
- 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;
- case "sessionstore-windows-restored":
- Services.obs.removeObserver(this, "sessionstore-windows-restored");
- this._preloadBlocklist();
- break;
- }
- },
-
- /* See nsIBlocklistService */
- isAddonBlocklisted: function Blocklist_isAddonBlocklisted(addon, appVersion, toolkitVersion) {
- return this.getAddonBlocklistState(addon, appVersion, toolkitVersion) ==
- Ci.nsIBlocklistService.STATE_BLOCKED;
- },
-
- /* See nsIBlocklistService */
- getAddonBlocklistState: function Blocklist_getAddonBlocklistState(addon, appVersion, toolkitVersion) {
- if (!this._isBlocklistLoaded())
- this._loadBlocklist();
- return this._getAddonBlocklistState(addon, 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 Blocklist_getAddonBlocklistStateCall(addon,
- addonEntries, appVersion, toolkitVersion) {
- if (!gBlocklistEnabled)
- return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
-
- if (!appVersion)
- appVersion = gApp.version;
- if (!toolkitVersion)
- toolkitVersion = gApp.platformVersion;
-
- var blItem = this._findMatchingAddonEntry(addonEntries, addon);
- if (!blItem)
- return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
-
- for (let currentblItem of blItem.versions) {
- if (currentblItem.includesItem(addon.version, appVersion, toolkitVersion))
- return currentblItem.severity >= gBlocklistLevel ? Ci.nsIBlocklistService.STATE_BLOCKED :
- Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
- }
- return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
- },
-
- /**
- * Returns the set of prefs of the add-on stored in the blocklist file
- * (probably to revert them on disabling).
- * @param addon
- * The add-on whose to-be-reset prefs are to be found.
- */
- _getAddonPrefs: function Blocklist_getAddonPrefs(addon) {
- let entry = this._findMatchingAddonEntry(this._addonEntries, addon);
- return entry.prefs.slice(0);
- },
-
- _findMatchingAddonEntry: function Blocklist_findMatchingAddonEntry(aAddonEntries,
- 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;
- }
-
- 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(addon, appVersion, toolkitVersion) {
- if (!gBlocklistEnabled)
- return "";
-
- if (!this._isBlocklistLoaded())
- this._loadBlocklist();
-
- let blItem = this._findMatchingAddonEntry(this._addonEntries, addon);
- if (!blItem || !blItem.blockID)
- return null;
-
- return this._createBlocklistURL(blItem.blockID);
- },
-
- _createBlocklistURL: function Blocklist_createBlocklistURL(id) {
- let url = Services.urlFormatter.formatURLPref(PREF_BLOCKLIST_ITEM_URL);
- url = url.replace(/%blockID%/g, id);
-
- return url;
- },
-
- notify: function Blocklist_notify(aTimer) {
- if (!gBlocklistEnabled)
- return;
-
- try {
- var dsURI = gPref.getCharPref(PREF_BLOCKLIST_URL);
- }
- catch (e) {
- LOG("Blocklist::notify: The " + PREF_BLOCKLIST_URL + " preference" +
- " is missing!");
- return;
- }
-
- var pingCountVersion = getPref("getIntPref", PREF_BLOCKLIST_PINGCOUNTVERSION, 0);
- var pingCountTotal = getPref("getIntPref", PREF_BLOCKLIST_PINGCOUNTTOTAL, 1);
- var daysSinceLastPing = 0;
- if (pingCountVersion == 0) {
- daysSinceLastPing = "new";
- }
- else {
- // Seconds in one day is used because nsIUpdateTimerManager stores the
- // last update time in seconds.
- let secondsInDay = 60 * 60 * 24;
- let lastUpdateTime = getPref("getIntPref", PREF_BLOCKLIST_LASTUPDATETIME, 0);
- if (lastUpdateTime == 0) {
- daysSinceLastPing = "invalid";
- }
- else {
- let now = Math.round(Date.now() / 1000);
- daysSinceLastPing = Math.floor((now - lastUpdateTime) / secondsInDay);
- }
-
- if (daysSinceLastPing == 0 || daysSinceLastPing == "invalid") {
- pingCountVersion = pingCountTotal = "invalid";
- }
- }
-
- if (pingCountVersion < 1)
- pingCountVersion = 1;
- if (pingCountTotal < 1)
- pingCountTotal = 1;
-
- dsURI = dsURI.replace(/%APP_ID%/g, gApp.ID);
- dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version);
- 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, UpdateChannel.get());
- 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(/%PING_COUNT%/g, pingCountVersion);
- dsURI = dsURI.replace(/%TOTAL_PING_COUNT%/g, pingCountTotal);
- dsURI = dsURI.replace(/%DAYS_SINCE_LAST_PING%/g, daysSinceLastPing);
- dsURI = dsURI.replace(/\+/g, "%2B");
-
- // Under normal operations it will take around 5,883,516 years before the
- // preferences used to store pingCountVersion and pingCountTotal will rollover
- // so this code doesn't bother trying to do the "right thing" here.
- if (pingCountVersion != "invalid") {
- pingCountVersion++;
- if (pingCountVersion > 2147483647) {
- // Rollover to -1 if the value is greater than what is support by an
- // integer preference. The -1 indicates that the counter has been reset.
- pingCountVersion = -1;
- }
- gPref.setIntPref(PREF_BLOCKLIST_PINGCOUNTVERSION, pingCountVersion);
- }
-
- if (pingCountTotal != "invalid") {
- pingCountTotal++;
- if (pingCountTotal > 2147483647) {
- // Rollover to 1 if the value is greater than what is support by an
- // integer preference.
- pingCountTotal = -1;
- }
- gPref.setIntPref(PREF_BLOCKLIST_PINGCOUNTTOTAL, pingCountTotal);
- }
-
- // Verify that the URI is valid
- try {
- var uri = newURI(dsURI);
- }
- catch (e) {
- LOG("Blocklist::notify: There was an error creating the blocklist URI\r\n" +
- "for: " + dsURI + ", error: " + e);
- return;
- }
-
- LOG("Blocklist::notify: Requesting " + uri.spec);
- var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
- createInstance(Ci.nsIXMLHttpRequest);
- request.open("GET", uri.spec, true);
- request.channel.notificationCallbacks = new gCertUtils.BadCertHandler();
- request.overrideMimeType("text/xml");
- request.setRequestHeader("Cache-Control", "no-cache");
- request.QueryInterface(Components.interfaces.nsIJSXMLHttpRequest);
-
- var self = this;
- request.addEventListener("error", function errorEventListener(event) {
- self.onXMLError(event); }, false);
- request.addEventListener("load", function loadEventListener(event) {
- self.onXMLLoad(event); }, false);
- request.send(null);
-
- // When the blocklist loads we need to compare it to the current copy so
- // make sure we have loaded it.
- if (!this._isBlocklistLoaded())
- this._loadBlocklist();
- },
-
- onXMLLoad: Task.async(function* (aEvent) {
- let request = aEvent.target;
- try {
- gCertUtils.checkCert(request.channel);
- }
- catch (e) {
- LOG("Blocklist::onXMLLoad: " + e);
- return;
- }
- let 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 oldAddonEntries = this._addonEntries;
- var oldPluginEntries = this._pluginEntries;
- this._addonEntries = [];
- this._pluginEntries = [];
-
- this._loadBlocklistFromString(request.responseText);
- this._blocklistUpdated(oldAddonEntries, oldPluginEntries);
-
- try {
- let path = OS.Path.join(OS.Constants.Path.profileDir, FILE_BLOCKLIST);
- yield OS.File.writeAtomic(path, request.responseText, {tmpPath: path + ".tmp"});
- } catch (e) {
- LOG("Blocklist::onXMLLoad: " + e);
- }
- }),
-
- onXMLError: function Blocklist_onXMLError(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 = "nsIXMLHttpRequest channel unavailable";
- // When status is 0 we don't have a valid channel.
- if (status != 0) {
- try {
- statusText = request.statusText;
- } catch (e) {
- }
- }
- LOG("Blocklist:onError: There was an error loading the blocklist file\r\n" +
- statusText);
- },
-
- /**
- * Finds the newest blocklist file from the application and the profile and
- * load it or does nothing if neither exist.
- */
- _loadBlocklist: function Blocklist_loadBlocklist() {
- this._addonEntries = [];
- this._pluginEntries = [];
- var profFile = FileUtils.getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
- if (profFile.exists()) {
- this._loadBlocklistFromFile(profFile);
- return;
- }
- var appFile = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
- if (appFile.exists()) {
- this._loadBlocklistFromFile(appFile);
- return;
- }
- LOG("Blocklist::_loadBlocklist: no XML File found");
- },
-
- /**
-# The blocklist XML file looks something like this:
-#
-# <blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist">
-# <emItems>
-# <emItem id="item_1@domain" blockID="i1">
-# <prefs>
-# <pref>accessibility.accesskeycausesactivation</pref>
-# <pref>accessibility.blockautorefresh</pref>
-# </prefs>
-# <versionRange minVersion="1.0" maxVersion="2.0.*">
-# <targetApplication id="{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}">
-# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
-# <versionRange minVersion="1.7" maxVersion="1.7.*"/>
-# </targetApplication>
-# <targetApplication id="toolkit@mozilla.org">
-# <versionRange minVersion="1.9" maxVersion="1.9.*"/>
-# </targetApplication>
-# </versionRange>
-# <versionRange minVersion="3.0" maxVersion="3.0.*">
-# <targetApplication id="{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}">
-# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
-# </targetApplication>
-# <targetApplication id="toolkit@mozilla.org">
-# <versionRange minVersion="1.9" maxVersion="1.9.*"/>
-# </targetApplication>
-# </versionRange>
-# </emItem>
-# <emItem id="item_2@domain" blockID="i2">
-# <versionRange minVersion="3.1" maxVersion="4.*"/>
-# </emItem>
-# <emItem id="item_3@domain">
-# <versionRange>
-# <targetApplication id="{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}">
-# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
-# </targetApplication>
-# </versionRange>
-# </emItem>
-# <emItem id="item_4@domain" blockID="i3">
-# <versionRange>
-# <targetApplication>
-# <versionRange minVersion="1.5" maxVersion="1.5.*"/>
-# </targetApplication>
-# </versionRange>
-# <emItem id="/@badperson\.com$/"/>
-# </emItems>
-# <pluginItems>
-# <pluginItem blockID="i4">
-# <!-- 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>
-# <certItems>
-# <!-- issuerName is the DER issuer name data base64 encoded... -->
-# <certItem issuerName="MA0xCzAJBgNVBAMMAmNh">
-# <!-- ... as is the serial number DER data -->
-# <serialNumber>AkHVNA==</serialNumber>
-# </certItem>
-# </certItems>
-# </blocklist>
- */
-
- _loadBlocklistFromFile: function Blocklist_loadBlocklistFromFile(file) {
- if (!gBlocklistEnabled) {
- LOG("Blocklist::_loadBlocklistFromFile: blocklist is disabled");
- return;
- }
-
- let telemetry = Services.telemetry;
-
- if (this._isBlocklistPreloaded()) {
- telemetry.getHistogramById("BLOCKLIST_SYNC_FILE_LOAD").add(false);
- this._loadBlocklistFromString(this._preloadedBlocklistContent);
- delete this._preloadedBlocklistContent;
- return;
- }
-
- if (!file.exists()) {
- LOG("Blocklist::_loadBlocklistFromFile: XML File does not exist " + file.path);
- return;
- }
-
- telemetry.getHistogramById("BLOCKLIST_SYNC_FILE_LOAD").add(true);
-
- let text = "";
- let fstream = null;
- let cstream = null;
-
- try {
- fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
- .createInstance(Components.interfaces.nsIFileInputStream);
- cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
- .createInstance(Components.interfaces.nsIConverterInputStream);
-
- fstream.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
- cstream.init(fstream, "UTF-8", 0, 0);
-
- let str = {};
- let read = 0;
-
- do {
- read = cstream.readString(0xffffffff, str); // read as much as we can and put it in str.value
- text += str.value;
- } while (read != 0);
- } catch (e) {
- LOG("Blocklist::_loadBlocklistFromFile: Failed to load XML file " + e);
- } finally {
- if (cstream)
- cstream.close();
- if (fstream)
- fstream.close();
- }
-
- if (text)
- this._loadBlocklistFromString(text);
- },
-
- _isBlocklistLoaded: function() {
- return this._addonEntries != null && this._pluginEntries != null;
- },
-
- _isBlocklistPreloaded: function() {
- return this._preloadedBlocklistContent != null;
- },
-
- /* Used for testing */
- _clear: function() {
- this._addonEntries = null;
- this._pluginEntries = null;
- this._preloadedBlocklistContent = null;
- },
-
- _preloadBlocklist: Task.async(function*() {
- let profPath = OS.Path.join(OS.Constants.Path.profileDir, FILE_BLOCKLIST);
- try {
- yield this._preloadBlocklistFile(profPath);
- return;
- } catch (e) {
- LOG("Blocklist::_preloadBlocklist: Failed to load XML file " + e)
- }
-
- var appFile = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
- try{
- yield this._preloadBlocklistFile(appFile.path);
- return;
- } catch (e) {
- LOG("Blocklist::_preloadBlocklist: Failed to load XML file " + e)
- }
-
- LOG("Blocklist::_preloadBlocklist: no XML File found");
- }),
-
- _preloadBlocklistFile: Task.async(function* (path){
- if (this._addonEntries) {
- // The file has been already loaded.
- return;
- }
-
- if (!gBlocklistEnabled) {
- LOG("Blocklist::_preloadBlocklistFile: blocklist is disabled");
- return;
- }
-
- let text = yield OS.File.read(path, { encoding: "utf-8" });
-
- if (!this._addonEntries) {
- // Store the content only if a sync load has not been performed in the meantime.
- this._preloadedBlocklistContent = text;
- }
- }),
-
- _loadBlocklistFromString : function Blocklist_loadBlocklistFromString(text) {
- try {
- var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
- createInstance(Ci.nsIDOMParser);
- var doc = parser.parseFromString(text, "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;
- for (let element of childNodes) {
- if (!(element instanceof Ci.nsIDOMElement))
- continue;
- switch (element.localName) {
- case "emItems":
- this._addonEntries = this._processItemNodes(element.childNodes, "em",
- this._handleEmItemNode);
- break;
- case "pluginItems":
- this._pluginEntries = this._processItemNodes(element.childNodes, "plugin",
- this._handlePluginItemNode);
- break;
- case "certItems":
- this._processItemNodes(element.childNodes, "cert",
- this._handleCertItemNode.bind(this));
- break;
- default:
- Services.obs.notifyObservers(element,
- "blocklist-data-" + element.localName,
- null);
- }
- }
- gCertBlocklistService.saveEntries();
- }
- catch (e) {
- LOG("Blocklist::_loadBlocklistFromFile: Error constructing blocklist " + e);
- return;
- }
- },
-
- _processItemNodes: function Blocklist_processItemNodes(itemNodes, prefix, handler) {
- var result = [];
- var itemName = prefix + "Item";
- for (var i = 0; i < itemNodes.length; ++i) {
- var blocklistElement = itemNodes.item(i);
- if (!(blocklistElement instanceof Ci.nsIDOMElement) ||
- blocklistElement.localName != itemName)
- continue;
-
- handler(blocklistElement, result);
- }
- return result;
- },
-
- _handleCertItemNode: function Blocklist_handleCertItemNode(blocklistElement,
- result) {
- let issuer = blocklistElement.getAttribute("issuerName");
- for (let snElement of blocklistElement.children) {
- try {
- gCertBlocklistService.revokeCertByIssuerAndSerial(issuer, snElement.textContent);
- } catch (e) {
- // we want to keep trying other elements since missing all items
- // is worse than missing one
- LOG("Blocklist::_handleCertItemNode: Error adding revoked cert " + e);
- }
- }
- },
-
- _handleEmItemNode: function Blocklist_handleEmItemNode(blocklistElement, result) {
- if (!matchesOSABI(blocklistElement))
- return;
-
- let blockEntry = {
- versions: [],
- prefs: [],
- 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;
-
- for (let x = 0; x < childNodes.length; x++) {
- var childElement = childNodes.item(x);
- if (!(childElement instanceof Ci.nsIDOMElement))
- continue;
- if (childElement.localName === "prefs") {
- let prefElements = childElement.childNodes;
- for (let i = 0; i < prefElements.length; i++) {
- let prefElement = prefElements.item(i);
- if (!(prefElement instanceof Ci.nsIDOMElement) ||
- prefElement.localName !== "pref")
- continue;
- blockEntry.prefs.push(prefElement.textContent);
- }
- }
- else if (childElement.localName === "versionRange")
- blockEntry.versions.push(new BlocklistItemData(childElement));
- }
- // if only the extension ID is specified block all versions of the
- // extension for the current application.
- if (blockEntry.versions.length == 0)
- blockEntry.versions.push(new BlocklistItemData(null));
-
- blockEntry.blockID = blocklistElement.getAttribute("blockID");
-
- result.push(blockEntry);
- },
-
- _handlePluginItemNode: function Blocklist_handlePluginItemNode(blocklistElement, result) {
- if (!matchesOSABI(blocklistElement))
- return;
-
- var matchNodes = blocklistElement.childNodes;
- var blockEntry = {
- matches: {},
- versions: [],
- blockID: null,
- infoURL: null,
- };
- var hasMatch = false;
- for (var x = 0; x < matchNodes.length; ++x) {
- var matchElement = matchNodes.item(x);
- if (!(matchElement instanceof Ci.nsIDOMElement))
- continue;
- if (matchElement.localName == "match") {
- var name = matchElement.getAttribute("name");
- var exp = matchElement.getAttribute("exp");
- try {
- blockEntry.matches[name] = new RegExp(exp, "m");
- hasMatch = true;
- } catch (e) {
- // Ignore invalid regular expressions
- }
- }
- if (matchElement.localName == "versionRange") {
- blockEntry.versions.push(new BlocklistItemData(matchElement));
- }
- else if (matchElement.localName == "infoURL") {
- blockEntry.infoURL = matchElement.textContent;
- }
- }
- // Plugin entries require *something* to match to an actual plugin
- if (!hasMatch)
- return;
- // Add a default versionRange if there wasn't one specified
- if (blockEntry.versions.length == 0)
- blockEntry.versions.push(new BlocklistItemData(null));
-
- blockEntry.blockID = blocklistElement.getAttribute("blockID");
-
- result.push(blockEntry);
- },
-
- /* See nsIBlocklistService */
- getPluginBlocklistState: function Blocklist_getPluginBlocklistState(plugin,
- appVersion, toolkitVersion) {
- if (!this._isBlocklistLoaded())
- 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 Blocklist_getPluginBlocklistState(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) {
- var matchFailed = false;
- for (var name in blockEntry.matches) {
- if (!(name in plugin) ||
- typeof(plugin[name]) != "string" ||
- !blockEntry.matches[name].test(plugin[name])) {
- matchFailed = true;
- break;
- }
- }
-
- if (matchFailed)
- continue;
-
- for (let blockEntryVersion of blockEntry.versions) {
- if (blockEntryVersion.includesItem(plugin.version, appVersion,
- toolkitVersion)) {
- if (blockEntryVersion.severity >= gBlocklistLevel)
- return Ci.nsIBlocklistService.STATE_BLOCKED;
- if (blockEntryVersion.severity == SEVERITY_OUTDATED) {
- let vulnerabilityStatus = blockEntryVersion.vulnerabilityStatus;
- if (vulnerabilityStatus == VULNERABILITYSTATUS_UPDATE_AVAILABLE)
- return Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE;
- if (vulnerabilityStatus == VULNERABILITYSTATUS_NO_UPDATE)
- return Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE;
- return Ci.nsIBlocklistService.STATE_OUTDATED;
- }
- return Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
- }
- }
- }
-
- return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
- },
-
- /**
- * Get the matching blocklist entry for the passed plugin, if
- * available.
- * @param plugin The plugin to find the block entry for.
- * @returns The block entry which matches the passed plugin, null
- * otherwise.
- */
- _getPluginBlockEntry: function (plugin) {
- if (!gBlocklistEnabled)
- return null;
-
- if (!this._isBlocklistLoaded())
- this._loadBlocklist();
-
- for each (let blockEntry in this._pluginEntries) {
- if (matchesAllPluginNames(blockEntry, plugin)) {
- return blockEntry;
- }
- }
-
- return null;
- },
-
- /* See nsIBlocklistService */
- getPluginBlocklistURL: function Blocklist_getPluginBlocklistURL(plugin) {
- let blockEntry = this._getPluginBlockEntry(plugin);
- if (!blockEntry || !blockEntry.blockID) {
- return null;
- }
-
- return this._createBlocklistURL(blockEntry.blockID);
- },
-
- /* See nsIBlocklistService */
- getPluginInfoURL: function (plugin) {
- let blockEntry = this._getPluginBlockEntry(plugin);
- if (!blockEntry || !blockEntry.blockID) {
- return null;
- }
-
- return blockEntry.infoURL;
- },
-
- _blocklistUpdated: function Blocklist_blocklistUpdated(oldAddonEntries, oldPluginEntries) {
- var addonList = [];
-
- // A helper function that reverts the prefs passed to default values.
- function resetPrefs(prefs) {
- for (let pref of prefs)
- gPref.clearUserPref(pref);
- }
- var self = this;
- const types = ["extension", "theme", "locale", "dictionary", "service"];
- AddonManager.getAddonsByTypes(types, function blocklistUpdated_getAddonsByTypes(addons) {
-
- for (let addon of addons) {
- let oldState = Ci.nsIBlocklistService.STATE_NOTBLOCKED;
- if (oldAddonEntries)
- oldState = self._getAddonBlocklistState(addon, oldAddonEntries);
- let state = self.getAddonBlocklistState(addon);
-
- LOG("Blocklist state for " + addon.id + " changed from " +
- oldState + " to " + state);
-
- // We don't want to re-warn about add-ons
- if (state == oldState)
- continue;
-
- if (state === Ci.nsIBlocklistService.STATE_BLOCKED) {
- // It's a hard block. We must reset certain preferences.
- let prefs = self._getAddonPrefs(addon);
- resetPrefs(prefs);
- }
-
- // Ensure that softDisabled is false if the add-on is not soft blocked
- if (state != Ci.nsIBlocklistService.STATE_SOFTBLOCKED)
- addon.softDisabled = false;
-
- // Don't warn about add-ons becoming unblocked.
- if (state == Ci.nsIBlocklistService.STATE_NOT_BLOCKED)
- continue;
-
- // If an add-on has dropped from hard to soft blocked just mark it as
- // soft disabled and don't warn about it.
- if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED &&
- oldState == Ci.nsIBlocklistService.STATE_BLOCKED) {
- addon.softDisabled = true;
- continue;
- }
-
- // If the add-on is already disabled for some reason then don't warn
- // about it
- if (!addon.isActive)
- continue;
-
- addonList.push({
- name: addon.name,
- version: addon.version,
- icon: addon.iconURL,
- disable: false,
- blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED,
- item: addon,
- url: self.getAddonBlocklistURL(addon),
- });
- }
-
- AddonManagerPrivate.updateAddonAppDisabledStates();
-
- var phs = Cc["@mozilla.org/plugin/host;1"].
- getService(Ci.nsIPluginHost);
- var plugins = phs.getPluginTags();
-
- for (let plugin of plugins) {
- let oldState = -1;
- if (oldPluginEntries)
- oldState = self._getPluginBlocklistState(plugin, oldPluginEntries);
- let state = self.getPluginBlocklistState(plugin);
- LOG("Blocklist state for " + plugin.name + " changed from " +
- oldState + " to " + state);
- // We don't want to re-warn about items
- if (state == oldState)
- continue;
-
- if (oldState == Ci.nsIBlocklistService.STATE_BLOCKED) {
- if (state == Ci.nsIBlocklistService.STATE_SOFTBLOCKED)
- plugin.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
- }
- else if (!plugin.disabled && state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
- if (state == Ci.nsIBlocklistService.STATE_OUTDATED) {
- gPref.setBoolPref(PREF_PLUGINS_NOTIFYUSER, true);
- }
- else if (state != Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE &&
- state != Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE) {
- addonList.push({
- name: plugin.name,
- version: plugin.version,
- icon: "chrome://mozapps/skin/plugins/pluginGeneric.png",
- disable: false,
- blocked: state == Ci.nsIBlocklistService.STATE_BLOCKED,
- item: plugin,
- url: self.getPluginBlocklistURL(plugin),
- });
- }
- }
- }
-
- if (addonList.length == 0) {
- Services.obs.notifyObservers(self, "blocklist-updated", "");
- return;
- }
-
- if ("@mozilla.org/addons/blocklist-prompt;1" in Cc) {
- try {
- let blockedPrompter = Cc["@mozilla.org/addons/blocklist-prompt;1"]
- .getService(Ci.nsIBlocklistPrompt);
- blockedPrompter.prompt(addonList);
- } catch (e) {
- LOG(e);
- }
- Services.obs.notifyObservers(self, "blocklist-updated", "");
- return;
- }
-
- var args = {
- restart: false,
- list: addonList
- };
- // This lets the dialog get the raw js object
- args.wrappedJSObject = args;
-
- /*
- Some tests run without UI, so the async code listens to a message
- that can be sent programatically
- */
- let applyBlocklistChanges = function blocklistUpdated_applyBlocklistChanges() {
- for (let addon of addonList) {
- if (!addon.disable)
- continue;
-
- if (addon.item instanceof Ci.nsIPluginTag)
- addon.item.enabledState = Ci.nsIPluginTag.STATE_DISABLED;
- else {
- // This add-on is softblocked.
- addon.item.softDisabled = true;
- // We must revert certain prefs.
- let prefs = self._getAddonPrefs(addon.item);
- resetPrefs(prefs);
- }
- }
-
- if (args.restart)
- restartApp();
-
- Services.obs.notifyObservers(self, "blocklist-updated", "");
- Services.obs.removeObserver(applyBlocklistChanges, "addon-blocklist-closed");
- }
-
- Services.obs.addObserver(applyBlocklistChanges, "addon-blocklist-closed", false);
-
- if (getPref("getBoolPref", PREF_BLOCKLIST_SUPPRESSUI, false)) {
- applyBlocklistChanges();
- return;
- }
-
- function blocklistUnloadHandler(event) {
- if (event.target.location == URI_BLOCKLIST_DIALOG) {
- applyBlocklistChanges();
- blocklistWindow.removeEventListener("unload", blocklistUnloadHandler);
- }
- }
-
- let blocklistWindow = Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
- "chrome,centerscreen,dialog,titlebar", args);
- if (blocklistWindow)
- blocklistWindow.addEventListener("unload", blocklistUnloadHandler, false);
- });
- },
-
- classID: Components.ID("{66354bc9-7ed1-4692-ae1d-8da97d6b205e}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
- Ci.nsIBlocklistService,
- Ci.nsITimerCallback]),
-};
-
-/**
- * Helper for constructing a blocklist.
- */
-function BlocklistItemData(versionRangeElement) {
- var versionRange = this.getBlocklistVersionRange(versionRangeElement);
- this.minVersion = versionRange.minVersion;
- this.maxVersion = versionRange.maxVersion;
- if (versionRangeElement && versionRangeElement.hasAttribute("severity"))
- this.severity = versionRangeElement.getAttribute("severity");
- else
- this.severity = DEFAULT_SEVERITY;
- if (versionRangeElement && versionRangeElement.hasAttribute("vulnerabilitystatus")) {
- this.vulnerabilityStatus = versionRangeElement.getAttribute("vulnerabilitystatus");
- } else {
- this.vulnerabilityStatus = VULNERABILITYSTATUS_NONE;
- }
- this.targetApps = { };
- var found = false;
-
- if (versionRangeElement) {
- for (var i = 0; i < versionRangeElement.childNodes.length; ++i) {
- var targetAppElement = versionRangeElement.childNodes.item(i);
- if (!(targetAppElement instanceof Ci.nsIDOMElement) ||
- 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);
- }
- }
- // Default to all versions of the current application when no targetApplication
- // elements were found
- if (!found)
- this.targetApps[gApp.ID] = this.getBlocklistAppVersions(null);
-}
-
-BlocklistItemData.prototype = {
- /**
- * 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 BlocklistItemData_includesItem(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 BlocklistItemData_matchesRange(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 BlocklistItemData_matchesTargetRange(appID, appVersion) {
- var blTargetApp = this.targetApps[appID];
- if (!blTargetApp)
- return false;
-
- for (let app of blTargetApp) {
- if (this.matchesRange(appVersion, app.minVersion, app.maxVersion))
- return true;
- }
-
- return false;
- },
-
- /**
- * Retrieves a version range (e.g. minVersion and maxVersion) for a
- * blocklist item's targetApplication element.
- * @param targetAppElement
- * A targetApplication blocklist element.
- * @returns An array of JS objects with the following properties:
- * "minVersion" The minimum version in a version range (default = null).
- * "maxVersion" The maximum version in a version range (default = null).
- */
- getBlocklistAppVersions: function BlocklistItemData_getBlocklistAppVersions(targetAppElement) {
- var appVersions = [ ];
-
- if (targetAppElement) {
- for (var i = 0; i < targetAppElement.childNodes.length; ++i) {
- var versionRangeElement = targetAppElement.childNodes.item(i);
- if (!(versionRangeElement instanceof Ci.nsIDOMElement) ||
- versionRangeElement.localName != "versionRange")
- continue;
- appVersions.push(this.getBlocklistVersionRange(versionRangeElement));
- }
- }
- // return minVersion = null and maxVersion = null if no specific versionRange
- // elements were found
- if (appVersions.length == 0)
- appVersions.push(this.getBlocklistVersionRange(null));
- return appVersions;
- },
-
- /**
- * Retrieves a version range (e.g. minVersion and maxVersion) for a blocklist
- * versionRange element.
- * @param versionRangeElement
- * The versionRange blocklist element.
- * @returns A JS object with the following properties:
- * "minVersion" The minimum version in a version range (default = null).
- * "maxVersion" The maximum version in a version range (default = null).
- */
- getBlocklistVersionRange: function BlocklistItemData_getBlocklistVersionRange(versionRangeElement) {
- var minVersion = null;
- var maxVersion = null;
- 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 };
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Blocklist]);