mirror of https://github.com/gorhill/uBlock.git
Add `:matches-prop()` pseudo CSS operator
`subject:matches-prop(arg)` Description: Allows to select an element by a property name (or chain of properties), and optionally the property value. Chainable: Yes. `subject`: Can be a plain CSS selector, or a procedural cosmetic filter. `arg`: A declaration in the form `chain=value`, where `chain` is a dot- separated string for the target property, and `value` is the optional property value to match. `value` can be literal text or literal regular expression. When no `value` is declared, the operator only tests for the presence of the target property Example: example.org##div:matches-prop(imanad) example.org##img:matches-prop(naturalWidth=160)
This commit is contained in:
parent
7be7e0b870
commit
aca7674bac
|
@ -173,6 +173,26 @@ class PSelectorMatchesPathTask extends PSelectorTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PSelectorMatchesPropTask extends PSelectorTask {
|
||||||
|
constructor(task) {
|
||||||
|
super();
|
||||||
|
this.props = task[1].attr.split('.');
|
||||||
|
this.reValue = task[1].value !== ''
|
||||||
|
? regexFromString(task[1].value, true)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
transpose(node, output) {
|
||||||
|
let value = node;
|
||||||
|
for ( const prop of this.props ) {
|
||||||
|
if ( value === undefined ) { return; }
|
||||||
|
if ( value === null ) { return; }
|
||||||
|
value = value[prop];
|
||||||
|
}
|
||||||
|
if ( this.reValue !== null && this.reValue.test(value) === false ) { return; }
|
||||||
|
output.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PSelectorMinTextLengthTask extends PSelectorTask {
|
class PSelectorMinTextLengthTask extends PSelectorTask {
|
||||||
constructor(task) {
|
constructor(task) {
|
||||||
super();
|
super();
|
||||||
|
@ -461,6 +481,7 @@ PSelector.prototype.operatorToTaskMap = new Map([
|
||||||
[ 'matches-css-before', PSelectorMatchesCSSBeforeTask ],
|
[ 'matches-css-before', PSelectorMatchesCSSBeforeTask ],
|
||||||
[ 'matches-media', PSelectorMatchesMediaTask ],
|
[ 'matches-media', PSelectorMatchesMediaTask ],
|
||||||
[ 'matches-path', PSelectorMatchesPathTask ],
|
[ 'matches-path', PSelectorMatchesPathTask ],
|
||||||
|
[ 'matches-prop', PSelectorMatchesPropTask ],
|
||||||
[ 'min-text-length', PSelectorMinTextLengthTask ],
|
[ 'min-text-length', PSelectorMinTextLengthTask ],
|
||||||
[ 'not', PSelectorIfNotTask ],
|
[ 'not', PSelectorIfNotTask ],
|
||||||
[ 'others', PSelectorOthersTask ],
|
[ 'others', PSelectorOthersTask ],
|
||||||
|
|
|
@ -19,12 +19,10 @@
|
||||||
Home: https://github.com/gorhill/uBlock
|
Home: https://github.com/gorhill/uBlock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
import Regex from '../lib/regexanalyzer/regex.js';
|
|
||||||
import * as cssTree from '../lib/csstree/css-tree.js';
|
import * as cssTree from '../lib/csstree/css-tree.js';
|
||||||
|
import Regex from '../lib/regexanalyzer/regex.js';
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
*
|
*
|
||||||
|
@ -781,21 +779,21 @@ class DomainListIterator {
|
||||||
let ready = false;
|
let ready = false;
|
||||||
while ( node !== 0 ) {
|
while ( node !== 0 ) {
|
||||||
switch ( this.parser.getNodeType(node) ) {
|
switch ( this.parser.getNodeType(node) ) {
|
||||||
case NODE_TYPE_OPTION_VALUE_DOMAIN_RAW:
|
case NODE_TYPE_OPTION_VALUE_DOMAIN_RAW:
|
||||||
this.item.hn = '';
|
this.item.hn = '';
|
||||||
this.item.not = false;
|
this.item.not = false;
|
||||||
this.item.bad = this.parser.getNodeFlags(node, NODE_FLAG_ERROR) !== 0;
|
this.item.bad = this.parser.getNodeFlags(node, NODE_FLAG_ERROR) !== 0;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_OPTION_VALUE_NOT:
|
case NODE_TYPE_OPTION_VALUE_NOT:
|
||||||
this.item.not = true;
|
this.item.not = true;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_OPTION_VALUE_DOMAIN:
|
case NODE_TYPE_OPTION_VALUE_DOMAIN:
|
||||||
this.item.hn = this.parser.getNodeTransform(node);
|
this.item.hn = this.parser.getNodeTransform(node);
|
||||||
this.value = this.item;
|
this.value = this.item;
|
||||||
ready = true;
|
ready = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
node = this.walker.next();
|
node = this.walker.next();
|
||||||
if ( ready ) { return this; }
|
if ( ready ) { return this; }
|
||||||
|
@ -859,17 +857,17 @@ export class AstFilterParser {
|
||||||
this.reInlineComment = /(?:\s+#).*?$/;
|
this.reInlineComment = /(?:\s+#).*?$/;
|
||||||
this.reNetException = /^@@/;
|
this.reNetException = /^@@/;
|
||||||
this.reNetAnchor = /(?:)\$[^,\w~]/;
|
this.reNetAnchor = /(?:)\$[^,\w~]/;
|
||||||
this.reHnAnchoredPlainAscii = /^\|\|[0-9a-z%&,\-.\/:;=?_]+$/;
|
this.reHnAnchoredPlainAscii = /^\|\|[0-9a-z%&,\-./:;=?_]+$/;
|
||||||
this.reHnAnchoredHostnameAscii = /^\|\|(?:[\da-z][\da-z_-]*\.)*[\da-z_-]*[\da-z]\^$/;
|
this.reHnAnchoredHostnameAscii = /^\|\|(?:[\da-z][\da-z_-]*\.)*[\da-z_-]*[\da-z]\^$/;
|
||||||
this.reHnAnchoredHostnameUnicode = /^\|\|(?:[\p{L}\p{N}][\p{L}\p{N}\u{2d}]*\.)*[\p{L}\p{N}\u{2d}]*[\p{L}\p{N}]\^$/u;
|
this.reHnAnchoredHostnameUnicode = /^\|\|(?:[\p{L}\p{N}][\p{L}\p{N}\u{2d}]*\.)*[\p{L}\p{N}\u{2d}]*[\p{L}\p{N}]\^$/u;
|
||||||
this.reHn3pAnchoredHostnameAscii = /^\|\|(?:[\da-z][\da-z_-]*\.)*[\da-z_-]*[\da-z]\^\$third-party$/;
|
this.reHn3pAnchoredHostnameAscii = /^\|\|(?:[\da-z][\da-z_-]*\.)*[\da-z_-]*[\da-z]\^\$third-party$/;
|
||||||
this.rePlainAscii = /^[0-9a-z%&\-.\/:;=?_]{2,}$/;
|
this.rePlainAscii = /^[0-9a-z%&\-./:;=?_]{2,}$/;
|
||||||
this.reNetHosts1 = /^127\.0\.0\.1 (?:[\da-z][\da-z_-]*\.)+[\da-z-]*[a-z]$/;
|
this.reNetHosts1 = /^127\.0\.0\.1 (?:[\da-z][\da-z_-]*\.)+[\da-z-]*[a-z]$/;
|
||||||
this.reNetHosts2 = /^0\.0\.0\.0 (?:[\da-z][\da-z_-]*\.)+[\da-z-]*[a-z]$/;
|
this.reNetHosts2 = /^0\.0\.0\.0 (?:[\da-z][\da-z_-]*\.)+[\da-z-]*[a-z]$/;
|
||||||
this.rePlainGenericCosmetic = /^##[.#][A-Za-z_][\w-]*$/;
|
this.rePlainGenericCosmetic = /^##[.#][A-Za-z_][\w-]*$/;
|
||||||
this.reHostnameAscii = /^(?:[\da-z][\da-z_-]*\.)*[\da-z][\da-z-]*[\da-z]$/;
|
this.reHostnameAscii = /^(?:[\da-z][\da-z_-]*\.)*[\da-z][\da-z-]*[\da-z]$/;
|
||||||
this.rePlainEntity = /^(?:[\da-z][\da-z_-]*\.)+\*$/;
|
this.rePlainEntity = /^(?:[\da-z][\da-z_-]*\.)+\*$/;
|
||||||
this.reHostsSink = /^[\w%.:\[\]-]+\s+/;
|
this.reHostsSink = /^[\w%.:[\]-]+\s+/;
|
||||||
this.reHostsRedirect = /(?:0\.0\.0\.0|broadcasthost|local|localhost(?:\.localdomain)?|ip6-\w+)(?:[^\w.-]|$)/;
|
this.reHostsRedirect = /(?:0\.0\.0\.0|broadcasthost|local|localhost(?:\.localdomain)?|ip6-\w+)(?:[^\w.-]|$)/;
|
||||||
this.reNetOptionComma = /,(?:~?[13a-z-]+(?:=.*?)?|_+)(?:,|$)/;
|
this.reNetOptionComma = /,(?:~?[13a-z-]+(?:=.*?)?|_+)(?:,|$)/;
|
||||||
this.rePointlessLeftAnchor = /^\|\|?\*+/;
|
this.rePointlessLeftAnchor = /^\|\|?\*+/;
|
||||||
|
@ -886,8 +884,8 @@ export class AstFilterParser {
|
||||||
this.rePreparseDirectiveIf = /^!#if /;
|
this.rePreparseDirectiveIf = /^!#if /;
|
||||||
this.rePreparseDirectiveAny = /^!#(?:else|endif|if |include )/;
|
this.rePreparseDirectiveAny = /^!#(?:else|endif|if |include )/;
|
||||||
this.reURL = /\bhttps?:\/\/\S+/;
|
this.reURL = /\bhttps?:\/\/\S+/;
|
||||||
this.reHasPatternSpecialChars = /[\*\^]/;
|
this.reHasPatternSpecialChars = /[*^]/;
|
||||||
this.rePatternAllSpecialChars = /[\*\^]+|[^\x00-\x7f]+/g;
|
this.rePatternAllSpecialChars = /[*^]+|[^\x00-\x7f]+/g;
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/1146
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/1146
|
||||||
// From https://codemirror.net/doc/manual.html#option_specialChars
|
// From https://codemirror.net/doc/manual.html#option_specialChars
|
||||||
this.reHasInvalidChar = /[\x00-\x1F\x7F-\x9F\xAD\u061C\u200B-\u200F\u2028\u2029\uFEFF\uFFF9-\uFFFC]/;
|
this.reHasInvalidChar = /[\x00-\x1F\x7F-\x9F\xAD\u061C\u200B-\u200F\u2028\u2029\uFEFF\uFFF9-\uFFFC]/;
|
||||||
|
@ -1315,148 +1313,148 @@ export class AstFilterParser {
|
||||||
const hasValue = (flags & NODE_FLAG_OPTION_HAS_VALUE) !== 0;
|
const hasValue = (flags & NODE_FLAG_OPTION_HAS_VALUE) !== 0;
|
||||||
bad = false; realBad = false;
|
bad = false; realBad = false;
|
||||||
switch ( type ) {
|
switch ( type ) {
|
||||||
case NODE_TYPE_NET_OPTION_NAME_ALL:
|
case NODE_TYPE_NET_OPTION_NAME_ALL:
|
||||||
realBad = isNegated || hasValue || modifierType !== 0;
|
realBad = isNegated || hasValue || modifierType !== 0;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_1P:
|
case NODE_TYPE_NET_OPTION_NAME_1P:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_3P:
|
case NODE_TYPE_NET_OPTION_NAME_3P:
|
||||||
realBad = hasValue;
|
realBad = hasValue;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_BADFILTER:
|
case NODE_TYPE_NET_OPTION_NAME_BADFILTER:
|
||||||
badfilter = true;
|
badfilter = true;
|
||||||
/* falls through */
|
/* falls through */
|
||||||
case NODE_TYPE_NET_OPTION_NAME_NOOP:
|
case NODE_TYPE_NET_OPTION_NAME_NOOP:
|
||||||
realBad = isNegated || hasValue;
|
realBad = isNegated || hasValue;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_CSS:
|
case NODE_TYPE_NET_OPTION_NAME_CSS:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_FONT:
|
case NODE_TYPE_NET_OPTION_NAME_FONT:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_IMAGE:
|
case NODE_TYPE_NET_OPTION_NAME_IMAGE:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_MEDIA:
|
case NODE_TYPE_NET_OPTION_NAME_MEDIA:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_OBJECT:
|
case NODE_TYPE_NET_OPTION_NAME_OBJECT:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_OTHER:
|
case NODE_TYPE_NET_OPTION_NAME_OTHER:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_SCRIPT:
|
case NODE_TYPE_NET_OPTION_NAME_SCRIPT:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_XHR:
|
case NODE_TYPE_NET_OPTION_NAME_XHR:
|
||||||
realBad = hasValue;
|
realBad = hasValue;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
requestTypeCount += 1;
|
requestTypeCount += 1;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_CNAME:
|
case NODE_TYPE_NET_OPTION_NAME_CNAME:
|
||||||
realBad = isException === false || isNegated || hasValue;
|
realBad = isException === false || isNegated || hasValue;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
modifierType = type;
|
modifierType = type;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_CSP:
|
case NODE_TYPE_NET_OPTION_NAME_CSP:
|
||||||
realBad = (hasValue || isException) === false ||
|
realBad = (hasValue || isException) === false ||
|
||||||
modifierType !== 0 ||
|
modifierType !== 0 ||
|
||||||
this.reBadCSP.test(
|
this.reBadCSP.test(
|
||||||
this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_CSP)
|
this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_CSP)
|
||||||
);
|
);
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
modifierType = type;
|
modifierType = type;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_DENYALLOW:
|
case NODE_TYPE_NET_OPTION_NAME_DENYALLOW:
|
||||||
realBad = isNegated || hasValue === false ||
|
realBad = isNegated || hasValue === false ||
|
||||||
this.getBranchFromType(NODE_TYPE_NET_OPTION_NAME_FROM) === 0;
|
this.getBranchFromType(NODE_TYPE_NET_OPTION_NAME_FROM) === 0;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_DOC:
|
case NODE_TYPE_NET_OPTION_NAME_DOC:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_FRAME:
|
case NODE_TYPE_NET_OPTION_NAME_FRAME:
|
||||||
realBad = hasValue;
|
realBad = hasValue;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
docTypeCount += 1;
|
docTypeCount += 1;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_EHIDE:
|
case NODE_TYPE_NET_OPTION_NAME_EHIDE:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_GHIDE:
|
case NODE_TYPE_NET_OPTION_NAME_GHIDE:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_SHIDE:
|
case NODE_TYPE_NET_OPTION_NAME_SHIDE:
|
||||||
realBad = isNegated || hasValue || modifierType !== 0;
|
realBad = isNegated || hasValue || modifierType !== 0;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
behaviorTypeCount += 1;
|
behaviorTypeCount += 1;
|
||||||
unredirectableTypeCount += 1;
|
unredirectableTypeCount += 1;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_EMPTY:
|
case NODE_TYPE_NET_OPTION_NAME_EMPTY:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_MP4:
|
case NODE_TYPE_NET_OPTION_NAME_MP4:
|
||||||
realBad = isNegated || hasValue || modifierType !== 0;
|
realBad = isNegated || hasValue || modifierType !== 0;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
modifierType = type;
|
modifierType = type;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_FROM:
|
case NODE_TYPE_NET_OPTION_NAME_FROM:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_METHOD:
|
case NODE_TYPE_NET_OPTION_NAME_METHOD:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_TO:
|
case NODE_TYPE_NET_OPTION_NAME_TO:
|
||||||
realBad = isNegated || hasValue === false;
|
realBad = isNegated || hasValue === false;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_GENERICBLOCK:
|
case NODE_TYPE_NET_OPTION_NAME_GENERICBLOCK:
|
||||||
bad = true;
|
bad = true;
|
||||||
realBad = isException === false || isNegated || hasValue;
|
realBad = isException === false || isNegated || hasValue;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_HEADER:
|
case NODE_TYPE_NET_OPTION_NAME_HEADER:
|
||||||
realBad = isNegated || hasValue === false;
|
realBad = isNegated || hasValue === false;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_IMPORTANT:
|
case NODE_TYPE_NET_OPTION_NAME_IMPORTANT:
|
||||||
realBad = isException || isNegated || hasValue;
|
realBad = isException || isNegated || hasValue;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_INLINEFONT:
|
case NODE_TYPE_NET_OPTION_NAME_INLINEFONT:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT:
|
case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT:
|
||||||
realBad = hasValue;
|
realBad = hasValue;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
modifierType = type;
|
modifierType = type;
|
||||||
unredirectableTypeCount += 1;
|
unredirectableTypeCount += 1;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_MATCHCASE:
|
case NODE_TYPE_NET_OPTION_NAME_MATCHCASE:
|
||||||
realBad = this.isRegexPattern() === false;
|
realBad = this.isRegexPattern() === false;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
|
case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
|
||||||
realBad = modifierType !== 0 ||
|
realBad = modifierType !== 0 ||
|
||||||
(hasValue || isException) === false ||
|
(hasValue || isException) === false ||
|
||||||
this.reBadPP.test(
|
this.reBadPP.test(
|
||||||
this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_PERMISSIONS)
|
this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_PERMISSIONS)
|
||||||
);
|
);
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
modifierType = type;
|
modifierType = type;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_PING:
|
case NODE_TYPE_NET_OPTION_NAME_PING:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_WEBSOCKET:
|
case NODE_TYPE_NET_OPTION_NAME_WEBSOCKET:
|
||||||
realBad = hasValue;
|
realBad = hasValue;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
requestTypeCount += 1;
|
requestTypeCount += 1;
|
||||||
unredirectableTypeCount += 1;
|
unredirectableTypeCount += 1;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_POPUNDER:
|
case NODE_TYPE_NET_OPTION_NAME_POPUNDER:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_POPUP:
|
case NODE_TYPE_NET_OPTION_NAME_POPUP:
|
||||||
realBad = hasValue;
|
realBad = hasValue;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
abstractTypeCount += 1;
|
abstractTypeCount += 1;
|
||||||
unredirectableTypeCount += 1;
|
unredirectableTypeCount += 1;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REDIRECT:
|
case NODE_TYPE_NET_OPTION_NAME_REDIRECT:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE:
|
case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REPLACE:
|
case NODE_TYPE_NET_OPTION_NAME_REPLACE:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM:
|
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM:
|
||||||
realBad = isNegated || (isException || hasValue) === false ||
|
realBad = isNegated || (isException || hasValue) === false ||
|
||||||
modifierType !== 0;
|
modifierType !== 0;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
modifierType = type;
|
modifierType = type;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM:
|
case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM:
|
||||||
realBad = isNegated || modifierType !== 0;
|
realBad = isNegated || modifierType !== 0;
|
||||||
if ( realBad ) { break; }
|
if ( realBad ) { break; }
|
||||||
modifierType = type;
|
modifierType = type;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_STRICT1P:
|
case NODE_TYPE_NET_OPTION_NAME_STRICT1P:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_STRICT3P:
|
case NODE_TYPE_NET_OPTION_NAME_STRICT3P:
|
||||||
realBad = isNegated || hasValue;
|
realBad = isNegated || hasValue;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_UNKNOWN:
|
case NODE_TYPE_NET_OPTION_NAME_UNKNOWN:
|
||||||
this.astError = AST_ERROR_OPTION_UNKNOWN;
|
this.astError = AST_ERROR_OPTION_UNKNOWN;
|
||||||
realBad = true;
|
realBad = true;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_WEBRTC:
|
case NODE_TYPE_NET_OPTION_NAME_WEBRTC:
|
||||||
realBad = true;
|
realBad = true;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_PATTERN_RAW:
|
case NODE_TYPE_NET_PATTERN_RAW:
|
||||||
realBad = this.hasOptions() === false &&
|
realBad = this.hasOptions() === false &&
|
||||||
this.getNetPattern().length <= 1;
|
this.getNetPattern().length <= 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ( bad || realBad ) {
|
if ( bad || realBad ) {
|
||||||
this.addNodeFlags(targetNode, NODE_FLAG_ERROR);
|
this.addNodeFlags(targetNode, NODE_FLAG_ERROR);
|
||||||
|
@ -1469,64 +1467,64 @@ export class AstFilterParser {
|
||||||
this.options.trustedSource !== true &&
|
this.options.trustedSource !== true &&
|
||||||
isException === false && badfilter === false;
|
isException === false && badfilter === false;
|
||||||
switch ( modifierType ) {
|
switch ( modifierType ) {
|
||||||
case NODE_TYPE_NET_OPTION_NAME_CNAME:
|
case NODE_TYPE_NET_OPTION_NAME_CNAME:
|
||||||
realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount;
|
realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_CSP:
|
case NODE_TYPE_NET_OPTION_NAME_CSP:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
|
case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
|
||||||
realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount;
|
realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_INLINEFONT:
|
case NODE_TYPE_NET_OPTION_NAME_INLINEFONT:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT:
|
case NODE_TYPE_NET_OPTION_NAME_INLINESCRIPT:
|
||||||
realBad = behaviorTypeCount;
|
realBad = behaviorTypeCount;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_EMPTY:
|
case NODE_TYPE_NET_OPTION_NAME_EMPTY:
|
||||||
realBad = abstractTypeCount || behaviorTypeCount;
|
realBad = abstractTypeCount || behaviorTypeCount;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_MEDIA:
|
case NODE_TYPE_NET_OPTION_NAME_MEDIA:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_MP4:
|
case NODE_TYPE_NET_OPTION_NAME_MP4:
|
||||||
realBad = abstractTypeCount || behaviorTypeCount || docTypeCount || requestTypeCount;
|
realBad = abstractTypeCount || behaviorTypeCount || docTypeCount || requestTypeCount;
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REDIRECT:
|
case NODE_TYPE_NET_OPTION_NAME_REDIRECT:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: {
|
case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE: {
|
||||||
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
|
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NODE_TYPE_NET_OPTION_NAME_REPLACE: {
|
||||||
|
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
|
||||||
|
if ( realBad ) { break; }
|
||||||
|
if ( requiresTrustedSource() ) {
|
||||||
|
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
|
||||||
|
realBad = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REPLACE: {
|
const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_REPLACE);
|
||||||
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
|
if ( parseReplaceValue(value) === undefined ) {
|
||||||
if ( realBad ) { break; }
|
this.astError = AST_ERROR_OPTION_BADVALUE;
|
||||||
if ( requiresTrustedSource() ) {
|
realBad = true;
|
||||||
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
|
}
|
||||||
realBad = true;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: {
|
||||||
const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_REPLACE);
|
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
|
||||||
if ( parseReplaceValue(value) === undefined ) {
|
if ( realBad ) { break; }
|
||||||
this.astError = AST_ERROR_OPTION_BADVALUE;
|
if ( requiresTrustedSource() ) {
|
||||||
realBad = true;
|
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
|
||||||
}
|
realBad = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: {
|
const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM);
|
||||||
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
|
if ( value !== '' && parseReplaceValue(value) === undefined ) {
|
||||||
if ( realBad ) { break; }
|
this.astError = AST_ERROR_OPTION_BADVALUE;
|
||||||
if ( requiresTrustedSource() ) {
|
realBad = true;
|
||||||
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
|
|
||||||
realBad = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM);
|
|
||||||
if ( value !== '' && parseReplaceValue(value) === undefined ) {
|
|
||||||
this.astError = AST_ERROR_OPTION_BADVALUE;
|
|
||||||
realBad = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM:
|
break;
|
||||||
realBad = abstractTypeCount || behaviorTypeCount;
|
}
|
||||||
break;
|
case NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM:
|
||||||
default:
|
realBad = abstractTypeCount || behaviorTypeCount;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if ( realBad ) {
|
if ( realBad ) {
|
||||||
const targetNode = this.getBranchFromType(modifierType);
|
const targetNode = this.getBranchFromType(modifierType);
|
||||||
|
@ -2061,15 +2059,15 @@ export class AstFilterParser {
|
||||||
parentBeg + optionEnd
|
parentBeg + optionEnd
|
||||||
);
|
);
|
||||||
switch ( nodeOptionType ) {
|
switch ( nodeOptionType ) {
|
||||||
case NODE_TYPE_NET_OPTION_NAME_DENYALLOW:
|
case NODE_TYPE_NET_OPTION_NAME_DENYALLOW:
|
||||||
this.linkDown(next, this.parseDomainList(next, '|'), 0b00000);
|
this.linkDown(next, this.parseDomainList(next, '|'), 0b00000);
|
||||||
break;
|
break;
|
||||||
case NODE_TYPE_NET_OPTION_NAME_FROM:
|
case NODE_TYPE_NET_OPTION_NAME_FROM:
|
||||||
case NODE_TYPE_NET_OPTION_NAME_TO:
|
case NODE_TYPE_NET_OPTION_NAME_TO:
|
||||||
this.linkDown(next, this.parseDomainList(next, '|', 0b11010));
|
this.linkDown(next, this.parseDomainList(next, '|', 0b11010));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.linkRight(prev, next);
|
this.linkRight(prev, next);
|
||||||
return this.throwHeadNode(head);
|
return this.throwHeadNode(head);
|
||||||
|
@ -2284,27 +2282,27 @@ export class AstFilterParser {
|
||||||
if ( (flags & NODE_FLAG_ERROR) !== 0 ) { continue; }
|
if ( (flags & NODE_FLAG_ERROR) !== 0 ) { continue; }
|
||||||
realBad = false;
|
realBad = false;
|
||||||
switch ( type ) {
|
switch ( type ) {
|
||||||
case NODE_TYPE_EXT_PATTERN_RESPONSEHEADER: {
|
case NODE_TYPE_EXT_PATTERN_RESPONSEHEADER: {
|
||||||
const pattern = this.getNodeString(targetNode);
|
const pattern = this.getNodeString(targetNode);
|
||||||
realBad =
|
realBad =
|
||||||
pattern !== '' && removableHTTPHeaders.has(pattern) === false ||
|
pattern !== '' && removableHTTPHeaders.has(pattern) === false ||
|
||||||
pattern === '' && isException === false;
|
pattern === '' && isException === false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN: {
|
||||||
|
if ( this.interactive !== true ) { break; }
|
||||||
|
if ( isException ) { break; }
|
||||||
|
const { trustedSource, trustedScriptletTokens } = this.options;
|
||||||
|
if ( trustedScriptletTokens instanceof Set === false ) { break; }
|
||||||
|
const token = this.getNodeString(targetNode);
|
||||||
|
if ( trustedScriptletTokens.has(token) && trustedSource !== true ) {
|
||||||
|
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
|
||||||
|
realBad = true;
|
||||||
}
|
}
|
||||||
case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN: {
|
break;
|
||||||
if ( this.interactive !== true ) { break; }
|
}
|
||||||
if ( isException ) { break; }
|
default:
|
||||||
const { trustedSource, trustedScriptletTokens } = this.options;
|
break;
|
||||||
if ( trustedScriptletTokens instanceof Set === false ) { break; }
|
|
||||||
const token = this.getNodeString(targetNode);
|
|
||||||
if ( trustedScriptletTokens.has(token) && trustedSource !== true ) {
|
|
||||||
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
|
|
||||||
realBad = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if ( realBad ) {
|
if ( realBad ) {
|
||||||
this.addNodeFlags(targetNode, NODE_FLAG_ERROR);
|
this.addNodeFlags(targetNode, NODE_FLAG_ERROR);
|
||||||
|
@ -2420,7 +2418,7 @@ export class AstFilterParser {
|
||||||
parentBeg + argsEnd
|
parentBeg + argsEnd
|
||||||
);
|
);
|
||||||
this.linkDown(next, this.parseExtPatternScriptletArglist(next));
|
this.linkDown(next, this.parseExtPatternScriptletArglist(next));
|
||||||
prev = this.linkRight(prev, next);
|
this.linkRight(prev, next);
|
||||||
return this.throwHeadNode(head);
|
return this.throwHeadNode(head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2474,12 +2472,12 @@ export class AstFilterParser {
|
||||||
const walker = this.getWalker(root);
|
const walker = this.getWalker(root);
|
||||||
for ( let node = walker.next(); node !== 0; node = walker.next() ) {
|
for ( let node = walker.next(); node !== 0; node = walker.next() ) {
|
||||||
switch ( this.getNodeType(node) ) {
|
switch ( this.getNodeType(node) ) {
|
||||||
case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN:
|
case NODE_TYPE_EXT_PATTERN_SCRIPTLET_TOKEN:
|
||||||
case NODE_TYPE_EXT_PATTERN_SCRIPTLET_ARG:
|
case NODE_TYPE_EXT_PATTERN_SCRIPTLET_ARG:
|
||||||
args.push(this.getNodeTransform(node));
|
args.push(this.getNodeTransform(node));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
walker.dispose();
|
walker.dispose();
|
||||||
|
@ -3206,6 +3204,7 @@ class ExtSelectorCompiler {
|
||||||
'matches-css-before',
|
'matches-css-before',
|
||||||
'matches-media',
|
'matches-media',
|
||||||
'matches-path',
|
'matches-path',
|
||||||
|
'matches-prop',
|
||||||
'min-text-length',
|
'min-text-length',
|
||||||
'others',
|
'others',
|
||||||
'shadow',
|
'shadow',
|
||||||
|
@ -3842,6 +3841,7 @@ class ExtSelectorCompiler {
|
||||||
case 'if-not':
|
case 'if-not':
|
||||||
return this.compileSelector(arg);
|
return this.compileSelector(arg);
|
||||||
case 'matches-attr':
|
case 'matches-attr':
|
||||||
|
case 'matches-prop':
|
||||||
return this.compileMatchAttrArgument(arg);
|
return this.compileMatchAttrArgument(arg);
|
||||||
case 'matches-css':
|
case 'matches-css':
|
||||||
return this.compileCSSDeclaration(arg);
|
return this.compileCSSDeclaration(arg);
|
||||||
|
@ -4037,7 +4037,7 @@ class ExtSelectorCompiler {
|
||||||
|
|
||||||
compileAttrList(s) {
|
compileAttrList(s) {
|
||||||
if ( s === '' ) { return s; }
|
if ( s === '' ) { return s; }
|
||||||
const attrs = s.split('\s*,\s*');
|
const attrs = s.split(/\s*,\s*/);
|
||||||
const out = [];
|
const out = [];
|
||||||
for ( const attr of attrs ) {
|
for ( const attr of attrs ) {
|
||||||
if ( attr !== '' ) {
|
if ( attr !== '' ) {
|
||||||
|
@ -4075,6 +4075,7 @@ export const proceduralOperatorTokens = new Map([
|
||||||
[ 'matches-css', 0b11 ],
|
[ 'matches-css', 0b11 ],
|
||||||
[ 'matches-media', 0b11 ],
|
[ 'matches-media', 0b11 ],
|
||||||
[ 'matches-path', 0b11 ],
|
[ 'matches-path', 0b11 ],
|
||||||
|
[ 'matches-prop', 0b11 ],
|
||||||
[ 'min-text-length', 0b01 ],
|
[ 'min-text-length', 0b01 ],
|
||||||
[ 'not', 0b01 ],
|
[ 'not', 0b01 ],
|
||||||
[ 'nth-ancestor', 0b00 ],
|
[ 'nth-ancestor', 0b00 ],
|
||||||
|
|
Loading…
Reference in New Issue