Add `trusted-prune-inbound-object` scriptlet

As per discussion with filter list maintainers.

To perform object pruning for any given call which has an object
as argument (hence "inbound").

Since `json-prune-stringify` scriptlet is a specific form of
pruning inbound objects, it has been removed.

The arguments for `trusted-prune-inbound-object` in order are:

- The name of the property to trap. Must be a function, and must
  exist when the scriptlet tries to install the trap.

- The position of the object to prune in the argument list when
  the trapped function is called. The position is 1-based and
  must be an integer greater than 0.

- The properties to prune (as with `json-prune`)

- The properties which must all be present for pruning to occur
  (as with `json-prune`)

- Varargs:
  - `, dontOverwrite, 1`: do not modify the target inbound object

Examples:

Remove `title` and `name` properties before passing the object to
`JSON.stringify` call:

  example.org##+js(trusted-prune-inbound-object, JSON.stringify, 1, title name)

Remove `status` property before passing the object to `Object.keys`
call but do not modify caller's instance of the object:

  example.org##+js(trusted-prune-inbound-object, Object.keys, 1, status, , dontOverwrite, 1)
This commit is contained in:
Raymond Hill 2023-10-21 09:31:50 -04:00
parent 287f7711aa
commit 1c9da227d7
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 56 additions and 36 deletions

View File

@ -1429,42 +1429,6 @@ function jsonPrune(
}); });
} }
/******************************************************************************/
builtinScriptlets.push({
name: 'json-prune-stringify.js',
fn: jsonPruneStringify,
dependencies: [
'object-prune.fn',
'safe-self.fn',
],
});
function jsonPruneStringify(
rawPrunePaths = '',
rawNeedlePaths = '',
stackNeedle = ''
) {
const safe = safeSelf();
const stackNeedleDetails = safe.initPattern(stackNeedle, { canNegate: true });
const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
JSON.stringify = new Proxy(JSON.stringify, {
apply: function(target, thisArg, args) {
const objBefore = args[0];
if ( objBefore instanceof Object ) {
const objAfter = objectPruneFn(
objBefore,
rawPrunePaths,
rawNeedlePaths,
stackNeedleDetails,
extraArgs
);
args[0] = objAfter || objBefore;
}
return Reflect.apply(target, thisArg, args);
},
});
}
/******************************************************************************* /*******************************************************************************
* *
* json-prune-fetch-response.js * json-prune-fetch-response.js
@ -4071,3 +4035,59 @@ function trustedClickElement(
} }
/******************************************************************************/ /******************************************************************************/
builtinScriptlets.push({
name: 'trusted-prune-inbound-object.js',
requiresTrust: true,
fn: trustedPruneInboundObject,
dependencies: [
'object-prune.fn',
'safe-self.fn',
],
});
function trustedPruneInboundObject(
entryPoint = '',
argPos = '',
rawPrunePaths = '',
rawNeedlePaths = ''
) {
if ( entryPoint === '' ) { return; }
let context = globalThis;
let prop = entryPoint;
for (;;) {
const pos = prop.indexOf('.');
if ( pos === -1 ) { break; }
context = context[prop.slice(0, pos)];
if ( context instanceof Object === false ) { return; }
prop = prop.slice(pos+1);
}
if ( typeof context[prop] !== 'function' ) { return; }
const argIndex = parseInt(argPos);
if ( isNaN(argIndex) ) { return; }
if ( argIndex < 1 ) { return; }
const safe = safeSelf();
const extraArgs = safe.getExtraArgs(Array.from(arguments), 4);
context[prop] = new Proxy(context[prop], {
apply: function(target, thisArg, args) {
const targetArg = argIndex <= args.length
? args[argIndex-1]
: undefined;
if ( targetArg instanceof Object ) {
const objBefore = extraArgs.dontOverwrite
? safe.JSON_parse(safe.JSON_stringify(targetArg))
: targetArg;
const objAfter = objectPruneFn(
objBefore,
rawPrunePaths,
rawNeedlePaths,
{ matchAll: true },
extraArgs
);
args[argIndex-1] = objAfter || objBefore;
}
return Reflect.apply(target, thisArg, args);
},
});
}
/******************************************************************************/