Skip to content

Commit

Permalink
fix: obfuscation of an array element can lead to undefined error (#312)
Browse files Browse the repository at this point in the history
* fix: obfuscation of an array element can lead to undefined error

* fix: typo

---------

Co-authored-by: Phan Shi Yu <[email protected]>
  • Loading branch information
phanshiyu and phanshiyu authored Aug 2, 2024
1 parent bc62924 commit 51d910e
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
9 changes: 8 additions & 1 deletion src/4.0/obfuscate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ const obfuscate = (_data: V4WrappedDocument, fields: string[] | string) => {

// fields to remove will contain the list of each expanded keys from the fields passed in parameter, it's for instance useful in case of
// object obfuscation, where the object itself is not part of the salts, but each individual keys are
const toBeRemovedLeafNodes = traverseAndFlatten(pick(data, fieldsAsArray), ({ path }) => path);
const toBeRemovedLeafNodes = traverseAndFlatten(
pick(data, fieldsAsArray),
({ path }) => path,
"",
// picking from an array can lead to unpicked items being left as undefined
// these 'undefined' leaf nodes should be removed and not lead to an exception
true
);
const salts = decodeSalt(data.proof.salts);

const obfuscatedData = toBeRemovedLeafNodes.map((field) => {
Expand Down
29 changes: 23 additions & 6 deletions src/4.0/traverseAndFlatten.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
export type LeafValue = string | number | boolean | null | Record<string, never> | [];

// we use a symbol just in case of conflicts with what the iteratee returns
const undefinedSym = Symbol("undefined value that should be filtered away");

function _traverseAndFlatten<IterateeValue>(
data: unknown,
iteratee: (data: { value: LeafValue; path: string }) => IterateeValue,
path = ""
path = "",
isRemoveUndefinedLeafNodes = false
): IterateeValue | IterateeValue[] {
if (Array.isArray(data)) {
// an empty array is considered a leaf node
Expand All @@ -13,7 +17,7 @@ function _traverseAndFlatten<IterateeValue>(
const results: IterateeValue[] = [];
for (let index = 0; index < data.length; index++) {
const value = data[index];
const result = _traverseAndFlatten(value, iteratee, `${path}[${index}]`);
const result = _traverseAndFlatten(value, iteratee, `${path}[${index}]`, isRemoveUndefinedLeafNodes);
if (Array.isArray(result)) {
results.push(...result);
} else {
Expand All @@ -29,23 +33,36 @@ function _traverseAndFlatten<IterateeValue>(
// an empty object is considered a leaf node
if (keys.length === 0) return iteratee({ value: {}, path });
return Object.keys(data).flatMap((key) =>
_traverseAndFlatten(data[key as keyof typeof data], iteratee, path ? `${path}.${key}` : key)
_traverseAndFlatten(
data[key as keyof typeof data],
iteratee,
path ? `${path}.${key}` : key,
isRemoveUndefinedLeafNodes
)
);
}

if (typeof data === "string" || typeof data === "number" || typeof data === "boolean" || data === null) {
return iteratee({ value: data, path });
}

if (data === undefined && isRemoveUndefinedLeafNodes) {
// mark undefined leaf node with a unique symbol that must be removed later
return undefinedSym as IterateeValue;
}

throw new Error(`Unexpected data '${data}' in '${path}'`);
}

/** Given a record, returns a list of all leaf nodes of value that is not undefined */
export function traverseAndFlatten<IterateeValue>(
data: Record<string, unknown>,
iteratee: (data: { value: LeafValue; path: string }) => IterateeValue,
path = ""
path = "",
/** by default throw when there are leaf nodes that are undefined, setting this to true will remove them instead */
isRemoveUndefinedLeafNodes = false
): IterateeValue[] {
const results = _traverseAndFlatten(data, iteratee, path);
return Array.isArray(results) ? results : [];
const results = _traverseAndFlatten(data, iteratee, path, isRemoveUndefinedLeafNodes);
// remove undefined leaf nodes
return Array.isArray(results) ? results.filter((v) => v !== undefinedSym) : [];
}

0 comments on commit 51d910e

Please sign in to comment.