| 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 606 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 617 * Defines whether the filter should distinguish between lower and upper case | 617 * Defines whether the filter should distinguish between lower and upper case |
| 618 * letters | 618 * letters |
| 619 * @param {string} [domains] | 619 * @param {string} [domains] |
| 620 * Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com" | 620 * Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com" |
| 621 * @param {boolean} [thirdParty] | 621 * @param {boolean} [thirdParty] |
| 622 * Defines whether the filter should apply to third-party or first-party | 622 * Defines whether the filter should apply to third-party or first-party |
| 623 * content only | 623 * content only |
| 624 * @param {string} [sitekeys] | 624 * @param {string} [sitekeys] |
| 625 * Public keys of websites that this filter should apply to | 625 * Public keys of websites that this filter should apply to |
| 626 * @param {?string} [rewrite] | 626 * @param {?string} [rewrite] |
| 627 * The (optional) rule specifying how to rewrite the URL. See | |
| 628 * RegExpFilter.prototype.rewrite. | |
| 629 * @param {?string} [resourceName] | |
| 630 * The name of the internal resource to which to rewrite the | 627 * The name of the internal resource to which to rewrite the |
| 631 * URL. e.g. if the value of the <code>rewrite</code> parameter is | 628 * URL. e.g. if the value of the <code>rewrite</code> parameter is |
| 632 * <code>abp-resource:blank-html</code>, this should be | 629 * <code>abp-resource:blank-html</code>, this should be |
| 633 * <code>blank-html</code>. | 630 * <code>blank-html</code>. |
| 634 * @constructor | 631 * @constructor |
| 635 * @augments ActiveFilter | 632 * @augments ActiveFilter |
| 636 */ | 633 */ |
| 637 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, | 634 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, |
| 638 thirdParty, sitekeys, rewrite, resourceName) | 635 thirdParty, sitekeys, rewrite) |
| 639 { | 636 { |
| 640 ActiveFilter.call(this, text, domains); | 637 ActiveFilter.call(this, text, domains); |
| 641 | 638 |
| 642 if (contentType != null) | 639 if (contentType != null) |
| 643 this.contentType = contentType; | 640 this.contentType = contentType; |
| 644 if (matchCase) | 641 if (matchCase) |
| 645 this.matchCase = matchCase; | 642 this.matchCase = matchCase; |
| 646 if (thirdParty != null) | 643 if (thirdParty != null) |
| 647 this.thirdParty = thirdParty; | 644 this.thirdParty = thirdParty; |
| 648 if (sitekeys != null) | 645 if (sitekeys != null) |
| 649 this.sitekeySource = sitekeys; | 646 this.sitekeySource = sitekeys; |
| 650 if (rewrite != null) | 647 if (rewrite != null) |
| 651 this.rewrite = rewrite; | 648 this.rewrite = rewrite; |
| 652 if (resourceName) | |
| 653 this.resourceName = resourceName; | |
| 654 | 649 |
| 655 if (!this.matchCase) | 650 if (!this.matchCase) |
| 656 regexpSource = regexpSource.toLowerCase(); | 651 regexpSource = regexpSource.toLowerCase(); |
| 657 | 652 |
| 658 if (regexpSource.length >= 2 && | 653 if (regexpSource.length >= 2 && |
| 659 regexpSource[0] == "/" && | 654 regexpSource[0] == "/" && |
| 660 regexpSource[regexpSource.length - 1] == "/") | 655 regexpSource[regexpSource.length - 1] == "/") |
| 661 { | 656 { |
| 662 // The filter is a regular expression - convert it immediately to | 657 // The filter is a regular expression - convert it immediately to |
| 663 // catch syntax errors | 658 // catch syntax errors |
| 664 let regexp = new RegExp(regexpSource.substring(1, regexpSource.length - 1)); | 659 let regexp = new RegExp(regexpSource.substring(1, regexpSource.length - 1)); |
| 665 Object.defineProperty(this, "regexp", {value: regexp}); | 660 Object.defineProperty(this, "regexp", {value: regexp}); |
| 666 } | 661 } |
| 667 else | 662 else |
| 668 { | 663 { |
| 669 // Patterns like /foo/bar/* exist so that they are not treated as regular | 664 // Patterns like /foo/bar/* exist so that they are not treated as regular |
| 670 // expressions. We drop any superfluous wildcards here so our optimizations | 665 // expressions. We drop any superfluous wildcards here so our optimizations |
| 671 // can kick in. | 666 // can kick in. |
| 672 if (this.rewrite == null || this.resourceName) | 667 regexpSource = regexpSource.replace(/^\*+/, "").replace(/\*+$/, ""); |
| 673 regexpSource = regexpSource.replace(/^\*+/, "").replace(/\*+$/, ""); | |
| 674 | 668 |
| 675 // No need to convert this filter to regular expression yet, do it on demand | 669 // No need to convert this filter to regular expression yet, do it on demand |
| 676 this.pattern = regexpSource; | 670 this.pattern = regexpSource; |
| 677 } | 671 } |
| 678 } | 672 } |
| 679 exports.RegExpFilter = RegExpFilter; | 673 exports.RegExpFilter = RegExpFilter; |
| 680 | 674 |
| 681 RegExpFilter.prototype = extend(ActiveFilter, { | 675 RegExpFilter.prototype = extend(ActiveFilter, { |
| 682 /** | 676 /** |
| 683 * Number of filters contained, will always be 1 (required to | 677 * Number of filters contained, will always be 1 (required to |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 699 */ | 693 */ |
| 700 pattern: null, | 694 pattern: null, |
| 701 /** | 695 /** |
| 702 * Regular expression to be used when testing against this filter | 696 * Regular expression to be used when testing against this filter |
| 703 * @type {RegExp} | 697 * @type {RegExp} |
| 704 */ | 698 */ |
| 705 get regexp() | 699 get regexp() |
| 706 { | 700 { |
| 707 let value = null; | 701 let value = null; |
| 708 | 702 |
| 709 let {pattern, rewrite, resourceName} = this; | 703 let {pattern} = this; |
| 710 if ((rewrite != null && !resourceName) || !isLiteralPattern(pattern)) | 704 if (!isLiteralPattern(pattern)) |
| 711 value = new RegExp(filterToRegExp(pattern, rewrite != null)); | 705 value = new RegExp(filterToRegExp(pattern)); |
|
hub
2019/04/16 13:44:27
There was a conflict here (removal of the last arg
Manish Jethani
2019/04/16 14:06:23
Acknowledged.
| |
| 712 | 706 |
| 713 Object.defineProperty(this, "regexp", {value}); | 707 Object.defineProperty(this, "regexp", {value}); |
| 714 return value; | 708 return value; |
| 715 }, | 709 }, |
| 716 /** | 710 /** |
| 717 * Content types the filter applies to, combination of values from | 711 * Content types the filter applies to, combination of values from |
| 718 * RegExpFilter.typeMap | 712 * RegExpFilter.typeMap |
| 719 * @type {number} | 713 * @type {number} |
| 720 */ | 714 */ |
| 721 contentType: 0x7FFFFFFF, | 715 contentType: 0x7FFFFFFF, |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 751 this.sitekeySource = null; | 745 this.sitekeySource = null; |
| 752 } | 746 } |
| 753 | 747 |
| 754 Object.defineProperty( | 748 Object.defineProperty( |
| 755 this, "sitekeys", {value: sitekeys, enumerable: true} | 749 this, "sitekeys", {value: sitekeys, enumerable: true} |
| 756 ); | 750 ); |
| 757 return this.sitekeys; | 751 return this.sitekeys; |
| 758 }, | 752 }, |
| 759 | 753 |
| 760 /** | 754 /** |
| 761 * The rule specifying how to rewrite the URL. | |
| 762 * The syntax is similar to the one of String.prototype.replace(). | |
| 763 * @type {?string} | |
| 764 */ | |
| 765 rewrite: null, | |
| 766 | |
| 767 /** | |
| 768 * The name of the internal resource to which to rewrite the | 755 * The name of the internal resource to which to rewrite the |
| 769 * URL. e.g. if the value of the <code>rewrite</code> property is | 756 * URL. e.g. if the value of the <code>$rewrite</code> option is |
| 770 * <code>abp-resource:blank-html</code>, this should be | 757 * <code>abp-resource:blank-html</code>, this should be |
| 771 * <code>blank-html</code>. | 758 * <code>blank-html</code>. |
| 772 * @type {?string} | 759 * @type {?string} |
| 773 */ | 760 */ |
| 774 resourceName: null, | 761 rewrite: null, |
| 775 | 762 |
| 776 /** | 763 /** |
| 777 * Tests whether the URL request matches this filter | 764 * Tests whether the URL request matches this filter |
| 778 * @param {URLRequest} request URL request to be tested | 765 * @param {URLRequest} request URL request to be tested |
| 779 * @param {number} typeMask bitmask of content / request types to match | 766 * @param {number} typeMask bitmask of content / request types to match |
| 780 * @param {string} [sitekey] public key provided by the document | 767 * @param {string} [sitekey] public key provided by the document |
| 781 * @return {boolean} true in case of a match | 768 * @return {boolean} true in case of a match |
| 782 */ | 769 */ |
| 783 matches(request, typeMask, sitekey) | 770 matches(request, typeMask, sitekey) |
| 784 { | 771 { |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 897 } | 884 } |
| 898 | 885 |
| 899 let contentType = null; | 886 let contentType = null; |
| 900 let matchCase = null; | 887 let matchCase = null; |
| 901 let domains = null; | 888 let domains = null; |
| 902 let sitekeys = null; | 889 let sitekeys = null; |
| 903 let thirdParty = null; | 890 let thirdParty = null; |
| 904 let collapse = null; | 891 let collapse = null; |
| 905 let csp = null; | 892 let csp = null; |
| 906 let rewrite = null; | 893 let rewrite = null; |
| 907 let resourceName = null; | |
| 908 let options; | 894 let options; |
| 909 let match = text.includes("$") ? Filter.optionsRegExp.exec(text) : null; | 895 let match = text.includes("$") ? Filter.optionsRegExp.exec(text) : null; |
| 910 if (match) | 896 if (match) |
| 911 { | 897 { |
| 912 options = match[1].split(","); | 898 options = match[1].split(","); |
| 913 text = match.input.substring(0, match.index); | 899 text = match.input.substring(0, match.index); |
| 914 for (let option of options) | 900 for (let option of options) |
| 915 { | 901 { |
| 916 let value = null; | 902 let value = null; |
| 917 let separatorIndex = option.indexOf("="); | 903 let separatorIndex = option.indexOf("="); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 965 collapse = !inverse; | 951 collapse = !inverse; |
| 966 break; | 952 break; |
| 967 case "sitekey": | 953 case "sitekey": |
| 968 if (!value) | 954 if (!value) |
| 969 return new InvalidFilter(origText, "filter_unknown_option"); | 955 return new InvalidFilter(origText, "filter_unknown_option"); |
| 970 sitekeys = value.toUpperCase(); | 956 sitekeys = value.toUpperCase(); |
| 971 break; | 957 break; |
| 972 case "rewrite": | 958 case "rewrite": |
| 973 if (value == null) | 959 if (value == null) |
| 974 return new InvalidFilter(origText, "filter_unknown_option"); | 960 return new InvalidFilter(origText, "filter_unknown_option"); |
| 975 rewrite = value; | 961 if (!value.startsWith("abp-resource:")) |
| 976 if (value.startsWith("abp-resource:")) | 962 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 977 resourceName = value.substring("abp-resource:".length); | 963 rewrite = value.substring("abp-resource:".length); |
|
hub
2019/04/16 13:44:27
There was another conflict here. We changed from s
Manish Jethani
2019/04/16 14:06:23
Acknowledged.
| |
| 978 break; | 964 break; |
| 979 default: | 965 default: |
| 980 return new InvalidFilter(origText, "filter_unknown_option"); | 966 return new InvalidFilter(origText, "filter_unknown_option"); |
| 981 } | 967 } |
| 982 } | 968 } |
| 983 } | 969 } |
| 984 } | 970 } |
| 985 | 971 |
| 986 // For security reasons, never match $rewrite filters | |
| 987 // against requests that might load any code to be executed. | |
| 988 // Unless it is to an internal resource. | |
| 989 if (rewrite != null && !resourceName) | |
| 990 { | |
| 991 if (contentType == null) | |
| 992 ({contentType} = RegExpFilter.prototype); | |
| 993 contentType &= ~(RegExpFilter.typeMap.SCRIPT | | |
| 994 RegExpFilter.typeMap.SUBDOCUMENT | | |
| 995 RegExpFilter.typeMap.OBJECT | | |
| 996 RegExpFilter.typeMap.OBJECT_SUBREQUEST); | |
| 997 } | |
| 998 | |
| 999 try | 972 try |
| 1000 { | 973 { |
| 1001 if (blocking) | 974 if (blocking) |
| 1002 { | 975 { |
| 1003 if (csp && Filter.invalidCSPRegExp.test(csp)) | 976 if (csp && Filter.invalidCSPRegExp.test(csp)) |
| 1004 return new InvalidFilter(origText, "filter_invalid_csp"); | 977 return new InvalidFilter(origText, "filter_invalid_csp"); |
| 1005 | 978 |
| 1006 if (resourceName) | 979 if (rewrite) |
| 1007 { | 980 { |
| 1008 if (text[0] == "|" && text[1] == "|") | 981 if (text[0] == "|" && text[1] == "|") |
| 1009 { | 982 { |
| 1010 if (!domains && thirdParty != false) | 983 if (!domains && thirdParty != false) |
| 1011 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 984 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 1012 } | 985 } |
| 1013 else if (text[0] == "*") | 986 else if (text[0] == "*") |
| 1014 { | 987 { |
| 1015 if (!domains) | 988 if (!domains) |
| 1016 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 989 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 1017 } | 990 } |
| 1018 else | 991 else |
| 1019 { | 992 { |
| 1020 return new InvalidFilter(origText, "filter_invalid_rewrite"); | 993 return new InvalidFilter(origText, "filter_invalid_rewrite"); |
| 1021 } | 994 } |
| 1022 } | 995 } |
| 1023 | 996 |
| 1024 return new BlockingFilter(origText, text, contentType, matchCase, domains, | 997 return new BlockingFilter(origText, text, contentType, matchCase, domains, |
| 1025 thirdParty, sitekeys, rewrite, resourceName, | 998 thirdParty, sitekeys, rewrite, |
| 1026 collapse, csp); | 999 collapse, csp); |
| 1027 } | 1000 } |
| 1028 return new WhitelistFilter(origText, text, contentType, matchCase, domains, | 1001 return new WhitelistFilter(origText, text, contentType, matchCase, domains, |
| 1029 thirdParty, sitekeys); | 1002 thirdParty, sitekeys); |
| 1030 } | 1003 } |
| 1031 catch (e) | 1004 catch (e) |
| 1032 { | 1005 { |
| 1033 return new InvalidFilter(origText, "filter_invalid_regexp"); | 1006 return new InvalidFilter(origText, "filter_invalid_regexp"); |
| 1034 } | 1007 } |
| 1035 }; | 1008 }; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1076 /** | 1049 /** |
| 1077 * Class for blocking filters | 1050 * Class for blocking filters |
| 1078 * @param {string} text see {@link Filter Filter()} | 1051 * @param {string} text see {@link Filter Filter()} |
| 1079 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} | 1052 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} |
| 1080 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} | 1053 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} |
| 1081 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} | 1054 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} |
| 1082 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} | 1055 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} |
| 1083 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()} | 1056 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()} |
| 1084 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()} | 1057 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()} |
| 1085 * @param {?string} [rewrite] | 1058 * @param {?string} [rewrite] |
| 1086 * The (optional) rule specifying how to rewrite the URL. See | |
| 1087 * RegExpFilter.prototype.rewrite. | |
| 1088 * @param {?string} [resourceName] | |
| 1089 * The name of the internal resource to which to rewrite the | 1059 * The name of the internal resource to which to rewrite the |
| 1090 * URL. e.g. if the value of the <code>rewrite</code> parameter is | 1060 * URL. e.g. if the value of the <code>rewrite</code> parameter is |
|
Manish Jethani
2019/04/16 13:54:06
We forgot this in master but let's do it here: $re
hub
2019/04/16 14:08:39
The function docs didn't get that fix. Doing both.
| |
| 1091 * <code>abp-resource:blank-html</code>, this should be | 1061 * <code>abp-resource:blank-html</code>, this should be |
| 1092 * <code>blank-html</code>. | 1062 * <code>blank-html</code>. |
| 1093 * @param {boolean} [collapse] | 1063 * @param {boolean} [collapse] |
| 1094 * defines whether the filter should collapse blocked content, can be null | 1064 * defines whether the filter should collapse blocked content, can be null |
| 1095 * @param {string} [csp] | 1065 * @param {string} [csp] |
| 1096 * Content Security Policy to inject when the filter matches | 1066 * Content Security Policy to inject when the filter matches |
| 1097 * @constructor | 1067 * @constructor |
| 1098 * @augments RegExpFilter | 1068 * @augments RegExpFilter |
| 1099 */ | 1069 */ |
| 1100 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, | 1070 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, |
| 1101 thirdParty, sitekeys, rewrite, resourceName, | 1071 thirdParty, sitekeys, rewrite, |
| 1102 collapse, csp) | 1072 collapse, csp) |
| 1103 { | 1073 { |
| 1104 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, | 1074 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, |
| 1105 thirdParty, sitekeys, rewrite, resourceName); | 1075 thirdParty, sitekeys, rewrite); |
| 1106 | 1076 |
| 1107 if (collapse != null) | 1077 if (collapse != null) |
| 1108 this.collapse = collapse; | 1078 this.collapse = collapse; |
| 1109 | 1079 |
| 1110 if (csp != null) | 1080 if (csp != null) |
| 1111 this.csp = csp; | 1081 this.csp = csp; |
| 1112 } | 1082 } |
| 1113 exports.BlockingFilter = BlockingFilter; | 1083 exports.BlockingFilter = BlockingFilter; |
| 1114 | 1084 |
| 1115 BlockingFilter.prototype = extend(RegExpFilter, { | 1085 BlockingFilter.prototype = extend(RegExpFilter, { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1128 */ | 1098 */ |
| 1129 csp: null, | 1099 csp: null, |
| 1130 | 1100 |
| 1131 /** | 1101 /** |
| 1132 * Rewrites an URL. | 1102 * Rewrites an URL. |
| 1133 * @param {string} url the URL to rewrite | 1103 * @param {string} url the URL to rewrite |
| 1134 * @return {string} the rewritten URL, or the original in case of failure | 1104 * @return {string} the rewritten URL, or the original in case of failure |
| 1135 */ | 1105 */ |
| 1136 rewriteUrl(url) | 1106 rewriteUrl(url) |
| 1137 { | 1107 { |
| 1138 if (this.resourceName) | 1108 return resourceMap.get(this.rewrite) || url; |
| 1139 return resourceMap.get(this.resourceName) || url; | |
| 1140 | |
| 1141 try | |
| 1142 { | |
| 1143 let rewrittenUrl = new URL(url.replace(this.regexp, this.rewrite), url); | |
| 1144 if (rewrittenUrl.origin == new URL(url).origin) | |
| 1145 return rewrittenUrl.href; | |
| 1146 } | |
| 1147 catch (e) | |
| 1148 { | |
| 1149 } | |
| 1150 | |
| 1151 return url; | |
| 1152 } | 1109 } |
| 1153 }); | 1110 }); |
| 1154 | 1111 |
| 1155 /** | 1112 /** |
| 1156 * Class for whitelist filters | 1113 * Class for whitelist filters |
| 1157 * @param {string} text see {@link Filter Filter()} | 1114 * @param {string} text see {@link Filter Filter()} |
| 1158 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} | 1115 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} |
| 1159 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} | 1116 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} |
| 1160 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} | 1117 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} |
| 1161 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} | 1118 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1355 | 1312 |
| 1356 /** | 1313 /** |
| 1357 * Script that should be executed | 1314 * Script that should be executed |
| 1358 * @type {string} | 1315 * @type {string} |
| 1359 */ | 1316 */ |
| 1360 get script() | 1317 get script() |
| 1361 { | 1318 { |
| 1362 return this.body; | 1319 return this.body; |
| 1363 } | 1320 } |
| 1364 }); | 1321 }); |
| OLD | NEW |