From 4f34f87c1bcdcb0e4deb289bec47f0aba2712ead Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Fri, 6 Sep 2024 10:41:40 -0500 Subject: [PATCH] make all jetstream configurations strict on tests --- test_helpers/mod.ts | 57 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/test_helpers/mod.ts b/test_helpers/mod.ts index 25e20f18..99ef90f3 100644 --- a/test_helpers/mod.ts +++ b/test_helpers/mod.ts @@ -48,6 +48,7 @@ export function jsopts() { jetstream: { max_file_store: 1024 * 1024, max_mem_store: 1024 * 1024, + strict: true, store_dir, }, }; @@ -92,10 +93,64 @@ export function jetstreamExportServerConf( return jetstreamServerConf(conf); } + +/** + * Checks if the given item is a plain object, excluding arrays and dates. + * + * @param {*} item - The item to check. + * @returns {boolean} True if the item is a plain object, false otherwise. + */ +function isObject(item: unknown) { + return (item && typeof item === 'object' && !Array.isArray(item) && !(item instanceof Date)) +} + +/** + * Recursively merges properties from source objects into a target object. If a property at the current level is an object, + * and both target and source have it, the property is merged. Otherwise, the source property overwrites the target property. + * This function does not modify the source objects and prevents prototype pollution by not allowing __proto__, constructor, + * and prototype property names. + * + * @param {Object} target - The target object to merge properties into. + * @param {...Object} sources - One or more source objects from which to merge properties. + * @returns {Object} The target object after merging properties from sources. + */ + // deno-lint-ignore no-explicit-any + export function deepMerge(target: any, ...sources: any[]) { + if (!sources.length) return target + + // Iterate through each source object without modifying the sources array + sources.forEach(source => { + if (isObject(target) && isObject(source)) { + for (const key in source) { + if (isObject(source[key])) { + if (key === '__proto__' || key === 'constructor' || key === 'prototype') { + continue // Skip potentially dangerous keys to prevent prototype pollution. + } + + if (!target[key] || !isObject(target[key])) { + target[key] = {} + } + + deepMerge(target[key], source[key]) + } else { + target[key] = source[key] + } + } + } + }) + + return target +} + export function jetstreamServerConf( opts: unknown = {}, ): Record { - const conf = Object.assign(jsopts(), opts); + const strict = { + jetstream: { + strict: true + } + } + const conf = deepMerge(jsopts(), opts, strict); if (typeof conf.jetstream.store_dir !== "string") { conf.jetstream.store_dir = Deno.makeTempDirSync({ prefix: "jetstream" }); }