Left: | ||
Right: |
OLD | NEW |
---|---|
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-present eyeo GmbH | 3 * Copyright (C) 2006-present 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 686 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
697 * Defines whether the filter should distinguish between lower and upper case | 697 * Defines whether the filter should distinguish between lower and upper case |
698 * letters | 698 * letters |
699 * @param {string} [domains] | 699 * @param {string} [domains] |
700 * Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com" | 700 * Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com" |
701 * @param {boolean} [thirdParty] | 701 * @param {boolean} [thirdParty] |
702 * Defines whether the filter should apply to third-party or first-party | 702 * Defines whether the filter should apply to third-party or first-party |
703 * content only | 703 * content only |
704 * @param {string} [sitekeys] | 704 * @param {string} [sitekeys] |
705 * Public keys of websites that this filter should apply to | 705 * Public keys of websites that this filter should apply to |
706 * @param {?string} [rewrite] | 706 * @param {?string} [rewrite] |
707 * The (optional) rule specifying how to rewrite the URL. See | |
708 * RegExpFilter.prototype.rewrite. | |
709 * @param {?string} [resourceName] | |
710 * The name of the internal resource to which to rewrite the | 707 * The name of the internal resource to which to rewrite the |
711 * URL. e.g. if the value of the <code>rewrite</code> parameter is | 708 * URL. e.g. if the value of the <code>rewrite</code> parameter is |
712 * <code>abp-resource:blank-html</code>, this should be | 709 * <code>abp-resource:blank-html</code>, this should be |
713 * <code>blank-html</code>. | 710 * <code>blank-html</code>. |
714 * @constructor | 711 * @constructor |
715 * @augments ActiveFilter | 712 * @augments ActiveFilter |
716 */ | 713 */ |
717 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, | 714 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, |
718 thirdParty, sitekeys, rewrite, resourceName) | 715 thirdParty, sitekeys, rewrite) |
719 { | 716 { |
720 ActiveFilter.call(this, text, domains); | 717 ActiveFilter.call(this, text, domains); |
721 | 718 |
722 if (contentType != null) | 719 if (contentType != null) |
723 this.contentType = contentType; | 720 this.contentType = contentType; |
724 if (matchCase) | 721 if (matchCase) |
725 this.matchCase = matchCase; | 722 this.matchCase = matchCase; |
726 if (thirdParty != null) | 723 if (thirdParty != null) |
727 this.thirdParty = thirdParty; | 724 this.thirdParty = thirdParty; |
728 if (sitekeys != null) | 725 if (sitekeys != null) |
729 this.sitekeySource = sitekeys; | 726 this.sitekeySource = sitekeys; |
730 if (rewrite != null) | 727 if (rewrite != null) |
731 this.rewrite = rewrite; | 728 this.rewrite = rewrite; |
732 if (resourceName) | |
733 this.resourceName = resourceName; | |
734 | 729 |
735 if (regexpSource.length >= 2 && | 730 if (regexpSource.length >= 2 && |
736 regexpSource[0] == "/" && | 731 regexpSource[0] == "/" && |
737 regexpSource[regexpSource.length - 1] == "/") | 732 regexpSource[regexpSource.length - 1] == "/") |
738 { | 733 { |
739 // The filter is a regular expression - convert it immediately to | 734 // The filter is a regular expression - convert it immediately to |
740 // catch syntax errors | 735 // catch syntax errors |
741 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), | 736 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), |
742 this.matchCase ? "" : "i"); | 737 this.matchCase ? "" : "i"); |
743 Object.defineProperty(this, "regexp", {value: regexp}); | 738 Object.defineProperty(this, "regexp", {value: regexp}); |
744 } | 739 } |
745 else | 740 else |
746 { | 741 { |
747 // Patterns like /foo/bar/* exist so that they are not treated as regular | 742 // Patterns like /foo/bar/* exist so that they are not treated as regular |
748 // expressions. We drop any superfluous wildcards here so our optimizations | 743 // expressions. We drop any superfluous wildcards here so our optimizations |
749 // can kick in. | 744 // can kick in. |
750 if (this.rewrite == null || this.resourceName) | 745 if (this.rewrite) |
Manish Jethani
2019/04/16 05:52:58
This actually has a somewhat opposite of the inten
hub
2019/04/16 12:23:06
Good catch.
| |
751 regexpSource = regexpSource.replace(/^\*+/, "").replace(/\*+$/, ""); | 746 regexpSource = regexpSource.replace(/^\*+/, "").replace(/\*+$/, ""); |
752 | 747 |
753 if (!this.matchCase && isLiteralPattern(regexpSource)) | 748 if (!this.matchCase && isLiteralPattern(regexpSource)) |
754 regexpSource = regexpSource.toLowerCase(); | 749 regexpSource = regexpSource.toLowerCase(); |
755 | 750 |
756 // No need to convert this filter to regular expression yet, do it on demand | 751 // No need to convert this filter to regular expression yet, do it on demand |
757 this.pattern = regexpSource; | 752 this.pattern = regexpSource; |
758 } | 753 } |
759 } | 754 } |
760 exports.RegExpFilter = RegExpFilter; | 755 exports.RegExpFilter = RegExpFilter; |
(...skipping 19 matching lines...) Expand all Loading... | |
780 */ | 775 */ |
781 pattern: null, | 776 pattern: null, |
782 /** | 777 /** |
783 * Regular expression to be used when testing against this filter | 778 * Regular expression to be used when testing against this filter |
784 * @type {RegExp} | 779 * @type {RegExp} |
785 */ | 780 */ |
786 get regexp() | 781 get regexp() |
787 { | 782 { |
788 let value = null; | 783 let value = null; |
789 | 784 |
790 let {pattern, rewrite, resourceName} = this; | 785 let {pattern} = this; |
791 if ((rewrite != null && !resourceName) || !isLiteralPattern(pattern)) | 786 if (!isLiteralPattern(pattern)) |
792 { | 787 value = new RegExp(filterToRegExp(pattern), this.matchCase ? "" : "i"); |
793 value = new RegExp(filterToRegExp(pattern, rewrite != null), | |
794 this.matchCase ? "" : "i"); | |
795 } | |
796 | 788 |
797 Object.defineProperty(this, "regexp", {value}); | 789 Object.defineProperty(this, "regexp", {value}); |
798 return value; | 790 return value; |
799 }, | 791 }, |
800 /** | 792 /** |
801 * Content types the filter applies to, combination of values from | 793 * Content types the filter applies to, combination of values from |
802 * RegExpFilter.typeMap | 794 * RegExpFilter.typeMap |
803 * @type {number} | 795 * @type {number} |
804 */ | 796 */ |
805 contentType: 0x7FFFFFFF, | 797 contentType: 0x7FFFFFFF, |
(...skipping 29 matching lines...) Expand all Loading... | |
835 this.sitekeySource = null; | 827 this.sitekeySource = null; |
836 } | 828 } |
837 | 829 |
838 Object.defineProperty( | 830 Object.defineProperty( |
839 this, "sitekeys", {value: sitekeys, enumerable: true} | 831 this, "sitekeys", {value: sitekeys, enumerable: true} |
840 ); | 832 ); |
841 return this.sitekeys; | 833 return this.sitekeys; |
842 }, | 834 }, |
843 | 835 |
844 /** | 836 /** |
845 * The rule specifying how to rewrite the URL. | |
846 * The syntax is similar to the one of String.prototype.replace(). | |
847 * @type {?string} | |
848 */ | |
849 rewrite: null, | |
850 | |
851 /** | |
852 * The name of the internal resource to which to rewrite the | 837 * The name of the internal resource to which to rewrite the |
853 * URL. e.g. if the value of the <code>rewrite</code> property is | 838 * URL. e.g. if the value of the <code>rewrite</code> property is |
Manish Jethani
2019/04/16 05:52:58
I think we can replace `<code>rewrite</code> prope
hub
2019/04/16 12:23:06
Done.
| |
854 * <code>abp-resource:blank-html</code>, this should be | 839 * <code>abp-resource:blank-html</code>, this should be |
855 * <code>blank-html</code>. | 840 * <code>blank-html</code>. |
856 * @type {?string} | 841 * @type {?string} |
857 */ | 842 */ |
858 resourceName: null, | 843 rewrite: null, |
859 | 844 |
860 /** | 845 /** |
861 * Tests whether the URL matches this filter | 846 * Tests whether the URL matches this filter |
862 * @param {string} location URL to be tested | 847 * @param {string} location URL to be tested |
863 * @param {number} typeMask bitmask of content / request types to match | 848 * @param {number} typeMask bitmask of content / request types to match |
864 * @param {string} [docDomain] domain name of the document that loads the URL | 849 * @param {string} [docDomain] domain name of the document that loads the URL |
865 * @param {boolean} [thirdParty] should be true if the URL is a third-party | 850 * @param {boolean} [thirdParty] should be true if the URL is a third-party |
866 * request | 851 * request |
867 * @param {string} [sitekey] public key provided by the document | 852 * @param {string} [sitekey] public key provided by the document |
868 * @return {boolean} true in case of a match | 853 * @return {boolean} true in case of a match |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
987 } | 972 } |
988 | 973 |
989 let contentType = null; | 974 let contentType = null; |
990 let matchCase = null; | 975 let matchCase = null; |
991 let domains = null; | 976 let domains = null; |
992 let sitekeys = null; | 977 let sitekeys = null; |
993 let thirdParty = null; | 978 let thirdParty = null; |
994 let collapse = null; | 979 let collapse = null; |
995 let csp = null; | 980 let csp = null; |
996 let rewrite = null; | 981 let rewrite = null; |
997 let resourceName = null; | |
998 let options; | 982 let options; |
999 let match = text.includes("$") ? Filter.optionsRegExp.exec(text) : null; | 983 let match = text.includes("$") ? Filter.optionsRegExp.exec(text) : null; |
1000 if (match) | 984 if (match) |
1001 { | 985 { |
1002 options = match[1].split(","); | 986 options = match[1].split(","); |
1003 text = match.input.substr(0, match.index); | 987 text = match.input.substr(0, match.index); |
1004 for (let option of options) | 988 for (let option of options) |
1005 { | 989 { |
1006 let value = null; | 990 let value = null; |
1007 let separatorIndex = option.indexOf("="); | 991 let separatorIndex = option.indexOf("="); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1053 break; | 1037 break; |
1054 case "collapse": | 1038 case "collapse": |
1055 collapse = !inverse; | 1039 collapse = !inverse; |
1056 break; | 1040 break; |
1057 case "sitekey": | 1041 case "sitekey": |
1058 if (!value) | 1042 if (!value) |
1059 return new InvalidFilter(origText, "filter_unknown_option"); | 1043 return new InvalidFilter(origText, "filter_unknown_option"); |
1060 sitekeys = value.toUpperCase(); | 1044 sitekeys = value.toUpperCase(); |
1061 break; | 1045 break; |
1062 case "rewrite": | 1046 case "rewrite": |
1063 if (value == null) | 1047 if (!value || !value.startsWith("abp-resource:")) |
Manish Jethani
2019/04/16 05:52:58
It doesn't matter _that_ much, but I'd just like t
hub
2019/04/16 12:23:06
I think I'm gonna go the safe route. Change was in
| |
1064 return new InvalidFilter(origText, "filter_unknown_option"); | 1048 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
1065 rewrite = value; | 1049 rewrite = value.substr("abp-resource:".length); |
1066 if (value.startsWith("abp-resource:")) | |
1067 resourceName = value.substr("abp-resource:".length); | |
1068 break; | 1050 break; |
1069 default: | 1051 default: |
1070 return new InvalidFilter(origText, "filter_unknown_option"); | 1052 return new InvalidFilter(origText, "filter_unknown_option"); |
1071 } | 1053 } |
1072 } | 1054 } |
1073 } | 1055 } |
1074 } | 1056 } |
1075 | 1057 |
1076 // For security reasons, never match $rewrite filters | |
1077 // against requests that might load any code to be executed. | |
1078 // Unless it is to an internal resource. | |
1079 if (rewrite != null && !resourceName) | |
1080 { | |
1081 if (contentType == null) | |
1082 ({contentType} = RegExpFilter.prototype); | |
1083 contentType &= ~(RegExpFilter.typeMap.SCRIPT | | |
1084 RegExpFilter.typeMap.SUBDOCUMENT | | |
1085 RegExpFilter.typeMap.OBJECT | | |
1086 RegExpFilter.typeMap.OBJECT_SUBREQUEST); | |
1087 } | |
1088 | |
1089 try | 1058 try |
1090 { | 1059 { |
1091 if (blocking) | 1060 if (blocking) |
1092 { | 1061 { |
1093 if (csp && Filter.invalidCSPRegExp.test(csp)) | 1062 if (csp && Filter.invalidCSPRegExp.test(csp)) |
1094 return new InvalidFilter(origText, "filter_invalid_csp"); | 1063 return new InvalidFilter(origText, "filter_invalid_csp"); |
1095 | 1064 |
1096 if (resourceName) | 1065 if (rewrite) |
1097 { | 1066 { |
1098 if (text[0] == "|" && text[1] == "|") | 1067 if (text[0] == "|" && text[1] == "|") |
1099 { | 1068 { |
1100 if (!domains && thirdParty != false) | 1069 if (!domains && thirdParty != false) |
1101 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 1070 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
1102 } | 1071 } |
1103 else if (text[0] == "*") | 1072 else if (text[0] == "*") |
1104 { | 1073 { |
1105 if (!domains) | 1074 if (!domains) |
1106 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 1075 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
1107 } | 1076 } |
1108 else | 1077 else |
1109 { | 1078 { |
1110 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 1079 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
1111 } | 1080 } |
1112 } | 1081 } |
1113 | 1082 |
1114 return new BlockingFilter(origText, text, contentType, matchCase, domains, | 1083 return new BlockingFilter(origText, text, contentType, matchCase, domains, |
1115 thirdParty, sitekeys, rewrite, resourceName, | 1084 thirdParty, sitekeys, rewrite, |
1116 collapse, csp); | 1085 collapse, csp); |
1117 } | 1086 } |
1118 return new WhitelistFilter(origText, text, contentType, matchCase, domains, | 1087 return new WhitelistFilter(origText, text, contentType, matchCase, domains, |
1119 thirdParty, sitekeys); | 1088 thirdParty, sitekeys); |
1120 } | 1089 } |
1121 catch (e) | 1090 catch (e) |
1122 { | 1091 { |
1123 return new InvalidFilter(origText, "filter_invalid_regexp"); | 1092 return new InvalidFilter(origText, "filter_invalid_regexp"); |
1124 } | 1093 } |
1125 }; | 1094 }; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1166 /** | 1135 /** |
1167 * Class for blocking filters | 1136 * Class for blocking filters |
1168 * @param {string} text see {@link Filter Filter()} | 1137 * @param {string} text see {@link Filter Filter()} |
1169 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} | 1138 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} |
1170 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} | 1139 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} |
1171 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} | 1140 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} |
1172 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} | 1141 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} |
1173 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()} | 1142 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()} |
1174 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()} | 1143 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()} |
1175 * @param {?string} [rewrite] | 1144 * @param {?string} [rewrite] |
1176 * The (optional) rule specifying how to rewrite the URL. See | |
1177 * RegExpFilter.prototype.rewrite. | |
1178 * @param {?string} [resourceName] | |
1179 * The name of the internal resource to which to rewrite the | 1145 * The name of the internal resource to which to rewrite the |
1180 * URL. e.g. if the value of the <code>rewrite</code> parameter is | 1146 * URL. e.g. if the value of the <code>rewrite</code> parameter is |
1181 * <code>abp-resource:blank-html</code>, this should be | 1147 * <code>abp-resource:blank-html</code>, this should be |
1182 * <code>blank-html</code>. | 1148 * <code>blank-html</code>. |
1183 * @param {boolean} [collapse] | 1149 * @param {boolean} [collapse] |
1184 * defines whether the filter should collapse blocked content, can be null | 1150 * defines whether the filter should collapse blocked content, can be null |
1185 * @param {string} [csp] | 1151 * @param {string} [csp] |
1186 * Content Security Policy to inject when the filter matches | 1152 * Content Security Policy to inject when the filter matches |
1187 * @constructor | 1153 * @constructor |
1188 * @augments RegExpFilter | 1154 * @augments RegExpFilter |
1189 */ | 1155 */ |
1190 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, | 1156 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, |
1191 thirdParty, sitekeys, rewrite, resourceName, | 1157 thirdParty, sitekeys, rewrite, |
1192 collapse, csp) | 1158 collapse, csp) |
1193 { | 1159 { |
1194 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, | 1160 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, |
1195 thirdParty, sitekeys, rewrite, resourceName); | 1161 thirdParty, sitekeys, rewrite); |
1196 | 1162 |
1197 if (collapse != null) | 1163 if (collapse != null) |
1198 this.collapse = collapse; | 1164 this.collapse = collapse; |
1199 | 1165 |
1200 if (csp != null) | 1166 if (csp != null) |
1201 this.csp = csp; | 1167 this.csp = csp; |
1202 } | 1168 } |
1203 exports.BlockingFilter = BlockingFilter; | 1169 exports.BlockingFilter = BlockingFilter; |
1204 | 1170 |
1205 BlockingFilter.prototype = extend(RegExpFilter, { | 1171 BlockingFilter.prototype = extend(RegExpFilter, { |
(...skipping 12 matching lines...) Expand all Loading... | |
1218 */ | 1184 */ |
1219 csp: null, | 1185 csp: null, |
1220 | 1186 |
1221 /** | 1187 /** |
1222 * Rewrites an URL. | 1188 * Rewrites an URL. |
1223 * @param {string} url the URL to rewrite | 1189 * @param {string} url the URL to rewrite |
1224 * @return {string} the rewritten URL, or the original in case of failure | 1190 * @return {string} the rewritten URL, or the original in case of failure |
1225 */ | 1191 */ |
1226 rewriteUrl(url) | 1192 rewriteUrl(url) |
1227 { | 1193 { |
1228 if (this.resourceName) | 1194 return resourceMap.get(this.rewrite) || url; |
1229 return resourceMap.get(this.resourceName) || url; | |
1230 | |
1231 try | |
1232 { | |
1233 let rewrittenUrl = new URL(url.replace(this.regexp, this.rewrite), url); | |
1234 if (rewrittenUrl.origin == new URL(url).origin) | |
1235 return rewrittenUrl.href; | |
1236 } | |
1237 catch (e) | |
1238 { | |
1239 } | |
1240 | |
1241 return url; | |
1242 } | 1195 } |
1243 }); | 1196 }); |
1244 | 1197 |
1245 /** | 1198 /** |
1246 * Class for whitelist filters | 1199 * Class for whitelist filters |
1247 * @param {string} text see {@link Filter Filter()} | 1200 * @param {string} text see {@link Filter Filter()} |
1248 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} | 1201 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} |
1249 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} | 1202 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} |
1250 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} | 1203 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} |
1251 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} | 1204 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1446 | 1399 |
1447 /** | 1400 /** |
1448 * Script that should be executed | 1401 * Script that should be executed |
1449 * @type {string} | 1402 * @type {string} |
1450 */ | 1403 */ |
1451 get script() | 1404 get script() |
1452 { | 1405 { |
1453 return this.body; | 1406 return this.body; |
1454 } | 1407 } |
1455 }); | 1408 }); |
OLD | NEW |