@@ -53,6 +53,9 @@ function safeSelf() {
5353 'RegExp_exec' : self . RegExp . prototype . exec ,
5454 'addEventListener' : self . EventTarget . prototype . addEventListener ,
5555 '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 ) ,
5659 'log' : console . log . bind ( console ) ,
5760 'uboLog' : function ( ...args ) {
5861 if ( args . length === 0 ) { return ; }
@@ -103,10 +106,15 @@ builtinScriptlets.push({
103106function patternToRegex ( pattern , flags = undefined ) {
104107 if ( pattern === '' ) { return / ^ / ; }
105108 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 {
107113 return new RegExp ( match [ 1 ] , match [ 2 ] || flags ) ;
108114 }
109- return new RegExp ( pattern . replace ( / [ . * + ? ^ $ { } ( ) | [ \] \\ ] / g, '\\$&' ) , flags ) ;
115+ catch ( ex ) {
116+ }
117+ return / ^ / ;
110118}
111119
112120/******************************************************************************/
@@ -210,11 +218,14 @@ function runAtHtmlElement(fn) {
210218/******************************************************************************/
211219
212220builtinScriptlets . 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+ ] ,
215226} ) ;
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 ) => {
218229 if ( ( i & 1 ) === 0 ) {
219230 const rawValue = a [ i + 1 ] ;
220231 const value = / ^ \d + $ / . test ( rawValue )
@@ -224,28 +235,7 @@ function getExtraArgsEntries(args, offset) {
224235 }
225236 return out ;
226237 } , [ ] ) ;
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 ) ;
249239}
250240
251241/******************************************************************************/
@@ -447,7 +437,7 @@ function setConstantCore(
447437 if ( Math . abs ( cValue ) > 0x7FFF ) { return ; }
448438 } else if ( trusted ) {
449439 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 ; }
451441 }
452442 } else {
453443 return ;
@@ -2415,7 +2405,7 @@ function xmlPrune(
24152405 log ( `xmlPrune: ${ item . constructor . name } .${ item . nodeName } removed` ) ;
24162406 }
24172407 } catch ( ex ) {
2418- if ( log ) { safeSelf ( ) . uboLog ( ex ) ; }
2408+ log ( ex ) ;
24192409 }
24202410 return xmlDoc ;
24212411 } ;
@@ -2438,13 +2428,12 @@ function xmlPrune(
24382428 if ( arg instanceof Request ) { return arg . url ; }
24392429 return String ( arg ) ;
24402430 } ;
2441- const realFetch = self . fetch ;
24422431 self . fetch = new Proxy ( self . fetch , {
24432432 apply : function ( target , thisArg , args ) {
24442433 if ( reUrl . test ( urlFromArg ( args [ 0 ] ) ) === false ) {
24452434 return Reflect . apply ( target , thisArg , args ) ;
24462435 }
2447- return realFetch ( ...args ) . then ( realResponse =>
2436+ return safe . fetch ( ...args ) . then ( realResponse =>
24482437 realResponse . text ( ) . then ( text =>
24492438 new Response ( pruneFromText ( text ) , {
24502439 status : realResponse . status ,
@@ -3329,4 +3318,103 @@ function trustedSetLocalStorageItem(key = '', value = '') {
33293318 setLocalStorageItemCore ( 'local' , true , key , value ) ;
33303319}
33313320
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+
33323420/******************************************************************************/
0 commit comments