From 1efdb245d1173105b554da787c8f3a02a8941bb4 Mon Sep 17 00:00:00 2001 From: Duc Trung Le Date: Mon, 6 Oct 2025 10:17:23 +0200 Subject: [PATCH 1/2] Store original Map and Symbol --- src/manager.ts | 80 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/src/manager.ts b/src/manager.ts index 74b0f65..521fb32 100644 --- a/src/manager.ts +++ b/src/manager.ts @@ -264,7 +264,7 @@ export namespace SecretsManager { if (symbols.has(id)) { lock(`Sign error: another plugin signed as "${id}".`); } - const token = Symbol(id); + const token = Private.OriginalSymbol(id); const plugin = factory(token); if (id !== plugin.id) { lock(`Sign error: plugin ID mismatch "${plugin.id}"≠"${id}".`); @@ -276,20 +276,87 @@ export namespace SecretsManager { } namespace Private { + namespace SafeMapNs { + // Capture the original Map constructor and prototype methods. + const MapConstructor = Object.getPrototypeOf(new Map()).constructor; + const _get = MapConstructor.prototype.get; + const _has = MapConstructor.prototype.has; + const _set = MapConstructor.prototype.set; + const _delete = MapConstructor.prototype.delete; + const _clear = MapConstructor.prototype.clear; + const _entries = MapConstructor.prototype.entries; + const _keys = MapConstructor.prototype.keys; + const _values = MapConstructor.prototype.values; + const _forEach = MapConstructor.prototype.forEach; + + export class SafeMap { + private _map: InstanceType; + + constructor(entries?: readonly (readonly [K, V])[] | null) { + this._map = Reflect.construct(MapConstructor, entries ? [entries] : []); + } + s; + get(key: K): V | undefined { + return _get.call(this._map, key); + } + has(key: K): boolean { + return _has.call(this._map, key); + } + entries() { + return _entries.call(this._map); + } + keys() { + return _keys.call(this._map); + } + values() { + return _values.call(this._map); + } + forEach(cb: (v: V, k: K, m: Map) => void) { + return _forEach.call(this._map, cb); + } + + set(key: K, value: V): this { + _set.call(this._map, key, value); + return this; + } + delete(key: K): boolean { + return _delete.call(this._map, key); + } + clear(): void { + _clear.call(this._map); + } + + get size(): number { + return this._map.size; + } + + // Iterator + [Symbol.iterator]() { + return _entries.call(this._map); + } + } + } + /** * Internal 'locked' status. */ let locked: boolean = false; + /** + * The original Symbol constructor, used to create unique symbols for plugin + * identification and namespace protection. + */ + export const OriginalSymbol = Symbol; + /** * The namespace associated to a symbol. */ - export const namespaces = new Map(); + export const namespaces = new SafeMapNs.SafeMap(); /** * The symbol associated to a namespace. */ - export const symbols = new Map(); + export const symbols = new SafeMapNs.SafeMap(); /** * Lock the manager. @@ -415,12 +482,15 @@ namespace Private { /** * The inputs elements attached to the manager. */ - export const inputs = new Map(); + export const inputs = new SafeMapNs.SafeMap(); /** * The secret path associated to an input. */ - export const secretPath = new Map(); + export const secretPath = new SafeMapNs.SafeMap< + HTMLInputElement, + SecretPath + >(); /** * Build the secret id from the namespace and id. From 8dc744797f59491687f888dd247646d5a8060f28 Mon Sep 17 00:00:00 2001 From: Duc Trung Le Date: Mon, 6 Oct 2025 10:37:02 +0200 Subject: [PATCH 2/2] comment --- src/manager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/manager.ts b/src/manager.ts index 521fb32..6a9c529 100644 --- a/src/manager.ts +++ b/src/manager.ts @@ -295,7 +295,6 @@ namespace Private { constructor(entries?: readonly (readonly [K, V])[] | null) { this._map = Reflect.construct(MapConstructor, entries ? [entries] : []); } - s; get(key: K): V | undefined { return _get.call(this._map, key); }