From aa4b8915abe012d472e406c5d1e37dd208c7ae7e Mon Sep 17 00:00:00 2001 From: Mike Maietta Date: Wed, 12 Feb 2025 22:42:57 -0800 Subject: [PATCH 1/3] fix: validate object key before deep assigning --- .changeset/fresh-rats-hide.md | 5 +++++ packages/builder-util/src/DebugLogger.ts | 18 +++++++++--------- packages/builder-util/src/deepAssign.ts | 12 +++++++++++- 3 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 .changeset/fresh-rats-hide.md diff --git a/.changeset/fresh-rats-hide.md b/.changeset/fresh-rats-hide.md new file mode 100644 index 00000000000..dfca283a66a --- /dev/null +++ b/.changeset/fresh-rats-hide.md @@ -0,0 +1,5 @@ +--- +"builder-util": patch +--- + +fix: validate object key before deep assigning diff --git a/packages/builder-util/src/DebugLogger.ts b/packages/builder-util/src/DebugLogger.ts index 8b33ce95365..0e38c0b652f 100644 --- a/packages/builder-util/src/DebugLogger.ts +++ b/packages/builder-util/src/DebugLogger.ts @@ -2,7 +2,7 @@ import { outputFile } from "fs-extra" import { serializeToYaml } from "./util" export class DebugLogger { - readonly data: any = {} + readonly data = new Map() constructor(readonly isEnabled = true) {} @@ -19,19 +19,19 @@ export class DebugLogger { lastName = p break } else { - if (o[p] == null) { - o[p] = Object.create(null) - } else if (typeof o[p] === "string") { - o[p] = [o[p]] + if (!o.has(p)) { + o.set(p, new Map()) + } else if (typeof o.get(p) === "string") { + o.set(p, [o.get(p)]) } - o = o[p] + o = o.get(p) } } - if (Array.isArray(o[lastName!])) { - o[lastName!] = [...o[lastName!], value] + if (Array.isArray(o.get(lastName!))) { + o.set(lastName!, [...o.get(lastName!), value]) } else { - o[lastName!] = value + o.set(lastName!, value) } } diff --git a/packages/builder-util/src/deepAssign.ts b/packages/builder-util/src/deepAssign.ts index ecb7498d7e3..ad22c6acf8e 100644 --- a/packages/builder-util/src/deepAssign.ts +++ b/packages/builder-util/src/deepAssign.ts @@ -27,10 +27,20 @@ function assignKey(target: any, from: any, key: string) { } } +function isValidKey(value: any) { + if (["string", "number", "symbol", "boolean"].includes(typeof value)) { + const protectedProperties = ["__proto__", "prototype", "constructor"] + return !protectedProperties.includes(value) + } + return value === null +} + function assign(to: any, from: any) { if (to !== from) { for (const key of Object.getOwnPropertyNames(from)) { - assignKey(to, from, key) + if (isValidKey(key)) { + assignKey(to, from, key) + } } } return to From 799341182955eb5c49de944cfccb659180129f54 Mon Sep 17 00:00:00 2001 From: Mike Maietta Date: Wed, 12 Feb 2025 23:11:06 -0800 Subject: [PATCH 2/3] convert map back to object for logging to data to yaml. move to designated file --- packages/builder-util/src/DebugLogger.ts | 6 ++++-- packages/builder-util/src/deepAssign.ts | 10 ++-------- packages/builder-util/src/mapper.ts | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 packages/builder-util/src/mapper.ts diff --git a/packages/builder-util/src/DebugLogger.ts b/packages/builder-util/src/DebugLogger.ts index 0e38c0b652f..52517934f76 100644 --- a/packages/builder-util/src/DebugLogger.ts +++ b/packages/builder-util/src/DebugLogger.ts @@ -1,5 +1,6 @@ import { outputFile } from "fs-extra" import { serializeToYaml } from "./util" +import { mapToObject } from "./mapper" export class DebugLogger { readonly data = new Map() @@ -36,9 +37,10 @@ export class DebugLogger { } save(file: string) { + const data = mapToObject(this.data) // toml and json doesn't correctly output multiline string as multiline - if (this.isEnabled && Object.keys(this.data).length > 0) { - return outputFile(file, serializeToYaml(this.data)) + if (this.isEnabled && Object.keys(data).length > 0) { + return outputFile(file, serializeToYaml(data)) } else { return Promise.resolve() } diff --git a/packages/builder-util/src/deepAssign.ts b/packages/builder-util/src/deepAssign.ts index ad22c6acf8e..478b1842043 100644 --- a/packages/builder-util/src/deepAssign.ts +++ b/packages/builder-util/src/deepAssign.ts @@ -1,3 +1,5 @@ +import { isValidKey } from "./mapper" + function isObject(x: any) { if (Array.isArray(x)) { return false @@ -27,14 +29,6 @@ function assignKey(target: any, from: any, key: string) { } } -function isValidKey(value: any) { - if (["string", "number", "symbol", "boolean"].includes(typeof value)) { - const protectedProperties = ["__proto__", "prototype", "constructor"] - return !protectedProperties.includes(value) - } - return value === null -} - function assign(to: any, from: any) { if (to !== from) { for (const key of Object.getOwnPropertyNames(from)) { diff --git a/packages/builder-util/src/mapper.ts b/packages/builder-util/src/mapper.ts new file mode 100644 index 00000000000..28c09f19401 --- /dev/null +++ b/packages/builder-util/src/mapper.ts @@ -0,0 +1,24 @@ +type RecursiveMap = Map + +export function mapToObject(map: RecursiveMap) { + const obj: any = {} + for (const [key, value] of map) { + if (!isValidKey(key)) { + continue + } + if (value instanceof Map) { + obj[key] = mapToObject(value) + } else { + obj[key] = value + } + } + return obj +} + +export function isValidKey(value: any) { + if (["string", "number", "symbol", "boolean"].includes(typeof value)) { + const protectedProperties = ["__proto__", "prototype", "constructor"] + return !protectedProperties.includes(value) + } + return value === null +} From d3a26bf885f3ae54163df6bb5ad098fd85aa4845 Mon Sep 17 00:00:00 2001 From: Mike Maietta Date: Wed, 12 Feb 2025 23:18:37 -0800 Subject: [PATCH 3/3] flip if-condition --- packages/builder-util/src/mapper.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/builder-util/src/mapper.ts b/packages/builder-util/src/mapper.ts index 28c09f19401..c46749f287a 100644 --- a/packages/builder-util/src/mapper.ts +++ b/packages/builder-util/src/mapper.ts @@ -15,10 +15,10 @@ export function mapToObject(map: RecursiveMap) { return obj } -export function isValidKey(value: any) { - if (["string", "number", "symbol", "boolean"].includes(typeof value)) { - const protectedProperties = ["__proto__", "prototype", "constructor"] - return !protectedProperties.includes(value) +export function isValidKey(key: any) { + const protectedProperties = ["__proto__", "prototype", "constructor"] + if (protectedProperties.includes(key)) { + return false } - return value === null + return ["string", "number", "symbol", "boolean"].includes(typeof key) || key === null }