diff --git a/src/js/resources/json-edit.js b/src/js/resources/json-edit.js index a95bc8c63..e4c6a8382 100644 --- a/src/js/resources/json-edit.js +++ b/src/js/resources/json-edit.js @@ -21,6 +21,7 @@ */ import { + collateFetchArgumentsFn, matchObjectPropertiesFn, parsePropertiesToMatchFn, } from './utils.js'; @@ -569,18 +570,8 @@ function jsonEditFetchResponseFn(trusted, jsonq = '') { const args = context.callArgs; const fetchPromise = context.reflect(); if ( propNeedles.size !== 0 ) { - const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } catch(ex) { - safe.uboErr(logPrefix, 'Error:', ex); - } - } - if ( args[1] instanceof Object ) { - objs.push(args[1]); - } - const matched = matchObjectPropertiesFn(propNeedles, ...objs); + const props = collateFetchArgumentsFn(...args); + const matched = matchObjectPropertiesFn(propNeedles, props); if ( matched === undefined ) { return fetchPromise; } if ( safe.logLevel > 1 ) { safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); @@ -618,6 +609,7 @@ function jsonEditFetchResponseFn(trusted, jsonq = '') { registerScriptlet(jsonEditFetchResponseFn, { name: 'json-edit-fetch-response.fn', dependencies: [ + collateFetchArgumentsFn, JSONPath, matchObjectPropertiesFn, parsePropertiesToMatchFn, @@ -716,17 +708,8 @@ function jsonEditFetchRequestFn(trusted, jsonq = '') { return context.reflect(); } if ( propNeedles.size !== 0 ) { - const objs = [ - resource instanceof Object ? resource : { url: `${resource}` } - ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } catch(ex) { - safe.uboErr(logPrefix, 'Error:', ex); - } - } - const matched = matchObjectPropertiesFn(propNeedles, ...objs); + const props = collateFetchArgumentsFn(resource, options); + const matched = matchObjectPropertiesFn(propNeedles, props); if ( matched === undefined ) { return context.reflect(); } if ( safe.logLevel > 1 ) { safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); @@ -745,6 +728,7 @@ function jsonEditFetchRequestFn(trusted, jsonq = '') { registerScriptlet(jsonEditFetchRequestFn, { name: 'json-edit-fetch-request.fn', dependencies: [ + collateFetchArgumentsFn, JSONPath, matchObjectPropertiesFn, parsePropertiesToMatchFn, @@ -986,18 +970,8 @@ function jsonlEditFetchResponseFn(trusted, jsonq = '') { const args = context.callArgs; const fetchPromise = context.reflect(); if ( propNeedles.size !== 0 ) { - const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } catch(ex) { - safe.uboErr(logPrefix, 'Error:', ex); - } - } - if ( args[1] instanceof Object ) { - objs.push(args[1]); - } - const matched = matchObjectPropertiesFn(propNeedles, ...objs); + const props = collateFetchArgumentsFn(...args); + const matched = matchObjectPropertiesFn(propNeedles, props); if ( matched === undefined ) { return fetchPromise; } if ( safe.logLevel > 1 ) { safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); @@ -1039,6 +1013,7 @@ function jsonlEditFetchResponseFn(trusted, jsonq = '') { registerScriptlet(jsonlEditFetchResponseFn, { name: 'jsonl-edit-fetch-response.fn', dependencies: [ + collateFetchArgumentsFn, JSONPath, jsonlEditFn, matchObjectPropertiesFn, diff --git a/src/js/resources/json-prune.js b/src/js/resources/json-prune.js index 08284e313..ec4207a2b 100644 --- a/src/js/resources/json-prune.js +++ b/src/js/resources/json-prune.js @@ -21,6 +21,7 @@ */ import { + collateFetchArgumentsFn, matchObjectPropertiesFn, parsePropertiesToMatchFn, } from './utils.js'; @@ -86,18 +87,8 @@ function jsonPruneFetchResponse( const applyHandler = function(target, thisArg, args) { const fetchPromise = Reflect.apply(target, thisArg, args); if ( propNeedles.size !== 0 ) { - const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } catch(ex) { - safe.uboErr(logPrefix, 'Error:', ex); - } - } - if ( args[1] instanceof Object ) { - objs.push(args[1]); - } - const matched = matchObjectPropertiesFn(propNeedles, ...objs); + const props = collateFetchArgumentsFn(...args); + const matched = matchObjectPropertiesFn(propNeedles, props); if ( matched === undefined ) { return fetchPromise; } if ( safe.logLevel > 1 ) { safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); @@ -148,6 +139,7 @@ function jsonPruneFetchResponse( registerScriptlet(jsonPruneFetchResponse, { name: 'json-prune-fetch-response.js', dependencies: [ + collateFetchArgumentsFn, matchObjectPropertiesFn, objectPruneFn, parsePropertiesToMatchFn, diff --git a/src/js/resources/prevent-fetch.js b/src/js/resources/prevent-fetch.js index 5bf03e081..7a161ecc0 100644 --- a/src/js/resources/prevent-fetch.js +++ b/src/js/resources/prevent-fetch.js @@ -21,6 +21,7 @@ */ import { + collateFetchArgumentsFn, generateContentFn, matchObjectPropertiesFn, parsePropertiesToMatchFn, @@ -75,32 +76,9 @@ function preventFetchFn( responseProps.type = { value: responseType }; } } - const fetchProps = (src, out) => { - if ( typeof src !== 'object' || src === null ) { return; } - const props = [ - 'body', 'cache', 'credentials', 'duplex', 'headers', - 'integrity', 'keepalive', 'method', 'mode', 'priority', - 'redirect', 'referrer', 'referrerPolicy', 'signal', - ]; - for ( const prop of props ) { - if ( src[prop] === undefined ) { continue; } - out[prop] = src[prop]; - } - }; - const fetchDetails = args => { - const out = {}; - if ( args[0] instanceof self.Request ) { - out.url = `${args[0].url}`; - fetchProps(args[0], out); - } else { - out.url = `${args[0]}`; - } - fetchProps(args[1], out); - return out; - }; proxyApplyFn('fetch', function fetch(context) { const { callArgs } = context; - const details = fetchDetails(callArgs); + const details = collateFetchArgumentsFn(...callArgs); if ( safe.logLevel > 1 || propsToMatch === '' && responseBody === '' ) { const out = Array.from(Object.entries(details)).map(a => `${a[0]}:${a[1]}`); safe.uboLog(logPrefix, `Called: ${out.join('\n')}`); @@ -136,6 +114,7 @@ function preventFetchFn( registerScriptlet(preventFetchFn, { name: 'prevent-fetch.fn', dependencies: [ + collateFetchArgumentsFn, generateContentFn, matchObjectPropertiesFn, parsePropertiesToMatchFn, diff --git a/src/js/resources/safe-self.js b/src/js/resources/safe-self.js index 43aec1d94..096f3c21d 100644 --- a/src/js/resources/safe-self.js +++ b/src/js/resources/safe-self.js @@ -47,6 +47,7 @@ export function safeSelf() { 'Object_fromEntries': Object.fromEntries.bind(Object), 'Object_getOwnPropertyDescriptor': Object.getOwnPropertyDescriptor.bind(Object), 'Object_hasOwn': Object.hasOwn.bind(Object), + 'Object_toString': Object.prototype.toString, 'RegExp': self.RegExp, 'RegExp_test': self.RegExp.prototype.test, 'RegExp_exec': self.RegExp.prototype.exec, diff --git a/src/js/resources/scriptlets.js b/src/js/resources/scriptlets.js index c935fdb9e..74a7beb81 100755 --- a/src/js/resources/scriptlets.js +++ b/src/js/resources/scriptlets.js @@ -35,6 +35,7 @@ import './replace-argument.js'; import './spoof-css.js'; import { + collateFetchArgumentsFn, generateContentFn, getExceptionTokenFn, getRandomTokenFn, @@ -314,6 +315,7 @@ builtinScriptlets.push({ name: 'replace-fetch-response.fn', fn: replaceFetchResponseFn, dependencies: [ + 'collate-fetch-arguments.fn', 'match-object-properties.fn', 'parse-properties-to-match.fn', 'safe-self.fn', @@ -338,19 +340,8 @@ function replaceFetchResponseFn( const fetchPromise = Reflect.apply(target, thisArg, args); if ( pattern === '' ) { return fetchPromise; } if ( propNeedles.size !== 0 ) { - const objs = [ args[0] instanceof Object ? args[0] : { url: args[0] } ]; - if ( objs[0] instanceof Request ) { - try { - objs[0] = safe.Request_clone.call(objs[0]); - } - catch(ex) { - safe.uboErr(logPrefix, ex); - } - } - if ( args[1] instanceof Object ) { - objs.push(args[1]); - } - const matched = matchObjectPropertiesFn(propNeedles, ...objs); + const props = collateFetchArgumentsFn(...args); + const matched = matchObjectPropertiesFn(propNeedles, props); if ( matched === undefined ) { return fetchPromise; } if ( safe.logLevel > 1 ) { safe.uboLog(logPrefix, `Matched "propsToMatch":\n\t${matched.join('\n\t')}`); diff --git a/src/js/resources/utils.js b/src/js/resources/utils.js index f44849519..7dcae18d1 100644 --- a/src/js/resources/utils.js +++ b/src/js/resources/utils.js @@ -62,6 +62,44 @@ registerScriptlet(getExceptionTokenFn, { /******************************************************************************/ +export function collateFetchArgumentsFn(resource, options) { + const safe = safeSelf(); + const props = [ + 'body', 'cache', 'credentials', 'duplex', 'headers', + 'integrity', 'keepalive', 'method', 'mode', 'priority', + 'redirect', 'referrer', 'referrerPolicy', 'signal', + ]; + const out = {}; + if ( collateFetchArgumentsFn.collateKnownProps === undefined ) { + collateFetchArgumentsFn.collateKnownProps = (src, out) => { + for ( const prop of props ) { + if ( src[prop] === undefined ) { continue; } + out[prop] = src[prop]; + } + }; + } + if ( + typeof resource !== 'object' || + safe.Object_toString.call(resource) !== '[object Request]' + ) { + out.url = `${resource}`; + } else { + collateFetchArgumentsFn.collateKnownProps(resource, out); + } + if ( typeof options === 'object' && options !== null ) { + collateFetchArgumentsFn.collateKnownProps(options, out); + } + return out; +} +registerScriptlet(collateFetchArgumentsFn, { + name: 'collate-fetch-arguments.fn', + dependencies: [ + safeSelf, + ], +}); + +/******************************************************************************/ + export function parsePropertiesToMatchFn(propsToMatch, implicit = '') { const safe = safeSelf(); const needles = new Map();