| 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-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 regexpSource = regexpSource.replace(/^\*+/, "").replace(/\*+$/, ""); |
| 751 regexpSource = regexpSource.replace(/^\*+/, "").replace(/\*+$/, ""); | |
| 752 | 746 |
| 753 if (!this.matchCase && isLiteralPattern(regexpSource)) | 747 if (!this.matchCase && isLiteralPattern(regexpSource)) |
| 754 regexpSource = regexpSource.toLowerCase(); | 748 regexpSource = regexpSource.toLowerCase(); |
| 755 | 749 |
| 756 // No need to convert this filter to regular expression yet, do it on demand | 750 // No need to convert this filter to regular expression yet, do it on demand |
| 757 this.pattern = regexpSource; | 751 this.pattern = regexpSource; |
| 758 } | 752 } |
| 759 } | 753 } |
| 760 exports.RegExpFilter = RegExpFilter; | 754 exports.RegExpFilter = RegExpFilter; |
| 761 | 755 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 780 */ | 774 */ |
| 781 pattern: null, | 775 pattern: null, |
| 782 /** | 776 /** |
| 783 * Regular expression to be used when testing against this filter | 777 * Regular expression to be used when testing against this filter |
| 784 * @type {RegExp} | 778 * @type {RegExp} |
| 785 */ | 779 */ |
| 786 get regexp() | 780 get regexp() |
| 787 { | 781 { |
| 788 let value = null; | 782 let value = null; |
| 789 | 783 |
| 790 let {pattern, rewrite, resourceName} = this; | 784 let {pattern} = this; |
| 791 if ((rewrite != null && !resourceName) || !isLiteralPattern(pattern)) | 785 if (!isLiteralPattern(pattern)) |
| 792 { | 786 value = new RegExp(filterToRegExp(pattern), this.matchCase ? "" : "i"); |
| 793 value = new RegExp(filterToRegExp(pattern, rewrite != null), | |
| 794 this.matchCase ? "" : "i"); | |
| 795 } | |
| 796 | 787 |
| 797 Object.defineProperty(this, "regexp", {value}); | 788 Object.defineProperty(this, "regexp", {value}); |
| 798 return value; | 789 return value; |
| 799 }, | 790 }, |
| 800 /** | 791 /** |
| 801 * Content types the filter applies to, combination of values from | 792 * Content types the filter applies to, combination of values from |
| 802 * RegExpFilter.typeMap | 793 * RegExpFilter.typeMap |
| 803 * @type {number} | 794 * @type {number} |
| 804 */ | 795 */ |
| 805 contentType: 0x7FFFFFFF, | 796 contentType: 0x7FFFFFFF, |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 835 this.sitekeySource = null; | 826 this.sitekeySource = null; |
| 836 } | 827 } |
| 837 | 828 |
| 838 Object.defineProperty( | 829 Object.defineProperty( |
| 839 this, "sitekeys", {value: sitekeys, enumerable: true} | 830 this, "sitekeys", {value: sitekeys, enumerable: true} |
| 840 ); | 831 ); |
| 841 return this.sitekeys; | 832 return this.sitekeys; |
| 842 }, | 833 }, |
| 843 | 834 |
| 844 /** | 835 /** |
| 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 | 836 * 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 | 837 * URL. e.g. if the value of the <code>$rewrite</code> option is |
| 854 * <code>abp-resource:blank-html</code>, this should be | 838 * <code>abp-resource:blank-html</code>, this should be |
| 855 * <code>blank-html</code>. | 839 * <code>blank-html</code>. |
| 856 * @type {?string} | 840 * @type {?string} |
| 857 */ | 841 */ |
| 858 resourceName: null, | 842 rewrite: null, |
| 859 | 843 |
| 860 /** | 844 /** |
| 861 * Tests whether the URL matches this filter | 845 * Tests whether the URL matches this filter |
| 862 * @param {string} location URL to be tested | 846 * @param {string} location URL to be tested |
| 863 * @param {number} typeMask bitmask of content / request types to match | 847 * @param {number} typeMask bitmask of content / request types to match |
| 864 * @param {string} [docDomain] domain name of the document that loads the URL | 848 * @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 | 849 * @param {boolean} [thirdParty] should be true if the URL is a third-party |
| 866 * request | 850 * request |
| 867 * @param {string} [sitekey] public key provided by the document | 851 * @param {string} [sitekey] public key provided by the document |
| 868 * @return {boolean} true in case of a match | 852 * @return {boolean} true in case of a match |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 987 } | 971 } |
| 988 | 972 |
| 989 let contentType = null; | 973 let contentType = null; |
| 990 let matchCase = null; | 974 let matchCase = null; |
| 991 let domains = null; | 975 let domains = null; |
| 992 let sitekeys = null; | 976 let sitekeys = null; |
| 993 let thirdParty = null; | 977 let thirdParty = null; |
| 994 let collapse = null; | 978 let collapse = null; |
| 995 let csp = null; | 979 let csp = null; |
| 996 let rewrite = null; | 980 let rewrite = null; |
| 997 let resourceName = null; | |
| 998 let options; | 981 let options; |
| 999 let match = text.includes("$") ? Filter.optionsRegExp.exec(text) : null; | 982 let match = text.includes("$") ? Filter.optionsRegExp.exec(text) : null; |
| 1000 if (match) | 983 if (match) |
| 1001 { | 984 { |
| 1002 options = match[1].split(","); | 985 options = match[1].split(","); |
| 1003 text = match.input.substr(0, match.index); | 986 text = match.input.substr(0, match.index); |
| 1004 for (let option of options) | 987 for (let option of options) |
| 1005 { | 988 { |
| 1006 let value = null; | 989 let value = null; |
| 1007 let separatorIndex = option.indexOf("="); | 990 let separatorIndex = option.indexOf("="); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1053 break; | 1036 break; |
| 1054 case "collapse": | 1037 case "collapse": |
| 1055 collapse = !inverse; | 1038 collapse = !inverse; |
| 1056 break; | 1039 break; |
| 1057 case "sitekey": | 1040 case "sitekey": |
| 1058 if (!value) | 1041 if (!value) |
| 1059 return new InvalidFilter(origText, "filter_unknown_option"); | 1042 return new InvalidFilter(origText, "filter_unknown_option"); |
| 1060 sitekeys = value.toUpperCase(); | 1043 sitekeys = value.toUpperCase(); |
| 1061 break; | 1044 break; |
| 1062 case "rewrite": | 1045 case "rewrite": |
| 1046 if (value == null) | |
| 1047 return new InvalidFilter(origText, "filter_unknown_option"); | |
| 1063 if (!value.startsWith("abp-resource:")) | 1048 if (!value.startsWith("abp-resource:")) |
|
Manish Jethani
2019/04/15 21:26:37
`value` could still be `null`?
hub
2019/04/16 04:56:24
Yeah. I'll simplify this now that we are going the
| |
| 1064 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 1049 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 1065 rewrite = value; | 1050 rewrite = value.substr("abp-resource:".length); |
| 1066 resourceName = value.substr("abp-resource:".length); | |
| 1067 break; | 1051 break; |
| 1068 default: | 1052 default: |
| 1069 return new InvalidFilter(origText, "filter_unknown_option"); | 1053 return new InvalidFilter(origText, "filter_unknown_option"); |
| 1070 } | 1054 } |
| 1071 } | 1055 } |
| 1072 } | 1056 } |
| 1073 } | 1057 } |
| 1074 | 1058 |
| 1075 // For security reasons, never match $rewrite filters | |
| 1076 // against requests that might load any code to be executed. | |
| 1077 // Unless it is to an internal resource. | |
| 1078 if (rewrite != null && !resourceName) | |
| 1079 { | |
| 1080 if (contentType == null) | |
| 1081 ({contentType} = RegExpFilter.prototype); | |
| 1082 contentType &= ~(RegExpFilter.typeMap.SCRIPT | | |
| 1083 RegExpFilter.typeMap.SUBDOCUMENT | | |
| 1084 RegExpFilter.typeMap.OBJECT | | |
| 1085 RegExpFilter.typeMap.OBJECT_SUBREQUEST); | |
| 1086 } | |
| 1087 | |
| 1088 try | 1059 try |
| 1089 { | 1060 { |
| 1090 if (blocking) | 1061 if (blocking) |
| 1091 { | 1062 { |
| 1092 if (csp && Filter.invalidCSPRegExp.test(csp)) | 1063 if (csp && Filter.invalidCSPRegExp.test(csp)) |
| 1093 return new InvalidFilter(origText, "filter_invalid_csp"); | 1064 return new InvalidFilter(origText, "filter_invalid_csp"); |
| 1094 | 1065 |
| 1095 if (resourceName) | 1066 if (rewrite) |
| 1096 { | 1067 { |
| 1097 if (text[0] == "|" && text[1] == "|") | 1068 if (text[0] == "|" && text[1] == "|") |
| 1098 { | 1069 { |
| 1099 if (!domains && thirdParty != false) | 1070 if (!domains && thirdParty != false) |
| 1100 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 1071 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 1101 } | 1072 } |
| 1102 else if (text[0] == "*") | 1073 else if (text[0] == "*") |
| 1103 { | 1074 { |
| 1104 if (!domains) | 1075 if (!domains) |
| 1105 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 1076 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 1106 } | 1077 } |
| 1107 else | 1078 else |
| 1108 { | 1079 { |
| 1109 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 1080 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 1110 } | 1081 } |
| 1111 } | 1082 } |
| 1112 | 1083 |
| 1113 return new BlockingFilter(origText, text, contentType, matchCase, domains, | 1084 return new BlockingFilter(origText, text, contentType, matchCase, domains, |
| 1114 thirdParty, sitekeys, rewrite, resourceName, | 1085 thirdParty, sitekeys, rewrite, |
| 1115 collapse, csp); | 1086 collapse, csp); |
| 1116 } | 1087 } |
| 1117 return new WhitelistFilter(origText, text, contentType, matchCase, domains, | 1088 return new WhitelistFilter(origText, text, contentType, matchCase, domains, |
| 1118 thirdParty, sitekeys); | 1089 thirdParty, sitekeys); |
| 1119 } | 1090 } |
| 1120 catch (e) | 1091 catch (e) |
| 1121 { | 1092 { |
| 1122 return new InvalidFilter(origText, "filter_invalid_regexp"); | 1093 return new InvalidFilter(origText, "filter_invalid_regexp"); |
| 1123 } | 1094 } |
| 1124 }; | 1095 }; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1165 /** | 1136 /** |
| 1166 * Class for blocking filters | 1137 * Class for blocking filters |
| 1167 * @param {string} text see {@link Filter Filter()} | 1138 * @param {string} text see {@link Filter Filter()} |
| 1168 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} | 1139 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} |
| 1169 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} | 1140 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} |
| 1170 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} | 1141 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} |
| 1171 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} | 1142 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} |
| 1172 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()} | 1143 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()} |
| 1173 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()} | 1144 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()} |
| 1174 * @param {?string} [rewrite] | 1145 * @param {?string} [rewrite] |
| 1175 * The (optional) rule specifying how to rewrite the URL. See | |
| 1176 * RegExpFilter.prototype.rewrite. | |
| 1177 * @param {?string} [resourceName] | |
| 1178 * The name of the internal resource to which to rewrite the | 1146 * The name of the internal resource to which to rewrite the |
| 1179 * URL. e.g. if the value of the <code>rewrite</code> parameter is | 1147 * URL. e.g. if the value of the <code>rewrite</code> parameter is |
| 1180 * <code>abp-resource:blank-html</code>, this should be | 1148 * <code>abp-resource:blank-html</code>, this should be |
| 1181 * <code>blank-html</code>. | 1149 * <code>blank-html</code>. |
| 1182 * @param {boolean} [collapse] | 1150 * @param {boolean} [collapse] |
| 1183 * defines whether the filter should collapse blocked content, can be null | 1151 * defines whether the filter should collapse blocked content, can be null |
| 1184 * @param {string} [csp] | 1152 * @param {string} [csp] |
| 1185 * Content Security Policy to inject when the filter matches | 1153 * Content Security Policy to inject when the filter matches |
| 1186 * @constructor | 1154 * @constructor |
| 1187 * @augments RegExpFilter | 1155 * @augments RegExpFilter |
| 1188 */ | 1156 */ |
| 1189 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, | 1157 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, |
| 1190 thirdParty, sitekeys, rewrite, resourceName, | 1158 thirdParty, sitekeys, rewrite, |
| 1191 collapse, csp) | 1159 collapse, csp) |
| 1192 { | 1160 { |
| 1193 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, | 1161 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, |
| 1194 thirdParty, sitekeys, rewrite, resourceName); | 1162 thirdParty, sitekeys, rewrite); |
| 1195 | 1163 |
| 1196 if (collapse != null) | 1164 if (collapse != null) |
| 1197 this.collapse = collapse; | 1165 this.collapse = collapse; |
| 1198 | 1166 |
| 1199 if (csp != null) | 1167 if (csp != null) |
| 1200 this.csp = csp; | 1168 this.csp = csp; |
| 1201 } | 1169 } |
| 1202 exports.BlockingFilter = BlockingFilter; | 1170 exports.BlockingFilter = BlockingFilter; |
| 1203 | 1171 |
| 1204 BlockingFilter.prototype = extend(RegExpFilter, { | 1172 BlockingFilter.prototype = extend(RegExpFilter, { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1217 */ | 1185 */ |
| 1218 csp: null, | 1186 csp: null, |
| 1219 | 1187 |
| 1220 /** | 1188 /** |
| 1221 * Rewrites an URL. | 1189 * Rewrites an URL. |
| 1222 * @param {string} url the URL to rewrite | 1190 * @param {string} url the URL to rewrite |
| 1223 * @return {string} the rewritten URL, or the original in case of failure | 1191 * @return {string} the rewritten URL, or the original in case of failure |
| 1224 */ | 1192 */ |
| 1225 rewriteUrl(url) | 1193 rewriteUrl(url) |
| 1226 { | 1194 { |
| 1227 if (this.resourceName) | 1195 return resourceMap.get(this.rewrite) || url; |
| 1228 return resourceMap.get(this.resourceName) || url; | |
| 1229 | |
| 1230 return url; | |
| 1231 } | 1196 } |
| 1232 }); | 1197 }); |
| 1233 | 1198 |
| 1234 /** | 1199 /** |
| 1235 * Class for whitelist filters | 1200 * Class for whitelist filters |
| 1236 * @param {string} text see {@link Filter Filter()} | 1201 * @param {string} text see {@link Filter Filter()} |
| 1237 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} | 1202 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} |
| 1238 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} | 1203 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} |
| 1239 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} | 1204 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} |
| 1240 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} | 1205 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1435 | 1400 |
| 1436 /** | 1401 /** |
| 1437 * Script that should be executed | 1402 * Script that should be executed |
| 1438 * @type {string} | 1403 * @type {string} |
| 1439 */ | 1404 */ |
| 1440 get script() | 1405 get script() |
| 1441 { | 1406 { |
| 1442 return this.body; | 1407 return this.body; |
| 1443 } | 1408 } |
| 1444 }); | 1409 }); |
| LEFT | RIGHT |