Fix properly reporting invalid filter options

Related issue:
- https://github.com/uBlockOrigin/uBlock-issues/issues/1134

Specifically;

- `beacon`, `ping`, and `websocket` cannot be redirected;
- it's ok to not specify a type when redirecting to `empty`
  resource;
- `csp=` option can't be mixed with other types, redirec
  directives, and more `csp=` options.
This commit is contained in:
Raymond Hill 2020-07-05 14:11:15 -04:00
parent 2476f5f830
commit dc64cfbd97
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
2 changed files with 37 additions and 27 deletions

View File

@ -23,6 +23,8 @@ $script,redirect=noop.js
*$redirect=empty
*$xhr,redirect=empty
*$csp=default-src 'none'
@ -41,5 +43,10 @@ $script,redirect=noop.js
! can't mix csp with other types or redirect directives
*$csp=default-src 'none',empty
*$csp=default-src 'none',redirect=empty
*$csp=default-src 'none',redirect=empty
*$redirect=empty,csp=default-src 'none'
*$csp=default-src 'none',xhr
*$csp=default-src 'none',ghide
*$csp=default-src 'none',csp=script-src 'none'
! bad regex
/(abc|def/$xhr

View File

@ -1908,7 +1908,8 @@ const OPTDomainList = 1 << 13;
const OPTType = 1 << 14;
const OPTNetworkType = 1 << 15;
const OPTRedirectType = 1 << 16;
const OPTNotSupported = 1 << 17;
const OPTRedirectableType = 1 << 17;
const OPTNotSupported = 1 << 18;
/******************************************************************************/
@ -1993,6 +1994,7 @@ Parser.prototype.OPTDomainList = OPTDomainList;
Parser.prototype.OPTType = OPTType;
Parser.prototype.OPTNetworkType = OPTNetworkType;
Parser.prototype.OPTRedirectType = OPTRedirectType;
Parser.prototype.OPTRedirectableType = OPTRedirectableType;
Parser.prototype.OPTNotSupported = OPTNotSupported;
/******************************************************************************/
@ -2006,41 +2008,41 @@ const netOptionTokens = new Map([
[ 'badfilter', OPTTokenBadfilter ],
[ 'cname', OPTTokenCname | OPTAllowOnly | OPTType ],
[ 'csp', OPTTokenCsp | OPTMustAssign | OPTAllowMayAssign ],
[ 'css', OPTTokenCss | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'stylesheet', OPTTokenCss | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'css', OPTTokenCss | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'stylesheet', OPTTokenCss | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'denyallow', OPTTokenDenyAllow | OPTMustAssign | OPTDomainList ],
[ 'doc', OPTTokenDoc | OPTType | OPTNetworkType ],
[ 'document', OPTTokenDoc | OPTType | OPTNetworkType ],
[ 'domain', OPTTokenDomain | OPTMustAssign | OPTDomainList ],
[ 'ehide', OPTTokenEhide | OPTType ],
[ 'elemhide', OPTTokenEhide | OPTType ],
[ 'empty', OPTTokenEmpty | OPTBlockOnly | OPTType | OPTNetworkType | OPTBlockOnly | OPTRedirectType ],
[ 'frame', OPTTokenFrame | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'subdocument', OPTTokenFrame | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'font', OPTTokenFont | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'empty', OPTTokenEmpty | OPTBlockOnly | OPTRedirectType ],
[ 'frame', OPTTokenFrame | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'subdocument', OPTTokenFrame | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'font', OPTTokenFont | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'genericblock', OPTTokenGenericblock | OPTNotSupported ],
[ 'ghide', OPTTokenGhide | OPTType ],
[ 'generichide', OPTTokenGhide | OPTType ],
[ 'image', OPTTokenImage | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'image', OPTTokenImage | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'important', OPTTokenImportant | OPTBlockOnly ],
[ 'inline-font', OPTTokenInlineFont | OPTType ],
[ 'inline-script', OPTTokenInlineScript | OPTType ],
[ 'media', OPTTokenMedia | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'mp4', OPTTokenMp4 | OPTType | OPTNetworkType | OPTBlockOnly | OPTRedirectType ],
[ 'object', OPTTokenObject | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'media', OPTTokenMedia | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'mp4', OPTTokenMp4 | OPTType | OPTNetworkType | OPTBlockOnly | OPTRedirectType | OPTRedirectableType ],
[ 'object', OPTTokenObject | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'object-subrequest', OPTTokenObject | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'other', OPTTokenOther | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'other', OPTTokenOther | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'ping', OPTTokenPing | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'beacon', OPTTokenPing | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'popunder', OPTTokenPopunder | OPTType ],
[ 'popup', OPTTokenPopup | OPTType ],
[ 'redirect', OPTTokenRedirect | OPTMustAssign | OPTBlockOnly | OPTRedirectType ],
[ 'redirect-rule', OPTTokenRedirectRule | OPTMustAssign | OPTBlockOnly | OPTRedirectType ],
[ 'script', OPTTokenScript | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'script', OPTTokenScript | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'shide', OPTTokenShide | OPTType ],
[ 'specifichide', OPTTokenShide | OPTType ],
[ 'xhr', OPTTokenXhr | OPTCanNegate| OPTType | OPTNetworkType ],
[ 'xmlhttprequest', OPTTokenXhr | OPTCanNegate | OPTType | OPTNetworkType ],
[ 'xhr', OPTTokenXhr | OPTCanNegate| OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'xmlhttprequest', OPTTokenXhr | OPTCanNegate | OPTType | OPTNetworkType | OPTRedirectableType ],
[ 'webrtc', OPTTokenWebrtc | OPTNotSupported ],
[ 'websocket', OPTTokenWebsocket | OPTCanNegate | OPTType | OPTNetworkType ],
]);
@ -2103,7 +2105,7 @@ const NetOptionsIterator = class {
const slices = this.parser.slices;
const optSlices = this.optSlices;
let typeCount = 0;
let networkTypeCount = 0;
let redirectableTypeCount = 0;
let redirectIndex = -1;
let cspIndex = -1;
let writePtr = 0;
@ -2158,8 +2160,8 @@ const NetOptionsIterator = class {
// Keep count of types
if ( hasBits(descriptor, OPTType) ) {
typeCount += 1;
if ( hasBits(descriptor, OPTNetworkType) ) {
networkTypeCount += 1;
if ( hasBits(descriptor, OPTRedirectableType) ) {
redirectableTypeCount += 1;
}
}
// Only one `redirect` or `csp` can be present
@ -2215,8 +2217,8 @@ const NetOptionsIterator = class {
}
// Invalid combinations of options
//
// `csp` can't be used with any other types
if ( cspIndex !== -1 && typeCount !== 0 ) {
// `csp` can't be used with any other types or redirection
if ( cspIndex !== -1 && ( typeCount !== 0 || redirectIndex !== -1 ) ) {
optSlices[cspIndex] = OPTTokenInvalid;
if ( this.interactive ) {
this.parser.markSlices(
@ -2226,17 +2228,18 @@ const NetOptionsIterator = class {
);
}
}
// `redirect` requires one single network type, EXCEPT for when we
// `redirect` requires one single redirectable type, EXCEPT for when we
// redirect to `empty`, in which case it is allowed to not have any
// network type specified.
if (
( redirectIndex !== -1 ) &&
( typeCount !== 1 || networkTypeCount !== 1 ) &&
( typeCount !== 0 || networkTypeCount !== 0 ||
redirectIndex !== -1 &&
redirectableTypeCount !== 1 && (
redirectableTypeCount !== 0 ||
typeCount !== 0 ||
this.parser.raw.slice(
this.parser.slices[optSlices[redirectIndex+4]+1],
this.parser.slices[optSlices[redirectIndex+0]+1],
this.parser.slices[optSlices[redirectIndex+5]+1]
) !== 'empty'
).endsWith('empty') === false
)
) {
optSlices[redirectIndex] = OPTTokenInvalid;