| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 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 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 81 * @type RegExp | 81 * @type RegExp |
| 82 */ | 82 */ |
| 83 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[ ^,\s]+)?)*)?$/; | 83 Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[ ^,\s]+)?)*)?$/; |
| 84 /** | 84 /** |
| 85 * Regular expression that options on a RegExp filter should match | 85 * Regular expression that options on a RegExp filter should match |
| 86 * @type RegExp | 86 * @type RegExp |
| 87 */ | 87 */ |
| 88 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/ ; | 88 Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/ ; |
| 89 /** | 89 /** |
| 90 * Regular expression that CSS property filters should match | 90 * Regular expression that CSS property filters should match |
| 91 * Properties must not contain " or ' | |
| 91 * @type RegExp | 92 * @type RegExp |
| 92 */ | 93 */ |
| 93 Filter.csspropertyRegExp = /\[\-abp\-properties=(["'])([^"']+)\1\]/; | 94 Filter.csspropertyRegExp = /\[\-abp\-properties=(["'])([^"']+)\1\]/; |
|
Sebastian Noack
2015/05/05 15:47:02
So we don't allow quotes in the value here. Should
Thomas Greiner
2015/05/06 12:08:32
Done, I added a comment as suggested. We could cha
Thomas Greiner
2015/05/06 15:33:07
Yes, there's currently no negative lookbehind in J
Sebastian Noack
2015/05/06 15:42:29
Yeah, let's stick to not allowing any quotes for n
| |
| 94 | 95 |
| 95 /** | 96 /** |
| 96 * Creates a filter of correct type from its text representation - does the basi c parsing and | 97 * Creates a filter of correct type from its text representation - does the basi c parsing and |
| 97 * calls the right constructor then. | 98 * calls the right constructor then. |
| 98 * | 99 * |
| 99 * @param {String} text as in Filter() | 100 * @param {String} text as in Filter() |
| 100 * @return {Filter} | 101 * @return {Filter} |
| 101 */ | 102 */ |
| 102 Filter.fromText = function(text) | 103 Filter.fromText = function(text) |
| 103 { | 104 { |
| (...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 collapse = true; | 712 collapse = true; |
| 712 else if (option == "~COLLAPSE") | 713 else if (option == "~COLLAPSE") |
| 713 collapse = false; | 714 collapse = false; |
| 714 else if (option == "SITEKEY" && typeof value != "undefined") | 715 else if (option == "SITEKEY" && typeof value != "undefined") |
| 715 sitekeys = value; | 716 sitekeys = value; |
| 716 else | 717 else |
| 717 return new InvalidFilter(origText, "Unknown option " + option.toLowerCas e()); | 718 return new InvalidFilter(origText, "Unknown option " + option.toLowerCas e()); |
| 718 } | 719 } |
| 719 } | 720 } |
| 720 | 721 |
| 721 if (!blocking && (contentType == null || (contentType & RegExpFilter.typeMap.D OCUMENT)) && | |
| 722 (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text )) | |
| 723 { | |
| 724 // Exception filters shouldn't apply to pages by default unless they start w ith a protocol name | |
| 725 if (contentType == null) | |
| 726 contentType = RegExpFilter.prototype.contentType; | |
| 727 contentType &= ~RegExpFilter.typeMap.DOCUMENT; | |
| 728 } | |
| 729 | |
| 730 try | 722 try |
| 731 { | 723 { |
| 732 if (blocking) | 724 if (blocking) |
| 733 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); | 725 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); |
| 734 else | 726 else |
| 735 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, sitekeys); | 727 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, sitekeys); |
| 736 } | 728 } |
| 737 catch (e) | 729 catch (e) |
| 738 { | 730 { |
| 739 return new InvalidFilter(origText, e); | 731 return new InvalidFilter(origText, e); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 758 DTD: 1, | 750 DTD: 1, |
| 759 MEDIA: 16384, | 751 MEDIA: 16384, |
| 760 FONT: 32768, | 752 FONT: 32768, |
| 761 | 753 |
| 762 BACKGROUND: 4, // Backwards compat, same as IMAGE | 754 BACKGROUND: 4, // Backwards compat, same as IMAGE |
| 763 | 755 |
| 764 POPUP: 0x10000000, | 756 POPUP: 0x10000000, |
| 765 ELEMHIDE: 0x40000000 | 757 ELEMHIDE: 0x40000000 |
| 766 }; | 758 }; |
| 767 | 759 |
| 768 // ELEMHIDE, POPUP option shouldn't be there by default | 760 // DOCUMENT, ELEMHIDE, POPUP options shouldn't be there by default |
| 769 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.ELEMHIDE | RegExpFi lter.typeMap.POPUP); | 761 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.DOCUMENT | RegExpFi lter.typeMap.ELEMHIDE | RegExpFilter.typeMap.POPUP); |
| 770 | 762 |
| 771 /** | 763 /** |
| 772 * Class for blocking filters | 764 * Class for blocking filters |
| 773 * @param {String} text see Filter() | 765 * @param {String} text see Filter() |
| 774 * @param {String} regexpSource see RegExpFilter() | 766 * @param {String} regexpSource see RegExpFilter() |
| 775 * @param {Number} contentType see RegExpFilter() | 767 * @param {Number} contentType see RegExpFilter() |
| 776 * @param {Boolean} matchCase see RegExpFilter() | 768 * @param {Boolean} matchCase see RegExpFilter() |
| 777 * @param {String} domains see RegExpFilter() | 769 * @param {String} domains see RegExpFilter() |
| 778 * @param {Boolean} thirdParty see RegExpFilter() | 770 * @param {Boolean} thirdParty see RegExpFilter() |
| 779 * @param {String} sitekeys see RegExpFilter() | 771 * @param {String} sitekeys see RegExpFilter() |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 879 */ | 871 */ |
| 880 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) | 872 ElemHideBase.fromText = function(text, domain, isException, tagName, attrRules, selector) |
| 881 { | 873 { |
| 882 if (!selector) | 874 if (!selector) |
| 883 { | 875 { |
| 884 if (tagName == "*") | 876 if (tagName == "*") |
| 885 tagName = ""; | 877 tagName = ""; |
| 886 | 878 |
| 887 let id = null; | 879 let id = null; |
| 888 let additional = ""; | 880 let additional = ""; |
| 889 if (attrRules) { | 881 if (attrRules) |
| 882 { | |
| 890 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g); | 883 attrRules = attrRules.match(/\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\)/g); |
| 891 for (let rule of attrRules) { | 884 for (let rule of attrRules) |
| 885 { | |
| 892 rule = rule.substr(1, rule.length - 2); | 886 rule = rule.substr(1, rule.length - 2); |
| 893 let separatorPos = rule.indexOf("="); | 887 let separatorPos = rule.indexOf("="); |
| 894 if (separatorPos > 0) { | 888 if (separatorPos > 0) |
| 889 { | |
| 895 rule = rule.replace(/=/, '="') + '"'; | 890 rule = rule.replace(/=/, '="') + '"'; |
| 896 additional += "[" + rule + "]"; | 891 additional += "[" + rule + "]"; |
| 897 } | 892 } |
| 898 else { | 893 else |
| 894 { | |
| 899 if (id) | 895 if (id) |
| 900 return new InvalidFilter(text, Utils.getString("filter_elemhide_dupl icate_id")); | 896 return new InvalidFilter(text, Utils.getString("filter_elemhide_dupl icate_id")); |
| 901 else | 897 |
| 902 id = rule; | 898 id = rule; |
| 903 } | 899 } |
| 904 } | 900 } |
| 905 } | 901 } |
| 906 | 902 |
| 907 if (id) | 903 if (id) |
| 908 selector = tagName + "." + id + additional + "," + tagName + "#" + id + ad ditional; | 904 selector = tagName + "." + id + additional + "," + tagName + "#" + id + ad ditional; |
| 909 else if (tagName || additional) | 905 else if (tagName || additional) |
| 910 selector = tagName + additional; | 906 selector = tagName + additional; |
| 911 else | 907 else |
| 912 return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriteria ")); | 908 return new InvalidFilter(text, Utils.getString("filter_elemhide_nocriteria ")); |
| 913 } | 909 } |
| 910 | |
| 914 if (isException) | 911 if (isException) |
| 915 return new ElemHideException(text, domain, selector); | 912 return new ElemHideException(text, domain, selector); |
| 916 else | 913 |
| 917 { | 914 let match = Filter.csspropertyRegExp.exec(selector); |
| 918 if (Filter.csspropertyRegExp.test(selector)) | 915 if (match) |
| 919 { | 916 { |
| 920 // CSS property filters are inefficient so we need to make sure that | 917 // CSS property filters are inefficient so we need to make sure that |
| 921 // they're only applied if they specify active domains | 918 // they're only applied if they specify active domains |
| 922 if (/,[^~]/.test("," + domain)) | 919 if (!/,[^~][^,.]*\.[^,]/.test("," + domain)) |
|
Sebastian Noack
2015/05/05 15:47:02
I wonder whether we should also look for at least
Thomas Greiner
2015/05/06 12:08:32
Good point but note that this still doesn't cover
Sebastian Noack
2015/05/06 13:07:48
Hmm, if we want to do it properly, I suppose we ha
| |
| 923 return new CSSPropertyFilter(text, domain, selector); | 920 return new InvalidFilter(text, Utils.getString("filter_cssproperty_nodomai n")); |
| 924 else | 921 |
|
Sebastian Noack
2015/05/05 15:47:02
Nit: Redundant else statement.
| |
| 925 return new InvalidFilter(text, Utils.getString("filter_cssproperty_nodom ain")); | 922 return new CSSPropertyFilter(text, domain, selector, match[2], |
| 926 } | 923 selector.substr(0, match.index), |
| 927 else | 924 selector.substr(match.index + match[0].length)); |
|
Sebastian Noack
2015/05/05 15:47:02
Nit: Redundant else statement.
Thomas Greiner
2015/05/06 12:08:32
Done.
| |
| 928 return new ElemHideFilter(text, domain, selector); | 925 } |
| 929 } | 926 |
| 927 return new ElemHideFilter(text, domain, selector); | |
| 930 }; | 928 }; |
| 931 | 929 |
| 932 /** | 930 /** |
| 933 * Class for element hiding filters | 931 * Class for element hiding filters |
| 934 * @param {String} text see Filter() | 932 * @param {String} text see Filter() |
| 935 * @param {String} domains see ElemHideBase() | 933 * @param {String} domains see ElemHideBase() |
| 936 * @param {String} selector see ElemHideBase() | 934 * @param {String} selector see ElemHideBase() |
| 937 * @constructor | 935 * @constructor |
| 938 * @augments ElemHideBase | 936 * @augments ElemHideBase |
| 939 */ | 937 */ |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 962 } | 960 } |
| 963 exports.ElemHideException = ElemHideException; | 961 exports.ElemHideException = ElemHideException; |
| 964 | 962 |
| 965 ElemHideException.prototype = | 963 ElemHideException.prototype = |
| 966 { | 964 { |
| 967 __proto__: ElemHideBase.prototype | 965 __proto__: ElemHideBase.prototype |
| 968 }; | 966 }; |
| 969 | 967 |
| 970 /** | 968 /** |
| 971 * Class for CSS property filters | 969 * Class for CSS property filters |
| 972 * @param {String} text see Filter() | 970 * @param {String} text see Filter() |
| 973 * @param {String} domains see ElemHideBase() | 971 * @param {String} domains see ElemHideBase() |
| 974 * @param {String} selector see ElemHideBase() | 972 * @param {String} selector see ElemHideBase() |
| 973 * @param {String} regexpSource see CSSPropertyFilter.regexpSource | |
| 974 * @param {String} selectorPrefix see CSSPropertyFilter.selectorPrefix | |
| 975 * @param {String} selectorSuffix see CSSPropertyFilter.selectorSuffix | |
| 975 * @constructor | 976 * @constructor |
| 976 * @augments ElemHideBase | 977 * @augments ElemHideBase |
| 977 */ | 978 */ |
| 978 function CSSPropertyFilter(text, domains, selector) | 979 function CSSPropertyFilter(text, domains, selector, regexpSource, |
| 980 selectorPrefix, selectorSuffix) | |
| 979 { | 981 { |
| 980 ElemHideBase.call(this, text, domains, selector); | 982 ElemHideBase.call(this, text, domains, selector); |
| 981 | 983 |
| 982 let properties; | 984 this.regexpSource = regexpSource; |
| 983 [properties, , this.regexpSource] = selector.match(Filter.csspropertyRegExp); | 985 this.selectorPrefix = selectorPrefix; |
| 984 [this.selectorPrefix, this.selectorSuffix] = selector.split(properties); | 986 this.selectorSuffix = selectorSuffix; |
| 985 } | 987 } |
| 986 exports.CSSPropertyFilter = CSSPropertyFilter; | 988 exports.CSSPropertyFilter = CSSPropertyFilter; |
| 987 | 989 |
| 988 CSSPropertyFilter.prototype = | 990 CSSPropertyFilter.prototype = |
| 989 { | 991 { |
| 990 __proto__: ElemHideBase.prototype, | 992 __proto__: ElemHideBase.prototype, |
| 991 | 993 |
| 992 /** | 994 /** |
| 993 * Expression from which a regular expression should be generated for matching | 995 * Expression from which a regular expression should be generated for matching |
| 994 * CSS properties - for delayed creation of the regexp property | 996 * CSS properties - for delayed creation of the regexpString property |
| 995 * @type String | 997 * @type String |
| 996 */ | 998 */ |
| 997 regexpSource: null, | 999 regexpSource: null, |
| 998 /** | 1000 /** |
| 999 * Substring of CSS selector before properties for the HTML elements that | 1001 * Substring of CSS selector before properties for the HTML elements that |
| 1000 * should be hidden | 1002 * should be hidden |
| 1001 * @type String | 1003 * @type String |
| 1002 */ | 1004 */ |
| 1003 selectorPrefix: null, | 1005 selectorPrefix: null, |
| 1004 /** | 1006 /** |
| 1005 * Substring of CSS selector after properties for the HTML elements that | 1007 * Substring of CSS selector after properties for the HTML elements that |
| 1006 * should be hidden | 1008 * should be hidden |
| 1007 * @type String | 1009 * @type String |
| 1008 */ | 1010 */ |
| 1009 selectorSuffix: null, | 1011 selectorSuffix: null, |
| 1010 | 1012 |
| 1011 /** | 1013 /** |
| 1012 * Regular expression to be used when testing CSS properties against | 1014 * Raw regular expression string to be used when testing CSS properties |
| 1013 * this filter | 1015 * against this filter |
| 1014 * @type RegExp | 1016 * @type String |
| 1015 */ | 1017 */ |
| 1016 get regexp() | 1018 get regexpString() |
|
Sebastian Noack
2015/05/05 15:47:02
Hmm, this is almost the same code we already have
Thomas Greiner
2015/05/06 12:08:32
You're right, the issue description doesn't explic
Sebastian Noack
2015/05/06 13:07:48
Well, objects get serialized when passed to conten
| |
| 1017 { | 1019 { |
| 1018 // Despite this property being cached, the getter is called | 1020 // Despite this property being cached, the getter is called |
| 1019 // several times on Safari, due to WebKit bug 132872 | 1021 // several times on Safari, due to WebKit bug 132872 |
| 1020 let prop = Object.getOwnPropertyDescriptor(this, "regexp"); | 1022 let prop = Object.getOwnPropertyDescriptor(this, "regexpString"); |
| 1021 if (prop) | 1023 if (prop) |
| 1022 return prop.value; | 1024 return prop.value; |
| 1023 | 1025 |
| 1024 let source = Filter.toRegExp(this.regexpSource); | 1026 let regexp = Filter.toRegExp(this.regexpSource); |
| 1025 let regexp = new RegExp(source, ""); | 1027 Object.defineProperty(this, "regexpString", {value: regexp}); |
| 1026 Object.defineProperty(this, "regexp", {value: regexp}); | |
| 1027 return regexp; | 1028 return regexp; |
| 1028 } | 1029 } |
| 1029 }; | 1030 }; |
| LEFT | RIGHT |