!import
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3 //@line 40 "/home/visbrero/mnt/roisin/rev_control/hg/mozilla/toolkit/mozapps/extensions/src/nsBlocklistService.js"
4 */
5
6 const Cc = Components.classes;
7 const Ci = Components.interfaces;
8 const Cr = Components.results;
9
10 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
11
12 const TOOLKIT_ID = "toolkit@mozilla.org"
13 const KEY_PROFILEDIR = "ProfD";
14 const KEY_APPDIR = "XCurProcD";
15 const FILE_BLOCKLIST = "blocklist.xml";
16 const PREF_BLOCKLIST_URL = "extensions.blocklist.url";
17 const PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
18 const PREF_BLOCKLIST_INTERVAL = "extensions.blocklist.interval";
19 const PREF_EM_LOGGING_ENABLED = "extensions.logging.enabled";
20 const XMLURI_BLOCKLIST = "http://www.mozilla.org/2006/addons-blocklist";
21 const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
22
23 const MODE_RDONLY = 0x01;
24 const MODE_WRONLY = 0x02;
25 const MODE_CREATE = 0x08;
26 const MODE_APPEND = 0x10;
27 const MODE_TRUNCATE = 0x20;
28
29 const PERMS_FILE = 0644;
30 const PERMS_DIRECTORY = 0755;
31
32 var gApp = null;
33 var gPref = null;
34 var gOS = null;
35 var gConsole = null;
36 var gVersionChecker = null;
37 var gLoggingEnabled = null;
38
39 // shared code for suppressing bad cert dialogs
40 //@line 40 "/home/visbrero/mnt/roisin/rev_control/hg/mozilla/toolkit/mozapps/shared/src/badCertHandler.js"
41
42 /**
43 * Only allow built-in certs for HTTPS connections. See bug 340198.
44 */
checkCert
45 function checkCert(channel) {
46 if (!channel.originalURI.schemeIs("https")) // bypass
47 return;
48
49 const Ci = Components.interfaces;
50 var cert =
51 channel.securityInfo.QueryInterface(Ci.nsISSLStatusProvider).
52 SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
53
54 var issuer = cert.issuer;
55 while (issuer && !cert.equals(issuer)) {
56 cert = issuer;
57 issuer = cert.issuer;
58 }
59
60 if (!issuer || issuer.tokenName != "Builtin Object Token")
61 throw "cert issuer is not built-in";
62 }
63
64 /**
65 * This class implements nsIBadCertListener. It's job is to prevent "bad cert"
66 * security dialogs from being shown to the user. It is better to simply fail
67 * if the certificate is bad. See bug 304286.
68 */
BadCertHandler
69 function BadCertHandler() {
70 }
71 BadCertHandler.prototype = {
72
73 // nsIChannelEventSink
onChannelRedirect
74 onChannelRedirect: function(oldChannel, newChannel, flags) {
75 // make sure the certificate of the old channel checks out before we follow
76 // a redirect from it. See bug 340198.
77 checkCert(oldChannel);
78 },
79
80 // Suppress any certificate errors
notifyCertProblem
81 notifyCertProblem: function(socketInfo, status, targetSite) {
82 return true;
83 },
84
85 // Suppress any ssl errors
notifySSLError
86 notifySSLError: function(socketInfo, error, targetSite) {
87 return true;
88 },
89
90 // nsIInterfaceRequestor
getInterface
91 getInterface: function(iid) {
92 return this.QueryInterface(iid);
93 },
94
95 // nsISupports
QueryInterface
96 QueryInterface: function(iid) {
97 if (!iid.equals(Components.interfaces.nsIChannelEventSink) &&
98 !iid.equals(Components.interfaces.nsIBadCertListener2) &&
99 !iid.equals(Components.interfaces.nsISSLErrorListener) &&
100 !iid.equals(Components.interfaces.nsIInterfaceRequestor) &&
101 !iid.equals(Components.interfaces.nsISupports))
102 throw Components.results.NS_ERROR_NO_INTERFACE;
103 return this;
104 }
105 };
106 //@line 77 "/home/visbrero/mnt/roisin/rev_control/hg/mozilla/toolkit/mozapps/extensions/src/nsBlocklistService.js"
107
108 /**
109 * Logs a string to the error console.
110 * @param string
111 * The string to write to the error console..
112 */
LOG
113 function LOG(string) {
114 if (gLoggingEnabled) {
115 dump("*** " + string + "\n");
116 if (gConsole)
117 gConsole.logStringMessage(string);
118 }
119 }
120
121 /**
122 * Gets a preference value, handling the case where there is no default.
123 * @param func
124 * The name of the preference function to call, on nsIPrefBranch
125 * @param preference
126 * The name of the preference
127 * @param defaultValue
128 * The default value to return in the event the preference has
129 * no setting
130 * @returns The value of the preference, or undefined if there was no
131 * user or default value.
132 */
getPref
Called: BackstagePass:getBoolPref (1 calls, 10 v-uS)
BackstagePass:getIntPref (1 calls, 11 v-uS)
133 function getPref(func, preference, defaultValue) {
134 try {
135 return gPref[func](preference);
136 }
137 catch (e) {
138 }
139 return defaultValue;
140 }
141
142 /**
143 * Gets the file at the specified hierarchy under a Directory Service key.
144 * @param key
145 * The Directory Service Key to start from
146 * @param pathArray
147 * An array of path components to locate beneath the directory
148 * specified by |key|. The last item in this array must be the
149 * leaf name of a file.
150 * @return nsIFile object for the file specified. The file is NOT created
151 * if it does not exist, however all required directories along
152 * the way are.
153 */
getFile
154 function getFile(key, pathArray) {
155 var fileLocator = Cc["@mozilla.org/file/directory_service;1"].
156 getService(Ci.nsIProperties);
157 var file = fileLocator.get(key, Ci.nsILocalFile);
158 for (var i = 0; i < pathArray.length - 1; ++i) {
159 file.append(pathArray[i]);
160 if (!file.exists())
161 file.create(Ci.nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
162 }
163 file.followLinks = false;
164 file.append(pathArray[pathArray.length - 1]);
165 return file;
166 }
167
168 /**
169 * Opens a safe file output stream for writing.
170 * @param file
171 * The file to write to.
172 * @param modeFlags
173 * (optional) File open flags. Can be undefined.
174 * @returns nsIFileOutputStream to write to.
175 */
openSafeFileOutputStream
176 function openSafeFileOutputStream(file, modeFlags) {
177 var fos = Cc["@mozilla.org/network/safe-file-output-stream;1"].
178 createInstance(Ci.nsIFileOutputStream);
179 if (modeFlags === undefined)
180 modeFlags = MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE;
181 if (!file.exists())
182 file.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
183 fos.init(file, modeFlags, PERMS_FILE, 0);
184 return fos;
185 }
186
187 /**
188 * Closes a safe file output stream.
189 * @param stream
190 * The stream to close.
191 */
closeSafeFileOutputStream
192 function closeSafeFileOutputStream(stream) {
193 if (stream instanceof Ci.nsISafeOutputStream)
194 stream.finish();
195 else
196 stream.close();
197 }
198
199 /**
200 * Constructs a URI to a spec.
201 * @param spec
202 * The spec to construct a URI to
203 * @returns The nsIURI constructed.
204 */
newURI
205 function newURI(spec) {
206 var ioServ = Cc["@mozilla.org/network/io-service;1"].
207 getService(Ci.nsIIOService);
208 return ioServ.newURI(spec, null, null);
209 }
210
211 /**
212 * Checks whether this blocklist element is valid for the current OS and ABI.
213 * If the element has an "os" attribute then the current OS must appear in
214 * it's comma separated list for the element to be valid. Similarly for the
215 * xpcomabi attribute.
216 */
matchesOSABI
217 function matchesOSABI(blocklistElement) {
218 if (blocklistElement.hasAttribute("os")) {
219 var choices = blocklistElement.getAttribute("os").split(",");
220 if (choices.length > 0 && choices.indexOf(gApp.OS) < 0)
221 return false;
222 }
223
224 if (blocklistElement.hasAttribute("xpcomabi")) {
225 choices = blocklistElement.getAttribute("xpcomabi").split(",");
226 if (choices.length > 0 && choices.indexOf(gApp.XPCOMABI) < 0)
227 return false;
228 }
229
230 return true;
231 }
232
233 /**
234 * Manages the Blocklist. The Blocklist is a representation of the contents of
235 * blocklist.xml and allows us to remotely disable / re-enable blocklisted
236 * items managed by the Extension Manager with an item's appDisabled property.
237 * It also blocklists plugins with data from blocklist.xml.
238 */
239
Blocklist
240 function Blocklist() {
241 gApp = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
242 gApp.QueryInterface(Ci.nsIXULRuntime);
243 gPref = Cc["@mozilla.org/preferences-service;1"].
244 getService(Ci.nsIPrefBranch2);
245 gVersionChecker = Cc["@mozilla.org/xpcom/version-comparator;1"].
246 getService(Ci.nsIVersionComparator);
247 gConsole = Cc["@mozilla.org/consoleservice;1"].
248 getService(Ci.nsIConsoleService);
249
250 gOS = Cc["@mozilla.org/observer-service;1"].
251 getService(Ci.nsIObserverService);
252 gOS.addObserver(this, "xpcom-shutdown", false);
253 }
254
255 Blocklist.prototype = {
256 /**
257 * Extension ID -> array of Version Ranges
258 * Each value in the version range array is a JS Object that has the
259 * following properties:
260 * "minVersion" The minimum version in a version range (default = 0)
261 * "maxVersion" The maximum version in a version range (default = *)
262 * "targetApps" Application ID -> array of Version Ranges
263 * (default = current application ID)
264 * Each value in the version range array is a JS Object that
265 * has the following properties:
266 * "minVersion" The minimum version in a version range
267 * (default = 0)
268 * "maxVersion" The maximum version in a version range
269 * (default = *)
270 */
271 _addonEntries: null,
272 _pluginEntries: null,
273
observe
274 observe: function (aSubject, aTopic, aData) {
275 switch (aTopic) {
276 case "app-startup":
277 gOS.addObserver(this, "plugins-list-updated", false);
278 gOS.addObserver(this, "profile-after-change", false);
279 gOS.addObserver(this, "quit-application", false);
280 break;
281 case "profile-after-change":
282 gLoggingEnabled = getPref("getBoolPref", PREF_EM_LOGGING_ENABLED, false);
283 var tm = Cc["@mozilla.org/updates/timer-manager;1"].
284 getService(Ci.nsIUpdateTimerManager);
285 var interval = getPref("getIntPref", PREF_BLOCKLIST_INTERVAL, 86400);
286 tm.registerTimer("blocklist-background-update-timer", this, interval);
287 break;
288 case "plugins-list-updated":
289 this._checkPluginsList();
290 break;
291 case "quit-application":
292 gOS.removeObserver(this, "plugins-list-updated");
293 gOS.removeObserver(this, "profile-after-change");
294 gOS.removeObserver(this, "quit-application");
295 break;
296 case "xpcom-shutdown":
297 gOS.removeObserver(this, "xpcom-shutdown");
298 gOS = null;
299 gPref = null;
300 gConsole = null;
301 gVersionChecker = null;
302 gApp = null;
303 break;
304 }
305 },
306
isAddonBlocklisted
307 isAddonBlocklisted: function(id, version, appVersion, toolkitVersion) {
308 if (!this._addonEntries)
309 this._loadBlocklist();
310 if (!appVersion)
311 appVersion = gApp.version;
312 if (!toolkitVersion)
313 toolkitVersion = gApp.platformVersion;
314
315 var blItem = this._addonEntries[id];
316 if (!blItem)
317 return false;
318
319 for (var i = 0; i < blItem.length; ++i) {
320 if (gVersionChecker.compare(version, blItem[i].minVersion) < 0 ||
321 gVersionChecker.compare(version, blItem[i].maxVersion) > 0)
322 continue;
323
324 var blTargetApp = blItem[i].targetApps[gApp.ID];
325 if (blTargetApp) {
326 for (var x = 0; x < blTargetApp.length; ++x) {
327 if (gVersionChecker.compare(appVersion, blTargetApp[x].minVersion) < 0 ||
328 gVersionChecker.compare(appVersion, blTargetApp[x].maxVersion) > 0)
329 continue;
330 return true;
331 }
332 }
333
334 blTargetApp = blItem[i].targetApps[TOOLKIT_ID];
335 if (!blTargetApp)
336 return false;
337 for (x = 0; x < blTargetApp.length; ++x) {
338 if (gVersionChecker.compare(toolkitVersion, blTargetApp[x].minVersion) < 0 ||
339 gVersionChecker.compare(toolkitVersion, blTargetApp[x].maxVersion) > 0)
340 continue;
341 return true;
342 }
343 }
344 return false;
345 },
346
notify
347 notify: function(aTimer) {
348 if (getPref("getBoolPref", PREF_BLOCKLIST_ENABLED, true) == false)
349 return;
350
351 try {
352 var dsURI = gPref.getCharPref(PREF_BLOCKLIST_URL);
353 }
354 catch (e) {
355 LOG("Blocklist::notify: The " + PREF_BLOCKLIST_URL + " preference" +
356 " is missing!");
357 return;
358 }
359
360 dsURI = dsURI.replace(/%APP_ID%/g, gApp.ID);
361 dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version);
362 // Verify that the URI is valid
363 try {
364 var uri = newURI(dsURI);
365 }
366 catch (e) {
367 LOG("Blocklist::notify: There was an error creating the blocklist URI\r\n" +
368 "for: " + dsURI + ", error: " + e);
369 return;
370 }
371
372 var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
373 createInstance(Ci.nsIXMLHttpRequest);
374 request.open("GET", uri.spec, true);
375 request.channel.notificationCallbacks = new BadCertHandler();
376 request.overrideMimeType("text/xml");
377 request.setRequestHeader("Cache-Control", "no-cache");
378 request.QueryInterface(Components.interfaces.nsIJSXMLHttpRequest);
379
380 var self = this;
anon:381:22
381 request.onerror = function(event) { self.onXMLError(event); };
anon:382:22
382 request.onload = function(event) { self.onXMLLoad(event); };
383 request.send(null);
384 },
385
onXMLLoad
386 onXMLLoad: function(aEvent) {
387 var request = aEvent.target;
388 try {
389 checkCert(request.channel);
390 }
391 catch (e) {
392 LOG("Blocklist::onXMLLoad: " + e);
393 return;
394 }
395 var responseXML = request.responseXML;
396 if (!responseXML || responseXML.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
397 (request.status != 200 && request.status != 0)) {
398 LOG("Blocklist::onXMLLoad: there was an error during load");
399 return;
400 }
401 var blocklistFile = getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
402 if (blocklistFile.exists())
403 blocklistFile.remove(false);
404 var fos = openSafeFileOutputStream(blocklistFile);
405 fos.write(request.responseText, request.responseText.length);
406 closeSafeFileOutputStream(fos);
407 this._loadBlocklistFromFile(getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]));
408 var em = Cc["@mozilla.org/extensions/manager;1"].
409 getService(Ci.nsIExtensionManager);
410 em.checkForBlocklistChanges();
411 this._checkPluginsList();
412 },
413
onXMLError
414 onXMLError: function(aEvent) {
415 try {
416 var request = aEvent.target;
417 // the following may throw (e.g. a local file or timeout)
418 var status = request.status;
419 }
420 catch (e) {
421 request = aEvent.target.channel.QueryInterface(Ci.nsIRequest);
422 status = request.status;
423 }
424 var statusText = request.statusText;
425 // When status is 0 we don't have a valid channel.
426 if (status == 0)
427 statusText = "nsIXMLHttpRequest channel unavailable";
428 LOG("Blocklist:onError: There was an error loading the blocklist file\r\n" +
429 statusText);
430 },
431
432 /**
433 * Finds the newest blocklist file from the application and the profile and
434 * load it or does nothing if neither exist.
435 */
_loadBlocklist
436 _loadBlocklist: function() {
437 this._addonEntries = { };
438 this._pluginEntries = { };
439 var profFile = getFile(KEY_PROFILEDIR, [FILE_BLOCKLIST]);
440 if (profFile.exists()) {
441 this._loadBlocklistFromFile(profFile);
442 return;
443 }
444 var appFile = getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
445 if (appFile.exists()) {
446 this._loadBlocklistFromFile(appFile);
447 return;
448 }
449 LOG("Blocklist::_loadBlocklist: no XML File found");
450 },
451
452 /**
453 //@line 472 "/home/visbrero/mnt/roisin/rev_control/hg/mozilla/toolkit/mozapps/extensions/src/nsBlocklistService.js"
454 */
455
_loadBlocklistFromFile
456 _loadBlocklistFromFile: function(file) {
457 if (getPref("getBoolPref", PREF_BLOCKLIST_ENABLED, true) == false) {
458 LOG("Blocklist::_loadBlocklistFromFile: blocklist is disabled");
459 return;
460 }
461
462 if (!file.exists()) {
463 LOG("Blocklist::_loadBlocklistFromFile: XML File does not exist");
464 return;
465 }
466
467 var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
468 .createInstance(Components.interfaces.nsIFileInputStream);
469 fileStream.init(file, MODE_RDONLY, PERMS_FILE, 0);
470 try {
471 var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
472 createInstance(Ci.nsIDOMParser);
473 var doc = parser.parseFromStream(fileStream, "UTF-8", file.fileSize, "text/xml");
474 if (doc.documentElement.namespaceURI != XMLURI_BLOCKLIST) {
475 LOG("Blocklist::_loadBlocklistFromFile: aborting due to incorrect " +
476 "XML Namespace.\r\nExpected: " + XMLURI_BLOCKLIST + "\r\n" +
477 "Received: " + doc.documentElement.namespaceURI);
478 return;
479 }
480
481 var childNodes = doc.documentElement.childNodes;
482 this._addonEntries = this._processItemNodes(childNodes, "em",
483 this._handleEmItemNode);
484 this._pluginEntries = this._processItemNodes(childNodes, "plugin",
485 this._handlePluginItemNode);
486 }
487 catch (e) {
488 LOG("Blocklist::_loadBlocklistFromFile: Error constructing blocklist " + e);
489 return;
490 }
491 fileStream.close();
492 },
493
_processItemNodes
494 _processItemNodes: function(deChildNodes, prefix, handler) {
495 var result = [];
496 var itemNodes;
497 var containerName = prefix + "Items";
498 for (var i = 0; i < deChildNodes.length; ++i) {
499 var emItemsElement = deChildNodes.item(i);
500 if (emItemsElement instanceof Ci.nsIDOMElement &&
501 emItemsElement.localName == containerName) {
502 itemNodes = emItemsElement.childNodes;
503 break;
504 }
505 }
506 if (!itemNodes)
507 return result;
508
509 var itemName = prefix + "Item";
510 for (var i = 0; i < itemNodes.length; ++i) {
511 var blocklistElement = itemNodes.item(i);
512 if (!(blocklistElement instanceof Ci.nsIDOMElement) ||
513 blocklistElement.localName != itemName)
514 continue;
515
516 handler(blocklistElement, result);
517 }
518 return result;
519 },
520
_handleEmItemNode
521 _handleEmItemNode: function(blocklistElement, result) {
522 if (!matchesOSABI(blocklistElement))
523 return;
524
525 var versionNodes = blocklistElement.childNodes;
526 var id = blocklistElement.getAttribute("id");
527 result[id] = [];
528 for (var x = 0; x < versionNodes.length; ++x) {
529 var versionRangeElement = versionNodes.item(x);
530 if (!(versionRangeElement instanceof Ci.nsIDOMElement) ||
531 versionRangeElement.localName != "versionRange")
532 continue;
533
534 result[id].push(new BlocklistItemData(versionRangeElement));
535 }
536 // if only the extension ID is specified block all versions of the
537 // extension for the current application.
538 if (result[id].length == 0)
539 result[id].push(new BlocklistItemData(null));
540 },
541
_handlePluginItemNode
542 _handlePluginItemNode: function(blocklistElement, result) {
543 if (!matchesOSABI(blocklistElement))
544 return;
545
546 var matchNodes = blocklistElement.childNodes;
547 var matchList;
548 for (var x = 0; x < matchNodes.length; ++x) {
549 var matchElement = matchNodes.item(x);
550 if (!(matchElement instanceof Ci.nsIDOMElement) ||
551 matchElement.localName != "match")
552 continue;
553
554 var name = matchElement.getAttribute("name");
555 var exp = matchElement.getAttribute("exp");
556 if (!matchList)
557 matchList = { };
558 matchList[name] = new RegExp(exp, "m");
559 }
560 if (matchList)
561 result.push(matchList);
562 },
563
_checkPlugin
564 _checkPlugin: function(plugin) {
565 for each (var matchList in this._pluginEntries) {
566 var matchFailed = false;
567 for (var name in matchList) {
568 if (typeof(plugin[name]) != "string" ||
569 !matchList[name].test(plugin[name])) {
570 matchFailed = true;
571 break;
572 }
573 }
574
575 if (!matchFailed) {
576 plugin.blocklisted = true;
577 return;
578 }
579 }
580 plugin.blocklisted = false;
581 },
582
_checkPluginsList
583 _checkPluginsList: function() {
584 if (!this._addonEntries)
585 this._loadBlocklist();
586 var phs = Cc["@mozilla.org/plugin/host;1"].
587 getService(Ci.nsIPluginHost);
588 phs.getPluginTags({ }).forEach(this._checkPlugin, this);
589 },
590
591 classDescription: "Blocklist Service",
592 contractID: "@mozilla.org/extensions/blocklist;1",
593 classID: Components.ID("{66354bc9-7ed1-4692-ae1d-8da97d6b205e}"),
594 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
595 Ci.nsIBlocklistService,
596 Ci.nsITimerCallback]),
597 _xpcom_categories: [{
598 category: "app-startup",
599 service: true
600 }]
601 };
602
603 /**
604 * Helper for constructing a blocklist.
605 */
BlocklistItemData
606 function BlocklistItemData(versionRangeElement) {
607 var versionRange = this.getBlocklistVersionRange(versionRangeElement);
608 this.minVersion = versionRange.minVersion;
609 this.maxVersion = versionRange.maxVersion;
610 this.targetApps = { };
611 var found = false;
612
613 if (versionRangeElement) {
614 for (var i = 0; i < versionRangeElement.childNodes.length; ++i) {
615 var targetAppElement = versionRangeElement.childNodes.item(i);
616 if (!(targetAppElement instanceof Ci.nsIDOMElement) ||
617 targetAppElement.localName != "targetApplication")
618 continue;
619 found = true;
620 // default to the current application if id is not provided.
621 var appID = targetAppElement.hasAttribute("id") ? targetAppElement.getAttribute("id") : gApp.ID;
622 this.targetApps[appID] = this.getBlocklistAppVersions(targetAppElement);
623 }
624 }
625 // Default to all versions of the extension and the current application when
626 // versionRange is not defined.
627 if (!found)
628 this.targetApps[gApp.ID] = this.getBlocklistAppVersions(null);
629 }
630
631 BlocklistItemData.prototype = {
632 /**
633 * Retrieves a version range (e.g. minVersion and maxVersion) for a
634 * blocklist item's targetApplication element.
635 * @param targetAppElement
636 * A targetApplication blocklist element.
637 * @returns An array of JS objects with the following properties:
638 * "minVersion" The minimum version in a version range (default = 0).
639 * "maxVersion" The maximum version in a version range (default = *).
640 */
getBlocklistAppVersions
641 getBlocklistAppVersions: function(targetAppElement) {
642 var appVersions = [ ];
643 var found = false;
644
645 if (targetAppElement) {
646 for (var i = 0; i < targetAppElement.childNodes.length; ++i) {
647 var versionRangeElement = targetAppElement.childNodes.item(i);
648 if (!(versionRangeElement instanceof Ci.nsIDOMElement) ||
649 versionRangeElement.localName != "versionRange")
650 continue;
651 found = true;
652 appVersions.push(this.getBlocklistVersionRange(versionRangeElement));
653 }
654 }
655 // return minVersion = 0 and maxVersion = * if not available
656 if (!found)
657 return [ this.getBlocklistVersionRange(null) ];
658 return appVersions;
659 },
660
661 /**
662 * Retrieves a version range (e.g. minVersion and maxVersion) for a blocklist
663 * versionRange element.
664 * @param versionRangeElement
665 * The versionRange blocklist element.
666 * @returns A JS object with the following properties:
667 * "minVersion" The minimum version in a version range (default = 0).
668 * "maxVersion" The maximum version in a version range (default = *).
669 */
getBlocklistVersionRange
670 getBlocklistVersionRange: function(versionRangeElement) {
671 var minVersion = "0";
672 var maxVersion = "*";
673 if (!versionRangeElement)
674 return { minVersion: minVersion, maxVersion: maxVersion };
675
676 if (versionRangeElement.hasAttribute("minVersion"))
677 minVersion = versionRangeElement.getAttribute("minVersion");
678 if (versionRangeElement.hasAttribute("maxVersion"))
679 maxVersion = versionRangeElement.getAttribute("maxVersion");
680
681 return { minVersion: minVersion, maxVersion: maxVersion };
682 }
683 };
684
NSGetModule
685 function NSGetModule(aCompMgr, aFileSpec) {
686 return XPCOMUtils.generateModule([Blocklist]);
687 }