Skip to content

Commit 266ec48

Browse files
committed
New static network filter option urlskip=
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.
1 parent 4b285c0 commit 266ec48

File tree

6 files changed

+215
-127
lines changed

6 files changed

+215
-127
lines changed

src/js/filtering-context.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ export const FilteringContext = class {
163163
this.stype = a;
164164
}
165165

166+
isRootDocument() {
167+
return (this.itype & MAIN_FRAME) !== 0;
168+
}
166169
isDocument() {
167170
return (this.itype & FRAME_ANY) !== 0;
168171
}

src/js/logger-ui.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ const processLoggerEntries = function(response) {
331331
parsed.type === 'main_frame' &&
332332
parsed.aliased === false && (
333333
parsed.filter === undefined ||
334-
parsed.filter.modifier !== true
334+
parsed.filter.modifier !== true && parsed.filter.source !== 'redirect'
335335
)
336336
) {
337337
const separator = createLogSeparator(parsed, unboxed.url);

src/js/pagestore.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -933,26 +933,34 @@ const PageStore = class {
933933
}
934934

935935
redirectNonBlockedRequest(fctxt) {
936-
const transformDirectives = staticNetFilteringEngine.transformRequest(fctxt);
937-
const pruneDirectives = fctxt.redirectURL === undefined &&
938-
staticNetFilteringEngine.hasQuery(fctxt) &&
939-
staticNetFilteringEngine.filterQuery(fctxt) ||
940-
undefined;
941-
if ( transformDirectives === undefined && pruneDirectives === undefined ) { return; }
942-
if ( logger.enabled !== true ) { return; }
943-
if ( transformDirectives !== undefined ) {
944-
fctxt.pushFilters(transformDirectives.map(a => a.logData()));
945-
}
946-
if ( pruneDirectives !== undefined ) {
947-
fctxt.pushFilters(pruneDirectives.map(a => a.logData()));
936+
const directives = [];
937+
staticNetFilteringEngine.transformRequest(fctxt, directives);
938+
if ( staticNetFilteringEngine.hasQuery(fctxt) ) {
939+
staticNetFilteringEngine.filterQuery(fctxt, directives);
948940
}
941+
if ( directives.length === 0 ) { return; }
942+
if ( logger.enabled !== true ) { return; }
943+
fctxt.pushFilters(directives.map(a => a.logData()));
949944
if ( fctxt.redirectURL === undefined ) { return; }
950945
fctxt.pushFilter({
951946
source: 'redirect',
952947
raw: fctxt.redirectURL
953948
});
954949
}
955950

951+
skipMainDocument(fctxt) {
952+
const directives = staticNetFilteringEngine.urlSkip(fctxt);
953+
if ( directives === undefined ) { return; }
954+
if ( logger.enabled !== true ) { return; }
955+
fctxt.pushFilters(directives.map(a => a.logData()));
956+
if ( fctxt.redirectURL !== undefined ) {
957+
fctxt.pushFilter({
958+
source: 'redirect',
959+
raw: fctxt.redirectURL
960+
});
961+
}
962+
}
963+
956964
filterCSPReport(fctxt) {
957965
if (
958966
sessionSwitches.evaluateZ(

src/js/static-filtering-parser.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ export const NODE_TYPE_NET_OPTION_NAME_REPLACE = iota++;
191191
export const NODE_TYPE_NET_OPTION_NAME_SCRIPT = iota++;
192192
export const NODE_TYPE_NET_OPTION_NAME_SHIDE = iota++;
193193
export const NODE_TYPE_NET_OPTION_NAME_TO = iota++;
194+
export const NODE_TYPE_NET_OPTION_NAME_URLSKIP = iota++;
194195
export const NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM = iota++;
195196
export const NODE_TYPE_NET_OPTION_NAME_XHR = iota++;
196197
export const NODE_TYPE_NET_OPTION_NAME_WEBRTC = iota++;
@@ -274,6 +275,7 @@ export const nodeTypeFromOptionName = new Map([
274275
[ 'shide', NODE_TYPE_NET_OPTION_NAME_SHIDE ],
275276
/* synonym */ [ 'specifichide', NODE_TYPE_NET_OPTION_NAME_SHIDE ],
276277
[ 'to', NODE_TYPE_NET_OPTION_NAME_TO ],
278+
[ 'urlskip', NODE_TYPE_NET_OPTION_NAME_URLSKIP ],
277279
[ 'uritransform', NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM ],
278280
[ 'xhr', NODE_TYPE_NET_OPTION_NAME_XHR ],
279281
/* synonym */ [ 'xmlhttprequest', NODE_TYPE_NET_OPTION_NAME_XHR ],
@@ -1441,6 +1443,7 @@ export class AstFilterParser {
14411443
case NODE_TYPE_NET_OPTION_NAME_REDIRECT:
14421444
case NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE:
14431445
case NODE_TYPE_NET_OPTION_NAME_REPLACE:
1446+
case NODE_TYPE_NET_OPTION_NAME_URLSKIP:
14441447
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM:
14451448
realBad = isNegated || (isException || hasValue) === false ||
14461449
modifierType !== 0;
@@ -1519,6 +1522,21 @@ export class AstFilterParser {
15191522
}
15201523
break;
15211524
}
1525+
case NODE_TYPE_NET_OPTION_NAME_URLSKIP: {
1526+
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
1527+
if ( realBad ) { break; }
1528+
if ( requiresTrustedSource() ) {
1529+
this.astError = AST_ERROR_UNTRUSTED_SOURCE;
1530+
realBad = true;
1531+
break;
1532+
}
1533+
const value = this.getNetOptionValue(NODE_TYPE_NET_OPTION_NAME_URLSKIP);
1534+
if ( value.startsWith('?') === false || value.length < 2 ) {
1535+
this.astError = AST_ERROR_OPTION_BADVALUE;
1536+
realBad = true;
1537+
}
1538+
break;
1539+
}
15221540
case NODE_TYPE_NET_OPTION_NAME_URLTRANSFORM: {
15231541
realBad = abstractTypeCount || behaviorTypeCount || unredirectableTypeCount;
15241542
if ( realBad ) { break; }
@@ -3139,6 +3157,7 @@ export const netOptionTokenDescriptors = new Map([
31393157
[ 'shide', { } ],
31403158
/* synonym */ [ 'specifichide', { } ],
31413159
[ 'to', { mustAssign: true } ],
3160+
[ 'urlskip', { mustAssign: true } ],
31423161
[ 'uritransform', { mustAssign: true } ],
31433162
[ 'xhr', { canNegate: true } ],
31443163
/* synonym */ [ 'xmlhttprequest', { canNegate: true } ],

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy