Improve `trusted-prune-inbound-object` scriptlet

Trap incoming argument only if it matches the properties to
prune and matches. If there is no match, the inbound object
is passed through untouched.
This commit is contained in:
Raymond Hill 2023-10-28 07:35:38 -04:00
parent 9829ee12a5
commit fc40393c81
No known key found for this signature in database
GPG Key ID: 25E1490B761470C2
1 changed files with 91 additions and 55 deletions

View File

@ -630,6 +630,7 @@ builtinScriptlets.push({
fn: objectPruneFn, fn: objectPruneFn,
dependencies: [ dependencies: [
'matches-stack-trace.fn', 'matches-stack-trace.fn',
'object-find-owner.fn',
'safe-self.fn', 'safe-self.fn',
'should-log.fn', 'should-log.fn',
], ],
@ -662,50 +663,10 @@ function objectPruneFn(
return; return;
} }
} }
if ( objectPruneFn.findOwner === undefined ) { if ( objectPruneFn.mustProcess === undefined ) {
objectPruneFn.findOwner = (root, path, prune = false) => {
let owner = root;
let chain = path;
for (;;) {
if ( typeof owner !== 'object' || owner === null ) { return false; }
const pos = chain.indexOf('.');
if ( pos === -1 ) {
if ( prune === false ) {
return owner.hasOwnProperty(chain);
}
let modified = false;
if ( chain === '*' ) {
for ( const key in owner ) {
if ( owner.hasOwnProperty(key) === false ) { continue; }
delete owner[key];
modified = true;
}
} else if ( owner.hasOwnProperty(chain) ) {
delete owner[chain];
modified = true;
}
return modified;
}
const prop = chain.slice(0, pos);
if (
prop === '[]' && Array.isArray(owner) ||
prop === '*' && owner instanceof Object
) {
const next = chain.slice(pos + 1);
let found = false;
for ( const key of Object.keys(owner) ) {
found = objectPruneFn.findOwner(owner[key], next, prune) || found;
}
return found;
}
if ( owner.hasOwnProperty(prop) === false ) { return false; }
owner = owner[prop];
chain = chain.slice(pos + 1);
}
};
objectPruneFn.mustProcess = (root, needlePaths) => { objectPruneFn.mustProcess = (root, needlePaths) => {
for ( const needlePath of needlePaths ) { for ( const needlePath of needlePaths ) {
if ( objectPruneFn.findOwner(root, needlePath) === false ) { if ( objectFindOwnerFn(root, needlePath) === false ) {
return false; return false;
} }
} }
@ -724,7 +685,7 @@ function objectPruneFn(
let outcome = 'nomatch'; let outcome = 'nomatch';
if ( objectPruneFn.mustProcess(obj, needlePaths) ) { if ( objectPruneFn.mustProcess(obj, needlePaths) ) {
for ( const path of prunePaths ) { for ( const path of prunePaths ) {
if ( objectPruneFn.findOwner(obj, path, true) ) { if ( objectFindOwnerFn(obj, path, true) ) {
outcome = 'match'; outcome = 'match';
} }
} }
@ -737,6 +698,58 @@ function objectPruneFn(
/******************************************************************************/ /******************************************************************************/
builtinScriptlets.push({
name: 'object-find-owner.fn',
fn: objectFindOwnerFn,
});
function objectFindOwnerFn(
root,
path,
prune = false
) {
let owner = root;
let chain = path;
for (;;) {
if ( typeof owner !== 'object' || owner === null ) { return false; }
const pos = chain.indexOf('.');
if ( pos === -1 ) {
if ( prune === false ) {
return owner.hasOwnProperty(chain);
}
let modified = false;
if ( chain === '*' ) {
for ( const key in owner ) {
if ( owner.hasOwnProperty(key) === false ) { continue; }
delete owner[key];
modified = true;
}
} else if ( owner.hasOwnProperty(chain) ) {
delete owner[chain];
modified = true;
}
return modified;
}
const prop = chain.slice(0, pos);
if (
prop === '[]' && Array.isArray(owner) ||
prop === '*' && owner instanceof Object
) {
const next = chain.slice(pos + 1);
let found = false;
for ( const key of Object.keys(owner) ) {
found = objectFindOwnerFn(owner[key], next, prune) || found;
}
return found;
}
if ( owner.hasOwnProperty(prop) === false ) { return false; }
owner = owner[prop];
chain = chain.slice(pos + 1);
}
return true;
}
/******************************************************************************/
builtinScriptlets.push({ builtinScriptlets.push({
name: 'set-cookie.fn', name: 'set-cookie.fn',
fn: setCookieFn, fn: setCookieFn,
@ -4055,6 +4068,7 @@ builtinScriptlets.push({
requiresTrust: true, requiresTrust: true,
fn: trustedPruneInboundObject, fn: trustedPruneInboundObject,
dependencies: [ dependencies: [
'object-find-owner.fn',
'object-prune.fn', 'object-prune.fn',
'safe-self.fn', 'safe-self.fn',
], ],
@ -4081,23 +4095,45 @@ function trustedPruneInboundObject(
if ( argIndex < 1 ) { return; } if ( argIndex < 1 ) { return; }
const safe = safeSelf(); const safe = safeSelf();
const extraArgs = safe.getExtraArgs(Array.from(arguments), 4); const extraArgs = safe.getExtraArgs(Array.from(arguments), 4);
const needlePaths = [];
if ( rawPrunePaths !== '' ) {
needlePaths.push(...rawPrunePaths.split(/ +/));
}
if ( rawNeedlePaths !== '' ) {
needlePaths.push(...rawNeedlePaths.split(/ +/));
}
const mustProcess = root => {
for ( const needlePath of needlePaths ) {
if ( objectFindOwnerFn(root, needlePath) === false ) {
return false;
}
}
return true;
};
context[prop] = new Proxy(context[prop], { context[prop] = new Proxy(context[prop], {
apply: function(target, thisArg, args) { apply: function(target, thisArg, args) {
const targetArg = argIndex <= args.length const targetArg = argIndex <= args.length
? args[argIndex-1] ? args[argIndex-1]
: undefined; : undefined;
if ( targetArg instanceof Object ) { if ( targetArg instanceof Object && mustProcess(targetArg) ) {
const objBefore = extraArgs.dontOverwrite let objBefore = targetArg;
? safe.JSON_parse(safe.JSON_stringify(targetArg)) if ( extraArgs.dontOverwrite ) {
: targetArg; try {
const objAfter = objectPruneFn( objBefore = safe.JSON_parse(safe.JSON_stringify(targetArg));
objBefore, } catch(_) {
rawPrunePaths, objBefore = undefined;
rawNeedlePaths, }
{ matchAll: true }, }
extraArgs if ( objBefore !== undefined ) {
); const objAfter = objectPruneFn(
args[argIndex-1] = objAfter || objBefore; objBefore,
rawPrunePaths,
rawNeedlePaths,
{ matchAll: true },
extraArgs
);
args[argIndex-1] = objAfter || objBefore;
}
} }
return Reflect.apply(target, thisArg, args); return Reflect.apply(target, thisArg, args);
}, },