@metamask-previews/passkey-controller 0.0.0-preview-4c0846313

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 (156) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +155 -0
  4. package/dist/PasskeyController.cjs +448 -0
  5. package/dist/PasskeyController.cjs.map +1 -0
  6. package/dist/PasskeyController.d.cts +168 -0
  7. package/dist/PasskeyController.d.cts.map +1 -0
  8. package/dist/PasskeyController.d.mts +168 -0
  9. package/dist/PasskeyController.d.mts.map +1 -0
  10. package/dist/PasskeyController.mjs +443 -0
  11. package/dist/PasskeyController.mjs.map +1 -0
  12. package/dist/ceremony-manager.cjs +134 -0
  13. package/dist/ceremony-manager.cjs.map +1 -0
  14. package/dist/ceremony-manager.d.cts +71 -0
  15. package/dist/ceremony-manager.d.cts.map +1 -0
  16. package/dist/ceremony-manager.d.mts +71 -0
  17. package/dist/ceremony-manager.d.mts.map +1 -0
  18. package/dist/ceremony-manager.mjs +130 -0
  19. package/dist/ceremony-manager.mjs.map +1 -0
  20. package/dist/constants.cjs +33 -0
  21. package/dist/constants.cjs.map +1 -0
  22. package/dist/constants.d.cts +30 -0
  23. package/dist/constants.d.cts.map +1 -0
  24. package/dist/constants.d.mts +30 -0
  25. package/dist/constants.d.mts.map +1 -0
  26. package/dist/constants.mjs +30 -0
  27. package/dist/constants.mjs.map +1 -0
  28. package/dist/errors.cjs +57 -0
  29. package/dist/errors.cjs.map +1 -0
  30. package/dist/errors.d.cts +34 -0
  31. package/dist/errors.d.cts.map +1 -0
  32. package/dist/errors.d.mts +34 -0
  33. package/dist/errors.d.mts.map +1 -0
  34. package/dist/errors.mjs +53 -0
  35. package/dist/errors.mjs.map +1 -0
  36. package/dist/index.cjs +19 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +9 -0
  39. package/dist/index.d.cts.map +1 -0
  40. package/dist/index.d.mts +9 -0
  41. package/dist/index.d.mts.map +1 -0
  42. package/dist/index.mjs +5 -0
  43. package/dist/index.mjs.map +1 -0
  44. package/dist/key-derivation.cjs +76 -0
  45. package/dist/key-derivation.cjs.map +1 -0
  46. package/dist/key-derivation.d.cts +43 -0
  47. package/dist/key-derivation.d.cts.map +1 -0
  48. package/dist/key-derivation.d.mts +43 -0
  49. package/dist/key-derivation.d.mts.map +1 -0
  50. package/dist/key-derivation.mjs +71 -0
  51. package/dist/key-derivation.mjs.map +1 -0
  52. package/dist/logger.cjs +9 -0
  53. package/dist/logger.cjs.map +1 -0
  54. package/dist/logger.d.cts +5 -0
  55. package/dist/logger.d.cts.map +1 -0
  56. package/dist/logger.d.mts +5 -0
  57. package/dist/logger.d.mts.map +1 -0
  58. package/dist/logger.mjs +6 -0
  59. package/dist/logger.mjs.map +1 -0
  60. package/dist/types.cjs +3 -0
  61. package/dist/types.cjs.map +1 -0
  62. package/dist/types.d.cts +92 -0
  63. package/dist/types.d.cts.map +1 -0
  64. package/dist/types.d.mts +92 -0
  65. package/dist/types.d.mts.map +1 -0
  66. package/dist/types.mjs +2 -0
  67. package/dist/types.mjs.map +1 -0
  68. package/dist/utils/crypto.cjs +55 -0
  69. package/dist/utils/crypto.cjs.map +1 -0
  70. package/dist/utils/crypto.d.cts +30 -0
  71. package/dist/utils/crypto.d.cts.map +1 -0
  72. package/dist/utils/crypto.d.mts +30 -0
  73. package/dist/utils/crypto.d.mts.map +1 -0
  74. package/dist/utils/crypto.mjs +49 -0
  75. package/dist/utils/crypto.mjs.map +1 -0
  76. package/dist/utils/encoding.cjs +42 -0
  77. package/dist/utils/encoding.cjs.map +1 -0
  78. package/dist/utils/encoding.d.cts +22 -0
  79. package/dist/utils/encoding.d.cts.map +1 -0
  80. package/dist/utils/encoding.d.mts +22 -0
  81. package/dist/utils/encoding.d.mts.map +1 -0
  82. package/dist/utils/encoding.mjs +36 -0
  83. package/dist/utils/encoding.mjs.map +1 -0
  84. package/dist/webauthn/constants.cjs +74 -0
  85. package/dist/webauthn/constants.cjs.map +1 -0
  86. package/dist/webauthn/constants.d.cts +68 -0
  87. package/dist/webauthn/constants.d.cts.map +1 -0
  88. package/dist/webauthn/constants.d.mts +68 -0
  89. package/dist/webauthn/constants.d.mts.map +1 -0
  90. package/dist/webauthn/constants.mjs +71 -0
  91. package/dist/webauthn/constants.mjs.map +1 -0
  92. package/dist/webauthn/decode-attestation-object.cjs +18 -0
  93. package/dist/webauthn/decode-attestation-object.cjs.map +1 -0
  94. package/dist/webauthn/decode-attestation-object.d.cts +10 -0
  95. package/dist/webauthn/decode-attestation-object.d.cts.map +1 -0
  96. package/dist/webauthn/decode-attestation-object.d.mts +10 -0
  97. package/dist/webauthn/decode-attestation-object.d.mts.map +1 -0
  98. package/dist/webauthn/decode-attestation-object.mjs +14 -0
  99. package/dist/webauthn/decode-attestation-object.mjs.map +1 -0
  100. package/dist/webauthn/decode-client-data-json.cjs +17 -0
  101. package/dist/webauthn/decode-client-data-json.cjs.map +1 -0
  102. package/dist/webauthn/decode-client-data-json.d.cts +9 -0
  103. package/dist/webauthn/decode-client-data-json.d.cts.map +1 -0
  104. package/dist/webauthn/decode-client-data-json.d.mts +9 -0
  105. package/dist/webauthn/decode-client-data-json.d.mts.map +1 -0
  106. package/dist/webauthn/decode-client-data-json.mjs +13 -0
  107. package/dist/webauthn/decode-client-data-json.mjs.map +1 -0
  108. package/dist/webauthn/match-expected-rp-id.cjs +43 -0
  109. package/dist/webauthn/match-expected-rp-id.cjs.map +1 -0
  110. package/dist/webauthn/match-expected-rp-id.d.cts +11 -0
  111. package/dist/webauthn/match-expected-rp-id.d.cts.map +1 -0
  112. package/dist/webauthn/match-expected-rp-id.d.mts +11 -0
  113. package/dist/webauthn/match-expected-rp-id.d.mts.map +1 -0
  114. package/dist/webauthn/match-expected-rp-id.mjs +39 -0
  115. package/dist/webauthn/match-expected-rp-id.mjs.map +1 -0
  116. package/dist/webauthn/parse-authenticator-data.cjs +69 -0
  117. package/dist/webauthn/parse-authenticator-data.cjs.map +1 -0
  118. package/dist/webauthn/parse-authenticator-data.d.cts +10 -0
  119. package/dist/webauthn/parse-authenticator-data.d.cts.map +1 -0
  120. package/dist/webauthn/parse-authenticator-data.d.mts +10 -0
  121. package/dist/webauthn/parse-authenticator-data.d.mts.map +1 -0
  122. package/dist/webauthn/parse-authenticator-data.mjs +65 -0
  123. package/dist/webauthn/parse-authenticator-data.mjs.map +1 -0
  124. package/dist/webauthn/types.cjs +3 -0
  125. package/dist/webauthn/types.cjs.map +1 -0
  126. package/dist/webauthn/types.d.cts +113 -0
  127. package/dist/webauthn/types.d.cts.map +1 -0
  128. package/dist/webauthn/types.d.mts +113 -0
  129. package/dist/webauthn/types.d.mts.map +1 -0
  130. package/dist/webauthn/types.mjs +2 -0
  131. package/dist/webauthn/types.mjs.map +1 -0
  132. package/dist/webauthn/verify-authentication-response.cjs +134 -0
  133. package/dist/webauthn/verify-authentication-response.cjs.map +1 -0
  134. package/dist/webauthn/verify-authentication-response.d.cts +63 -0
  135. package/dist/webauthn/verify-authentication-response.d.cts.map +1 -0
  136. package/dist/webauthn/verify-authentication-response.d.mts +63 -0
  137. package/dist/webauthn/verify-authentication-response.d.mts.map +1 -0
  138. package/dist/webauthn/verify-authentication-response.mjs +130 -0
  139. package/dist/webauthn/verify-authentication-response.mjs.map +1 -0
  140. package/dist/webauthn/verify-registration-response.cjs +205 -0
  141. package/dist/webauthn/verify-registration-response.cjs.map +1 -0
  142. package/dist/webauthn/verify-registration-response.d.cts +60 -0
  143. package/dist/webauthn/verify-registration-response.d.cts.map +1 -0
  144. package/dist/webauthn/verify-registration-response.d.mts +60 -0
  145. package/dist/webauthn/verify-registration-response.d.mts.map +1 -0
  146. package/dist/webauthn/verify-registration-response.mjs +201 -0
  147. package/dist/webauthn/verify-registration-response.mjs.map +1 -0
  148. package/dist/webauthn/verify-signature.cjs +176 -0
  149. package/dist/webauthn/verify-signature.cjs.map +1 -0
  150. package/dist/webauthn/verify-signature.d.cts +21 -0
  151. package/dist/webauthn/verify-signature.d.cts.map +1 -0
  152. package/dist/webauthn/verify-signature.d.mts +21 -0
  153. package/dist/webauthn/verify-signature.d.mts.map +1 -0
  154. package/dist/webauthn/verify-signature.mjs +172 -0
  155. package/dist/webauthn/verify-signature.mjs.map +1 -0
  156. package/package.json +78 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceremony-manager.cjs","sourceRoot":"","sources":["../src/ceremony-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n PasskeyAuthenticationCeremony,\n PasskeyRegistrationCeremony,\n} from './types';\n\n/** WebAuthn `timeout` for credential creation and assertion (ms). */\nexport const WEBAUTHN_TIMEOUT_MS = 60_000;\n\n/**\n * Extra allowance beyond {@link WEBAUTHN_TIMEOUT_MS} before in-memory\n * ceremony state is discarded (covers slow UX and clock skew).\n */\nexport const CEREMONY_TTL_SLACK_MS = 15_000;\n\n/**\n * Maximum age for in-flight registration or authentication ceremony state\n * (between options and verified response). This bounds the lifetime of a\n * single WebAuthn ceremony only; it is not a user login session timeout.\n */\nexport const CEREMONY_MAX_AGE_MS = WEBAUTHN_TIMEOUT_MS + CEREMONY_TTL_SLACK_MS;\n\n/**\n * Upper bound on concurrent in-memory ceremonies per flow type (registration\n * vs authentication), for abuse / leak protection.\n */\nexport const MAX_CONCURRENT_PASSKEY_CEREMONIES = 16;\n\ntype CeremonyFlow = 'registration' | 'authentication';\n\n/**\n * In-memory store for in-flight WebAuthn ceremonies (registration vs authentication),\n * keyed by base64url challenge. Enforces TTL and a per-flow size cap; not user session state.\n */\nexport class CeremonyManager {\n readonly #registrationMap = new Map<string, PasskeyRegistrationCeremony>();\n\n readonly #authenticationMap = new Map<\n string,\n PasskeyAuthenticationCeremony\n >();\n\n /**\n * Challenge-keyed map for prune/capacity helpers.\n *\n * @param ceremonyType - Which in-flight ceremony map to use.\n * @returns The registration or authentication ceremony map for the given flow.\n */\n #getMap(\n ceremonyType: CeremonyFlow,\n ): Map<string, PasskeyRegistrationCeremony | PasskeyAuthenticationCeremony> {\n return ceremonyType === 'registration'\n ? this.#registrationMap\n : this.#authenticationMap;\n }\n\n #pruneExpired(ceremonyType: CeremonyFlow): void {\n const now = Date.now();\n const map = this.#getMap(ceremonyType);\n for (const [key, ceremony] of map) {\n if (now - ceremony.createdAt > CEREMONY_MAX_AGE_MS) {\n map.delete(key);\n }\n }\n }\n\n /**\n * Removes the oldest entry (by `createdAt`) until size is below the cap.\n *\n * @param ceremonyType - Which in-flight ceremony map to evict from.\n */\n #enforceCapacity(ceremonyType: CeremonyFlow): void {\n const map = this.#getMap(ceremonyType);\n while (map.size >= MAX_CONCURRENT_PASSKEY_CEREMONIES) {\n let oldestKey: string | undefined;\n let oldestTime = Infinity;\n for (const [mapKey, ceremony] of map) {\n if (ceremony.createdAt < oldestTime) {\n oldestTime = ceremony.createdAt;\n oldestKey = mapKey;\n }\n }\n if (oldestKey === undefined) {\n break;\n }\n map.delete(oldestKey);\n }\n }\n\n /**\n * Records registration ceremony state after pruning expired rows and evicting oldest if at cap.\n *\n * @param challenge - Same base64url challenge as in the creation options `challenge` field.\n * @param ceremony - Payload to retrieve when the registration response returns.\n */\n saveRegistrationCeremony(\n challenge: string,\n ceremony: PasskeyRegistrationCeremony,\n ): void {\n this.#pruneExpired('registration');\n this.#enforceCapacity('registration');\n this.#registrationMap.set(challenge, ceremony);\n }\n\n /**\n * Records authentication ceremony state after pruning expired rows and evicting oldest if at cap.\n *\n * @param challenge - Same base64url challenge as in the request options `challenge` field.\n * @param ceremony - Payload to retrieve when the assertion response returns.\n */\n saveAuthenticationCeremony(\n challenge: string,\n ceremony: PasskeyAuthenticationCeremony,\n ): void {\n this.#pruneExpired('authentication');\n this.#enforceCapacity('authentication');\n this.#authenticationMap.set(challenge, ceremony);\n }\n\n /**\n * Returns registration ceremony for a challenge, pruning expired entries on this map first.\n *\n * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).\n * @returns Stored ceremony, or `undefined` if none or expired.\n */\n getRegistrationCeremony(\n challenge: string,\n ): PasskeyRegistrationCeremony | undefined {\n this.#pruneExpired('registration');\n return this.#registrationMap.get(challenge);\n }\n\n /**\n * Returns authentication ceremony for a challenge, pruning expired entries on this map first.\n *\n * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).\n * @returns Stored ceremony, or `undefined` if none or expired.\n */\n getAuthenticationCeremony(\n challenge: string,\n ): PasskeyAuthenticationCeremony | undefined {\n this.#pruneExpired('authentication');\n return this.#authenticationMap.get(challenge);\n }\n\n /**\n * Removes a registration ceremony by challenge.\n *\n * @param challenge - Map key for the ceremony to remove.\n * @returns Whether an entry was deleted.\n */\n deleteRegistrationCeremony(challenge: string): boolean {\n return this.#registrationMap.delete(challenge);\n }\n\n /**\n * Removes an authentication ceremony by challenge.\n *\n * @param challenge - Map key for the ceremony to remove.\n * @returns Whether an entry was deleted.\n */\n deleteAuthenticationCeremony(challenge: string): boolean {\n return this.#authenticationMap.delete(challenge);\n }\n\n /** Drops all in-flight registration and authentication ceremonies. */\n clear(): void {\n this.#registrationMap.clear();\n this.#authenticationMap.clear();\n }\n}\n"]}
@@ -0,0 +1,71 @@
1
+ import type { PasskeyAuthenticationCeremony, PasskeyRegistrationCeremony } from "./types.cjs";
2
+ /** WebAuthn `timeout` for credential creation and assertion (ms). */
3
+ export declare const WEBAUTHN_TIMEOUT_MS = 60000;
4
+ /**
5
+ * Extra allowance beyond {@link WEBAUTHN_TIMEOUT_MS} before in-memory
6
+ * ceremony state is discarded (covers slow UX and clock skew).
7
+ */
8
+ export declare const CEREMONY_TTL_SLACK_MS = 15000;
9
+ /**
10
+ * Maximum age for in-flight registration or authentication ceremony state
11
+ * (between options and verified response). This bounds the lifetime of a
12
+ * single WebAuthn ceremony only; it is not a user login session timeout.
13
+ */
14
+ export declare const CEREMONY_MAX_AGE_MS: number;
15
+ /**
16
+ * Upper bound on concurrent in-memory ceremonies per flow type (registration
17
+ * vs authentication), for abuse / leak protection.
18
+ */
19
+ export declare const MAX_CONCURRENT_PASSKEY_CEREMONIES = 16;
20
+ /**
21
+ * In-memory store for in-flight WebAuthn ceremonies (registration vs authentication),
22
+ * keyed by base64url challenge. Enforces TTL and a per-flow size cap; not user session state.
23
+ */
24
+ export declare class CeremonyManager {
25
+ #private;
26
+ /**
27
+ * Records registration ceremony state after pruning expired rows and evicting oldest if at cap.
28
+ *
29
+ * @param challenge - Same base64url challenge as in the creation options `challenge` field.
30
+ * @param ceremony - Payload to retrieve when the registration response returns.
31
+ */
32
+ saveRegistrationCeremony(challenge: string, ceremony: PasskeyRegistrationCeremony): void;
33
+ /**
34
+ * Records authentication ceremony state after pruning expired rows and evicting oldest if at cap.
35
+ *
36
+ * @param challenge - Same base64url challenge as in the request options `challenge` field.
37
+ * @param ceremony - Payload to retrieve when the assertion response returns.
38
+ */
39
+ saveAuthenticationCeremony(challenge: string, ceremony: PasskeyAuthenticationCeremony): void;
40
+ /**
41
+ * Returns registration ceremony for a challenge, pruning expired entries on this map first.
42
+ *
43
+ * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).
44
+ * @returns Stored ceremony, or `undefined` if none or expired.
45
+ */
46
+ getRegistrationCeremony(challenge: string): PasskeyRegistrationCeremony | undefined;
47
+ /**
48
+ * Returns authentication ceremony for a challenge, pruning expired entries on this map first.
49
+ *
50
+ * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).
51
+ * @returns Stored ceremony, or `undefined` if none or expired.
52
+ */
53
+ getAuthenticationCeremony(challenge: string): PasskeyAuthenticationCeremony | undefined;
54
+ /**
55
+ * Removes a registration ceremony by challenge.
56
+ *
57
+ * @param challenge - Map key for the ceremony to remove.
58
+ * @returns Whether an entry was deleted.
59
+ */
60
+ deleteRegistrationCeremony(challenge: string): boolean;
61
+ /**
62
+ * Removes an authentication ceremony by challenge.
63
+ *
64
+ * @param challenge - Map key for the ceremony to remove.
65
+ * @returns Whether an entry was deleted.
66
+ */
67
+ deleteAuthenticationCeremony(challenge: string): boolean;
68
+ /** Drops all in-flight registration and authentication ceremonies. */
69
+ clear(): void;
70
+ }
71
+ //# sourceMappingURL=ceremony-manager.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceremony-manager.d.cts","sourceRoot":"","sources":["../src/ceremony-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,2BAA2B,EAC5B,oBAAgB;AAEjB,qEAAqE;AACrE,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAA8C,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAIpD;;;GAGG;AACH,qBAAa,eAAe;;IAuD1B;;;;;OAKG;IACH,wBAAwB,CACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,2BAA2B,GACpC,IAAI;IAMP;;;;;OAKG;IACH,0BAA0B,CACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,6BAA6B,GACtC,IAAI;IAMP;;;;;OAKG;IACH,uBAAuB,CACrB,SAAS,EAAE,MAAM,GAChB,2BAA2B,GAAG,SAAS;IAK1C;;;;;OAKG;IACH,yBAAyB,CACvB,SAAS,EAAE,MAAM,GAChB,6BAA6B,GAAG,SAAS;IAK5C;;;;;OAKG;IACH,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItD;;;;;OAKG;IACH,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIxD,sEAAsE;IACtE,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,71 @@
1
+ import type { PasskeyAuthenticationCeremony, PasskeyRegistrationCeremony } from "./types.mjs";
2
+ /** WebAuthn `timeout` for credential creation and assertion (ms). */
3
+ export declare const WEBAUTHN_TIMEOUT_MS = 60000;
4
+ /**
5
+ * Extra allowance beyond {@link WEBAUTHN_TIMEOUT_MS} before in-memory
6
+ * ceremony state is discarded (covers slow UX and clock skew).
7
+ */
8
+ export declare const CEREMONY_TTL_SLACK_MS = 15000;
9
+ /**
10
+ * Maximum age for in-flight registration or authentication ceremony state
11
+ * (between options and verified response). This bounds the lifetime of a
12
+ * single WebAuthn ceremony only; it is not a user login session timeout.
13
+ */
14
+ export declare const CEREMONY_MAX_AGE_MS: number;
15
+ /**
16
+ * Upper bound on concurrent in-memory ceremonies per flow type (registration
17
+ * vs authentication), for abuse / leak protection.
18
+ */
19
+ export declare const MAX_CONCURRENT_PASSKEY_CEREMONIES = 16;
20
+ /**
21
+ * In-memory store for in-flight WebAuthn ceremonies (registration vs authentication),
22
+ * keyed by base64url challenge. Enforces TTL and a per-flow size cap; not user session state.
23
+ */
24
+ export declare class CeremonyManager {
25
+ #private;
26
+ /**
27
+ * Records registration ceremony state after pruning expired rows and evicting oldest if at cap.
28
+ *
29
+ * @param challenge - Same base64url challenge as in the creation options `challenge` field.
30
+ * @param ceremony - Payload to retrieve when the registration response returns.
31
+ */
32
+ saveRegistrationCeremony(challenge: string, ceremony: PasskeyRegistrationCeremony): void;
33
+ /**
34
+ * Records authentication ceremony state after pruning expired rows and evicting oldest if at cap.
35
+ *
36
+ * @param challenge - Same base64url challenge as in the request options `challenge` field.
37
+ * @param ceremony - Payload to retrieve when the assertion response returns.
38
+ */
39
+ saveAuthenticationCeremony(challenge: string, ceremony: PasskeyAuthenticationCeremony): void;
40
+ /**
41
+ * Returns registration ceremony for a challenge, pruning expired entries on this map first.
42
+ *
43
+ * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).
44
+ * @returns Stored ceremony, or `undefined` if none or expired.
45
+ */
46
+ getRegistrationCeremony(challenge: string): PasskeyRegistrationCeremony | undefined;
47
+ /**
48
+ * Returns authentication ceremony for a challenge, pruning expired entries on this map first.
49
+ *
50
+ * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).
51
+ * @returns Stored ceremony, or `undefined` if none or expired.
52
+ */
53
+ getAuthenticationCeremony(challenge: string): PasskeyAuthenticationCeremony | undefined;
54
+ /**
55
+ * Removes a registration ceremony by challenge.
56
+ *
57
+ * @param challenge - Map key for the ceremony to remove.
58
+ * @returns Whether an entry was deleted.
59
+ */
60
+ deleteRegistrationCeremony(challenge: string): boolean;
61
+ /**
62
+ * Removes an authentication ceremony by challenge.
63
+ *
64
+ * @param challenge - Map key for the ceremony to remove.
65
+ * @returns Whether an entry was deleted.
66
+ */
67
+ deleteAuthenticationCeremony(challenge: string): boolean;
68
+ /** Drops all in-flight registration and authentication ceremonies. */
69
+ clear(): void;
70
+ }
71
+ //# sourceMappingURL=ceremony-manager.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceremony-manager.d.mts","sourceRoot":"","sources":["../src/ceremony-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAC7B,2BAA2B,EAC5B,oBAAgB;AAEjB,qEAAqE;AACrE,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAA8C,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,iCAAiC,KAAK,CAAC;AAIpD;;;GAGG;AACH,qBAAa,eAAe;;IAuD1B;;;;;OAKG;IACH,wBAAwB,CACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,2BAA2B,GACpC,IAAI;IAMP;;;;;OAKG;IACH,0BAA0B,CACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,6BAA6B,GACtC,IAAI;IAMP;;;;;OAKG;IACH,uBAAuB,CACrB,SAAS,EAAE,MAAM,GAChB,2BAA2B,GAAG,SAAS;IAK1C;;;;;OAKG;IACH,yBAAyB,CACvB,SAAS,EAAE,MAAM,GAChB,6BAA6B,GAAG,SAAS;IAK5C;;;;;OAKG;IACH,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItD;;;;;OAKG;IACH,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIxD,sEAAsE;IACtE,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,130 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _CeremonyManager_instances, _CeremonyManager_registrationMap, _CeremonyManager_authenticationMap, _CeremonyManager_getMap, _CeremonyManager_pruneExpired, _CeremonyManager_enforceCapacity;
7
+ /** WebAuthn `timeout` for credential creation and assertion (ms). */
8
+ export const WEBAUTHN_TIMEOUT_MS = 60000;
9
+ /**
10
+ * Extra allowance beyond {@link WEBAUTHN_TIMEOUT_MS} before in-memory
11
+ * ceremony state is discarded (covers slow UX and clock skew).
12
+ */
13
+ export const CEREMONY_TTL_SLACK_MS = 15000;
14
+ /**
15
+ * Maximum age for in-flight registration or authentication ceremony state
16
+ * (between options and verified response). This bounds the lifetime of a
17
+ * single WebAuthn ceremony only; it is not a user login session timeout.
18
+ */
19
+ export const CEREMONY_MAX_AGE_MS = WEBAUTHN_TIMEOUT_MS + CEREMONY_TTL_SLACK_MS;
20
+ /**
21
+ * Upper bound on concurrent in-memory ceremonies per flow type (registration
22
+ * vs authentication), for abuse / leak protection.
23
+ */
24
+ export const MAX_CONCURRENT_PASSKEY_CEREMONIES = 16;
25
+ /**
26
+ * In-memory store for in-flight WebAuthn ceremonies (registration vs authentication),
27
+ * keyed by base64url challenge. Enforces TTL and a per-flow size cap; not user session state.
28
+ */
29
+ export class CeremonyManager {
30
+ constructor() {
31
+ _CeremonyManager_instances.add(this);
32
+ _CeremonyManager_registrationMap.set(this, new Map());
33
+ _CeremonyManager_authenticationMap.set(this, new Map());
34
+ }
35
+ /**
36
+ * Records registration ceremony state after pruning expired rows and evicting oldest if at cap.
37
+ *
38
+ * @param challenge - Same base64url challenge as in the creation options `challenge` field.
39
+ * @param ceremony - Payload to retrieve when the registration response returns.
40
+ */
41
+ saveRegistrationCeremony(challenge, ceremony) {
42
+ __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_pruneExpired).call(this, 'registration');
43
+ __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_enforceCapacity).call(this, 'registration');
44
+ __classPrivateFieldGet(this, _CeremonyManager_registrationMap, "f").set(challenge, ceremony);
45
+ }
46
+ /**
47
+ * Records authentication ceremony state after pruning expired rows and evicting oldest if at cap.
48
+ *
49
+ * @param challenge - Same base64url challenge as in the request options `challenge` field.
50
+ * @param ceremony - Payload to retrieve when the assertion response returns.
51
+ */
52
+ saveAuthenticationCeremony(challenge, ceremony) {
53
+ __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_pruneExpired).call(this, 'authentication');
54
+ __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_enforceCapacity).call(this, 'authentication');
55
+ __classPrivateFieldGet(this, _CeremonyManager_authenticationMap, "f").set(challenge, ceremony);
56
+ }
57
+ /**
58
+ * Returns registration ceremony for a challenge, pruning expired entries on this map first.
59
+ *
60
+ * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).
61
+ * @returns Stored ceremony, or `undefined` if none or expired.
62
+ */
63
+ getRegistrationCeremony(challenge) {
64
+ __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_pruneExpired).call(this, 'registration');
65
+ return __classPrivateFieldGet(this, _CeremonyManager_registrationMap, "f").get(challenge);
66
+ }
67
+ /**
68
+ * Returns authentication ceremony for a challenge, pruning expired entries on this map first.
69
+ *
70
+ * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).
71
+ * @returns Stored ceremony, or `undefined` if none or expired.
72
+ */
73
+ getAuthenticationCeremony(challenge) {
74
+ __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_pruneExpired).call(this, 'authentication');
75
+ return __classPrivateFieldGet(this, _CeremonyManager_authenticationMap, "f").get(challenge);
76
+ }
77
+ /**
78
+ * Removes a registration ceremony by challenge.
79
+ *
80
+ * @param challenge - Map key for the ceremony to remove.
81
+ * @returns Whether an entry was deleted.
82
+ */
83
+ deleteRegistrationCeremony(challenge) {
84
+ return __classPrivateFieldGet(this, _CeremonyManager_registrationMap, "f").delete(challenge);
85
+ }
86
+ /**
87
+ * Removes an authentication ceremony by challenge.
88
+ *
89
+ * @param challenge - Map key for the ceremony to remove.
90
+ * @returns Whether an entry was deleted.
91
+ */
92
+ deleteAuthenticationCeremony(challenge) {
93
+ return __classPrivateFieldGet(this, _CeremonyManager_authenticationMap, "f").delete(challenge);
94
+ }
95
+ /** Drops all in-flight registration and authentication ceremonies. */
96
+ clear() {
97
+ __classPrivateFieldGet(this, _CeremonyManager_registrationMap, "f").clear();
98
+ __classPrivateFieldGet(this, _CeremonyManager_authenticationMap, "f").clear();
99
+ }
100
+ }
101
+ _CeremonyManager_registrationMap = new WeakMap(), _CeremonyManager_authenticationMap = new WeakMap(), _CeremonyManager_instances = new WeakSet(), _CeremonyManager_getMap = function _CeremonyManager_getMap(ceremonyType) {
102
+ return ceremonyType === 'registration'
103
+ ? __classPrivateFieldGet(this, _CeremonyManager_registrationMap, "f")
104
+ : __classPrivateFieldGet(this, _CeremonyManager_authenticationMap, "f");
105
+ }, _CeremonyManager_pruneExpired = function _CeremonyManager_pruneExpired(ceremonyType) {
106
+ const now = Date.now();
107
+ const map = __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_getMap).call(this, ceremonyType);
108
+ for (const [key, ceremony] of map) {
109
+ if (now - ceremony.createdAt > CEREMONY_MAX_AGE_MS) {
110
+ map.delete(key);
111
+ }
112
+ }
113
+ }, _CeremonyManager_enforceCapacity = function _CeremonyManager_enforceCapacity(ceremonyType) {
114
+ const map = __classPrivateFieldGet(this, _CeremonyManager_instances, "m", _CeremonyManager_getMap).call(this, ceremonyType);
115
+ while (map.size >= MAX_CONCURRENT_PASSKEY_CEREMONIES) {
116
+ let oldestKey;
117
+ let oldestTime = Infinity;
118
+ for (const [mapKey, ceremony] of map) {
119
+ if (ceremony.createdAt < oldestTime) {
120
+ oldestTime = ceremony.createdAt;
121
+ oldestKey = mapKey;
122
+ }
123
+ }
124
+ if (oldestKey === undefined) {
125
+ break;
126
+ }
127
+ map.delete(oldestKey);
128
+ }
129
+ };
130
+ //# sourceMappingURL=ceremony-manager.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceremony-manager.mjs","sourceRoot":"","sources":["../src/ceremony-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n PasskeyAuthenticationCeremony,\n PasskeyRegistrationCeremony,\n} from './types';\n\n/** WebAuthn `timeout` for credential creation and assertion (ms). */\nexport const WEBAUTHN_TIMEOUT_MS = 60_000;\n\n/**\n * Extra allowance beyond {@link WEBAUTHN_TIMEOUT_MS} before in-memory\n * ceremony state is discarded (covers slow UX and clock skew).\n */\nexport const CEREMONY_TTL_SLACK_MS = 15_000;\n\n/**\n * Maximum age for in-flight registration or authentication ceremony state\n * (between options and verified response). This bounds the lifetime of a\n * single WebAuthn ceremony only; it is not a user login session timeout.\n */\nexport const CEREMONY_MAX_AGE_MS = WEBAUTHN_TIMEOUT_MS + CEREMONY_TTL_SLACK_MS;\n\n/**\n * Upper bound on concurrent in-memory ceremonies per flow type (registration\n * vs authentication), for abuse / leak protection.\n */\nexport const MAX_CONCURRENT_PASSKEY_CEREMONIES = 16;\n\ntype CeremonyFlow = 'registration' | 'authentication';\n\n/**\n * In-memory store for in-flight WebAuthn ceremonies (registration vs authentication),\n * keyed by base64url challenge. Enforces TTL and a per-flow size cap; not user session state.\n */\nexport class CeremonyManager {\n readonly #registrationMap = new Map<string, PasskeyRegistrationCeremony>();\n\n readonly #authenticationMap = new Map<\n string,\n PasskeyAuthenticationCeremony\n >();\n\n /**\n * Challenge-keyed map for prune/capacity helpers.\n *\n * @param ceremonyType - Which in-flight ceremony map to use.\n * @returns The registration or authentication ceremony map for the given flow.\n */\n #getMap(\n ceremonyType: CeremonyFlow,\n ): Map<string, PasskeyRegistrationCeremony | PasskeyAuthenticationCeremony> {\n return ceremonyType === 'registration'\n ? this.#registrationMap\n : this.#authenticationMap;\n }\n\n #pruneExpired(ceremonyType: CeremonyFlow): void {\n const now = Date.now();\n const map = this.#getMap(ceremonyType);\n for (const [key, ceremony] of map) {\n if (now - ceremony.createdAt > CEREMONY_MAX_AGE_MS) {\n map.delete(key);\n }\n }\n }\n\n /**\n * Removes the oldest entry (by `createdAt`) until size is below the cap.\n *\n * @param ceremonyType - Which in-flight ceremony map to evict from.\n */\n #enforceCapacity(ceremonyType: CeremonyFlow): void {\n const map = this.#getMap(ceremonyType);\n while (map.size >= MAX_CONCURRENT_PASSKEY_CEREMONIES) {\n let oldestKey: string | undefined;\n let oldestTime = Infinity;\n for (const [mapKey, ceremony] of map) {\n if (ceremony.createdAt < oldestTime) {\n oldestTime = ceremony.createdAt;\n oldestKey = mapKey;\n }\n }\n if (oldestKey === undefined) {\n break;\n }\n map.delete(oldestKey);\n }\n }\n\n /**\n * Records registration ceremony state after pruning expired rows and evicting oldest if at cap.\n *\n * @param challenge - Same base64url challenge as in the creation options `challenge` field.\n * @param ceremony - Payload to retrieve when the registration response returns.\n */\n saveRegistrationCeremony(\n challenge: string,\n ceremony: PasskeyRegistrationCeremony,\n ): void {\n this.#pruneExpired('registration');\n this.#enforceCapacity('registration');\n this.#registrationMap.set(challenge, ceremony);\n }\n\n /**\n * Records authentication ceremony state after pruning expired rows and evicting oldest if at cap.\n *\n * @param challenge - Same base64url challenge as in the request options `challenge` field.\n * @param ceremony - Payload to retrieve when the assertion response returns.\n */\n saveAuthenticationCeremony(\n challenge: string,\n ceremony: PasskeyAuthenticationCeremony,\n ): void {\n this.#pruneExpired('authentication');\n this.#enforceCapacity('authentication');\n this.#authenticationMap.set(challenge, ceremony);\n }\n\n /**\n * Returns registration ceremony for a challenge, pruning expired entries on this map first.\n *\n * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).\n * @returns Stored ceremony, or `undefined` if none or expired.\n */\n getRegistrationCeremony(\n challenge: string,\n ): PasskeyRegistrationCeremony | undefined {\n this.#pruneExpired('registration');\n return this.#registrationMap.get(challenge);\n }\n\n /**\n * Returns authentication ceremony for a challenge, pruning expired entries on this map first.\n *\n * @param challenge - Base64url challenge from decoded `clientDataJSON` (matches stored key).\n * @returns Stored ceremony, or `undefined` if none or expired.\n */\n getAuthenticationCeremony(\n challenge: string,\n ): PasskeyAuthenticationCeremony | undefined {\n this.#pruneExpired('authentication');\n return this.#authenticationMap.get(challenge);\n }\n\n /**\n * Removes a registration ceremony by challenge.\n *\n * @param challenge - Map key for the ceremony to remove.\n * @returns Whether an entry was deleted.\n */\n deleteRegistrationCeremony(challenge: string): boolean {\n return this.#registrationMap.delete(challenge);\n }\n\n /**\n * Removes an authentication ceremony by challenge.\n *\n * @param challenge - Map key for the ceremony to remove.\n * @returns Whether an entry was deleted.\n */\n deleteAuthenticationCeremony(challenge: string): boolean {\n return this.#authenticationMap.delete(challenge);\n }\n\n /** Drops all in-flight registration and authentication ceremonies. */\n clear(): void {\n this.#registrationMap.clear();\n this.#authenticationMap.clear();\n }\n}\n"]}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PasskeyControllerErrorMessage = exports.PasskeyControllerErrorCode = exports.controllerName = void 0;
4
+ exports.controllerName = 'PasskeyController';
5
+ /**
6
+ * Stable programmatic codes for {@link PasskeyControllerError}.
7
+ * Use these instead of matching `message` strings.
8
+ */
9
+ exports.PasskeyControllerErrorCode = {
10
+ NotEnrolled: 'not_enrolled',
11
+ NoRegistrationCeremony: 'no_registration_ceremony',
12
+ RegistrationVerificationFailed: 'registration_verification_failed',
13
+ NoAuthenticationCeremony: 'no_authentication_ceremony',
14
+ AuthenticationVerificationFailed: 'authentication_verification_failed',
15
+ MissingKeyMaterial: 'missing_key_material',
16
+ VaultKeyDecryptionFailed: 'vault_key_decryption_failed',
17
+ VaultKeyMismatch: 'vault_key_mismatch',
18
+ };
19
+ /**
20
+ * Human-readable messages for {@link PasskeyControllerError}.
21
+ */
22
+ var PasskeyControllerErrorMessage;
23
+ (function (PasskeyControllerErrorMessage) {
24
+ PasskeyControllerErrorMessage["NotEnrolled"] = "PasskeyController - Passkey is not enrolled";
25
+ PasskeyControllerErrorMessage["NoRegistrationCeremony"] = "PasskeyController - No active passkey registration ceremony";
26
+ PasskeyControllerErrorMessage["RegistrationVerificationFailed"] = "PasskeyController - Passkey registration verification failed";
27
+ PasskeyControllerErrorMessage["NoAuthenticationCeremony"] = "PasskeyController - No active passkey authentication ceremony";
28
+ PasskeyControllerErrorMessage["AuthenticationVerificationFailed"] = "PasskeyController - Passkey authentication verification failed";
29
+ PasskeyControllerErrorMessage["MissingKeyMaterial"] = "PasskeyController - Passkey assertion missing required key material";
30
+ PasskeyControllerErrorMessage["VaultKeyDecryptionFailed"] = "PasskeyController - Passkey vault key decryption failed";
31
+ PasskeyControllerErrorMessage["VaultKeyMismatch"] = "PasskeyController - Passkey authentication does not match the current vault key";
32
+ })(PasskeyControllerErrorMessage || (exports.PasskeyControllerErrorMessage = PasskeyControllerErrorMessage = {}));
33
+ //# sourceMappingURL=constants.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.cjs","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG,mBAAmB,CAAC;AAElD;;;GAGG;AACU,QAAA,0BAA0B,GAAG;IACxC,WAAW,EAAE,cAAc;IAC3B,sBAAsB,EAAE,0BAA0B;IAClD,8BAA8B,EAAE,kCAAkC;IAClE,wBAAwB,EAAE,4BAA4B;IACtD,gCAAgC,EAAE,oCAAoC;IACtE,kBAAkB,EAAE,sBAAsB;IAC1C,wBAAwB,EAAE,6BAA6B;IACvD,gBAAgB,EAAE,oBAAoB;CAC9B,CAAC;AAKX;;GAEG;AACH,IAAY,6BASX;AATD,WAAY,6BAA6B;IACvC,4FAA2D,CAAA;IAC3D,uHAAsF,CAAA;IACtF,gIAA+F,CAAA;IAC/F,2HAA0F,CAAA;IAC1F,oIAAmG,CAAA;IACnG,2HAA0F,CAAA;IAC1F,qHAAoF,CAAA;IACpF,qIAAoG,CAAA;AACtG,CAAC,EATW,6BAA6B,6CAA7B,6BAA6B,QASxC","sourcesContent":["export const controllerName = 'PasskeyController';\n\n/**\n * Stable programmatic codes for {@link PasskeyControllerError}.\n * Use these instead of matching `message` strings.\n */\nexport const PasskeyControllerErrorCode = {\n NotEnrolled: 'not_enrolled',\n NoRegistrationCeremony: 'no_registration_ceremony',\n RegistrationVerificationFailed: 'registration_verification_failed',\n NoAuthenticationCeremony: 'no_authentication_ceremony',\n AuthenticationVerificationFailed: 'authentication_verification_failed',\n MissingKeyMaterial: 'missing_key_material',\n VaultKeyDecryptionFailed: 'vault_key_decryption_failed',\n VaultKeyMismatch: 'vault_key_mismatch',\n} as const;\n\nexport type PasskeyControllerErrorCode =\n (typeof PasskeyControllerErrorCode)[keyof typeof PasskeyControllerErrorCode];\n\n/**\n * Human-readable messages for {@link PasskeyControllerError}.\n */\nexport enum PasskeyControllerErrorMessage {\n NotEnrolled = `${controllerName} - Passkey is not enrolled`,\n NoRegistrationCeremony = `${controllerName} - No active passkey registration ceremony`,\n RegistrationVerificationFailed = `${controllerName} - Passkey registration verification failed`,\n NoAuthenticationCeremony = `${controllerName} - No active passkey authentication ceremony`,\n AuthenticationVerificationFailed = `${controllerName} - Passkey authentication verification failed`,\n MissingKeyMaterial = `${controllerName} - Passkey assertion missing required key material`,\n VaultKeyDecryptionFailed = `${controllerName} - Passkey vault key decryption failed`,\n VaultKeyMismatch = `${controllerName} - Passkey authentication does not match the current vault key`,\n}\n"]}
@@ -0,0 +1,30 @@
1
+ export declare const controllerName = "PasskeyController";
2
+ /**
3
+ * Stable programmatic codes for {@link PasskeyControllerError}.
4
+ * Use these instead of matching `message` strings.
5
+ */
6
+ export declare const PasskeyControllerErrorCode: {
7
+ readonly NotEnrolled: "not_enrolled";
8
+ readonly NoRegistrationCeremony: "no_registration_ceremony";
9
+ readonly RegistrationVerificationFailed: "registration_verification_failed";
10
+ readonly NoAuthenticationCeremony: "no_authentication_ceremony";
11
+ readonly AuthenticationVerificationFailed: "authentication_verification_failed";
12
+ readonly MissingKeyMaterial: "missing_key_material";
13
+ readonly VaultKeyDecryptionFailed: "vault_key_decryption_failed";
14
+ readonly VaultKeyMismatch: "vault_key_mismatch";
15
+ };
16
+ export type PasskeyControllerErrorCode = (typeof PasskeyControllerErrorCode)[keyof typeof PasskeyControllerErrorCode];
17
+ /**
18
+ * Human-readable messages for {@link PasskeyControllerError}.
19
+ */
20
+ export declare enum PasskeyControllerErrorMessage {
21
+ NotEnrolled = "PasskeyController - Passkey is not enrolled",
22
+ NoRegistrationCeremony = "PasskeyController - No active passkey registration ceremony",
23
+ RegistrationVerificationFailed = "PasskeyController - Passkey registration verification failed",
24
+ NoAuthenticationCeremony = "PasskeyController - No active passkey authentication ceremony",
25
+ AuthenticationVerificationFailed = "PasskeyController - Passkey authentication verification failed",
26
+ MissingKeyMaterial = "PasskeyController - Passkey assertion missing required key material",
27
+ VaultKeyDecryptionFailed = "PasskeyController - Passkey vault key decryption failed",
28
+ VaultKeyMismatch = "PasskeyController - Passkey authentication does not match the current vault key"
29
+ }
30
+ //# sourceMappingURL=constants.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.cts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,sBAAsB,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;CAS7B,CAAC;AAEX,MAAM,MAAM,0BAA0B,GACpC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,OAAO,0BAA0B,CAAC,CAAC;AAE/E;;GAEG;AACH,oBAAY,6BAA6B;IACvC,WAAW,gDAAgD;IAC3D,sBAAsB,gEAAgE;IACtF,8BAA8B,iEAAiE;IAC/F,wBAAwB,kEAAkE;IAC1F,gCAAgC,mEAAmE;IACnG,kBAAkB,wEAAwE;IAC1F,wBAAwB,4DAA4D;IACpF,gBAAgB,oFAAoF;CACrG"}
@@ -0,0 +1,30 @@
1
+ export declare const controllerName = "PasskeyController";
2
+ /**
3
+ * Stable programmatic codes for {@link PasskeyControllerError}.
4
+ * Use these instead of matching `message` strings.
5
+ */
6
+ export declare const PasskeyControllerErrorCode: {
7
+ readonly NotEnrolled: "not_enrolled";
8
+ readonly NoRegistrationCeremony: "no_registration_ceremony";
9
+ readonly RegistrationVerificationFailed: "registration_verification_failed";
10
+ readonly NoAuthenticationCeremony: "no_authentication_ceremony";
11
+ readonly AuthenticationVerificationFailed: "authentication_verification_failed";
12
+ readonly MissingKeyMaterial: "missing_key_material";
13
+ readonly VaultKeyDecryptionFailed: "vault_key_decryption_failed";
14
+ readonly VaultKeyMismatch: "vault_key_mismatch";
15
+ };
16
+ export type PasskeyControllerErrorCode = (typeof PasskeyControllerErrorCode)[keyof typeof PasskeyControllerErrorCode];
17
+ /**
18
+ * Human-readable messages for {@link PasskeyControllerError}.
19
+ */
20
+ export declare enum PasskeyControllerErrorMessage {
21
+ NotEnrolled = "PasskeyController - Passkey is not enrolled",
22
+ NoRegistrationCeremony = "PasskeyController - No active passkey registration ceremony",
23
+ RegistrationVerificationFailed = "PasskeyController - Passkey registration verification failed",
24
+ NoAuthenticationCeremony = "PasskeyController - No active passkey authentication ceremony",
25
+ AuthenticationVerificationFailed = "PasskeyController - Passkey authentication verification failed",
26
+ MissingKeyMaterial = "PasskeyController - Passkey assertion missing required key material",
27
+ VaultKeyDecryptionFailed = "PasskeyController - Passkey vault key decryption failed",
28
+ VaultKeyMismatch = "PasskeyController - Passkey authentication does not match the current vault key"
29
+ }
30
+ //# sourceMappingURL=constants.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.mts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,sBAAsB,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;CAS7B,CAAC;AAEX,MAAM,MAAM,0BAA0B,GACpC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,OAAO,0BAA0B,CAAC,CAAC;AAE/E;;GAEG;AACH,oBAAY,6BAA6B;IACvC,WAAW,gDAAgD;IAC3D,sBAAsB,gEAAgE;IACtF,8BAA8B,iEAAiE;IAC/F,wBAAwB,kEAAkE;IAC1F,gCAAgC,mEAAmE;IACnG,kBAAkB,wEAAwE;IAC1F,wBAAwB,4DAA4D;IACpF,gBAAgB,oFAAoF;CACrG"}
@@ -0,0 +1,30 @@
1
+ export const controllerName = 'PasskeyController';
2
+ /**
3
+ * Stable programmatic codes for {@link PasskeyControllerError}.
4
+ * Use these instead of matching `message` strings.
5
+ */
6
+ export const PasskeyControllerErrorCode = {
7
+ NotEnrolled: 'not_enrolled',
8
+ NoRegistrationCeremony: 'no_registration_ceremony',
9
+ RegistrationVerificationFailed: 'registration_verification_failed',
10
+ NoAuthenticationCeremony: 'no_authentication_ceremony',
11
+ AuthenticationVerificationFailed: 'authentication_verification_failed',
12
+ MissingKeyMaterial: 'missing_key_material',
13
+ VaultKeyDecryptionFailed: 'vault_key_decryption_failed',
14
+ VaultKeyMismatch: 'vault_key_mismatch',
15
+ };
16
+ /**
17
+ * Human-readable messages for {@link PasskeyControllerError}.
18
+ */
19
+ export var PasskeyControllerErrorMessage;
20
+ (function (PasskeyControllerErrorMessage) {
21
+ PasskeyControllerErrorMessage["NotEnrolled"] = "PasskeyController - Passkey is not enrolled";
22
+ PasskeyControllerErrorMessage["NoRegistrationCeremony"] = "PasskeyController - No active passkey registration ceremony";
23
+ PasskeyControllerErrorMessage["RegistrationVerificationFailed"] = "PasskeyController - Passkey registration verification failed";
24
+ PasskeyControllerErrorMessage["NoAuthenticationCeremony"] = "PasskeyController - No active passkey authentication ceremony";
25
+ PasskeyControllerErrorMessage["AuthenticationVerificationFailed"] = "PasskeyController - Passkey authentication verification failed";
26
+ PasskeyControllerErrorMessage["MissingKeyMaterial"] = "PasskeyController - Passkey assertion missing required key material";
27
+ PasskeyControllerErrorMessage["VaultKeyDecryptionFailed"] = "PasskeyController - Passkey vault key decryption failed";
28
+ PasskeyControllerErrorMessage["VaultKeyMismatch"] = "PasskeyController - Passkey authentication does not match the current vault key";
29
+ })(PasskeyControllerErrorMessage || (PasskeyControllerErrorMessage = {}));
30
+ //# sourceMappingURL=constants.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.mjs","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAElD;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,WAAW,EAAE,cAAc;IAC3B,sBAAsB,EAAE,0BAA0B;IAClD,8BAA8B,EAAE,kCAAkC;IAClE,wBAAwB,EAAE,4BAA4B;IACtD,gCAAgC,EAAE,oCAAoC;IACtE,kBAAkB,EAAE,sBAAsB;IAC1C,wBAAwB,EAAE,6BAA6B;IACvD,gBAAgB,EAAE,oBAAoB;CAC9B,CAAC;AAKX;;GAEG;AACH,MAAM,CAAN,IAAY,6BASX;AATD,WAAY,6BAA6B;IACvC,4FAA2D,CAAA;IAC3D,uHAAsF,CAAA;IACtF,gIAA+F,CAAA;IAC/F,2HAA0F,CAAA;IAC1F,oIAAmG,CAAA;IACnG,2HAA0F,CAAA;IAC1F,qHAAoF,CAAA;IACpF,qIAAoG,CAAA;AACtG,CAAC,EATW,6BAA6B,KAA7B,6BAA6B,QASxC","sourcesContent":["export const controllerName = 'PasskeyController';\n\n/**\n * Stable programmatic codes for {@link PasskeyControllerError}.\n * Use these instead of matching `message` strings.\n */\nexport const PasskeyControllerErrorCode = {\n NotEnrolled: 'not_enrolled',\n NoRegistrationCeremony: 'no_registration_ceremony',\n RegistrationVerificationFailed: 'registration_verification_failed',\n NoAuthenticationCeremony: 'no_authentication_ceremony',\n AuthenticationVerificationFailed: 'authentication_verification_failed',\n MissingKeyMaterial: 'missing_key_material',\n VaultKeyDecryptionFailed: 'vault_key_decryption_failed',\n VaultKeyMismatch: 'vault_key_mismatch',\n} as const;\n\nexport type PasskeyControllerErrorCode =\n (typeof PasskeyControllerErrorCode)[keyof typeof PasskeyControllerErrorCode];\n\n/**\n * Human-readable messages for {@link PasskeyControllerError}.\n */\nexport enum PasskeyControllerErrorMessage {\n NotEnrolled = `${controllerName} - Passkey is not enrolled`,\n NoRegistrationCeremony = `${controllerName} - No active passkey registration ceremony`,\n RegistrationVerificationFailed = `${controllerName} - Passkey registration verification failed`,\n NoAuthenticationCeremony = `${controllerName} - No active passkey authentication ceremony`,\n AuthenticationVerificationFailed = `${controllerName} - Passkey authentication verification failed`,\n MissingKeyMaterial = `${controllerName} - Passkey assertion missing required key material`,\n VaultKeyDecryptionFailed = `${controllerName} - Passkey vault key decryption failed`,\n VaultKeyMismatch = `${controllerName} - Passkey authentication does not match the current vault key`,\n}\n"]}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PasskeyControllerError = void 0;
4
+ /**
5
+ * Error class for PasskeyController-related errors.
6
+ */
7
+ class PasskeyControllerError extends Error {
8
+ /**
9
+ * @param message - The error message.
10
+ * @param options - Error options or an `Error` instance used as `cause` (Keyring-style overload).
11
+ */
12
+ constructor(message, options) {
13
+ super(message);
14
+ this.name = 'PasskeyControllerError';
15
+ const cause = options instanceof Error ? options : options?.cause;
16
+ const code = options instanceof Error ? undefined : options?.code;
17
+ const context = options instanceof Error ? undefined : options?.context;
18
+ if (cause) {
19
+ this.cause = cause;
20
+ }
21
+ if (code) {
22
+ this.code = code;
23
+ }
24
+ if (context) {
25
+ this.context = context;
26
+ }
27
+ Object.setPrototypeOf(this, PasskeyControllerError.prototype);
28
+ }
29
+ toJSON() {
30
+ return {
31
+ name: this.name,
32
+ message: this.message,
33
+ code: this.code,
34
+ context: this.context,
35
+ stack: this.stack,
36
+ cause: this.cause
37
+ ? {
38
+ name: this.cause.name,
39
+ message: this.cause.message,
40
+ stack: this.cause.stack,
41
+ }
42
+ : undefined,
43
+ };
44
+ }
45
+ toString() {
46
+ let result = `${this.name}: ${this.message}`;
47
+ if (this.code) {
48
+ result += ` [${this.code}]`;
49
+ }
50
+ if (this.cause) {
51
+ result += `\n Caused by: ${this.cause}`;
52
+ }
53
+ return result;
54
+ }
55
+ }
56
+ exports.PasskeyControllerError = PasskeyControllerError;
57
+ //# sourceMappingURL=errors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.cjs","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAoBA;;GAEG;AACH,MAAa,sBAAuB,SAAQ,KAAK;IAO/C;;;OAGG;IACH,YACE,OAAe,EACf,OAA+C;QAE/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QAErC,MAAM,KAAK,GAAG,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC;QAClE,MAAM,IAAI,GAAG,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC;QAClE,MAAM,OAAO,GAAG,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC;QAExE,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,CAAC;QACD,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,CAAC;QAED,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;IAED,MAAM;QACJ,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACf,CAAC,CAAC;oBACE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;oBACrB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO;oBAC3B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK;iBACxB;gBACH,CAAC,CAAC,SAAS;SACd,CAAC;IACJ,CAAC;IAEQ,QAAQ;QACf,IAAI,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC;QAC9B,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,kBAAkB,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AA9DD,wDA8DC","sourcesContent":["import type { PasskeyControllerErrorCode as PasskeyControllerErrorCodeType } from './constants';\n\n/**\n * Options for creating a {@link PasskeyControllerError}.\n */\nexport type PasskeyControllerErrorOptions = {\n /**\n * The underlying error that caused this error (for error chaining).\n */\n cause?: Error;\n /**\n * Stable code for programmatic handling (see {@link PasskeyControllerErrorCode}).\n */\n code?: PasskeyControllerErrorCodeType;\n /**\n * Additional context for debugging or reporting.\n */\n context?: Record<string, unknown>;\n};\n\n/**\n * Error class for PasskeyController-related errors.\n */\nexport class PasskeyControllerError extends Error {\n code?: PasskeyControllerErrorCodeType;\n\n context?: Record<string, unknown>;\n\n cause?: Error;\n\n /**\n * @param message - The error message.\n * @param options - Error options or an `Error` instance used as `cause` (Keyring-style overload).\n */\n constructor(\n message: string,\n options?: PasskeyControllerErrorOptions | Error,\n ) {\n super(message);\n this.name = 'PasskeyControllerError';\n\n const cause = options instanceof Error ? options : options?.cause;\n const code = options instanceof Error ? undefined : options?.code;\n const context = options instanceof Error ? undefined : options?.context;\n\n if (cause) {\n this.cause = cause;\n }\n if (code) {\n this.code = code;\n }\n if (context) {\n this.context = context;\n }\n\n Object.setPrototypeOf(this, PasskeyControllerError.prototype);\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n context: this.context,\n stack: this.stack,\n cause: this.cause\n ? {\n name: this.cause.name,\n message: this.cause.message,\n stack: this.cause.stack,\n }\n : undefined,\n };\n }\n\n override toString(): string {\n let result = `${this.name}: ${this.message}`;\n if (this.code) {\n result += ` [${this.code}]`;\n }\n if (this.cause) {\n result += `\\n Caused by: ${this.cause}`;\n }\n return result;\n }\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import type { PasskeyControllerErrorCode as PasskeyControllerErrorCodeType } from "./constants.cjs";
2
+ /**
3
+ * Options for creating a {@link PasskeyControllerError}.
4
+ */
5
+ export type PasskeyControllerErrorOptions = {
6
+ /**
7
+ * The underlying error that caused this error (for error chaining).
8
+ */
9
+ cause?: Error;
10
+ /**
11
+ * Stable code for programmatic handling (see {@link PasskeyControllerErrorCode}).
12
+ */
13
+ code?: PasskeyControllerErrorCodeType;
14
+ /**
15
+ * Additional context for debugging or reporting.
16
+ */
17
+ context?: Record<string, unknown>;
18
+ };
19
+ /**
20
+ * Error class for PasskeyController-related errors.
21
+ */
22
+ export declare class PasskeyControllerError extends Error {
23
+ code?: PasskeyControllerErrorCodeType;
24
+ context?: Record<string, unknown>;
25
+ cause?: Error;
26
+ /**
27
+ * @param message - The error message.
28
+ * @param options - Error options or an `Error` instance used as `cause` (Keyring-style overload).
29
+ */
30
+ constructor(message: string, options?: PasskeyControllerErrorOptions | Error);
31
+ toJSON(): Record<string, unknown>;
32
+ toString(): string;
33
+ }
34
+ //# sourceMappingURL=errors.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.cts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,IAAI,8BAA8B,EAAE,wBAAoB;AAEhG;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,8BAA8B,CAAC;IACtC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,CAAC;AAEF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,IAAI,CAAC,EAAE,8BAA8B,CAAC;IAEtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd;;;OAGG;gBAED,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,6BAA6B,GAAG,KAAK;IAsBjD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAiBxB,QAAQ,IAAI,MAAM;CAU5B"}
@@ -0,0 +1,34 @@
1
+ import type { PasskeyControllerErrorCode as PasskeyControllerErrorCodeType } from "./constants.mjs";
2
+ /**
3
+ * Options for creating a {@link PasskeyControllerError}.
4
+ */
5
+ export type PasskeyControllerErrorOptions = {
6
+ /**
7
+ * The underlying error that caused this error (for error chaining).
8
+ */
9
+ cause?: Error;
10
+ /**
11
+ * Stable code for programmatic handling (see {@link PasskeyControllerErrorCode}).
12
+ */
13
+ code?: PasskeyControllerErrorCodeType;
14
+ /**
15
+ * Additional context for debugging or reporting.
16
+ */
17
+ context?: Record<string, unknown>;
18
+ };
19
+ /**
20
+ * Error class for PasskeyController-related errors.
21
+ */
22
+ export declare class PasskeyControllerError extends Error {
23
+ code?: PasskeyControllerErrorCodeType;
24
+ context?: Record<string, unknown>;
25
+ cause?: Error;
26
+ /**
27
+ * @param message - The error message.
28
+ * @param options - Error options or an `Error` instance used as `cause` (Keyring-style overload).
29
+ */
30
+ constructor(message: string, options?: PasskeyControllerErrorOptions | Error);
31
+ toJSON(): Record<string, unknown>;
32
+ toString(): string;
33
+ }
34
+ //# sourceMappingURL=errors.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.mts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,IAAI,8BAA8B,EAAE,wBAAoB;AAEhG;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;OAEG;IACH,IAAI,CAAC,EAAE,8BAA8B,CAAC;IACtC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,CAAC;AAEF;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,IAAI,CAAC,EAAE,8BAA8B,CAAC;IAEtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAElC,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd;;;OAGG;gBAED,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,6BAA6B,GAAG,KAAK;IAsBjD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAiBxB,QAAQ,IAAI,MAAM;CAU5B"}