Skip to content

Commit 5ebdbf3

Browse files
committed
Add static network filter option: permissions
Related discussion: uBlockOrigin/uBlock-issues#2714 Reference: https://adguard.com/kb/general/ad-filtering/create-own-filters/#permissions-modifier Example: ||example.org^$permissions=browsing-topics=() Difference with AdGuard's syntax: use `|` to separate permissions policy directives instead of `\,` -- uBO will replace instances of `|` with `, `: *$permissions=oversized-images=()|unsized-media=() Eventually uBO will support AdGuard's syntax of using escaped commas, but not for this first iteration.
1 parent 8d09c56 commit 5ebdbf3

File tree

3 files changed

+71
-13
lines changed

3 files changed

+71
-13
lines changed

‎src/js/static-filtering-parser.js‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export const NODE_TYPE_NET_OPTION_NAME_MP4 = iota++;
178178
export const NODE_TYPE_NET_OPTION_NAME_NOOP = iota++;
179179
export const NODE_TYPE_NET_OPTION_NAME_OBJECT = iota++;
180180
export const NODE_TYPE_NET_OPTION_NAME_OTHER = iota++;
181+
export const NODE_TYPE_NET_OPTION_NAME_PERMISSIONS = iota++;
181182
export const NODE_TYPE_NET_OPTION_NAME_PING = iota++;
182183
export const NODE_TYPE_NET_OPTION_NAME_POPUNDER = iota++;
183184
export const NODE_TYPE_NET_OPTION_NAME_POPUP = iota++;
@@ -252,6 +253,7 @@ export const nodeTypeFromOptionName = new Map([
252253
[ 'object', NODE_TYPE_NET_OPTION_NAME_OBJECT ],
253254
/* synonym */ [ 'object-subrequest', NODE_TYPE_NET_OPTION_NAME_OBJECT ],
254255
[ 'other', NODE_TYPE_NET_OPTION_NAME_OTHER ],
256+
[ 'permissions', NODE_TYPE_NET_OPTION_NAME_PERMISSIONS ],
255257
[ 'ping', NODE_TYPE_NET_OPTION_NAME_PING ],
256258
/* synonym */ [ 'beacon', NODE_TYPE_NET_OPTION_NAME_PING ],
257259
[ 'popunder', NODE_TYPE_NET_OPTION_NAME_POPUNDER ],
@@ -1293,6 +1295,11 @@ export class AstFilterParser {
12931295
case NODE_TYPE_NET_OPTION_NAME_MATCHCASE:
12941296
realBad = this.isRegexPattern() === false;
12951297
break;
1298+
case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
1299+
realBad = modifierType !== 0 || (hasValue || isException) === false;
1300+
if ( realBad ) { break; }
1301+
modifierType = type;
1302+
break;
12961303
case NODE_TYPE_NET_OPTION_NAME_PING:
12971304
case NODE_TYPE_NET_OPTION_NAME_WEBSOCKET:
12981305
realBad = hasValue;
@@ -1349,6 +1356,7 @@ export class AstFilterParser {
13491356
realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount;
13501357
break;
13511358
case NODE_TYPE_NET_OPTION_NAME_CSP:
1359+
case NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
13521360
realBad = abstractTypeCount || behaviorTypeCount || requestTypeCount;
13531361
break;
13541362
case NODE_TYPE_NET_OPTION_NAME_INLINEFONT:

‎src/js/static-net-filtering.js‎

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,22 @@ const MODIFIER_TYPE_REDIRECT = 1;
182182
const MODIFIER_TYPE_REDIRECTRULE = 2;
183183
const MODIFIER_TYPE_REMOVEPARAM = 3;
184184
const MODIFIER_TYPE_CSP = 4;
185+
const MODIFIER_TYPE_PERMISSIONS = 5;
185186

186187
const modifierTypeFromName = new Map([
187188
[ 'redirect', MODIFIER_TYPE_REDIRECT ],
188189
[ 'redirect-rule', MODIFIER_TYPE_REDIRECTRULE ],
189190
[ 'removeparam', MODIFIER_TYPE_REMOVEPARAM ],
190191
[ 'csp', MODIFIER_TYPE_CSP ],
192+
[ 'permissions', MODIFIER_TYPE_PERMISSIONS ],
191193
]);
192194

193195
const modifierNameFromType = new Map([
194196
[ MODIFIER_TYPE_REDIRECT, 'redirect' ],
195197
[ MODIFIER_TYPE_REDIRECTRULE, 'redirect-rule' ],
196198
[ MODIFIER_TYPE_REMOVEPARAM, 'removeparam' ],
197199
[ MODIFIER_TYPE_CSP, 'csp' ],
200+
[ MODIFIER_TYPE_PERMISSIONS, 'permissions' ],
198201
]);
199202

200203
//const typeValueFromCatBits = catBits => (catBits >>> TypeBitsOffset) & 0b11111;
@@ -3169,6 +3172,7 @@ class FilterCompiler {
31693172
]);
31703173
this.modifierIdToNormalizedId = new Map([
31713174
[ sfp.NODE_TYPE_NET_OPTION_NAME_CSP, MODIFIER_TYPE_CSP ],
3175+
[ sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS, MODIFIER_TYPE_PERMISSIONS ],
31723176
[ sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT, MODIFIER_TYPE_REDIRECT ],
31733177
[ sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE, MODIFIER_TYPE_REDIRECTRULE ],
31743178
[ sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM, MODIFIER_TYPE_REMOVEPARAM ],
@@ -3438,6 +3442,12 @@ class FilterCompiler {
34383442
this.processMethodOption(parser.getNetOptionValue(id));
34393443
this.optionUnitBits |= this.METHOD_BIT;
34403444
break;
3445+
case sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
3446+
if ( this.processModifierOption(id, parser.getNetOptionValue(id)) === false ) {
3447+
return false;
3448+
}
3449+
this.optionUnitBits |= this.PERMISSIONS_BIT;
3450+
break;
34413451
case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT: {
34423452
const actualId = this.action === AllowAction
34433453
? sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE
@@ -3554,6 +3564,7 @@ class FilterCompiler {
35543564
case sfp.NODE_TYPE_NET_OPTION_NAME_FROM:
35553565
case sfp.NODE_TYPE_NET_OPTION_NAME_HEADER:
35563566
case sfp.NODE_TYPE_NET_OPTION_NAME_METHOD:
3567+
case sfp.NODE_TYPE_NET_OPTION_NAME_PERMISSIONS:
35573568
case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECT:
35583569
case sfp.NODE_TYPE_NET_OPTION_NAME_REDIRECTRULE:
35593570
case sfp.NODE_TYPE_NET_OPTION_NAME_REMOVEPARAM:
@@ -3622,8 +3633,12 @@ class FilterCompiler {
36223633
this.optionUnitBits |= this.NOT_TYPE_BIT;
36233634
}
36243635

3625-
// CSP directives implicitly apply only to document/subdocument.
3626-
if ( this.modifyType === MODIFIER_TYPE_CSP ) {
3636+
// CSP/permissions options implicitly apply only to
3637+
// document/subdocument.
3638+
if (
3639+
this.modifyType === MODIFIER_TYPE_CSP ||
3640+
this.modifyType === MODIFIER_TYPE_PERMISSIONS
3641+
) {
36273642
if ( this.typeBits === 0 ) {
36283643
this.processTypeOption(sfp.NODE_TYPE_NET_OPTION_NAME_DOC, false);
36293644
this.processTypeOption(sfp.NODE_TYPE_NET_OPTION_NAME_FRAME, false);
@@ -4013,17 +4028,18 @@ class FilterCompiler {
40134028
}
40144029
}
40154030

4016-
FilterCompiler.prototype.FROM_BIT = 0b00000000001;
4017-
FilterCompiler.prototype.TO_BIT = 0b00000000010;
4018-
FilterCompiler.prototype.DENYALLOW_BIT = 0b00000000100;
4019-
FilterCompiler.prototype.HEADER_BIT = 0b00000001000;
4020-
FilterCompiler.prototype.STRICT_PARTY_BIT = 0b00000010000;
4021-
FilterCompiler.prototype.CSP_BIT = 0b00000100000;
4022-
FilterCompiler.prototype.REMOVEPARAM_BIT = 0b00001000000;
4023-
FilterCompiler.prototype.REDIRECT_BIT = 0b00010000000;
4024-
FilterCompiler.prototype.NOT_TYPE_BIT = 0b00100000000;
4025-
FilterCompiler.prototype.IMPORTANT_BIT = 0b01000000000;
4026-
FilterCompiler.prototype.METHOD_BIT = 0b10000000000;
4031+
FilterCompiler.prototype.FROM_BIT = 0b000000000001;
4032+
FilterCompiler.prototype.TO_BIT = 0b000000000010;
4033+
FilterCompiler.prototype.DENYALLOW_BIT = 0b000000000100;
4034+
FilterCompiler.prototype.HEADER_BIT = 0b000000001000;
4035+
FilterCompiler.prototype.STRICT_PARTY_BIT = 0b000000010000;
4036+
FilterCompiler.prototype.CSP_BIT = 0b000000100000;
4037+
FilterCompiler.prototype.REMOVEPARAM_BIT = 0b000001000000;
4038+
FilterCompiler.prototype.REDIRECT_BIT = 0b000010000000;
4039+
FilterCompiler.prototype.NOT_TYPE_BIT = 0b000100000000;
4040+
FilterCompiler.prototype.IMPORTANT_BIT = 0b001000000000;
4041+
FilterCompiler.prototype.METHOD_BIT = 0b010000000000;
4042+
FilterCompiler.prototype.PERMISSIONS_BIT = 0b100000000000;
40274043

40284044
FilterCompiler.prototype.FILTER_OK = 0;
40294045
FilterCompiler.prototype.FILTER_INVALID = 1;

‎src/js/traffic.js‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ const onHeadersReceived = function(details) {
557557
modifiedHeaders = true;
558558
}
559559

560+
if ( injectPP(fctxt, pageStore, responseHeaders) === true ) {
561+
modifiedHeaders = true;
562+
}
563+
560564
// https://bugzilla.mozilla.org/show_bug.cgi?id=1376932
561565
// Prevent document from being cached by the browser if we modified it,
562566
// either through HTML filtering and/or modified response headers.
@@ -1004,6 +1008,36 @@ const injectCSP = function(fctxt, pageStore, responseHeaders) {
10041008

10051009
/******************************************************************************/
10061010

1011+
const injectPP = function(fctxt, pageStore, responseHeaders) {
1012+
const permissions = [];
1013+
const directives = staticNetFilteringEngine.matchAndFetchModifiers(fctxt, 'permissions');
1014+
if ( directives !== undefined ) {
1015+
for ( const directive of directives ) {
1016+
if ( directive.result !== 1 ) { continue; }
1017+
permissions.push(directive.value.replace('|', ', '));
1018+
}
1019+
}
1020+
1021+
if ( logger.enabled && directives !== undefined ) {
1022+
fctxt.setRealm('network')
1023+
.pushFilters(directives.map(a => a.logData()))
1024+
.toLogger();
1025+
}
1026+
1027+
if ( permissions.length === 0 ) { return; }
1028+
1029+
µb.updateToolbarIcon(fctxt.tabId, 0x02);
1030+
1031+
responseHeaders.push({
1032+
name: 'permissions-policy',
1033+
value: permissions.join(', ')
1034+
});
1035+
1036+
return true;
1037+
};
1038+
1039+
/******************************************************************************/
1040+
10071041
// https://github.com/gorhill/uBlock/issues/1163
10081042
// "Block elements by size".
10091043
// https://github.com/gorhill/uBlock/issues/1390#issuecomment-187310719

0 commit comments

Comments
 (0)