@openvtc/pnm-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +129 -0
  2. package/dist/did/derive-signing-key.d.ts +19 -0
  3. package/dist/did/derive-signing-key.d.ts.map +1 -0
  4. package/dist/did/derive-signing-key.js +96 -0
  5. package/dist/did/derive-signing-key.js.map +1 -0
  6. package/dist/did/index.d.ts +5 -0
  7. package/dist/did/index.d.ts.map +1 -0
  8. package/dist/did/index.js +5 -0
  9. package/dist/did/index.js.map +1 -0
  10. package/dist/did/peer.d.ts +37 -0
  11. package/dist/did/peer.d.ts.map +1 -0
  12. package/dist/did/peer.js +49 -0
  13. package/dist/did/peer.js.map +1 -0
  14. package/dist/did/verification-method.d.ts +43 -0
  15. package/dist/did/verification-method.d.ts.map +1 -0
  16. package/dist/did/verification-method.js +32 -0
  17. package/dist/did/verification-method.js.map +1 -0
  18. package/dist/did/verify.d.ts +49 -0
  19. package/dist/did/verify.d.ts.map +1 -0
  20. package/dist/did/verify.js +89 -0
  21. package/dist/did/verify.js.map +1 -0
  22. package/dist/didcomm/index.d.ts +235 -0
  23. package/dist/didcomm/index.d.ts.map +1 -0
  24. package/dist/didcomm/index.js +415 -0
  25. package/dist/didcomm/index.js.map +1 -0
  26. package/dist/inbound/confirm.d.ts +50 -0
  27. package/dist/inbound/confirm.d.ts.map +1 -0
  28. package/dist/inbound/confirm.js +64 -0
  29. package/dist/inbound/confirm.js.map +1 -0
  30. package/dist/inbound/dedup.d.ts +9 -0
  31. package/dist/inbound/dedup.d.ts.map +1 -0
  32. package/dist/inbound/dedup.js +31 -0
  33. package/dist/inbound/dedup.js.map +1 -0
  34. package/dist/inbound/index.d.ts +3 -0
  35. package/dist/inbound/index.d.ts.map +1 -0
  36. package/dist/inbound/index.js +3 -0
  37. package/dist/inbound/index.js.map +1 -0
  38. package/dist/index.d.ts +14 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +14 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/onboarding/index.d.ts +2 -0
  43. package/dist/onboarding/index.d.ts.map +1 -0
  44. package/dist/onboarding/index.js +2 -0
  45. package/dist/onboarding/index.js.map +1 -0
  46. package/dist/onboarding/swap.d.ts +60 -0
  47. package/dist/onboarding/swap.d.ts.map +1 -0
  48. package/dist/onboarding/swap.js +148 -0
  49. package/dist/onboarding/swap.js.map +1 -0
  50. package/dist/provision/adopt.d.ts +31 -0
  51. package/dist/provision/adopt.d.ts.map +1 -0
  52. package/dist/provision/adopt.js +114 -0
  53. package/dist/provision/adopt.js.map +1 -0
  54. package/dist/provision/armor.d.ts +19 -0
  55. package/dist/provision/armor.d.ts.map +1 -0
  56. package/dist/provision/armor.js +243 -0
  57. package/dist/provision/armor.js.map +1 -0
  58. package/dist/provision/crc24.d.ts +5 -0
  59. package/dist/provision/crc24.d.ts.map +1 -0
  60. package/dist/provision/crc24.js +30 -0
  61. package/dist/provision/crc24.js.map +1 -0
  62. package/dist/provision/hpke.d.ts +17 -0
  63. package/dist/provision/hpke.d.ts.map +1 -0
  64. package/dist/provision/hpke.js +60 -0
  65. package/dist/provision/hpke.js.map +1 -0
  66. package/dist/provision/index.d.ts +10 -0
  67. package/dist/provision/index.d.ts.map +1 -0
  68. package/dist/provision/index.js +16 -0
  69. package/dist/provision/index.js.map +1 -0
  70. package/dist/provision/open.d.ts +28 -0
  71. package/dist/provision/open.d.ts.map +1 -0
  72. package/dist/provision/open.js +224 -0
  73. package/dist/provision/open.js.map +1 -0
  74. package/dist/provision/request.d.ts +65 -0
  75. package/dist/provision/request.d.ts.map +1 -0
  76. package/dist/provision/request.js +53 -0
  77. package/dist/provision/request.js.map +1 -0
  78. package/dist/provision/run.d.ts +76 -0
  79. package/dist/provision/run.d.ts.map +1 -0
  80. package/dist/provision/run.js +110 -0
  81. package/dist/provision/run.js.map +1 -0
  82. package/dist/provision/send.d.ts +85 -0
  83. package/dist/provision/send.d.ts.map +1 -0
  84. package/dist/provision/send.js +87 -0
  85. package/dist/provision/send.js.map +1 -0
  86. package/dist/provision/types.d.ts +110 -0
  87. package/dist/provision/types.d.ts.map +1 -0
  88. package/dist/provision/types.js +17 -0
  89. package/dist/provision/types.js.map +1 -0
  90. package/dist/rp-login/didcomm.d.ts +34 -0
  91. package/dist/rp-login/didcomm.d.ts.map +1 -0
  92. package/dist/rp-login/didcomm.js +72 -0
  93. package/dist/rp-login/didcomm.js.map +1 -0
  94. package/dist/rp-login/index.d.ts +3 -0
  95. package/dist/rp-login/index.d.ts.map +1 -0
  96. package/dist/rp-login/index.js +3 -0
  97. package/dist/rp-login/index.js.map +1 -0
  98. package/dist/rp-login/step-up.d.ts +43 -0
  99. package/dist/rp-login/step-up.d.ts.map +1 -0
  100. package/dist/rp-login/step-up.js +118 -0
  101. package/dist/rp-login/step-up.js.map +1 -0
  102. package/dist/siop/index.d.ts +3 -0
  103. package/dist/siop/index.d.ts.map +1 -0
  104. package/dist/siop/index.js +3 -0
  105. package/dist/siop/index.js.map +1 -0
  106. package/dist/siop/login-client.d.ts +29 -0
  107. package/dist/siop/login-client.d.ts.map +1 -0
  108. package/dist/siop/login-client.js +79 -0
  109. package/dist/siop/login-client.js.map +1 -0
  110. package/dist/siop/self-issued.d.ts +96 -0
  111. package/dist/siop/self-issued.d.ts.map +1 -0
  112. package/dist/siop/self-issued.js +162 -0
  113. package/dist/siop/self-issued.js.map +1 -0
  114. package/dist/store/holder-identity.d.ts +241 -0
  115. package/dist/store/holder-identity.d.ts.map +1 -0
  116. package/dist/store/holder-identity.js +441 -0
  117. package/dist/store/holder-identity.js.map +1 -0
  118. package/dist/store/index.d.ts +4 -0
  119. package/dist/store/index.d.ts.map +1 -0
  120. package/dist/store/index.js +4 -0
  121. package/dist/store/index.js.map +1 -0
  122. package/dist/store/kv-store.d.ts +51 -0
  123. package/dist/store/kv-store.d.ts.map +1 -0
  124. package/dist/store/kv-store.js +100 -0
  125. package/dist/store/kv-store.js.map +1 -0
  126. package/dist/store/secret-wrap.d.ts +109 -0
  127. package/dist/store/secret-wrap.d.ts.map +1 -0
  128. package/dist/store/secret-wrap.js +85 -0
  129. package/dist/store/secret-wrap.js.map +1 -0
  130. package/dist/trust-tasks/index.d.ts +2 -0
  131. package/dist/trust-tasks/index.d.ts.map +1 -0
  132. package/dist/trust-tasks/index.js +2 -0
  133. package/dist/trust-tasks/index.js.map +1 -0
  134. package/dist/trust-tasks/sign.d.ts +31 -0
  135. package/dist/trust-tasks/sign.d.ts.map +1 -0
  136. package/dist/trust-tasks/sign.js +141 -0
  137. package/dist/trust-tasks/sign.js.map +1 -0
  138. package/dist/util/timing.d.ts +14 -0
  139. package/dist/util/timing.d.ts.map +1 -0
  140. package/dist/util/timing.js +20 -0
  141. package/dist/util/timing.js.map +1 -0
  142. package/dist/vault/delete.d.ts +19 -0
  143. package/dist/vault/delete.d.ts.map +1 -0
  144. package/dist/vault/delete.js +35 -0
  145. package/dist/vault/delete.js.map +1 -0
  146. package/dist/vault/index.d.ts +8 -0
  147. package/dist/vault/index.d.ts.map +1 -0
  148. package/dist/vault/index.js +7 -0
  149. package/dist/vault/index.js.map +1 -0
  150. package/dist/vault/list.d.ts +96 -0
  151. package/dist/vault/list.d.ts.map +1 -0
  152. package/dist/vault/list.js +106 -0
  153. package/dist/vault/list.js.map +1 -0
  154. package/dist/vault/proxy-login.d.ts +100 -0
  155. package/dist/vault/proxy-login.d.ts.map +1 -0
  156. package/dist/vault/proxy-login.js +106 -0
  157. package/dist/vault/proxy-login.js.map +1 -0
  158. package/dist/vault/release.d.ts +33 -0
  159. package/dist/vault/release.d.ts.map +1 -0
  160. package/dist/vault/release.js +83 -0
  161. package/dist/vault/release.js.map +1 -0
  162. package/dist/vault/sign-trust-task.d.ts +26 -0
  163. package/dist/vault/sign-trust-task.d.ts.map +1 -0
  164. package/dist/vault/sign-trust-task.js +53 -0
  165. package/dist/vault/sign-trust-task.js.map +1 -0
  166. package/dist/vault/transport.d.ts +50 -0
  167. package/dist/vault/transport.d.ts.map +1 -0
  168. package/dist/vault/transport.js +118 -0
  169. package/dist/vault/transport.js.map +1 -0
  170. package/dist/vault/upsert.d.ts +102 -0
  171. package/dist/vault/upsert.d.ts.map +1 -0
  172. package/dist/vault/upsert.js +92 -0
  173. package/dist/vault/upsert.js.map +1 -0
  174. package/dist/vta/bridge-mediator-session.d.ts +26 -0
  175. package/dist/vta/bridge-mediator-session.d.ts.map +1 -0
  176. package/dist/vta/bridge-mediator-session.js +37 -0
  177. package/dist/vta/bridge-mediator-session.js.map +1 -0
  178. package/dist/vta/bridge-memory.d.ts +80 -0
  179. package/dist/vta/bridge-memory.d.ts.map +1 -0
  180. package/dist/vta/bridge-memory.js +162 -0
  181. package/dist/vta/bridge-memory.js.map +1 -0
  182. package/dist/vta/client.d.ts +40 -0
  183. package/dist/vta/client.d.ts.map +1 -0
  184. package/dist/vta/client.js +91 -0
  185. package/dist/vta/client.js.map +1 -0
  186. package/dist/vta/contexts.d.ts +60 -0
  187. package/dist/vta/contexts.d.ts.map +1 -0
  188. package/dist/vta/contexts.js +118 -0
  189. package/dist/vta/contexts.js.map +1 -0
  190. package/dist/vta/didcomm.d.ts +57 -0
  191. package/dist/vta/didcomm.d.ts.map +1 -0
  192. package/dist/vta/didcomm.js +138 -0
  193. package/dist/vta/didcomm.js.map +1 -0
  194. package/dist/vta/errors.d.ts +20 -0
  195. package/dist/vta/errors.d.ts.map +1 -0
  196. package/dist/vta/errors.js +64 -0
  197. package/dist/vta/errors.js.map +1 -0
  198. package/dist/vta/index.d.ts +15 -0
  199. package/dist/vta/index.d.ts.map +1 -0
  200. package/dist/vta/index.js +15 -0
  201. package/dist/vta/index.js.map +1 -0
  202. package/dist/vta/mediation.d.ts +80 -0
  203. package/dist/vta/mediation.d.ts.map +1 -0
  204. package/dist/vta/mediation.js +29 -0
  205. package/dist/vta/mediation.js.map +1 -0
  206. package/dist/vta/mediator-client.d.ts +66 -0
  207. package/dist/vta/mediator-client.d.ts.map +1 -0
  208. package/dist/vta/mediator-client.js +139 -0
  209. package/dist/vta/mediator-client.js.map +1 -0
  210. package/dist/vta/pickup.d.ts +81 -0
  211. package/dist/vta/pickup.d.ts.map +1 -0
  212. package/dist/vta/pickup.js +30 -0
  213. package/dist/vta/pickup.js.map +1 -0
  214. package/dist/vta/protocol.d.ts +76 -0
  215. package/dist/vta/protocol.d.ts.map +1 -0
  216. package/dist/vta/protocol.js +30 -0
  217. package/dist/vta/protocol.js.map +1 -0
  218. package/dist/vta/smoke.d.ts +59 -0
  219. package/dist/vta/smoke.d.ts.map +1 -0
  220. package/dist/vta/smoke.js +408 -0
  221. package/dist/vta/smoke.js.map +1 -0
  222. package/dist/vta/transport.d.ts +55 -0
  223. package/dist/vta/transport.d.ts.map +1 -0
  224. package/dist/vta/transport.js +2 -0
  225. package/dist/vta/transport.js.map +1 -0
  226. package/dist/vta/types.d.ts +50 -0
  227. package/dist/vta/types.d.ts.map +1 -0
  228. package/dist/vta/types.js +2 -0
  229. package/dist/vta/types.js.map +1 -0
  230. package/dist/vta/wallet-session.d.ts +87 -0
  231. package/dist/vta/wallet-session.d.ts.map +1 -0
  232. package/dist/vta/wallet-session.js +106 -0
  233. package/dist/vta/wallet-session.js.map +1 -0
  234. package/dist/webauthn/base64url.d.ts +3 -0
  235. package/dist/webauthn/base64url.d.ts.map +1 -0
  236. package/dist/webauthn/base64url.js +17 -0
  237. package/dist/webauthn/base64url.js.map +1 -0
  238. package/dist/webauthn/index.d.ts +4 -0
  239. package/dist/webauthn/index.d.ts.map +1 -0
  240. package/dist/webauthn/index.js +4 -0
  241. package/dist/webauthn/index.js.map +1 -0
  242. package/dist/webauthn/multikey.d.ts +26 -0
  243. package/dist/webauthn/multikey.d.ts.map +1 -0
  244. package/dist/webauthn/multikey.js +91 -0
  245. package/dist/webauthn/multikey.js.map +1 -0
  246. package/dist/webauthn/register.d.ts +36 -0
  247. package/dist/webauthn/register.d.ts.map +1 -0
  248. package/dist/webauthn/register.js +77 -0
  249. package/dist/webauthn/register.js.map +1 -0
  250. package/package.json +56 -0
@@ -0,0 +1,441 @@
1
+ import { ed25519, x25519 } from "@noble/curves/ed25519.js";
2
+ import { base64url } from "@openvtc/vti-didcomm-js";
3
+ import { createDidPeer2 } from "../did/index.js";
4
+ import { Identity } from "../didcomm/index.js";
5
+ import { unwrapSecret, wrapSecret, } from "./secret-wrap.js";
6
+ // v3: the holder is a single **Ed25519-rooted `did:peer:2`** the wallet
7
+ // MINTS locally on first run. v2 used a `did:key`, which can sign + derive
8
+ // an X25519 keyAgreement key but CANNOT advertise a service endpoint — so
9
+ // an RP can't reach the wallet for inbound (RP-initiated) requests. A
10
+ // did:peer:2 encodes both keys plus the wallet's mediator service inline,
11
+ // making the wallet reachable, while staying self-certifying (resolves
12
+ // with no network).
13
+ //
14
+ // v4: the holder is an Ed25519 **`did:key`** the VTA MINTS during the
15
+ // provision-integration flow. The wallet ships its ephemeral did:key to
16
+ // the VTA, which mints a long-term admin DID + keys + authorization VC
17
+ // and ships them back HPKE-sealed; the wallet adopts the result as its
18
+ // holder. The DID method changes — did:key has no service endpoint, so
19
+ // the wallet is no longer reachable inbound at the holder layer. RP-
20
+ // initiated DIDComm is out-of-scope for v4 (the wallet only initiates).
21
+ //
22
+ // v4 reads ALWAYS preferred over v3 by the strict loader; v3 records left
23
+ // over from a pre-v4 wallet surface as `RequiresReonboardError` so the
24
+ // operator can re-onboard at a VTA and adopt a freshly-minted v4 identity.
25
+ //
26
+ // The Ed25519 secret is the persisted root in both shapes: it IS the
27
+ // authentication key, and the X25519 keyAgreement key is its Montgomery
28
+ // form, re-derived on every load.
29
+ const STORE_KEY = "pnm/holder-identity/v3";
30
+ // Legacy single-VTA v4 key. Read-only after multi-VTA landed; records
31
+ // found here are migrated to the per-vta path on first access and the
32
+ // legacy key is deleted. Kept defined (not exported) so the migration
33
+ // helper can read it without re-typing the constant.
34
+ const STORE_KEY_V4_LEGACY = "pnm/holder-identity/v4";
35
+ // Per-VTA v4 key prefix. Each VTA the wallet has been onboarded at
36
+ // has its own record under `{prefix}{vtaDid}`. The trailing `/`
37
+ // disambiguates the prefix-scan from the legacy singleton key so a
38
+ // caller listing records doesn't accidentally pick up the legacy
39
+ // row before its migration ran.
40
+ const STORE_KEY_V4_PREFIX = "pnm/holder-identity/v4/";
41
+ function v4Key(vtaDid) {
42
+ return STORE_KEY_V4_PREFIX + vtaDid;
43
+ }
44
+ /**
45
+ * Migrate the legacy single-VTA v4 record (if present) to its
46
+ * per-vta key, using the record's own `vtaDid` field as the path
47
+ * suffix. Idempotent: a second call after migration is a no-op
48
+ * (legacy key is gone, return value is `null`). Returns the migrated
49
+ * record so the immediate caller can use it without a second read.
50
+ *
51
+ * Called inline from every read path so installs predating multi-VTA
52
+ * are picked up on whichever read fires first after upgrade.
53
+ */
54
+ async function migrateLegacyV4Record(store) {
55
+ const legacy = await store.get(STORE_KEY_V4_LEGACY);
56
+ if (!legacy)
57
+ return null;
58
+ // Write FIRST, delete after — a crash between the two leaves the
59
+ // legacy row in place; the next read re-runs the migration.
60
+ await store.put(v4Key(legacy.vtaDid), legacy);
61
+ await store.delete(STORE_KEY_V4_LEGACY);
62
+ return legacy;
63
+ }
64
+ /**
65
+ * Generate-or-load the wallet's holder identity (a `did:peer:2`) from a
66
+ * `KVStore`. Only the Ed25519 secret is persisted; the DID + kids are
67
+ * persisted alongside it (the DID is immutable once minted), and the X25519
68
+ * keyAgreement key is re-derived on every load.
69
+ *
70
+ * Persistence is wrapped via the optional [`HolderIdentityOptions.secretWrap`]
71
+ * — production extensions supply a `WebAuthnPrfSecretWrap` so storage
72
+ * exfil yields ciphertext, not the wallet's signing key. Callers that
73
+ * omit the wrap fall back to plaintext (legacy behaviour); the
74
+ * loader handles both shapes for backward compatibility.
75
+ */
76
+ export async function generateOrLoadHolderIdentity(store, opts) {
77
+ const persisted = await store.get(STORE_KEY);
78
+ if (persisted) {
79
+ let edSecret;
80
+ if (persisted.wrappedSecret) {
81
+ // New shape: read through the wrap. A wrap-algorithm
82
+ // mismatch (record wrapped with X, caller supplied Y)
83
+ // throws — the loader can't silently fall back without
84
+ // risking a secret leak.
85
+ edSecret = await unwrapSecret(persisted.wrappedSecret, opts?.secretWrap);
86
+ }
87
+ else if (persisted.edSecretB64u) {
88
+ // Legacy shape: plaintext base64url. Pre-H1 wallets.
89
+ edSecret = base64url.decode(persisted.edSecretB64u);
90
+ }
91
+ else {
92
+ throw new Error("persisted holder record missing both wrappedSecret and edSecretB64u");
93
+ }
94
+ return {
95
+ ...buildHolder(edSecret, persisted.did, persisted.signingKid, persisted.keyAgreementKid),
96
+ freshlyMinted: false,
97
+ };
98
+ }
99
+ const edSecret = ed25519.utils.randomSecretKey();
100
+ const edPublic = ed25519.getPublicKey(edSecret);
101
+ const x25519Public = x25519.getPublicKey(ed25519.utils.toMontgomerySecret(edSecret));
102
+ const peer = createDidPeer2({
103
+ ed25519PublicKey: edPublic,
104
+ x25519PublicKey: x25519Public,
105
+ ...(opts?.mediatorDid ? { service: { serviceEndpoint: opts.mediatorDid } } : {}),
106
+ });
107
+ const wrapped = await wrapSecret(edSecret, opts?.secretWrap);
108
+ const record = {
109
+ did: peer.did,
110
+ signingKid: peer.authKid,
111
+ keyAgreementKid: peer.keyAgreementKid,
112
+ wrappedSecret: wrapped,
113
+ ...(opts?.mediatorDid ? { mediatorDid: opts.mediatorDid } : {}),
114
+ };
115
+ await store.put(STORE_KEY, record);
116
+ return {
117
+ ...buildHolder(edSecret, peer.did, peer.authKid, peer.keyAgreementKid),
118
+ freshlyMinted: true,
119
+ };
120
+ }
121
+ /** Reconstruct the signing + DIDComm identities from the Ed25519 root secret
122
+ * and the (persisted/minted) did:peer + its VM ids. */
123
+ function buildHolder(edSecret, did, signingKid, keyAgreementKid) {
124
+ const edPublic = ed25519.getPublicKey(edSecret);
125
+ const xPrivate = ed25519.utils.toMontgomerySecret(edSecret);
126
+ const xPublic = x25519.getPublicKey(xPrivate);
127
+ const signing = {
128
+ did,
129
+ kid: signingKid,
130
+ privateKey: edSecret,
131
+ publicKey: edPublic,
132
+ };
133
+ const identity = Identity.fromSecretJwk({
134
+ did,
135
+ kid: keyAgreementKid,
136
+ jwk: {
137
+ kty: "OKP",
138
+ crv: "X25519",
139
+ x: base64url.encode(xPublic),
140
+ d: base64url.encode(xPrivate),
141
+ },
142
+ });
143
+ return { identity, signing };
144
+ }
145
+ /** Forget every persisted holder identity. Mostly for tests / hard
146
+ * reset (the options page "wipe wallet" button). Clears the v3 row,
147
+ * the legacy single-VTA v4 row, AND every per-vta v4 record. After
148
+ * this the wallet looks freshly installed at every VTA. */
149
+ export async function clearHolderIdentity(store) {
150
+ await store.delete(STORE_KEY);
151
+ await store.delete(STORE_KEY_V4_LEGACY);
152
+ const perVtaKeys = await store.keys(STORE_KEY_V4_PREFIX);
153
+ for (const k of perVtaKeys) {
154
+ await store.delete(k);
155
+ }
156
+ }
157
+ /** Thrown by `loadHolderStrict` when neither a v3 nor a v4 holder record
158
+ * exists — the wallet is on a fresh install and the operator should
159
+ * proceed with onboarding. */
160
+ export class NoHolderError extends Error {
161
+ constructor() {
162
+ super("no persisted holder identity — onboard with a VTA");
163
+ this.name = "NoHolderError";
164
+ }
165
+ }
166
+ /** Thrown by `loadHolderStrict` when a v3 (self-derived did:peer) record
167
+ * exists but no v4 (VTA-minted did:key) record. The wallet was built
168
+ * before the M2C identity migration; the operator must re-onboard so the
169
+ * VTA mints a fresh long-term DID. The old did:peer is unusable as the
170
+ * wallet's holder going forward — every RP that recognised it must be
171
+ * re-granted with the new VTA-minted DID.
172
+ *
173
+ * `previousDid` is the v3 DID, surfaced for the migration UI so the
174
+ * operator can audit what they're abandoning. */
175
+ export class RequiresReonboardError extends Error {
176
+ previousDid;
177
+ constructor(previousDid) {
178
+ super(`pre-v4 holder identity (${previousDid}) — re-onboard required: ` +
179
+ "this build expects a VTA-minted holder DID. Connect to a VTA to mint a fresh identity.");
180
+ this.name = "RequiresReonboardError";
181
+ this.previousDid = previousDid;
182
+ }
183
+ }
184
+ /** Load the wallet's holder identity for the given VTA, strictly
185
+ * preferring v4.
186
+ *
187
+ * - v4 record for `vtaDid` present → return the VTA-minted holder.
188
+ * - no v4 record for `vtaDid` but a legacy single-VTA v4 record
189
+ * exists → migrate it to the per-vta path (transparently) and
190
+ * return if its `vtaDid` matches the requested one.
191
+ * - no v4 (for `vtaDid` or legacy) but v3 present → throw
192
+ * `RequiresReonboardError` (the operator needs to re-onboard so the
193
+ * VTA mints a v4 identity).
194
+ * - none of the above → throw `NoHolderError` (fresh install). */
195
+ export async function loadHolderStrict(store, opts) {
196
+ let v4 = await store.get(v4Key(opts.vtaDid));
197
+ if (!v4) {
198
+ // Inline migration of the legacy single-VTA v4 record. If the
199
+ // legacy row's vtaDid matches the requested one, use it now;
200
+ // otherwise fall through (the wallet is onboarded at a different
201
+ // VTA than the one being asked for).
202
+ const migrated = await migrateLegacyV4Record(store);
203
+ if (migrated && migrated.vtaDid === opts.vtaDid) {
204
+ v4 = migrated;
205
+ }
206
+ }
207
+ if (v4) {
208
+ const edSecret = await unwrapSecret(v4.wrappedSecret, opts.secretWrap);
209
+ return {
210
+ ...buildHolder(edSecret, v4.did, v4.signingKid, v4.keyAgreementKid),
211
+ freshlyMinted: false,
212
+ };
213
+ }
214
+ const v3 = await store.get(STORE_KEY);
215
+ if (v3) {
216
+ throw new RequiresReonboardError(v3.did);
217
+ }
218
+ throw new NoHolderError();
219
+ }
220
+ /** Persist a freshly-minted VTA holder as the wallet's v4 identity.
221
+ *
222
+ * Returns the rebuilt `HolderIdentityResult` so the caller can use the
223
+ * identity immediately without an extra load. Clears any pre-existing
224
+ * v3 record on a successful install — the migration is a one-way move
225
+ * and a stale v3 record sitting alongside v4 is just a footgun for a
226
+ * future loader. */
227
+ export async function installVtaMintedHolder(store, opts) {
228
+ if (opts.edSeed.length !== 32) {
229
+ throw new Error(`installVtaMintedHolder: edSeed must be 32 bytes (got ${opts.edSeed.length})`);
230
+ }
231
+ const wrapped = await wrapSecret(opts.edSeed, opts.secretWrap);
232
+ const record = {
233
+ did: opts.did,
234
+ signingKid: opts.signingKid,
235
+ keyAgreementKid: opts.keyAgreementKid,
236
+ wrappedSecret: wrapped,
237
+ vtaDid: opts.vtaDid,
238
+ ...(opts.vtaUrl ? { vtaUrl: opts.vtaUrl } : {}),
239
+ schemaVersion: 4,
240
+ };
241
+ await store.put(v4Key(opts.vtaDid), record);
242
+ // Migration: drop the legacy did:peer record so the next strict load
243
+ // doesn't re-prompt the operator to re-onboard. Without this, a wallet
244
+ // that successfully onboarded but kept the v3 row would loop on its
245
+ // first reload.
246
+ await store.delete(STORE_KEY);
247
+ // Also drop the legacy single-VTA v4 record if present — the per-vta
248
+ // record is the new source of truth. Idempotent: a no-op if the
249
+ // legacy row was already migrated or never existed.
250
+ await store.delete(STORE_KEY_V4_LEGACY);
251
+ return {
252
+ ...buildHolder(opts.edSeed, opts.did, opts.signingKid, opts.keyAgreementKid),
253
+ freshlyMinted: true,
254
+ };
255
+ }
256
+ /** Re-wrap the persisted v4 holder secret in place, preserving the
257
+ * wallet's DID + verification-method ids + VTA provenance.
258
+ *
259
+ * The canonical caller is the popup's post-onboard "Encrypt your
260
+ * wallet?" prompt: the operator clicks the button, the popup runs
261
+ * `navigator.credentials.create` (visible context, fresh user
262
+ * gesture), and re-wraps the existing passthrough record under
263
+ * the PRF-derived AES-GCM key. The wallet DID stays the same — no
264
+ * re-grant in any RP ACL, no re-onboarding.
265
+ *
266
+ * Mirrors the v3 `rewrapHolderSecret` but reads + writes the v4
267
+ * record (`STORE_KEY_V4`). Future cleanup could consolidate the
268
+ * two into one schema-version-aware function; kept separate for
269
+ * now so the v3 path's legacy `edSecretB64u` fallback doesn't
270
+ * leak into v4's cleaner shape.
271
+ *
272
+ * Throws if no v4 record exists. The popup should only invoke this
273
+ * AFTER `installVtaMintedHolder` has run. */
274
+ export async function rewrapHolderV4Secret(store, opts) {
275
+ let persisted = await store.get(v4Key(opts.vtaDid));
276
+ if (!persisted) {
277
+ // Try migrating a legacy single-VTA row into the per-vta path,
278
+ // then re-read. Same idempotent helper used by `loadHolderStrict`.
279
+ const migrated = await migrateLegacyV4Record(store);
280
+ if (migrated && migrated.vtaDid === opts.vtaDid) {
281
+ persisted = migrated;
282
+ }
283
+ }
284
+ if (!persisted) {
285
+ throw new Error(`no persisted v4 holder identity to re-wrap for ${opts.vtaDid}`);
286
+ }
287
+ // 1. Recover the raw seed using the from-wrap. `unwrapSecret`
288
+ // dispatches on the stored record's `algorithm`, so a
289
+ // PassthroughWrap record opens regardless of which wrap the
290
+ // caller supplies (they're typically passing the new
291
+ // encryption-target wrap, not the existing passthrough).
292
+ const edSecret = await unwrapSecret(persisted.wrappedSecret, opts.fromWrap);
293
+ // 2. Re-wrap with the to-wrap and write back. Same shape as
294
+ // `installVtaMintedHolder`'s write path; only `wrappedSecret`
295
+ // actually changes.
296
+ const wrapped = await wrapSecret(edSecret, opts.toWrap);
297
+ const next = {
298
+ did: persisted.did,
299
+ signingKid: persisted.signingKid,
300
+ keyAgreementKid: persisted.keyAgreementKid,
301
+ wrappedSecret: wrapped,
302
+ vtaDid: persisted.vtaDid,
303
+ ...(persisted.vtaUrl ? { vtaUrl: persisted.vtaUrl } : {}),
304
+ schemaVersion: 4,
305
+ };
306
+ await store.put(v4Key(persisted.vtaDid), next);
307
+ return {
308
+ ...buildHolder(edSecret, persisted.did, persisted.signingKid, persisted.keyAgreementKid),
309
+ freshlyMinted: false,
310
+ };
311
+ }
312
+ /** Inspect the persisted state without throwing. Used by the popup to
313
+ * decide which onboarding screen to show.
314
+ *
315
+ * For v4 records, `wrapAlgorithm` reveals whether the secret is
316
+ * encrypted at rest. `"passthrough"` means plaintext (the operator
317
+ * hasn't enabled encryption); anything else (currently only
318
+ * `"webauthn-prf-aes-gcm"`) means the popup needs to run an
319
+ * unlock ceremony before offscreen can load the holder identity.
320
+ *
321
+ * When `vtaDid` is passed: returns the state for that specific
322
+ * VTA's holder record. Used by the popup's active-VTA probe.
323
+ * When `vtaDid` is omitted: returns the first v4 record found
324
+ * (after migrating any legacy single-VTA row), else falls back to
325
+ * v3 / none. Used for the initial fresh-install / migration-banner
326
+ * decision before an active VTA has been selected. */
327
+ export async function holderIdentityState(store, vtaDid) {
328
+ // Migrate the legacy row if present — it joins the per-vta keyspace
329
+ // and will be picked up by the lookups below.
330
+ await migrateLegacyV4Record(store);
331
+ if (vtaDid !== undefined) {
332
+ const v4 = await store.get(v4Key(vtaDid));
333
+ if (v4) {
334
+ return {
335
+ kind: "v4",
336
+ did: v4.did,
337
+ vtaDid: v4.vtaDid,
338
+ wrapAlgorithm: v4.wrappedSecret.algorithm,
339
+ };
340
+ }
341
+ }
342
+ else {
343
+ // No specific VTA — scan the per-vta keyspace and return the
344
+ // first match. The popup uses this for the migration banner
345
+ // detection (any v4 present at all → skip the v3 banner).
346
+ const keys = await store.keys(STORE_KEY_V4_PREFIX);
347
+ if (keys.length > 0) {
348
+ const first = await store.get(keys[0]);
349
+ if (first) {
350
+ return {
351
+ kind: "v4",
352
+ did: first.did,
353
+ vtaDid: first.vtaDid,
354
+ wrapAlgorithm: first.wrappedSecret.algorithm,
355
+ };
356
+ }
357
+ }
358
+ }
359
+ const v3 = await store.get(STORE_KEY);
360
+ if (v3)
361
+ return { kind: "v3", did: v3.did };
362
+ return { kind: "none" };
363
+ }
364
+ /** Enumerate every v4 holder record on disk — one per VTA the wallet
365
+ * has been onboarded at. Powers the popup's multi-VTA dropdown
366
+ * (PR 2). Migrates the legacy single-VTA row inline so a wallet
367
+ * upgraded from a single-VTA build surfaces its one wallet here. */
368
+ export async function listHolderRecords(store) {
369
+ await migrateLegacyV4Record(store);
370
+ const keys = await store.keys(STORE_KEY_V4_PREFIX);
371
+ const out = [];
372
+ for (const k of keys) {
373
+ const r = await store.get(k);
374
+ if (!r)
375
+ continue;
376
+ out.push({
377
+ vtaDid: r.vtaDid,
378
+ did: r.did,
379
+ wrapAlgorithm: r.wrappedSecret.algorithm,
380
+ });
381
+ }
382
+ return out;
383
+ }
384
+ /** Delete the v4 holder record for a specific VTA. Companion to
385
+ * `installVtaMintedHolder`. Idempotent: a no-op when the record is
386
+ * already gone. Other VTAs' records are left alone — call
387
+ * `clearHolderIdentity` to wipe every wallet on this device. */
388
+ export async function forgetHolderRecord(store, vtaDid) {
389
+ await store.delete(v4Key(vtaDid));
390
+ }
391
+ /**
392
+ * Re-wrap the persisted holder secret in place, preserving the
393
+ * wallet's DID + verification-method ids + mediator endpoint.
394
+ *
395
+ * Used by the extension's settings UI when the operator flips
396
+ * the `encryptHolderSecret` toggle — the existing wallet keeps
397
+ * its identity (no re-grant in any RP ACL) but the on-disk
398
+ * secret transitions between plaintext and wrap-encrypted.
399
+ *
400
+ * Returns the rebuilt `HolderIdentityResult` so the caller can
401
+ * report the (unchanged) DID back to the operator immediately.
402
+ *
403
+ * Errors if no persisted record exists — caller should check
404
+ * `freshlyMinted` semantics first (a fresh-mint wallet has no
405
+ * pre-existing secret to re-wrap).
406
+ */
407
+ export async function rewrapHolderSecret(store, opts) {
408
+ const persisted = await store.get(STORE_KEY);
409
+ if (!persisted) {
410
+ throw new Error("no persisted holder identity to re-wrap");
411
+ }
412
+ // 1. Recover the raw secret using the from-wrap.
413
+ let edSecret;
414
+ if (persisted.wrappedSecret) {
415
+ edSecret = await unwrapSecret(persisted.wrappedSecret, opts.fromWrap);
416
+ }
417
+ else if (persisted.edSecretB64u) {
418
+ edSecret = base64url.decode(persisted.edSecretB64u);
419
+ }
420
+ else {
421
+ throw new Error("persisted record missing both wrappedSecret and edSecretB64u");
422
+ }
423
+ // 2. Re-wrap with the to-wrap and write back. Drop the legacy
424
+ // plaintext slot on the way out so a partially-migrated
425
+ // record can't load through the legacy path on the next
426
+ // boot.
427
+ const wrapped = await wrapSecret(edSecret, opts.toWrap);
428
+ const next = {
429
+ did: persisted.did,
430
+ signingKid: persisted.signingKid,
431
+ keyAgreementKid: persisted.keyAgreementKid,
432
+ wrappedSecret: wrapped,
433
+ ...(persisted.mediatorDid ? { mediatorDid: persisted.mediatorDid } : {}),
434
+ };
435
+ await store.put(STORE_KEY, next);
436
+ return {
437
+ ...buildHolder(edSecret, persisted.did, persisted.signingKid, persisted.keyAgreementKid),
438
+ freshlyMinted: false,
439
+ };
440
+ }
441
+ //# sourceMappingURL=holder-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"holder-identity.js","sourceRoot":"","sources":["../../src/store/holder-identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from "./kv-store.js";
2
+ export * from "./holder-identity.js";
3
+ export * from "./secret-wrap.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from "./kv-store.js";
2
+ export * from "./holder-identity.js";
3
+ export * from "./secret-wrap.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Minimal async key/value store. Two implementations ship:
3
+ *
4
+ * - `InMemoryKVStore` — for tests and ephemeral sessions.
5
+ * - `IndexedDBKVStore` — for browser persistence.
6
+ *
7
+ * Anything stored MUST be JSON-serialisable. The store does not
8
+ * encrypt at rest — callers wrap values in WebAuthn PRF-derived keys
9
+ * (or similar) before writing if the value is sensitive (e.g. a
10
+ * holder identity's secret JWK).
11
+ */
12
+ export interface KVStore {
13
+ get<T = unknown>(key: string): Promise<T | undefined>;
14
+ put(key: string, value: unknown): Promise<void>;
15
+ delete(key: string): Promise<void>;
16
+ /** Enumerate keys, optionally filtered to those starting with
17
+ * `prefix`. Order is unspecified. Used for prefix-scanned
18
+ * collections (e.g. multi-VTA holder records under
19
+ * `pnm/holder-identity/v4/`). */
20
+ keys(prefix?: string): Promise<string[]>;
21
+ }
22
+ /** Backing for tests. Forgets state on process exit. */
23
+ export declare class InMemoryKVStore implements KVStore {
24
+ private readonly map;
25
+ get<T>(key: string): Promise<T | undefined>;
26
+ put(key: string, value: unknown): Promise<void>;
27
+ delete(key: string): Promise<void>;
28
+ keys(prefix?: string): Promise<string[]>;
29
+ }
30
+ /**
31
+ * `IndexedDB`-backed `KVStore`. Single object store, single
32
+ * database. Suitable for browser + extension contexts where
33
+ * `indexedDB` is available. Node 22+ has `indexedDB` via the
34
+ * `node:sqlite`-backed implementation behind a flag; tests should
35
+ * use `InMemoryKVStore` instead.
36
+ */
37
+ export declare class IndexedDBKVStore implements KVStore {
38
+ private readonly dbName;
39
+ private readonly storeName;
40
+ private dbPromise;
41
+ constructor(opts?: {
42
+ dbName?: string;
43
+ storeName?: string;
44
+ });
45
+ get<T>(key: string): Promise<T | undefined>;
46
+ put(key: string, value: unknown): Promise<void>;
47
+ delete(key: string): Promise<void>;
48
+ keys(prefix?: string): Promise<string[]>;
49
+ private openDb;
50
+ }
51
+ //# sourceMappingURL=kv-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-store.d.ts","sourceRoot":"","sources":["../../src/store/kv-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACtD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC;;;sCAGkC;IAClC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC1C;AAED,wDAAwD;AACxD,qBAAa,eAAgB,YAAW,OAAO;IAC7C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA8B;IAE5C,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAK3C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAO/C;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,OAAO;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,SAAS,CAAqC;gBAE1C,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;IAKpD,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAU3C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAoB9C,OAAO,CAAC,MAAM;CAef"}
@@ -0,0 +1,100 @@
1
+ /** Backing for tests. Forgets state on process exit. */
2
+ export class InMemoryKVStore {
3
+ map = new Map();
4
+ async get(key) {
5
+ const v = this.map.get(key);
6
+ return v === undefined ? undefined : structuredClone(v);
7
+ }
8
+ async put(key, value) {
9
+ this.map.set(key, structuredClone(value));
10
+ }
11
+ async delete(key) {
12
+ this.map.delete(key);
13
+ }
14
+ async keys(prefix) {
15
+ const out = [];
16
+ for (const k of this.map.keys()) {
17
+ if (prefix === undefined || k.startsWith(prefix))
18
+ out.push(k);
19
+ }
20
+ return out;
21
+ }
22
+ }
23
+ /**
24
+ * `IndexedDB`-backed `KVStore`. Single object store, single
25
+ * database. Suitable for browser + extension contexts where
26
+ * `indexedDB` is available. Node 22+ has `indexedDB` via the
27
+ * `node:sqlite`-backed implementation behind a flag; tests should
28
+ * use `InMemoryKVStore` instead.
29
+ */
30
+ export class IndexedDBKVStore {
31
+ dbName;
32
+ storeName;
33
+ dbPromise = null;
34
+ constructor(opts) {
35
+ this.dbName = opts?.dbName ?? "pnm";
36
+ this.storeName = opts?.storeName ?? "kv";
37
+ }
38
+ async get(key) {
39
+ const db = await this.openDb();
40
+ return new Promise((resolve, reject) => {
41
+ const tx = db.transaction(this.storeName, "readonly");
42
+ const req = tx.objectStore(this.storeName).get(key);
43
+ req.onsuccess = () => resolve(req.result);
44
+ req.onerror = () => reject(req.error);
45
+ });
46
+ }
47
+ async put(key, value) {
48
+ const db = await this.openDb();
49
+ await new Promise((resolve, reject) => {
50
+ const tx = db.transaction(this.storeName, "readwrite");
51
+ tx.objectStore(this.storeName).put(value, key);
52
+ tx.oncomplete = () => resolve();
53
+ tx.onerror = () => reject(tx.error);
54
+ });
55
+ }
56
+ async delete(key) {
57
+ const db = await this.openDb();
58
+ await new Promise((resolve, reject) => {
59
+ const tx = db.transaction(this.storeName, "readwrite");
60
+ tx.objectStore(this.storeName).delete(key);
61
+ tx.oncomplete = () => resolve();
62
+ tx.onerror = () => reject(tx.error);
63
+ });
64
+ }
65
+ async keys(prefix) {
66
+ const db = await this.openDb();
67
+ // Use a key range when a prefix is provided so IndexedDB does the
68
+ // filtering — avoids walking the entire keyspace for a handful of
69
+ // matches. The upper bound is `prefix + '￿'` (the highest
70
+ // BMP code point), giving a half-open range that captures every
71
+ // string starting with `prefix`.
72
+ const range = prefix !== undefined
73
+ ? IDBKeyRange.bound(prefix, prefix + "￿", false, false)
74
+ : undefined;
75
+ return new Promise((resolve, reject) => {
76
+ const tx = db.transaction(this.storeName, "readonly");
77
+ const store = tx.objectStore(this.storeName);
78
+ const req = range !== undefined ? store.getAllKeys(range) : store.getAllKeys();
79
+ req.onsuccess = () => resolve(req.result.map(String));
80
+ req.onerror = () => reject(req.error);
81
+ });
82
+ }
83
+ openDb() {
84
+ if (this.dbPromise)
85
+ return this.dbPromise;
86
+ this.dbPromise = new Promise((resolve, reject) => {
87
+ const req = indexedDB.open(this.dbName, 1);
88
+ req.onupgradeneeded = () => {
89
+ const db = req.result;
90
+ if (!db.objectStoreNames.contains(this.storeName)) {
91
+ db.createObjectStore(this.storeName);
92
+ }
93
+ };
94
+ req.onsuccess = () => resolve(req.result);
95
+ req.onerror = () => reject(req.error);
96
+ });
97
+ return this.dbPromise;
98
+ }
99
+ }
100
+ //# sourceMappingURL=kv-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kv-store.js","sourceRoot":"","sources":["../../src/store/kv-store.ts"],"names":[],"mappings":"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"}