Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <http://adblockplus.org/>, | 2 * This file is part of Adblock Plus <http://adblockplus.org/>, |
3 * Copyright (C) 2006-2014 Eyeo GmbH | 3 * Copyright (C) 2006-2014 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 /** | 18 /** |
19 * @fileOverview Definition of Filter class and its subclasses. | 19 * @fileOverview Definition of Filter class and its subclasses. |
20 */ | 20 */ |
21 | 21 |
22 let {FilterNotifier} = require("filterNotifier"); | 22 let {FilterNotifier} = require("filterNotifier"); |
23 let {Utils} = require("utils"); | |
Wladimir Palant
2014/08/01 10:50:21
This is a pretty self-contained module, it shouldn
Thomas Greiner
2014/08/11 17:18:15
Done.
| |
24 | 23 |
25 /** | 24 /** |
26 * Abstract base class for filters | 25 * Abstract base class for filters |
27 * | 26 * |
28 * @param {String} text string representation of the filter | 27 * @param {String} text string representation of the filter |
29 * @constructor | 28 * @constructor |
30 */ | 29 */ |
31 function Filter(text) | 30 function Filter(text) |
32 { | 31 { |
33 this.text = text; | 32 this.text = text; |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
209 | 208 |
210 /** | 209 /** |
211 * See Filter.serialize() | 210 * See Filter.serialize() |
212 */ | 211 */ |
213 serialize: function(buffer) {} | 212 serialize: function(buffer) {} |
214 }; | 213 }; |
215 | 214 |
216 /** | 215 /** |
217 * Abstract base class for filters that can get hits | 216 * Abstract base class for filters that can get hits |
218 * @param {String} text see Filter() | 217 * @param {String} text see Filter() |
219 * @param {String} domains (optional) Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com" | 218 * @param {String} [domains] Domains that the filter is restricted to separated by domainSeparator e.g. "foo.com|bar.com|~baz.com" |
220 * @param {String} siteKeys (optional) Public keys of websites that this filter should apply to, e.g. "foo|bar|~baz" | |
Wladimir Palant
2014/08/01 10:50:21
I don't really see how exceptions are useful here,
Thomas Greiner
2014/08/11 17:18:15
The issue stated that $sitekey should be handled e
| |
221 * @constructor | 219 * @constructor |
222 * @augments Filter | 220 * @augments Filter |
223 */ | 221 */ |
224 function ActiveFilter(text, domains, siteKeys) | 222 function ActiveFilter(text, domains) |
225 { | 223 { |
226 Filter.call(this, text); | 224 Filter.call(this, text); |
227 | 225 |
228 this.domainSource = domains; | 226 this.domainSource = domains; |
229 this.siteKeySource = siteKeys; | |
Thomas Greiner
2014/08/11 17:18:15
Done.
| |
230 } | 227 } |
231 exports.ActiveFilter = ActiveFilter; | 228 exports.ActiveFilter = ActiveFilter; |
232 | 229 |
233 ActiveFilter.prototype = | 230 ActiveFilter.prototype = |
234 { | 231 { |
235 __proto__: Filter.prototype, | 232 __proto__: Filter.prototype, |
236 | 233 |
237 _disabled: false, | 234 _disabled: false, |
238 _hitCount: 0, | 235 _hitCount: 0, |
239 _lastHit: 0, | 236 _lastHit: 0, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 * @type Boolean | 317 * @type Boolean |
321 */ | 318 */ |
322 domainSourceIsUpperCase: false, | 319 domainSourceIsUpperCase: false, |
323 | 320 |
324 /** | 321 /** |
325 * Map containing domains that this filter should match on/not match on or nul l if the filter should match on all domains | 322 * Map containing domains that this filter should match on/not match on or nul l if the filter should match on all domains |
326 * @type Object | 323 * @type Object |
327 */ | 324 */ |
328 get domains() | 325 get domains() |
329 { | 326 { |
327 // Despite this property being cached, the getter is called | |
328 // several times on Safari, due to WebKit bug 132872 | |
329 let prop = Object.getOwnPropertyDescriptor(this, "domains"); | |
330 if (prop) | |
331 return prop.value; | |
332 | |
330 let domains = null; | 333 let domains = null; |
331 | 334 |
332 if (this.domainSource) | 335 if (this.domainSource) |
333 { | 336 { |
334 let source = this.domainSource; | 337 let source = this.domainSource; |
335 if (!this.domainSourceIsUpperCase) { | 338 if (!this.domainSourceIsUpperCase) { |
336 // RegExpFilter already have uppercase domains | 339 // RegExpFilter already have uppercase domains |
337 source = source.toUpperCase(); | 340 source = source.toUpperCase(); |
338 } | 341 } |
339 let list = source.split(this.domainSeparator); | 342 let list = source.split(this.domainSeparator); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 } | 380 } |
378 | 381 |
379 this.domainSource = null; | 382 this.domainSource = null; |
380 } | 383 } |
381 | 384 |
382 Object.defineProperty(this, "domains", {value: domains, enumerable: true}); | 385 Object.defineProperty(this, "domains", {value: domains, enumerable: true}); |
383 return this.domains; | 386 return this.domains; |
384 }, | 387 }, |
385 | 388 |
386 /** | 389 /** |
387 * String that the siteKey property should be generated from | 390 * Array containing public keys of websites that this filter should apply to |
388 * @type String | 391 * @type Array of String |
389 */ | 392 */ |
390 siteKeySource: null, | 393 sitekeys: null, |
391 | |
392 /** | |
393 * Map containing public keys of websites that this filter should apply to | |
394 * @type Object | |
395 */ | |
396 get siteKeys() | |
397 { | |
398 let siteKeys = null; | |
399 | |
400 if (this.siteKeySource) | |
401 { | |
402 let source = this.siteKeySource; | |
403 let list = source.split("|"); | |
404 if (list.length == 1 && list[0][0] != "~") | |
405 { | |
406 // Fast track for the common one-sitekey scenario | |
407 siteKeys = {__proto__: null, "": false}; | |
408 siteKeys[list[0]] = true; | |
409 } | |
410 else | |
411 { | |
412 let hasIncludes = false; | |
413 for (let i = 0; i < list.length; i++) | |
414 { | |
415 let siteKey = list[i]; | |
416 if (siteKey == "") | |
417 continue; | |
418 | |
419 let include; | |
420 if (siteKey[0] == "~") | |
421 { | |
422 include = false; | |
423 siteKey = siteKey.substr(1); | |
424 } | |
425 else | |
426 { | |
427 include = true; | |
428 hasIncludes = true; | |
429 } | |
430 | |
431 if (!siteKeys) | |
432 siteKeys = Object.create(null); | |
433 | |
434 siteKeys[siteKey] = include; | |
435 } | |
436 siteKeys[""] = !hasIncludes; | |
437 } | |
438 | |
439 this.siteKeySource = null; | |
440 } | |
441 | |
442 Object.defineProperty(this, "siteKeys", {value: siteKeys, enumerable: true}) ; | |
443 return this.siteKeys; | |
444 }, | |
445 | 394 |
446 /** | 395 /** |
447 * Checks whether this filter is active on a domain. | 396 * Checks whether this filter is active on a domain. |
448 */ | 397 * @param {String} docDomain domain name of the document that loads the URL |
449 isActiveOnDomain: function(/**String*/ docDomain) /**Boolean*/ | 398 * @param {String} [sitekey] public key provided by the document |
450 { | 399 * @return {Boolean} true in case of the filter being active |
400 */ | |
401 isActiveOnDomain: function(docDomain, sitekey) | |
402 { | |
403 // Sitekeys are case-sensitive so we shouldn't convert them to upper-case to avoid false | |
404 // positives here. Instead we need to change the way filter options are pars ed. | |
405 if (this.sitekeys && (!sitekey || this.sitekeys.indexOf(sitekey.toUpperCase( )) < 0)) | |
406 return false; | |
407 | |
451 // If no domains are set the rule matches everywhere | 408 // If no domains are set the rule matches everywhere |
452 if (!this.domains) | 409 if (!this.domains) |
453 return true; | 410 return true; |
454 | 411 |
455 // If the document has no host name, match only if the filter isn't restrict ed to specific domains | 412 // If the document has no host name, match only if the filter isn't restrict ed to specific domains |
456 if (!docDomain) | 413 if (!docDomain) |
457 return this.domains[""]; | 414 return this.domains[""]; |
458 | 415 |
459 if (this.ignoreTrailingDot) | 416 if (this.ignoreTrailingDot) |
460 docDomain = docDomain.replace(/\.+$/, ""); | 417 docDomain = docDomain.replace(/\.+$/, ""); |
(...skipping 22 matching lines...) Expand all Loading... | |
483 | 440 |
484 if (this.ignoreTrailingDot) | 441 if (this.ignoreTrailingDot) |
485 docDomain = docDomain.replace(/\.+$/, ""); | 442 docDomain = docDomain.replace(/\.+$/, ""); |
486 docDomain = docDomain.toUpperCase(); | 443 docDomain = docDomain.toUpperCase(); |
487 | 444 |
488 for (let domain in this.domains) | 445 for (let domain in this.domains) |
489 if (this.domains[domain] && domain != docDomain && (domain.length <= docDo main.length || domain.indexOf("." + docDomain) != domain.length - docDomain.leng th - 1)) | 446 if (this.domains[domain] && domain != docDomain && (domain.length <= docDo main.length || domain.indexOf("." + docDomain) != domain.length - docDomain.leng th - 1)) |
490 return false; | 447 return false; |
491 | 448 |
492 return true; | 449 return true; |
493 }, | |
494 | |
495 /** | |
496 * Checks whether the provided site key is valid and active on a page | |
497 */ | |
498 isActiveOnPage: function(/**String*/ docDomain, /**String*/ docLocation, /**St ring*/ siteKey) /**Boolean*/ | |
Wladimir Palant
2014/08/01 10:50:21
I don't think that this is the right place to perf
Thomas Greiner
2014/08/11 17:18:15
Done.
| |
499 { | |
500 // If no site keys are set the rule matches everywhere | |
501 if (!this.siteKeys) | |
502 return true; | |
503 | |
504 // If the document has not provided a sitekey, match only if the filter isn' t restricted by sitekeys | |
505 if (!docDomain || !siteKey) | |
506 return this.siteKeys[""]; | |
507 | |
508 // If the document has provided an invalid sitekey the filter should not mat ch | |
509 if (siteKey.indexOf("_") < 0) | |
510 return false; | |
511 | |
512 let [key, signature] = siteKey.split("_", 2); | |
513 let formattedKey = key.replace(/=/g, "").toUpperCase(); | |
514 if (!(formattedKey in this.siteKeys) || !Utils.crypto) | |
515 return this.siteKeys[""]; | |
516 | |
517 // Website specifies a key that we know but is the signature valid? | |
518 let uri = Services.io.newURI(docLocation, null, null); | |
519 let host = uri.asciiHost; | |
520 if (uri.port > 0) | |
521 host += ":" + uri.port; | |
522 let params = [ | |
523 uri.path.replace(/#.*/, ""), // REQUEST_URI | |
524 host, // HTTP_HOST | |
525 Utils.httpProtocol.userAgent // HTTP_USER_AGENT | |
526 ]; | |
527 if (Utils.verifySignature(key, signature, params.join("\0"))) | |
528 return this.siteKeys[formattedKey]; | |
529 | |
530 return !this.siteKeys[formattedKey]; | |
531 }, | 450 }, |
532 | 451 |
533 /** | 452 /** |
534 * See Filter.serialize() | 453 * See Filter.serialize() |
535 */ | 454 */ |
536 serialize: function(buffer) | 455 serialize: function(buffer) |
537 { | 456 { |
538 if (this._disabled || this._hitCount || this._lastHit) | 457 if (this._disabled || this._hitCount || this._lastHit) |
539 { | 458 { |
540 Filter.prototype.serialize.call(this, buffer); | 459 Filter.prototype.serialize.call(this, buffer); |
541 if (this._disabled) | 460 if (this._disabled) |
542 buffer.push("disabled=true"); | 461 buffer.push("disabled=true"); |
543 if (this._hitCount) | 462 if (this._hitCount) |
544 buffer.push("hitCount=" + this._hitCount); | 463 buffer.push("hitCount=" + this._hitCount); |
545 if (this._lastHit) | 464 if (this._lastHit) |
546 buffer.push("lastHit=" + this._lastHit); | 465 buffer.push("lastHit=" + this._lastHit); |
547 } | 466 } |
548 } | 467 } |
549 }; | 468 }; |
550 | 469 |
551 /** | 470 /** |
552 * Abstract base class for RegExp-based filters | 471 * Abstract base class for RegExp-based filters |
553 * @param {String} text see Filter() | 472 * @param {String} text see Filter() |
554 * @param {String} regexpSource filter part that the regular expression should b e build from | 473 * @param {String} regexpSource filter part that the regular expression should b e build from |
555 * @param {Number} contentType (optional) Content types the filter applies to, combination of values from RegExpFilter.typeMap | 474 * @param {Number} [contentType] Content types the filter applies to, combinatio n of values from RegExpFilter.typeMap |
556 * @param {Boolean} matchCase (optional) Defines whether the filter should dis tinguish between lower and upper case letters | 475 * @param {Boolean} [matchCase] Defines whether the filter should distinguish be tween lower and upper case letters |
557 * @param {String} domains (optional) Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com" | 476 * @param {String} [domains] Domains that the filter is restricted to, e.g. "foo .com|bar.com|~baz.com" |
558 * @param {Boolean} thirdParty (optional) Defines whether the filter should app ly to third-party or first-party content only | 477 * @param {Boolean} [thirdParty] Defines whether the filter should apply to thir d-party or first-party content only |
559 * @param {String} siteKeys (optional) Public keys of websites that this fil ter should apply to, e.g. "foo|bar|~baz" | 478 * @param {String} [sitekeys] Public keys of websites that this filter should ap ply to |
560 * @constructor | 479 * @constructor |
561 * @augments ActiveFilter | 480 * @augments ActiveFilter |
562 */ | 481 */ |
563 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, third Party, siteKeys) | 482 function RegExpFilter(text, regexpSource, contentType, matchCase, domains, third Party, sitekeys) |
564 { | 483 { |
565 ActiveFilter.call(this, text, domains, siteKeys); | 484 ActiveFilter.call(this, text, domains, sitekeys); |
566 | 485 |
567 if (contentType != null) | 486 if (contentType != null) |
568 this.contentType = contentType; | 487 this.contentType = contentType; |
569 if (matchCase) | 488 if (matchCase) |
570 this.matchCase = matchCase; | 489 this.matchCase = matchCase; |
571 if (thirdParty != null) | 490 if (thirdParty != null) |
572 this.thirdParty = thirdParty; | 491 this.thirdParty = thirdParty; |
492 if (sitekeys != null) | |
493 this.sitekeySource = sitekeys; | |
573 | 494 |
574 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpS ource.length - 1] == "/") | 495 if (regexpSource.length >= 2 && regexpSource[0] == "/" && regexpSource[regexpS ource.length - 1] == "/") |
575 { | 496 { |
576 // The filter is a regular expression - convert it immediately to catch synt ax errors | 497 // The filter is a regular expression - convert it immediately to catch synt ax errors |
577 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), thi s.matchCase ? "" : "i"); | 498 let regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), thi s.matchCase ? "" : "i"); |
578 Object.defineProperty(this, "regexp", {value: regexp}); | 499 Object.defineProperty(this, "regexp", {value: regexp}); |
579 } | 500 } |
580 else | 501 else |
581 { | 502 { |
582 // No need to convert this filter to regular expression yet, do it on demand | 503 // No need to convert this filter to regular expression yet, do it on demand |
(...skipping 26 matching lines...) Expand all Loading... | |
609 * Expression from which a regular expression should be generated - for delaye d creation of the regexp property | 530 * Expression from which a regular expression should be generated - for delaye d creation of the regexp property |
610 * @type String | 531 * @type String |
611 */ | 532 */ |
612 regexpSource: null, | 533 regexpSource: null, |
613 /** | 534 /** |
614 * Regular expression to be used when testing against this filter | 535 * Regular expression to be used when testing against this filter |
615 * @type RegExp | 536 * @type RegExp |
616 */ | 537 */ |
617 get regexp() | 538 get regexp() |
618 { | 539 { |
540 // Despite this property being cached, the getter is called | |
541 // several times on Safari, due to WebKit bug 132872 | |
542 let prop = Object.getOwnPropertyDescriptor(this, "regexp"); | |
543 if (prop) | |
544 return prop.value; | |
545 | |
619 // Remove multiple wildcards | 546 // Remove multiple wildcards |
620 let source = this.regexpSource | 547 let source = this.regexpSource |
621 .replace(/\*+/g, "*") // remove multiple wildcards | 548 .replace(/\*+/g, "*") // remove multiple wildcards |
622 .replace(/\^\|$/, "^") // remove anchors following separator placeho lder | 549 .replace(/\^\|$/, "^") // remove anchors following separator placeho lder |
623 .replace(/\W/g, "\\$&") // escape special symbols | 550 .replace(/\W/g, "\\$&") // escape special symbols |
624 .replace(/\\\*/g, ".*") // replace wildcards by .* | 551 .replace(/\\\*/g, ".*") // replace wildcards by .* |
625 // process separator placeholders (all ANSI characters but alphanumeric ch aracters and _%.-) | 552 // process separator placeholders (all ANSI characters but alphanumeric ch aracters and _%.-) |
626 .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\ x60\\x7B-\\x7F]|$)") | 553 .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\ x60\\x7B-\\x7F]|$)") |
627 .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process extended anchor at expression start | 554 .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?") // process extended anchor at expression start |
628 .replace(/^\\\|/, "^") // process anchor at expression start | 555 .replace(/^\\\|/, "^") // process anchor at expression start |
(...skipping 15 matching lines...) Expand all Loading... | |
644 * @type Boolean | 571 * @type Boolean |
645 */ | 572 */ |
646 matchCase: false, | 573 matchCase: false, |
647 /** | 574 /** |
648 * Defines whether the filter should apply to third-party or first-party conte nt only. Can be null (apply to all content). | 575 * Defines whether the filter should apply to third-party or first-party conte nt only. Can be null (apply to all content). |
649 * @type Boolean | 576 * @type Boolean |
650 */ | 577 */ |
651 thirdParty: null, | 578 thirdParty: null, |
652 | 579 |
653 /** | 580 /** |
581 * String that the sitekey property should be generated from | |
582 * @type String | |
583 */ | |
584 sitekeySource: null, | |
585 | |
586 /** | |
587 * Array containing public keys of websites that this filter should apply to | |
588 * @type Array of String | |
589 */ | |
590 get sitekeys() | |
591 { | |
592 // Despite this property being cached, the getter is called | |
593 // several times on Safari, due to WebKit bug 132872 | |
594 let prop = Object.getOwnPropertyDescriptor(this, "sitekeys"); | |
595 if (prop) | |
596 return prop.value; | |
597 | |
598 let sitekeys = null; | |
599 | |
600 if (this.sitekeySource) | |
601 { | |
602 sitekeys = this.sitekeySource.split("|"); | |
603 this.sitekeySource = null; | |
604 } | |
605 | |
606 Object.defineProperty(this, "sitekeys", {value: sitekeys, enumerable: true}) ; | |
607 return this.sitekeys; | |
608 }, | |
609 | |
610 /** | |
654 * Tests whether the URL matches this filter | 611 * Tests whether the URL matches this filter |
655 * @param {String} location URL to be tested | 612 * @param {String} location URL to be tested |
656 * @param {String} contentType content type identifier of the URL | 613 * @param {String} contentType content type identifier of the URL |
657 * @param {String} docDomain domain name of the document that loads the URL | 614 * @param {String} docDomain domain name of the document that loads the URL |
658 * @param {Boolean} thirdParty should be true if the URL is a third-party requ est | 615 * @param {Boolean} thirdParty should be true if the URL is a third-party requ est |
659 * @param {String} docLocation location of the document that loads the URL | 616 * @param {String} sitekey public key provided by the document |
660 * @param {String} siteKey public key provided by the document | |
661 * @return {Boolean} true in case of a match | 617 * @return {Boolean} true in case of a match |
662 */ | 618 */ |
663 matches: function(location, contentType, docDomain, thirdParty, docLocation, s iteKey) | 619 matches: function(location, contentType, docDomain, thirdParty, sitekey) |
664 { | 620 { |
665 if (this.regexp.test(location) && | 621 if (this.regexp.test(location) && |
666 (RegExpFilter.typeMap[contentType] & this.contentType) != 0 && | 622 (RegExpFilter.typeMap[contentType] & this.contentType) != 0 && |
667 (this.thirdParty == null || this.thirdParty == thirdParty) && | 623 (this.thirdParty == null || this.thirdParty == thirdParty) && |
668 this.isActiveOnDomain(docDomain) && | 624 this.isActiveOnDomain(docDomain, sitekey)) |
669 this.isActiveOnPage(docDomain, docLocation, siteKey)) | |
670 { | 625 { |
671 return true; | 626 return true; |
672 } | 627 } |
673 | 628 |
674 return false; | 629 return false; |
675 } | 630 } |
676 }; | 631 }; |
677 | 632 |
678 // Required to optimize Matcher, see also RegExpFilter.prototype.length | 633 // Required to optimize Matcher, see also RegExpFilter.prototype.length |
679 Object.defineProperty(RegExpFilter.prototype, "0", | 634 Object.defineProperty(RegExpFilter.prototype, "0", |
(...skipping 11 matching lines...) Expand all Loading... | |
691 let origText = text; | 646 let origText = text; |
692 if (text.indexOf("@@") == 0) | 647 if (text.indexOf("@@") == 0) |
693 { | 648 { |
694 blocking = false; | 649 blocking = false; |
695 text = text.substr(2); | 650 text = text.substr(2); |
696 } | 651 } |
697 | 652 |
698 let contentType = null; | 653 let contentType = null; |
699 let matchCase = null; | 654 let matchCase = null; |
700 let domains = null; | 655 let domains = null; |
701 let siteKeys = null; | 656 let sitekeys = null; |
702 let thirdParty = null; | 657 let thirdParty = null; |
703 let collapse = null; | 658 let collapse = null; |
704 let options; | 659 let options; |
705 let match = (text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null); | 660 let match = (text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null); |
706 if (match) | 661 if (match) |
707 { | 662 { |
708 options = match[1].toUpperCase().split(","); | 663 options = match[1].toUpperCase().split(","); |
709 text = match.input.substr(0, match.index); | 664 text = match.input.substr(0, match.index); |
710 for (let option of options) | 665 for (let option of options) |
711 { | 666 { |
(...skipping 25 matching lines...) Expand all Loading... | |
737 domains = value; | 692 domains = value; |
738 else if (option == "THIRD_PARTY") | 693 else if (option == "THIRD_PARTY") |
739 thirdParty = true; | 694 thirdParty = true; |
740 else if (option == "~THIRD_PARTY") | 695 else if (option == "~THIRD_PARTY") |
741 thirdParty = false; | 696 thirdParty = false; |
742 else if (option == "COLLAPSE") | 697 else if (option == "COLLAPSE") |
743 collapse = true; | 698 collapse = true; |
744 else if (option == "~COLLAPSE") | 699 else if (option == "~COLLAPSE") |
745 collapse = false; | 700 collapse = false; |
746 else if (option == "SITEKEY" && typeof value != "undefined") | 701 else if (option == "SITEKEY" && typeof value != "undefined") |
747 siteKeys = value; | 702 sitekeys = value; |
748 else | 703 else |
749 return new InvalidFilter(origText, "Unknown option " + option.toLowerCas e()); | 704 return new InvalidFilter(origText, "Unknown option " + option.toLowerCas e()); |
750 } | 705 } |
751 } | 706 } |
752 | 707 |
753 if (!blocking && (contentType == null || (contentType & RegExpFilter.typeMap.D OCUMENT)) && | 708 if (!blocking && (contentType == null || (contentType & RegExpFilter.typeMap.D OCUMENT)) && |
754 (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text )) | 709 (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text )) |
755 { | 710 { |
756 // Exception filters shouldn't apply to pages by default unless they start w ith a protocol name | 711 // Exception filters shouldn't apply to pages by default unless they start w ith a protocol name |
757 if (contentType == null) | 712 if (contentType == null) |
758 contentType = RegExpFilter.prototype.contentType; | 713 contentType = RegExpFilter.prototype.contentType; |
759 contentType &= ~RegExpFilter.typeMap.DOCUMENT; | 714 contentType &= ~RegExpFilter.typeMap.DOCUMENT; |
760 } | 715 } |
761 | 716 |
762 try | 717 try |
763 { | 718 { |
764 if (blocking) | 719 if (blocking) |
765 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, siteKeys, collapse); | 720 return new BlockingFilter(origText, text, contentType, matchCase, domains, thirdParty, sitekeys, collapse); |
766 else | 721 else |
767 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, siteKeys); | 722 return new WhitelistFilter(origText, text, contentType, matchCase, domains , thirdParty, sitekeys); |
768 } | 723 } |
769 catch (e) | 724 catch (e) |
770 { | 725 { |
771 return new InvalidFilter(origText, e); | 726 return new InvalidFilter(origText, e); |
772 } | 727 } |
773 } | 728 } |
774 | 729 |
775 /** | 730 /** |
776 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks | 731 * Maps type strings like "SCRIPT" or "OBJECT" to bit masks |
777 */ | 732 */ |
(...skipping 23 matching lines...) Expand all Loading... | |
801 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.ELEMHIDE | RegExpFi lter.typeMap.POPUP); | 756 RegExpFilter.prototype.contentType &= ~(RegExpFilter.typeMap.ELEMHIDE | RegExpFi lter.typeMap.POPUP); |
802 | 757 |
803 /** | 758 /** |
804 * Class for blocking filters | 759 * Class for blocking filters |
805 * @param {String} text see Filter() | 760 * @param {String} text see Filter() |
806 * @param {String} regexpSource see RegExpFilter() | 761 * @param {String} regexpSource see RegExpFilter() |
807 * @param {Number} contentType see RegExpFilter() | 762 * @param {Number} contentType see RegExpFilter() |
808 * @param {Boolean} matchCase see RegExpFilter() | 763 * @param {Boolean} matchCase see RegExpFilter() |
809 * @param {String} domains see RegExpFilter() | 764 * @param {String} domains see RegExpFilter() |
810 * @param {Boolean} thirdParty see RegExpFilter() | 765 * @param {Boolean} thirdParty see RegExpFilter() |
811 * @param {String} siteKeys see RegExpFilter() | 766 * @param {String} sitekeys see RegExpFilter() |
812 * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null | 767 * @param {Boolean} collapse defines whether the filter should collapse blocked content, can be null |
813 * @constructor | 768 * @constructor |
814 * @augments RegExpFilter | 769 * @augments RegExpFilter |
815 */ | 770 */ |
816 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty, siteKeys, collapse) | 771 function BlockingFilter(text, regexpSource, contentType, matchCase, domains, thi rdParty, sitekeys, collapse) |
817 { | 772 { |
818 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, siteKeys); | 773 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); |
819 | 774 |
820 this.collapse = collapse; | 775 this.collapse = collapse; |
821 } | 776 } |
822 exports.BlockingFilter = BlockingFilter; | 777 exports.BlockingFilter = BlockingFilter; |
823 | 778 |
824 BlockingFilter.prototype = | 779 BlockingFilter.prototype = |
825 { | 780 { |
826 __proto__: RegExpFilter.prototype, | 781 __proto__: RegExpFilter.prototype, |
827 | 782 |
828 /** | 783 /** |
829 * Defines whether the filter should collapse blocked content. Can be null (us e the global preference). | 784 * Defines whether the filter should collapse blocked content. Can be null (us e the global preference). |
830 * @type Boolean | 785 * @type Boolean |
831 */ | 786 */ |
832 collapse: null | 787 collapse: null |
833 }; | 788 }; |
834 | 789 |
835 /** | 790 /** |
836 * Class for whitelist filters | 791 * Class for whitelist filters |
837 * @param {String} text see Filter() | 792 * @param {String} text see Filter() |
838 * @param {String} regexpSource see RegExpFilter() | 793 * @param {String} regexpSource see RegExpFilter() |
839 * @param {Number} contentType see RegExpFilter() | 794 * @param {Number} contentType see RegExpFilter() |
840 * @param {Boolean} matchCase see RegExpFilter() | 795 * @param {Boolean} matchCase see RegExpFilter() |
841 * @param {String} domains see RegExpFilter() | 796 * @param {String} domains see RegExpFilter() |
842 * @param {Boolean} thirdParty see RegExpFilter() | 797 * @param {Boolean} thirdParty see RegExpFilter() |
843 * @param {String} siteKeys see RegExpFilter() | 798 * @param {String} sitekeys see RegExpFilter() |
844 * @constructor | 799 * @constructor |
845 * @augments RegExpFilter | 800 * @augments RegExpFilter |
846 */ | 801 */ |
847 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, th irdParty, siteKeys) | 802 function WhitelistFilter(text, regexpSource, contentType, matchCase, domains, th irdParty, sitekeys) |
848 { | 803 { |
849 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, siteKeys); | 804 RegExpFilter.call(this, text, regexpSource, contentType, matchCase, domains, t hirdParty, sitekeys); |
850 } | 805 } |
851 exports.WhitelistFilter = WhitelistFilter; | 806 exports.WhitelistFilter = WhitelistFilter; |
852 | 807 |
853 WhitelistFilter.prototype = | 808 WhitelistFilter.prototype = |
854 { | 809 { |
855 __proto__: RegExpFilter.prototype | 810 __proto__: RegExpFilter.prototype |
856 } | 811 } |
857 | 812 |
858 /** | 813 /** |
859 * Base class for element hiding filters | 814 * Base class for element hiding filters |
860 * @param {String} text see Filter() | 815 * @param {String} text see Filter() |
861 * @param {String} domains (optional) Host names or domains the filter should be restricted to | 816 * @param {String} [domains] Host names or domains the filter should be restrict ed to |
862 * @param {String} selector CSS selector for the HTML elements that should be hidden | 817 * @param {String} selector CSS selector for the HTML elements that should be hidden |
863 * @constructor | 818 * @constructor |
864 * @augments ActiveFilter | 819 * @augments ActiveFilter |
865 */ | 820 */ |
866 function ElemHideBase(text, domains, selector) | 821 function ElemHideBase(text, domains, selector) |
867 { | 822 { |
868 ActiveFilter.call(this, text, domains || null); | 823 ActiveFilter.call(this, text, domains || null); |
869 | 824 |
870 if (domains) | 825 if (domains) |
871 this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, " ").toLowerCase(); | 826 this.selectorDomain = domains.replace(/,~[^,]+/g, "").replace(/^~[^,]+,?/, " ").toLowerCase(); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
985 function ElemHideException(text, domains, selector) | 940 function ElemHideException(text, domains, selector) |
986 { | 941 { |
987 ElemHideBase.call(this, text, domains, selector); | 942 ElemHideBase.call(this, text, domains, selector); |
988 } | 943 } |
989 exports.ElemHideException = ElemHideException; | 944 exports.ElemHideException = ElemHideException; |
990 | 945 |
991 ElemHideException.prototype = | 946 ElemHideException.prototype = |
992 { | 947 { |
993 __proto__: ElemHideBase.prototype | 948 __proto__: ElemHideBase.prototype |
994 }; | 949 }; |
LEFT | RIGHT |