Skip to content

Commit 8f152f8

Browse files
authored
Store original Map and Symbol (#18)
* Store original Map and Symbol * comment
1 parent 33fa534 commit 8f152f8

File tree

1 file changed

+74
-5
lines changed

1 file changed

+74
-5
lines changed

src/manager.ts

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export namespace SecretsManager {
264264
if (symbols.has(id)) {
265265
lock(`Sign error: another plugin signed as "${id}".`);
266266
}
267-
const token = Symbol(id);
267+
const token = Private.OriginalSymbol(id);
268268
const plugin = factory(token);
269269
if (id !== plugin.id) {
270270
lock(`Sign error: plugin ID mismatch "${plugin.id}"≠"${id}".`);
@@ -276,20 +276,86 @@ export namespace SecretsManager {
276276
}
277277

278278
namespace Private {
279+
namespace SafeMapNs {
280+
// Capture the original Map constructor and prototype methods.
281+
const MapConstructor = Object.getPrototypeOf(new Map()).constructor;
282+
const _get = MapConstructor.prototype.get;
283+
const _has = MapConstructor.prototype.has;
284+
const _set = MapConstructor.prototype.set;
285+
const _delete = MapConstructor.prototype.delete;
286+
const _clear = MapConstructor.prototype.clear;
287+
const _entries = MapConstructor.prototype.entries;
288+
const _keys = MapConstructor.prototype.keys;
289+
const _values = MapConstructor.prototype.values;
290+
const _forEach = MapConstructor.prototype.forEach;
291+
292+
export class SafeMap<K, V> {
293+
private _map: InstanceType<typeof MapConstructor>;
294+
295+
constructor(entries?: readonly (readonly [K, V])[] | null) {
296+
this._map = Reflect.construct(MapConstructor, entries ? [entries] : []);
297+
}
298+
get(key: K): V | undefined {
299+
return _get.call(this._map, key);
300+
}
301+
has(key: K): boolean {
302+
return _has.call(this._map, key);
303+
}
304+
entries() {
305+
return _entries.call(this._map);
306+
}
307+
keys() {
308+
return _keys.call(this._map);
309+
}
310+
values() {
311+
return _values.call(this._map);
312+
}
313+
forEach(cb: (v: V, k: K, m: Map<K, V>) => void) {
314+
return _forEach.call(this._map, cb);
315+
}
316+
317+
set(key: K, value: V): this {
318+
_set.call(this._map, key, value);
319+
return this;
320+
}
321+
delete(key: K): boolean {
322+
return _delete.call(this._map, key);
323+
}
324+
clear(): void {
325+
_clear.call(this._map);
326+
}
327+
328+
get size(): number {
329+
return this._map.size;
330+
}
331+
332+
// Iterator
333+
[Symbol.iterator]() {
334+
return _entries.call(this._map);
335+
}
336+
}
337+
}
338+
279339
/**
280340
* Internal 'locked' status.
281341
*/
282342
let locked: boolean = false;
283343

344+
/**
345+
* The original Symbol constructor, used to create unique symbols for plugin
346+
* identification and namespace protection.
347+
*/
348+
export const OriginalSymbol = Symbol;
349+
284350
/**
285351
* The namespace associated to a symbol.
286352
*/
287-
export const namespaces = new Map<symbol, string>();
353+
export const namespaces = new SafeMapNs.SafeMap<symbol, string>();
288354

289355
/**
290356
* The symbol associated to a namespace.
291357
*/
292-
export const symbols = new Map<string, symbol>();
358+
export const symbols = new SafeMapNs.SafeMap<string, symbol>();
293359

294360
/**
295361
* Lock the manager.
@@ -415,12 +481,15 @@ namespace Private {
415481
/**
416482
* The inputs elements attached to the manager.
417483
*/
418-
export const inputs = new Map<string, HTMLInputElement>();
484+
export const inputs = new SafeMapNs.SafeMap<string, HTMLInputElement>();
419485

420486
/**
421487
* The secret path associated to an input.
422488
*/
423-
export const secretPath = new Map<HTMLInputElement, SecretPath>();
489+
export const secretPath = new SafeMapNs.SafeMap<
490+
HTMLInputElement,
491+
SecretPath
492+
>();
424493

425494
/**
426495
* Build the secret id from the namespace and id.

0 commit comments

Comments
 (0)