Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/filterClasses.js

Issue 4559243822759936: Issue 431/432 - Remove special handling for the $sitekey option (Closed)
Patch Set: Created July 28, 2014, 2:44 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH 3 * Copyright (C) 2006-2014 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 /** 18 /**
19 * @fileOverview Definition of Filter class and its subclasses. 19 * @fileOverview Definition of Filter class and its subclasses.
20 */ 20 */
21 21
22 let {FilterNotifier} = require("filterNotifier"); 22 let {FilterNotifier} = require("filterNotifier");
23 let {Utils} = require("utils");
Wladimir Palant 2014/08/01 10:50:21 This is a pretty self-contained module, it shouldn
Thomas Greiner 2014/08/11 17:18:15 Done.
23 24
24 /** 25 /**
25 * Abstract base class for filters 26 * Abstract base class for filters
26 * 27 *
27 * @param {String} text string representation of the filter 28 * @param {String} text string representation of the filter
28 * @constructor 29 * @constructor
29 */ 30 */
30 function Filter(text) 31 function Filter(text)
31 { 32 {
32 this.text = text; 33 this.text = text;
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 /** 210 /**
210 * See Filter.serialize() 211 * See Filter.serialize()
211 */ 212 */
212 serialize: function(buffer) {} 213 serialize: function(buffer) {}
213 }; 214 };
214 215
215 /** 216 /**
216 * Abstract base class for filters that can get hits 217 * Abstract base class for filters that can get hits
217 * @param {String} text see Filter() 218 * @param {String} text see Filter()
218 * @param {String} domains (optional) Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com" 219 * @param {String} domains (optional) Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com"
220 * @param {String} siteKeys (optional) Public keys of websites that this filter should apply to, e.g. "foo|bar|~baz"
Wladimir Palant 2014/08/01 10:50:21 I don't really see how exceptions are useful here,
Thomas Greiner 2014/08/11 17:18:15 The issue stated that $sitekey should be handled e
219 * @constructor 221 * @constructor
220 * @augments Filter 222 * @augments Filter
221 */ 223 */
222 function ActiveFilter(text, domains) 224 function ActiveFilter(text, domains, siteKeys)
223 { 225 {
224 Filter.call(this, text); 226 Filter.call(this, text);
225 227
226 this.domainSource = domains; 228 this.domainSource = domains;
229 this.siteKeySource = siteKeys;
Thomas Greiner 2014/08/11 17:18:15 Done.
227 } 230 }
228 exports.ActiveFilter = ActiveFilter; 231 exports.ActiveFilter = ActiveFilter;
229 232
230 ActiveFilter.prototype = 233 ActiveFilter.prototype =
231 { 234 {
232 __proto__: Filter.prototype, 235 __proto__: Filter.prototype,
233 236
234 _disabled: false, 237 _disabled: false,
235 _hitCount: 0, 238 _hitCount: 0,
236 _lastHit: 0, 239 _lastHit: 0,
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 } 377 }
375 378
376 this.domainSource = null; 379 this.domainSource = null;
377 } 380 }
378 381
379 Object.defineProperty(this, "domains", {value: domains, enumerable: true}); 382 Object.defineProperty(this, "domains", {value: domains, enumerable: true});
380 return this.domains; 383 return this.domains;
381 }, 384 },
382 385
383 /** 386 /**
387 * String that the siteKey property should be generated from
388 * @type String
389 */
390 siteKeySource: null,
391
392 /**
393 * Map containing public keys of websites that this filter should apply to
394 * @type Object
395 */
396 get siteKeys()
397 {
398 let siteKeys = null;
399
400 if (this.siteKeySource)
401 {
402 let source = this.siteKeySource;
403 let list = source.split("|");
404 if (list.length == 1 && list[0][0] != "~")
405 {
406 // Fast track for the common one-sitekey scenario
407 siteKeys = {__proto__: null, "": false};
408 siteKeys[list[0]] = true;
409 }
410 else
411 {
412 let hasIncludes = false;
413 for (let i = 0; i < list.length; i++)
414 {
415 let siteKey = list[i];
416 if (siteKey == "")
417 continue;
418
419 let include;
420 if (siteKey[0] == "~")
421 {
422 include = false;
423 siteKey = siteKey.substr(1);
424 }
425 else
426 {
427 include = true;
428 hasIncludes = true;
429 }
430
431 if (!siteKeys)
432 siteKeys = Object.create(null);
433
434 siteKeys[siteKey] = include;
435 }
436 siteKeys[""] = !hasIncludes;
437 }
438
439 this.siteKeySource = null;
440 }
441
442 Object.defineProperty(this, "siteKeys", {value: siteKeys, enumerable: true}) ;
443 return this.siteKeys;
444 },
445
446 /**
384 * Checks whether this filter is active on a domain. 447 * Checks whether this filter is active on a domain.
385 */ 448 */
386 isActiveOnDomain: function(/**String*/ docDomain) /**Boolean*/ 449 isActiveOnDomain: function(/**String*/ docDomain) /**Boolean*/
387 { 450 {
388 // If no domains are set the rule matches everywhere 451 // If no domains are set the rule matches everywhere
389 if (!this.domains) 452 if (!this.domains)
390 return true; 453 return true;
391 454
392 // If the document has no host name, match only if the filter isn't restrict ed to specific domains 455 // If the document has no host name, match only if the filter isn't restrict ed to specific domains
393 if (!docDomain) 456 if (!docDomain)
(...skipping 29 matching lines...) Expand all
423 docDomain = docDomain.toUpperCase(); 486 docDomain = docDomain.toUpperCase();
424 487
425 for (let domain in this.domains) 488 for (let domain in this.domains)
426 if (this.domains[domain] && domain != docDomain && (domain.length <= docDo main.length || domain.indexOf("." + docDomain) != domain.length - docDomain.leng th - 1)) 489 if (this.domains[domain] && domain != docDomain && (domain.length <= docDo main.length || domain.indexOf("." + docDomain) != domain.length - docDomain.leng th - 1))
427 return false; 490 return false;
428 491
429 return true; 492 return true;
430 }, 493 },
431 494
432 /** 495 /**
496 * Checks whether the provided site key is valid and active on a page
497 */
498 isActiveOnPage: function(/**String*/ docDomain, /**String*/ docLocation, /**St ring*/ siteKey) /**Boolean*/
Wladimir Palant 2014/08/01 10:50:21 I don't think that this is the right place to perf
Thomas Greiner 2014/08/11 17:18:15 Done.
499 {
500 // If no site keys are set the rule matches everywhere
501 if (!this.siteKeys)
502 return true;
503
504 // If the document has not provided a sitekey, match only if the filter isn' t restricted by sitekeys
505 if (!docDomain || !siteKey)
506 return this.siteKeys[""];
507
508 // If the document has provided an invalid sitekey the filter should not mat ch
509 if (siteKey.indexOf("_") < 0)
510 return false;
511
512 let [key, signature] = siteKey.split("_", 2);
513 let formattedKey = key.replace(/=/g, "").toUpperCase();
514 if (!(formattedKey in this.siteKeys) || !Utils.crypto)
515 return this.siteKeys[""];
516
517 // Website specifies a key that we know but is the signature valid?
518 let uri = Services.io.newURI(docLocation, null, null);
519 let host = uri.asciiHost;
520 if (uri.port > 0)
521 host += ":" + uri.port;
522 let params = [
523 uri.path.replace(/#.*/, ""), // REQUEST_URI
524 host, // HTTP_HOST
525 Utils.httpProtocol.userAgent // HTTP_USER_AGENT
526 ];
527 if (Utils.verifySignature(key, signature, params.join("\0")))
528 return this.siteKeys[formattedKey];
529
530 return !this.siteKeys[formattedKey];
531 },
532
533 /**
433 * See Filter.serialize() 534 * See Filter.serialize()
434 */ 535 */
435 serialize: function(buffer) 536 serialize: function(buffer)
436 { 537 {
437 if (this._disabled || this._hitCount || this._lastHit) 538 if (this._disabled || this._hitCount || this._lastHit)
438 { 539 {
439 Filter.prototype.serialize.call(this, buffer); 540 Filter.prototype.serialize.call(this, buffer);
440 if (this._disabled) 541 if (this._disabled)
441 buffer.push("disabled=true"); 542 buffer.push("disabled=true");
442 if (this._hitCount) 543 if (this._hitCount)
443 buffer.push("hitCount=" + this._hitCount); 544 buffer.push("hitCount=" + this._hitCount);
444 if (this._lastHit) 545 if (this._lastHit)
445 buffer.push("lastHit=" + this._lastHit); 546 buffer.push("lastHit=" + this._lastHit);
446 } 547 }
447 } 548 }
448 }; 549 };
449 550
450 /** 551 /**
451 * Abstract base class for RegExp-based filters 552 * Abstract base class for RegExp-based filters
452 * @param {String} text see Filter() 553 * @param {String} text see Filter()
453 * @param {String} regexpSource filter part that the regular expression should b e build from 554 * @param {String} regexpSource filter part that the regular expression should b e build from
454 * @param {Number} contentType (optional) Content types the filter applies to, combination of values from RegExpFilter.typeMap 555 * @param {Number} contentType (optional) Content types the filter applies to, combination of values from RegExpFilter.typeMap
455 * @param {Boolean} matchCase (optional) Defines whether the filter should dis tinguish between lower and upper case letters 556 * @param {Boolean} matchCase (optional) Defines whether the filter should dis tinguish between lower and upper case letters
456 * @param {String} domains (optional) Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com" 557 * @param {String} domains (optional) Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com"
457 * @param {Boolean} thirdParty (optional) Defines whether the filter should app ly to third-party or first-party content only 558 * @param {Boolean} thirdParty (optional) Defines whether the filter should app ly to third-party or first-party content only
559 * @param {String} siteKeys (optional) Public keys of websites that this fil ter should apply to, e.g. "foo|bar|~baz"
458 * @constructor 560 * @constructor
459 * @augments ActiveFilter 561 * @augments ActiveFilter
460 */ 562 */
461 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, third Party) 563 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, third Party, siteKeys)
462 { 564 {
463 ActiveFilter.call(this, text, domains); 565 ActiveFilter.call(this, text, domains, siteKeys);
464 566
465 if (contentType != null) 567 if (contentType != null)
466 this.contentType = contentType; 568 this.contentType = contentType;
467 if (matchCase) 569 if (matchCase)
468 this.matchCase = matchCase; 570 this.matchCase = matchCase;
469 if (thirdParty != null) 571 if (thirdParty != null)
470 this.thirdParty = thirdParty; 572 this.thirdParty = thirdParty;
471 573
472 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpS ource.length - 1] == "/") 574 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpS ource.length - 1] == "/")
473 { 575 {
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
547 * @type Boolean 649 * @type Boolean
548 */ 650 */
549 thirdParty: null, 651 thirdParty: null,
550 652
551 /** 653 /**
552 * Tests whether the URL matches this filter 654 * Tests whether the URL matches this filter
553 * @param {String} location URL to be tested 655 * @param {String} location URL to be tested
554 * @param {String} contentType content type identifier of the URL 656 * @param {String} contentType content type identifier of the URL
555 * @param {String} docDomain domain name of the document that loads the URL 657 * @param {String} docDomain domain name of the document that loads the URL
556 * @param {Boolean} thirdParty should be true if the URL is a third-party requ est 658 * @param {Boolean} thirdParty should be true if the URL is a third-party requ est
659 * @param {String} docLocation location of the document that loads the URL
660 * @param {String} siteKey public key provided by the document
557 * @return {Boolean} true in case of a match 661 * @return {Boolean} true in case of a match
558 */ 662 */
559 matches: function(location, contentType, docDomain, thirdParty) 663 matches: function(location, contentType, docDomain, thirdParty, docLocation, s iteKey)
560 { 664 {
561 if (this.regexp.test(location) && 665 if (this.regexp.test(location) &&
562 (RegExpFilter.typeMap[contentType] & this.contentType) != 0 && 666 (RegExpFilter.typeMap[contentType] & this.contentType) != 0 &&
563 (this.thirdParty == null || this.thirdParty == thirdParty) && 667 (this.thirdParty == null || this.thirdParty == thirdParty) &&
564 this.isActiveOnDomain(docDomain)) 668 this.isActiveOnDomain(docDomain) &&
669 this.isActiveOnPage(docDomain, docLocation, siteKey))
565 { 670 {
566 return true; 671 return true;
567 } 672 }
568 673
569 return false; 674 return false;
570 } 675 }
571 }; 676 };
572 677
573 // Required to optimize Matcher, see also RegExpFilter.prototype.length 678 // Required to optimize Matcher, see also RegExpFilter.prototype.length
574 Object.defineProperty(RegExpFilter.prototype, "0", 679 Object.defineProperty(RegExpFilter.prototype, "0",
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 domains = value; 737 domains = value;
633 else if (option == "THIRD_PARTY") 738 else if (option == "THIRD_PARTY")
634 thirdParty = true; 739 thirdParty = true;
635 else if (option == "~THIRD_PARTY") 740 else if (option == "~THIRD_PARTY")
636 thirdParty = false; 741 thirdParty = false;
637 else if (option == "COLLAPSE") 742 else if (option == "COLLAPSE")
638 collapse = true; 743 collapse = true;
639 else if (option == "~COLLAPSE") 744 else if (option == "~COLLAPSE")
640 collapse = false; 745 collapse = false;
641 else if (option == "SITEKEY" && typeof value != "undefined") 746 else if (option == "SITEKEY" && typeof value != "undefined")
642 siteKeys = value.split(/\|/); 747 siteKeys = value;
643 else 748 else
644 return new InvalidFilter(origText, "Unknown option " + option.toLowerCas e()); 749 return new InvalidFilter(origText, "Unknown option " + option.toLowerCas e());
645 } 750 }
646 } 751 }
647 752
648 if (!blocking && (contentType == null || (contentType & RegExpFilter.typeMap.D OCUMENT)) && 753 if (!blocking && (contentType == null || (contentType & RegExpFilter.typeMap.D OCUMENT)) &&
649 (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text )) 754 (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text ))
650 { 755 {
651 // Exception filters shouldn't apply to pages by default unless they start w ith a protocol name 756 // Exception filters shouldn't apply to pages by default unless they start w ith a protocol name
652 if (contentType == null) 757 if (contentType == null)
653 contentType = RegExpFilter.prototype.contentType; 758 contentType = RegExpFilter.prototype.contentType;
654 contentType &= ~RegExpFilter.typeMap.DOCUMENT; 759 contentType &= ~RegExpFilter.typeMap.DOCUMENT;
655 } 760 }
656 if (!blocking && siteKeys)
657 contentType = RegExpFilter.typeMap.DOCUMENT;
658 761
659 try 762 try
660 { 763 {
661 if (blocking) 764 if (blocking)
662 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, collapse); 765 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, siteKeys, collapse);
663 else 766 else
664 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, siteKeys); 767 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, siteKeys);
665 } 768 }
666 catch (e) 769 catch (e)
667 { 770 {
668 return new InvalidFilter(origText, e); 771 return new InvalidFilter(origText, e);
669 } 772 }
670 } 773 }
671 774
672 /** 775 /**
(...skipping 25 matching lines...) Expand all
698 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.ELEMHIDE | RegExpFi lter.typeMap.POPUP); 801 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.ELEMHIDE | RegExpFi lter.typeMap.POPUP);
699 802
700 /** 803 /**
701 * Class for blocking filters 804 * Class for blocking filters
702 * @param {String} text see Filter() 805 * @param {String} text see Filter()
703 * @param {String} regexpSource see RegExpFilter() 806 * @param {String} regexpSource see RegExpFilter()
704 * @param {Number} contentType see RegExpFilter() 807 * @param {Number} contentType see RegExpFilter()
705 * @param {Boolean} matchCase see RegExpFilter() 808 * @param {Boolean} matchCase see RegExpFilter()
706 * @param {String} domains see RegExpFilter() 809 * @param {String} domains see RegExpFilter()
707 * @param {Boolean} thirdParty see RegExpFilter() 810 * @param {Boolean} thirdParty see RegExpFilter()
811 * @param {String} siteKeys see RegExpFilter()
708 * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null 812 * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null
709 * @constructor 813 * @constructor
710 * @augments RegExpFilter 814 * @augments RegExpFilter
711 */ 815 */
712 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty, collapse) 816 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty, siteKeys, collapse)
713 { 817 {
714 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty); 818 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, siteKeys);
715 819
716 this.collapse = collapse; 820 this.collapse = collapse;
717 } 821 }
718 exports.BlockingFilter = BlockingFilter; 822 exports.BlockingFilter = BlockingFilter;
719 823
720 BlockingFilter.prototype = 824 BlockingFilter.prototype =
721 { 825 {
722 __proto__: RegExpFilter.prototype, 826 __proto__: RegExpFilter.prototype,
723 827
724 /** 828 /**
725 * Defines whether the filter should collapse blocked content. Can be null (us e the global preference). 829 * Defines whether the filter should collapse blocked content. Can be null (us e the global preference).
726 * @type Boolean 830 * @type Boolean
727 */ 831 */
728 collapse: null 832 collapse: null
729 }; 833 };
730 834
731 /** 835 /**
732 * Class for whitelist filters 836 * Class for whitelist filters
733 * @param {String} text see Filter() 837 * @param {String} text see Filter()
734 * @param {String} regexpSource see RegExpFilter() 838 * @param {String} regexpSource see RegExpFilter()
735 * @param {Number} contentType see RegExpFilter() 839 * @param {Number} contentType see RegExpFilter()
736 * @param {Boolean} matchCase see RegExpFilter() 840 * @param {Boolean} matchCase see RegExpFilter()
737 * @param {String} domains see RegExpFilter() 841 * @param {String} domains see RegExpFilter()
738 * @param {Boolean} thirdParty see RegExpFilter() 842 * @param {Boolean} thirdParty see RegExpFilter()
739 * @param {String[]} siteKeys public keys of websites that this filter should ap ply to 843 * @param {String} siteKeys see RegExpFilter()
740 * @constructor 844 * @constructor
741 * @augments RegExpFilter 845 * @augments RegExpFilter
742 */ 846 */
743 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, th irdParty, siteKeys) 847 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, th irdParty, siteKeys)
744 { 848 {
745 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty); 849 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, siteKeys);
746
747 if (siteKeys != null)
748 this.siteKeys = siteKeys;
749 } 850 }
750 exports.WhitelistFilter = WhitelistFilter; 851 exports.WhitelistFilter = WhitelistFilter;
751 852
752 WhitelistFilter.prototype = 853 WhitelistFilter.prototype =
753 { 854 {
754 __proto__: RegExpFilter.prototype, 855 __proto__: RegExpFilter.prototype
755
756 /**
757 * List of public keys of websites that this filter should apply to
758 * @type String[]
759 */
760 siteKeys: null
761 } 856 }
762 857
763 /** 858 /**
764 * Base class for element hiding filters 859 * Base class for element hiding filters
765 * @param {String} text see Filter() 860 * @param {String} text see Filter()
766 * @param {String} domains (optional) Host names or domains the filter should be restricted to 861 * @param {String} domains (optional) Host names or domains the filter should be restricted to
767 * @param {String} selector CSS selector for the HTML elements that should be hidden 862 * @param {String} selector CSS selector for the HTML elements that should be hidden
768 * @constructor 863 * @constructor
769 * @augments ActiveFilter 864 * @augments ActiveFilter
770 */ 865 */
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
890 function ElemHideException(text, domains, selector) 985 function ElemHideException(text, domains, selector)
891 { 986 {
892 ElemHideBase.call(this, text, domains, selector); 987 ElemHideBase.call(this, text, domains, selector);
893 } 988 }
894 exports.ElemHideException = ElemHideException; 989 exports.ElemHideException = ElemHideException;
895 990
896 ElemHideException.prototype = 991 ElemHideException.prototype =
897 { 992 {
898 __proto__: ElemHideBase.prototype 993 __proto__: ElemHideBase.prototype
899 }; 994 };
OLDNEW
« lib/contentPolicy.js ('K') | « lib/contentPolicy.js ('k') | lib/matcher.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld