@@ -53,6 +53,9 @@ function safeSelf() {
53
53
'RegExp_exec' : self . RegExp . prototype . exec ,
54
54
'addEventListener' : self . EventTarget . prototype . addEventListener ,
55
55
'removeEventListener' : self . EventTarget . prototype . removeEventListener ,
56
+ 'fetch' : self . fetch ,
57
+ 'jsonParse' : self . JSON . parse . bind ( self . JSON ) ,
58
+ 'jsonStringify' : self . JSON . stringify . bind ( self . JSON ) ,
56
59
'log' : console . log . bind ( console ) ,
57
60
'uboLog' : function ( ...args ) {
58
61
if ( args . length === 0 ) { return ; }
@@ -103,10 +106,15 @@ builtinScriptlets.push({
103
106
function patternToRegex ( pattern , flags = undefined ) {
104
107
if ( pattern === '' ) { return / ^ / ; }
105
108
const match = / ^ \/ ( .+ ) \/ ( [ g i m s u ] * ) $ / . exec ( pattern ) ;
106
- if ( match !== null ) {
109
+ if ( match === null ) {
110
+ return new RegExp ( pattern . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) , flags ) ;
111
+ }
112
+ try {
107
113
return new RegExp ( match [ 1 ] , match [ 2 ] || flags ) ;
108
114
}
109
- return new RegExp ( pattern . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) , flags ) ;
115
+ catch ( ex ) {
116
+ }
117
+ return / ^ / ;
110
118
}
111
119
112
120
/******************************************************************************/
@@ -210,11 +218,14 @@ function runAtHtmlElement(fn) {
210
218
/******************************************************************************/
211
219
212
220
builtinScriptlets . push ( {
213
- name : 'get-extra-args-entries.fn' ,
214
- fn : getExtraArgsEntries ,
221
+ name : 'get-extra-args.fn' ,
222
+ fn : getExtraArgs ,
223
+ dependencies : [
224
+ 'get-extra-args-entries.fn' ,
225
+ ] ,
215
226
} ) ;
216
- function getExtraArgsEntries ( args , offset ) {
217
- return args . slice ( offset ) . reduce ( ( out , v , i , a ) => {
227
+ function getExtraArgs ( args , offset = 0 ) {
228
+ const entries = args . slice ( offset ) . reduce ( ( out , v , i , a ) => {
218
229
if ( ( i & 1 ) === 0 ) {
219
230
const rawValue = a [ i + 1 ] ;
220
231
const value = / ^ \d + $ / . test ( rawValue )
@@ -224,28 +235,7 @@ function getExtraArgsEntries(args, offset) {
224
235
}
225
236
return out ;
226
237
} , [ ] ) ;
227
- }
228
-
229
- builtinScriptlets . push ( {
230
- name : 'get-extra-args-map.fn' ,
231
- fn : getExtraArgsMap ,
232
- dependencies : [
233
- 'get-extra-args-entries.fn' ,
234
- ] ,
235
- } ) ;
236
- function getExtraArgsMap ( args , offset = 0 ) {
237
- return new Map ( getExtraArgsEntries ( args , offset ) ) ;
238
- }
239
-
240
- builtinScriptlets . push ( {
241
- name : 'get-extra-args.fn' ,
242
- fn : getExtraArgs ,
243
- dependencies : [
244
- 'get-extra-args-entries.fn' ,
245
- ] ,
246
- } ) ;
247
- function getExtraArgs ( args , offset = 0 ) {
248
- return Object . fromEntries ( getExtraArgsEntries ( args , offset ) ) ;
238
+ return Object . fromEntries ( entries ) ;
249
239
}
250
240
251
241
/******************************************************************************/
@@ -447,7 +437,7 @@ function setConstantCore(
447
437
if ( Math . abs ( cValue ) > 0x7FFF ) { return ; }
448
438
} else if ( trusted ) {
449
439
if ( cValue . startsWith ( '{' ) && cValue . endsWith ( '}' ) ) {
450
- try { cValue = JSON . parse ( cValue ) . value ; } catch ( ex ) { return ; }
440
+ try { cValue = safe . jsonParse ( cValue ) . value ; } catch ( ex ) { return ; }
451
441
}
452
442
} else {
453
443
return ;
@@ -2415,7 +2405,7 @@ function xmlPrune(
2415
2405
log ( `xmlPrune: ${ item . constructor . name } .${ item . nodeName } removed` ) ;
2416
2406
}
2417
2407
} catch ( ex ) {
2418
- if ( log ) { safeSelf ( ) . uboLog ( ex ) ; }
2408
+ log ( ex ) ;
2419
2409
}
2420
2410
return xmlDoc ;
2421
2411
} ;
@@ -2438,13 +2428,12 @@ function xmlPrune(
2438
2428
if ( arg instanceof Request ) { return arg . url ; }
2439
2429
return String ( arg ) ;
2440
2430
} ;
2441
- const realFetch = self . fetch ;
2442
2431
self . fetch = new Proxy ( self . fetch , {
2443
2432
apply : function ( target , thisArg , args ) {
2444
2433
if ( reUrl . test ( urlFromArg ( args [ 0 ] ) ) === false ) {
2445
2434
return Reflect . apply ( target , thisArg , args ) ;
2446
2435
}
2447
- return realFetch ( ...args ) . then ( realResponse =>
2436
+ return safe . fetch ( ...args ) . then ( realResponse =>
2448
2437
realResponse . text ( ) . then ( text =>
2449
2438
new Response ( pruneFromText ( text ) , {
2450
2439
status : realResponse . status ,
@@ -3329,4 +3318,103 @@ function trustedSetLocalStorageItem(key = '', value = '') {
3329
3318
setLocalStorageItemCore ( 'local' , true , key , value ) ;
3330
3319
}
3331
3320
3321
+ /*******************************************************************************
3322
+ *
3323
+ * trusted-replace-fetch-response.js
3324
+ *
3325
+ * Replaces response text content of fetch requests if all given parameters
3326
+ * match.
3327
+ *
3328
+ * Reference:
3329
+ * https://github.com/AdguardTeam/Scriptlets/blob/master/src/scriptlets/trusted-replace-fetch-response.js
3330
+ *
3331
+ **/
3332
+
3333
+ builtinScriptlets . push ( {
3334
+ name : 'trusted-replace-fetch-response.js' ,
3335
+ requiresTrust : true ,
3336
+ fn : trustedReplaceFetchResponse ,
3337
+ dependencies : [
3338
+ 'get-extra-args.fn' ,
3339
+ 'pattern-to-regex.fn' ,
3340
+ 'safe-self.fn' ,
3341
+ 'should-log.fn' ,
3342
+ ] ,
3343
+ } ) ;
3344
+ function trustedReplaceFetchResponse (
3345
+ pattern = '' ,
3346
+ replacement = '' ,
3347
+ propsToMatch = ''
3348
+ ) {
3349
+ const safe = safeSelf ( ) ;
3350
+ const extraArgs = getExtraArgs ( Array . from ( arguments ) , 3 ) ;
3351
+ const logLevel = shouldLog ( {
3352
+ log : pattern === '' || extraArgs . log ,
3353
+ } ) ;
3354
+ const log = logLevel ? ( ( ...args ) => { safe . uboLog ( ...args ) ; } ) : ( ( ) => { } ) ;
3355
+ if ( pattern === '*' ) { pattern = '.*' ; }
3356
+ const rePattern = patternToRegex ( pattern ) ;
3357
+ const propNeedles = new Map ( ) ;
3358
+ for ( const needle of propsToMatch . split ( / \s + / ) ) {
3359
+ const [ prop , value ] = needle . split ( ':' ) ;
3360
+ if ( prop === '' ) { continue ; }
3361
+ propNeedles . set ( prop , patternToRegex ( value ) ) ;
3362
+ }
3363
+ self . fetch = new Proxy ( self . fetch , {
3364
+ apply : function ( target , thisArg , args ) {
3365
+ if ( logLevel === true ) {
3366
+ log ( 'trusted-replace-fetch-response:' , JSON . stringify ( Array . from ( args ) ) . slice ( 1 , - 1 ) ) ;
3367
+ }
3368
+ const fetchPromise = Reflect . apply ( target , thisArg , args ) ;
3369
+ if ( pattern === '' ) { return fetchPromise ; }
3370
+ let skip = false ;
3371
+ if ( propNeedles . size !== 0 ) {
3372
+ const fetchDetails = { } ;
3373
+ if ( args [ 0 ] instanceof self . Request ) {
3374
+ Object . assign ( fetchDetails , args [ 0 ] ) ;
3375
+ } else {
3376
+ Object . assign ( fetchDetails , { url : args [ 0 ] } ) ;
3377
+ }
3378
+ if ( args [ 1 ] instanceof Object ) {
3379
+ Object . assign ( fetchDetails , args [ 1 ] ) ;
3380
+ }
3381
+ for ( const prop of Object . keys ( fetchDetails ) ) {
3382
+ let value = fetchDetails [ prop ] ;
3383
+ if ( typeof value !== 'string' ) {
3384
+ try { value = JSON . stringify ( value ) ; }
3385
+ catch ( ex ) { }
3386
+ }
3387
+ if ( typeof value !== 'string' ) { continue ; }
3388
+ const needle = propNeedles . get ( prop ) ;
3389
+ if ( needle === undefined ) { continue ; }
3390
+ if ( needle . test ( value ) ) { continue ; }
3391
+ skip = true ;
3392
+ break ;
3393
+ }
3394
+ }
3395
+ if ( skip ) { return fetchPromise ; }
3396
+ return fetchPromise . then ( responseBefore => {
3397
+ return responseBefore . text ( ) . then ( textBefore => {
3398
+ const textAfter = textBefore . replace ( rePattern , replacement ) ;
3399
+ const responseAfter = new Response ( textAfter , {
3400
+ status : responseBefore . status ,
3401
+ statusText : responseBefore . statusText ,
3402
+ headers : responseBefore . headers ,
3403
+ } ) ;
3404
+ Object . defineProperties ( responseAfter , {
3405
+ ok : { value : responseBefore . ok } ,
3406
+ redirected : { value : responseBefore . redirected } ,
3407
+ type : { value : responseBefore . type } ,
3408
+ url : { value : responseBefore . url } ,
3409
+ } ) ;
3410
+ return responseAfter ;
3411
+ } ) . catch ( reason => {
3412
+ log ( 'trusted-replace-fetch-response:' , reason ) ;
3413
+ return responseBefore ;
3414
+ } ) ;
3415
+ } ) ;
3416
+ }
3417
+ } ) ;
3418
+ }
3419
+
3332
3420
/******************************************************************************/
0 commit comments