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..52517934f76 100644 --- a/packages/builder-util/src/DebugLogger.ts +++ b/packages/builder-util/src/DebugLogger.ts @@ -1,8 +1,9 @@ import { outputFile } from "fs-extra" import { serializeToYaml } from "./util" +import { mapToObject } from "./mapper" export class DebugLogger { - readonly data: any = {} + readonly data = new Map() constructor(readonly isEnabled = true) {} @@ -19,26 +20,27 @@ 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) } } 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 ecb7498d7e3..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 @@ -30,7 +32,9 @@ function assignKey(target: any, from: any, key: string) { 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 diff --git a/packages/builder-util/src/mapper.ts b/packages/builder-util/src/mapper.ts new file mode 100644 index 00000000000..c46749f287a --- /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(key: any) { + const protectedProperties = ["__proto__", "prototype", "constructor"] + if (protectedProperties.includes(key)) { + return false + } + return ["string", "number", "symbol", "boolean"].includes(typeof key) || key === null +}