fix(js): CryptoKey clone hook honours the structuredClone seen map (#423) (#425)

_structuredClone dispatches platform-object hooks as hook(value, seen), but the
CryptoKey hook took only `src` and never touched the memo, and hook branches
return before the generic seen.set. So one CryptoKey referenced twice in a graph
cloned into two distinct objects (and re-registered its key material each time),
where structuredClone preserves reference identity within a graph.

Consult and populate `seen` in the hook. Adds a parity test asserting a key
reached twice clones to one shared object that crypto.subtle still accepts.
This commit is contained in:
Andrey Mnatsakanov authored and GitHub committed 2026-07-16 12:42:07 +02:00
1 parent 891d850d19
commit 8698afc065
2 files changed
+41 -1

No files matched your search

+6 -1
View File
@@ -7094,8 +7094,13 @@ if (!globalThis.crypto.subtle) {
// _structuredClone via Symbol.toStringTag ("CryptoKey"); registered lazily
// because structuredClone is defined before this block (issue #389).
globalThis.__obscura_clone_hooks = globalThis.__obscura_clone_hooks || {};
globalThis.__obscura_clone_hooks["CryptoKey"] = function (src) {
// `seen` is the clone memo _structuredClone hands every hook. Populate it so
// one key reached twice in a graph clones to one shared object (and its key
// material is registered once), matching structuredClone's identity rules.
globalThis.__obscura_clone_hooks["CryptoKey"] = function (src, seen) {
if (seen && seen.has(src)) return seen.get(src);
const copy = makeKey(src.type, src.extractable, src.algorithm, src.usages, keyBytes(src));
if (seen) seen.set(src, copy);
return copy;
};