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

Side by Side Diff: lib/filterClasses.js

Issue 30046558: Fixed #4 - Disable $rewrite option for all but internal redirect (Closed) Base URL: https://hg.adblockplus.org/adblockpluscore/
Patch Set: Updated doc Created April 16, 2019, 2:08 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 606 matching lines...) Expand 10 before | Expand all | Expand 10 after
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> option 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
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));
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
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
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
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);
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
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> option is
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
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
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 });
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