Skip to content

Commit

Permalink
New static network filter option urlskip=
Browse files Browse the repository at this point in the history
Related issue:
uBlockOrigin/uBlock-issues#3206

The main purpose is to bypass URLs designed to track whether a user
visited a specific URL, typically used in click-tracking links.

The `urlskip=` option ...

- ... is valid only when used in a trusted filter list
- ... is enforced only on top documents
- ... is enforced on both blocked and non-blocked documents
- ... is a modifier, i.e. it cannot be used along with other
      modifier options in a single filter

The syntax is `urlskip=[steps]`, where steps is a space-separated
list of extraction directives detailing what action to perform on
the current URL.

The only supported directive in this first commit is `?name`,
which purpose is to extract the value of a named URL parameter
and use the result as the new URL. Example:

  ||example.com/path/to/tracker$urlskip=?url

The above filter will cause navigation to

  https://example.com/path/to/tracker?url=https://example.org/

to automatically bypass navigation to `example.com` and navigate
directly to

  https://example.org/

It is possible to recursively extract URL parameters by using
more than one directive, example:

  ||example.com/path/to/tracker$urlskip=?url ?to

More extraction capabilities may be added in the future.
  • Loading branch information
gorhill committed Sep 15, 2024
1 parent 4b285c0 commit 266ec48
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 127 deletions.
3 changes: 3 additions & 0 deletions src/js/filtering-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ export const FilteringContext = class {
this.stype = a;
}

isRootDocument() {
return (this.itype & MAIN_FRAME) !== 0;
}
isDocument() {
return (this.itype & FRAME_ANY) !== 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/js/logger-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ const processLoggerEntries = function(response) {
parsed.type === 'main_frame' &&
parsed.aliased === false && (
parsed.filter === undefined ||
parsed.filter.modifier !== true
parsed.filter.modifier !== true && parsed.filter.source !== 'redirect'
)
) {
const separator = createLogSeparator(parsed, unboxed.url);
Expand Down
32 changes: 20 additions & 12 deletions src/js/pagestore.js
Original file line number Diff line number Diff line change
Expand Up @@ -933,26 +933,34 @@ const PageStore = class {
}

redirectNonBlockedRequest(fctxt) {
const transformDirectives = staticNetFilteringEngine.transformRequest(fctxt);
const pruneDirectives = fctxt.redirectURL === undefined &&
staticNetFilteringEngine.hasQuery(fctxt) &&
staticNetFilteringEngine.filterQuery(fctxt) ||
undefined;
if ( transformDirectives === undefined && pruneDirectives === undefined ) { return; }
if ( logger.enabled !== true ) { return; }
if ( transformDirectives !== undefined ) {
fctxt.pushFilters(transformDirectives.map(a => a.logData()));
}
if ( pruneDirectives !== undefined ) {
fctxt.pushFilters(pruneDirectives.map(a => a.logData()));
const directives = [];
staticNetFilteringEngine.transformRequest(fctxt, directives);
if ( staticNetFilteringEngine.hasQuery(fctxt) ) {
staticNetFilteringEngine.filterQuery(fctxt, directives);
}
if ( directives.length === 0 ) { return; }
if ( logger.enabled !== true ) { return; }
fctxt.pushFilters(directives.map(a => a.logData()));
if ( fctxt.redirectURL === undefined ) { return; }
fctxt.pushFilter({
source: 'redirect',
raw: fctxt.redirectURL
});
}

skipMainDocument(fctxt) {
const directives = staticNetFilteringEngine.urlSkip(fctxt);
if ( directives === undefined ) { return; }
if ( logger.enabled !== true ) { return; }
fctxt.pushFilters(directives.map(a => a.logData()));
if ( fctxt.redirectURL !== undefined ) {
fctxt.pushFilter({
source: 'redirect',
raw: fctxt.redirectURL
});
}
}

filterCSPReport(fctxt) {
if (
sessionSwitches.evaluateZ(
Expand Down
19 changes: 19 additions & 0 deletions src/js/static-filtering-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ export const NODE_TYPE_NET_OPTION_NAME_REPLACE = iota++;
export const NODE_TYPE_NET_OPTION_NAME_SCRIPT = iota++;
export const NODE_TYPE_NET_OPTION_NAME_SHIDE = iota++;
export const NODE_TYPE_NET_OPTION_NAME_TO = iota++;
export const NODE_TYPE_NET_OPTION_NAME_URLSKIP = iota++;
export const NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM = iota++;
export const NODE_TYPE_NET_OPTION_NAME_XHR = iota++;
export const NODE_TYPE_NET_OPTION_NAME_WEBRTC = iota++;
Expand Down Expand Up @@ -274,6 +275,7 @@ export const nodeTypeFromOptionName = new Map([
[ 'shide', NODE_TYPE_NET_OPTION_NAME_SHIDE ],
/* synonym */ [ 'specifichide', NODE_TYPE_NET_OPTION_NAME_SHIDE ],
[ 'to', NODE_TYPE_NET_OPTION_NAME_TO ],
[ 'urlskip', NODE_TYPE_NET_OPTION_NAME_URLSKIP ],
[ 'uritransform', NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM ],
[ 'xhr', NODE_TYPE_NET_OPTION_NAME_XHR ],
/* synonym */ [ 'xmlhttprequest', NODE_TYPE_NET_OPTION_NAME_XHR ],
Expand Down Expand Up @@ -1441,6 +1443,7 @@ export class AstFilterParser {
case NODE_TYPE_NET_OPTION_NAME_REDIRECT:
case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE:
case NODE_TYPE_NET_OPTION_NAME_REPLACE:
case NODE_TYPE_NET_OPTION_NAME_URLSKIP:
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM:
realBad = isNegated || (isException || hasValue) === false ||
modifierType !== 0;
Expand Down Expand Up @@ -1519,6 +1522,21 @@ export class AstFilterParser {
}
break;
}
case NODE_TYPE_NET_OPTION_NAME_URLSKIP: {
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
if ( realBad ) { break; }
if ( requiresTrustedSource() ) {
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
realBad = true;
break;
}
const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLSKIP);
if ( value.startsWith('?') === false || value.length < 2 ) {
this.astError = AST_ERROR_OPTION_BADVALUE;
realBad = true;
}
break;
}
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: {
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
if ( realBad ) { break; }
Expand Down Expand Up @@ -3139,6 +3157,7 @@ export const netOptionTokenDescriptors = new Map([
[ 'shide', { } ],
/* synonym */ [ 'specifichide', { } ],
[ 'to', { mustAssign: true } ],
[ 'urlskip', { mustAssign: true } ],
[ 'uritransform', { mustAssign: true } ],
[ 'xhr', { canNegate: true } ],
/* synonym */ [ 'xmlhttprequest', { canNegate: true } ],
Expand Down
Loading

0 comments on commit 266ec48

Please sign in to comment.