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

Side by Side Diff: lib/filterClasses.js

Issue 30045566: Fixed #4 - Disable rewrite option for all but internal redirect (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Review fixes. Created April 16, 2019, 12:17 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
« no previous file with comments | « no previous file | test/filterClasses.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
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":
1063 if (value == null) 1046 if (value == null)
1064 return new InvalidFilter(origText, "filter_unknown_option"); 1047 return new InvalidFilter(origText, "filter_unknown_option");
1065 rewrite = value; 1048 if (!value.startsWith("abp-resource:"))
1066 if (value.startsWith("abp-resource:")) 1049 return new InvalidFilter(origText, "filter_invalid_rewrite");
1067 resourceName = value.substr("abp-resource:".length); 1050 rewrite = value.substr("abp-resource:".length);
1068 break; 1051 break;
1069 default: 1052 default:
1070 return new InvalidFilter(origText, "filter_unknown_option"); 1053 return new InvalidFilter(origText, "filter_unknown_option");
1071 } 1054 }
1072 } 1055 }
1073 } 1056 }
1074 } 1057 }
1075 1058
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 1059 try
1090 { 1060 {
1091 if (blocking) 1061 if (blocking)
1092 { 1062 {
1093 if (csp && Filter.invalidCSPRegExp.test(csp)) 1063 if (csp && Filter.invalidCSPRegExp.test(csp))
1094 return new InvalidFilter(origText, "filter_invalid_csp"); 1064 return new InvalidFilter(origText, "filter_invalid_csp");
1095 1065
1096 if (resourceName) 1066 if (rewrite)
1097 { 1067 {
1098 if (text[0] == "|" && text[1] == "|") 1068 if (text[0] == "|" && text[1] == "|")
1099 { 1069 {
1100 if (!domains && thirdParty != false) 1070 if (!domains && thirdParty != false)
1101 return new InvalidFilter(origText, "filter_invalid_rewrite"); 1071 return new InvalidFilter(origText, "filter_invalid_rewrite");
1102 } 1072 }
1103 else if (text[0] == "*") 1073 else if (text[0] == "*")
1104 { 1074 {
1105 if (!domains) 1075 if (!domains)
1106 return new InvalidFilter(origText, "filter_invalid_rewrite"); 1076 return new InvalidFilter(origText, "filter_invalid_rewrite");
1107 } 1077 }
1108 else 1078 else
1109 { 1079 {
1110 return new InvalidFilter(origText, "filter_invalid_rewrite"); 1080 return new InvalidFilter(origText, "filter_invalid_rewrite");
1111 } 1081 }
1112 } 1082 }
1113 1083
1114 return new BlockingFilter(origText, text, contentType, matchCase, domains, 1084 return new BlockingFilter(origText, text, contentType, matchCase, domains,
1115 thirdParty, sitekeys, rewrite, resourceName, 1085 thirdParty, sitekeys, rewrite,
1116 collapse, csp); 1086 collapse, csp);
1117 } 1087 }
1118 return new WhitelistFilter(origText, text, contentType, matchCase, domains, 1088 return new WhitelistFilter(origText, text, contentType, matchCase, domains,
1119 thirdParty, sitekeys); 1089 thirdParty, sitekeys);
1120 } 1090 }
1121 catch (e) 1091 catch (e)
1122 { 1092 {
1123 return new InvalidFilter(origText, "filter_invalid_regexp"); 1093 return new InvalidFilter(origText, "filter_invalid_regexp");
1124 } 1094 }
1125 }; 1095 };
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1166 /** 1136 /**
1167 * Class for blocking filters 1137 * Class for blocking filters
1168 * @param {string} text see {@link Filter Filter()} 1138 * @param {string} text see {@link Filter Filter()}
1169 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} 1139 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()}
1170 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} 1140 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()}
1171 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} 1141 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()}
1172 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()} 1142 * @param {string} [domains] see {@link RegExpFilter RegExpFilter()}
1173 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()} 1143 * @param {boolean} [thirdParty] see {@link RegExpFilter RegExpFilter()}
1174 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()} 1144 * @param {string} [sitekeys] see {@link RegExpFilter RegExpFilter()}
1175 * @param {?string} [rewrite] 1145 * @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 1146 * 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 1147 * URL. e.g. if the value of the <code>rewrite</code> parameter is
1181 * <code>abp-resource:blank-html</code>, this should be 1148 * <code>abp-resource:blank-html</code>, this should be
1182 * <code>blank-html</code>. 1149 * <code>blank-html</code>.
1183 * @param {boolean} [collapse] 1150 * @param {boolean} [collapse]
1184 * defines whether the filter should collapse blocked content, can be null 1151 * defines whether the filter should collapse blocked content, can be null
1185 * @param {string} [csp] 1152 * @param {string} [csp]
1186 * Content Security Policy to inject when the filter matches 1153 * Content Security Policy to inject when the filter matches
1187 * @constructor 1154 * @constructor
1188 * @augments RegExpFilter 1155 * @augments RegExpFilter
1189 */ 1156 */
1190 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, 1157 function BlockingFilter(text, regexpSource, contentType, matchCase, domains,
1191 thirdParty, sitekeys, rewrite, resourceName, 1158 thirdParty, sitekeys, rewrite,
1192 collapse, csp) 1159 collapse, csp)
1193 { 1160 {
1194 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, 1161 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains,
1195 thirdParty, sitekeys, rewrite, resourceName); 1162 thirdParty, sitekeys, rewrite);
1196 1163
1197 if (collapse != null) 1164 if (collapse != null)
1198 this.collapse = collapse; 1165 this.collapse = collapse;
1199 1166
1200 if (csp != null) 1167 if (csp != null)
1201 this.csp = csp; 1168 this.csp = csp;
1202 } 1169 }
1203 exports.BlockingFilter = BlockingFilter; 1170 exports.BlockingFilter = BlockingFilter;
1204 1171
1205 BlockingFilter.prototype = extend(RegExpFilter, { 1172 BlockingFilter.prototype = extend(RegExpFilter, {
(...skipping 12 matching lines...) Expand all
1218 */ 1185 */
1219 csp: null, 1186 csp: null,
1220 1187
1221 /** 1188 /**
1222 * Rewrites an URL. 1189 * Rewrites an URL.
1223 * @param {string} url the URL to rewrite 1190 * @param {string} url the URL to rewrite
1224 * @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
1225 */ 1192 */
1226 rewriteUrl(url) 1193 rewriteUrl(url)
1227 { 1194 {
1228 if (this.resourceName) 1195 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 } 1196 }
1243 }); 1197 });
1244 1198
1245 /** 1199 /**
1246 * Class for whitelist filters 1200 * Class for whitelist filters
1247 * @param {string} text see {@link Filter Filter()} 1201 * @param {string} text see {@link Filter Filter()}
1248 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()} 1202 * @param {string} regexpSource see {@link RegExpFilter RegExpFilter()}
1249 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()} 1203 * @param {number} [contentType] see {@link RegExpFilter RegExpFilter()}
1250 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()} 1204 * @param {boolean} [matchCase] see {@link RegExpFilter RegExpFilter()}
1251 * @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
1446 1400
1447 /** 1401 /**
1448 * Script that should be executed 1402 * Script that should be executed
1449 * @type {string} 1403 * @type {string}
1450 */ 1404 */
1451 get script() 1405 get script()
1452 { 1406 {
1453 return this.body; 1407 return this.body;
1454 } 1408 }
1455 }); 1409 });
OLDNEW
« no previous file with comments | « no previous file | test/filterClasses.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld