From 6906b00b0e734dbe59d1a3a91f07ec1007166b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Mon, 3 Apr 2023 17:18:52 +0200 Subject: [PATCH] fix(core): Prevent augmentObject from creating infinitely deep proxies (#5893) fixes #5848 --- packages/workflow/src/AugmentObject.ts | 41 ++++++++++++-------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/packages/workflow/src/AugmentObject.ts b/packages/workflow/src/AugmentObject.ts index a56fd7cb06..515f7a554c 100644 --- a/packages/workflow/src/AugmentObject.ts +++ b/packages/workflow/src/AugmentObject.ts @@ -1,18 +1,9 @@ import type { IDataObject } from './Interfaces'; const augmentedObjects = new WeakSet(); + function augment(value: T): T { - if ( - typeof value !== 'object' || - value === null || - value instanceof RegExp || - augmentedObjects.has(value) - ) - return value; - - // Track augmented objects to prevent infinite recursion in cases where an object contains circular references - augmentedObjects.add(value); - + if (typeof value !== 'object' || value === null || value instanceof RegExp) return value; if (value instanceof Date) return new Date(value.valueOf()) as T; // eslint-disable-next-line @typescript-eslint/no-use-before-define @@ -23,6 +14,8 @@ function augment(value: T): T { } export function augmentArray(data: T[]): T[] { + if (augmentedObjects.has(data)) return data; + let newData: unknown[] | undefined = undefined; function getData(): unknown[] { @@ -32,7 +25,7 @@ export function augmentArray(data: T[]): T[] { return newData; } - return new Proxy(data, { + const proxy = new Proxy(data, { deleteProperty(target, key: string) { return Reflect.deleteProperty(getData(), key); }, @@ -63,24 +56,25 @@ export function augmentArray(data: T[]): T[] { return Reflect.ownKeys(newData !== undefined ? newData : target); }, set(target, key: string, newValue: unknown) { - if (newValue !== null && typeof newValue === 'object') { - // Always proxy all objects. Like that we can check in get simply if it - // is a proxy and it does then not matter if it was already there from the - // beginning and it got proxied at some point or set later and so theoretically - // does not have to get proxied - newValue = new Proxy(newValue, {}); - } - - return Reflect.set(getData(), key, newValue); + // Always proxy all objects. Like that we can check in get simply if it + // is a proxy and it does then not matter if it was already there from the + // beginning and it got proxied at some point or set later and so theoretically + // does not have to get proxied + return Reflect.set(getData(), key, augment(newValue)); }, }); + + augmentedObjects.add(proxy); + return proxy; } export function augmentObject(data: T): T { + if (augmentedObjects.has(data)) return data; + const newData = {} as IDataObject; const deletedProperties: Array = []; - return new Proxy(data, { + const proxy = new Proxy(data, { get(target, key: string, receiver): unknown { if (deletedProperties.indexOf(key) !== -1) { return undefined; @@ -144,4 +138,7 @@ export function augmentObject(data: T): T { }; }, }); + + augmentedObjects.add(proxy); + return proxy; }