| 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 |