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 |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
18 "use strict"; | 18 "use strict"; |
19 | 19 |
20 /** | 20 /** |
21 * @fileOverview Definition of Filter class and its subclasses. | 21 * @fileOverview Definition of Filter class and its subclasses. |
22 */ | 22 */ |
23 | 23 |
24 const {FilterNotifier} = require("./filterNotifier"); | 24 const {filterNotifier} = require("./filterNotifier"); |
25 const {extend} = require("./coreUtils"); | 25 const {extend} = require("./coreUtils"); |
26 const {filterToRegExp} = require("./common"); | 26 const {filterToRegExp} = require("./common"); |
27 | 27 |
28 /** | 28 /** |
29 * All known unique domain sources mapped to their parsed values. | 29 * All known unique domain sources mapped to their parsed values. |
30 * @type {Map.<string,Map.<string,boolean>>} | 30 * @type {Map.<string,Map.<string,boolean>>} |
31 */ | 31 */ |
32 let knownDomainMaps = new Map(); | 32 let knownDomainMaps = new Map(); |
33 | 33 |
34 /** | 34 /** |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 * | 116 * |
117 * @param {string} text as in Filter() | 117 * @param {string} text as in Filter() |
118 * @return {Filter} | 118 * @return {Filter} |
119 */ | 119 */ |
120 Filter.fromText = function(text) | 120 Filter.fromText = function(text) |
121 { | 121 { |
122 let filter = Filter.knownFilters.get(text); | 122 let filter = Filter.knownFilters.get(text); |
123 if (filter) | 123 if (filter) |
124 return filter; | 124 return filter; |
125 | 125 |
126 let match = text.includes("#") ? Filter.contentRegExp.exec(text) : null; | 126 if (text[0] == "!") |
127 if (match) | 127 { |
128 { | |
129 let propsMatch; | |
130 if (!match[2] && match[3].includes("[-") && | |
131 (propsMatch = /\[-abp-properties=(["'])([^"']+)\1\]/.exec(match[3]))) | |
132 { | |
133 // This is legacy CSS properties syntax, convert to current syntax | |
134 let prefix = match[3].substr(0, propsMatch.index); | |
135 let expression = propsMatch[2]; | |
136 let suffix = match[3].substr(propsMatch.index + propsMatch[0].length); | |
137 return Filter.fromText(`${match[1]}#?#` + | |
138 `${prefix}:-abp-properties(${expression})${suffix}`); | |
139 } | |
140 | |
141 filter = ContentFilter.fromText(text, match[1], match[2], match[3]); | |
142 } | |
143 else if (text[0] == "!") | |
144 filter = new CommentFilter(text); | 128 filter = new CommentFilter(text); |
| 129 } |
145 else | 130 else |
146 filter = RegExpFilter.fromText(text); | 131 { |
| 132 let match = text.includes("#") ? Filter.contentRegExp.exec(text) : null; |
| 133 if (match) |
| 134 filter = ContentFilter.fromText(text, match[1], match[2], match[3]); |
| 135 else |
| 136 filter = RegExpFilter.fromText(text); |
| 137 } |
147 | 138 |
148 Filter.knownFilters.set(filter.text, filter); | 139 Filter.knownFilters.set(filter.text, filter); |
149 return filter; | 140 return filter; |
150 }; | 141 }; |
151 | 142 |
152 /** | 143 /** |
153 * Deserializes a filter | 144 * Deserializes a filter |
154 * | 145 * |
155 * @param {Object} obj map of serialized properties and their values | 146 * @param {Object} obj map of serialized properties and their values |
156 * @return {Filter} filter or null if the filter couldn't be created | 147 * @return {Filter} filter or null if the filter couldn't be created |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 option.substr(cspMatch[0].length).trim().replace(/ +/g, " "); | 222 option.substr(cspMatch[0].length).trim().replace(/ +/g, " "); |
232 } | 223 } |
233 else | 224 else |
234 options[i] = option.replace(/ +/g, ""); | 225 options[i] = option.replace(/ +/g, ""); |
235 } | 226 } |
236 | 227 |
237 return beforeOptions + "$" + options.join(); | 228 return beforeOptions + "$" + options.join(); |
238 }; | 229 }; |
239 | 230 |
240 /** | 231 /** |
241 * @see filterToRegExp | |
242 */ | |
243 Filter.toRegExp = filterToRegExp; | |
244 | |
245 /** | |
246 * Class for invalid filters | 232 * Class for invalid filters |
247 * @param {string} text see {@link Filter Filter()} | 233 * @param {string} text see {@link Filter Filter()} |
248 * @param {string} reason Reason why this filter is invalid | 234 * @param {string} reason Reason why this filter is invalid |
249 * @constructor | 235 * @constructor |
250 * @augments Filter | 236 * @augments Filter |
251 */ | 237 */ |
252 function InvalidFilter(text, reason) | 238 function InvalidFilter(text, reason) |
253 { | 239 { |
254 Filter.call(this, text); | 240 Filter.call(this, text); |
255 | 241 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 get disabled() | 312 get disabled() |
327 { | 313 { |
328 return this._disabled; | 314 return this._disabled; |
329 }, | 315 }, |
330 set disabled(value) | 316 set disabled(value) |
331 { | 317 { |
332 if (value != this._disabled) | 318 if (value != this._disabled) |
333 { | 319 { |
334 let oldValue = this._disabled; | 320 let oldValue = this._disabled; |
335 this._disabled = value; | 321 this._disabled = value; |
336 FilterNotifier.triggerListeners("filter.disabled", this, value, oldValue); | 322 filterNotifier.emit("filter.disabled", this, value, oldValue); |
337 } | 323 } |
338 return this._disabled; | 324 return this._disabled; |
339 }, | 325 }, |
340 | 326 |
341 /** | 327 /** |
342 * Number of hits on the filter since the last reset | 328 * Number of hits on the filter since the last reset |
343 * @type {number} | 329 * @type {number} |
344 */ | 330 */ |
345 get hitCount() | 331 get hitCount() |
346 { | 332 { |
347 return this._hitCount; | 333 return this._hitCount; |
348 }, | 334 }, |
349 set hitCount(value) | 335 set hitCount(value) |
350 { | 336 { |
351 if (value != this._hitCount) | 337 if (value != this._hitCount) |
352 { | 338 { |
353 let oldValue = this._hitCount; | 339 let oldValue = this._hitCount; |
354 this._hitCount = value; | 340 this._hitCount = value; |
355 FilterNotifier.triggerListeners("filter.hitCount", this, value, oldValue); | 341 filterNotifier.emit("filter.hitCount", this, value, oldValue); |
356 } | 342 } |
357 return this._hitCount; | 343 return this._hitCount; |
358 }, | 344 }, |
359 | 345 |
360 /** | 346 /** |
361 * Last time the filter had a hit (in milliseconds since the beginning of the | 347 * Last time the filter had a hit (in milliseconds since the beginning of the |
362 * epoch) | 348 * epoch) |
363 * @type {number} | 349 * @type {number} |
364 */ | 350 */ |
365 get lastHit() | 351 get lastHit() |
366 { | 352 { |
367 return this._lastHit; | 353 return this._lastHit; |
368 }, | 354 }, |
369 set lastHit(value) | 355 set lastHit(value) |
370 { | 356 { |
371 if (value != this._lastHit) | 357 if (value != this._lastHit) |
372 { | 358 { |
373 let oldValue = this._lastHit; | 359 let oldValue = this._lastHit; |
374 this._lastHit = value; | 360 this._lastHit = value; |
375 FilterNotifier.triggerListeners("filter.lastHit", this, value, oldValue); | 361 filterNotifier.emit("filter.lastHit", this, value, oldValue); |
376 } | 362 } |
377 return this._lastHit; | 363 return this._lastHit; |
378 }, | 364 }, |
379 | 365 |
380 /** | 366 /** |
381 * String that the domains property should be generated from | 367 * String that the domains property should be generated from |
382 * @type {?string} | 368 * @type {?string} |
383 */ | 369 */ |
384 domainSource: null, | 370 domainSource: null, |
385 | 371 |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 * for delayed creation of the regexp property | 641 * for delayed creation of the regexp property |
656 * @type {string} | 642 * @type {string} |
657 */ | 643 */ |
658 regexpSource: null, | 644 regexpSource: null, |
659 /** | 645 /** |
660 * Regular expression to be used when testing against this filter | 646 * Regular expression to be used when testing against this filter |
661 * @type {RegExp} | 647 * @type {RegExp} |
662 */ | 648 */ |
663 get regexp() | 649 get regexp() |
664 { | 650 { |
665 let source = Filter.toRegExp(this.regexpSource, this.rewrite == null); | 651 let source = filterToRegExp(this.regexpSource, this.rewrite != null); |
666 let regexp = new RegExp(source, this.matchCase ? "" : "i"); | 652 let regexp = new RegExp(source, this.matchCase ? "" : "i"); |
667 Object.defineProperty(this, "regexp", {value: regexp}); | 653 Object.defineProperty(this, "regexp", {value: regexp}); |
668 this.regexpSource = null; | 654 this.regexpSource = null; |
669 return regexp; | 655 return regexp; |
670 }, | 656 }, |
671 /** | 657 /** |
672 * Content types the filter applies to, combination of values from | 658 * Content types the filter applies to, combination of values from |
673 * RegExpFilter.typeMap | 659 * RegExpFilter.typeMap |
674 * @type {number} | 660 * @type {number} |
675 */ | 661 */ |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
788 if (inverse) | 774 if (inverse) |
789 { | 775 { |
790 if (contentType == null) | 776 if (contentType == null) |
791 ({contentType} = RegExpFilter.prototype); | 777 ({contentType} = RegExpFilter.prototype); |
792 contentType &= ~type; | 778 contentType &= ~type; |
793 } | 779 } |
794 else | 780 else |
795 { | 781 { |
796 contentType |= type; | 782 contentType |= type; |
797 | 783 |
798 if (type == RegExpFilter.typeMap.CSP && value) | 784 if (type == RegExpFilter.typeMap.CSP) |
| 785 { |
| 786 if (!value) |
| 787 return new InvalidFilter(origText, "filter_invalid_csp"); |
799 csp = value; | 788 csp = value; |
| 789 } |
800 } | 790 } |
801 } | 791 } |
802 else | 792 else |
803 { | 793 { |
804 switch (option.toLowerCase()) | 794 switch (option.toLowerCase()) |
805 { | 795 { |
806 case "match-case": | 796 case "match-case": |
807 matchCase = !inverse; | 797 matchCase = !inverse; |
808 break; | 798 break; |
809 case "domain": | 799 case "domain": |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1187 | 1177 |
1188 /** | 1178 /** |
1189 * Script that should be executed | 1179 * Script that should be executed |
1190 * @type {string} | 1180 * @type {string} |
1191 */ | 1181 */ |
1192 get script() | 1182 get script() |
1193 { | 1183 { |
1194 return this.body; | 1184 return this.body; |
1195 } | 1185 } |
1196 }); | 1186 }); |
LEFT | RIGHT |