@learncard/sss-key-manager 0.1.24 → 0.2.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 (56) hide show
  1. package/README.md +12 -95
  2. package/dist/api-client.d.ts +44 -7
  3. package/dist/api-client.d.ts.map +1 -1
  4. package/dist/atomic-operations.d.ts +10 -2
  5. package/dist/atomic-operations.d.ts.map +1 -1
  6. package/dist/email-relay-crypto.d.ts +49 -0
  7. package/dist/email-relay-crypto.d.ts.map +1 -0
  8. package/dist/escrow-attestation.d.ts +8 -0
  9. package/dist/escrow-attestation.d.ts.map +1 -0
  10. package/dist/escrow-crypto.d.ts +52 -0
  11. package/dist/escrow-crypto.d.ts.map +1 -0
  12. package/dist/escrow-pin.d.ts +22 -0
  13. package/dist/escrow-pin.d.ts.map +1 -0
  14. package/dist/index.d.ts +13 -4
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/key-manager.d.ts +2 -0
  17. package/dist/key-manager.d.ts.map +1 -1
  18. package/dist/qr-login.d.ts.map +1 -1
  19. package/dist/recovery-phrase.d.ts +6 -0
  20. package/dist/recovery-phrase.d.ts.map +1 -1
  21. package/dist/sss-key-manager.cjs.development.js +2891 -355
  22. package/dist/sss-key-manager.cjs.development.js.map +4 -4
  23. package/dist/sss-key-manager.cjs.production.min.js +33 -33
  24. package/dist/sss-key-manager.cjs.production.min.js.map +4 -4
  25. package/dist/sss-key-manager.esm.js +2891 -355
  26. package/dist/sss-key-manager.esm.js.map +4 -4
  27. package/dist/sss-strategy.d.ts +74 -4
  28. package/dist/sss-strategy.d.ts.map +1 -1
  29. package/dist/storage.d.ts +1 -0
  30. package/dist/storage.d.ts.map +1 -1
  31. package/dist/types.d.ts +87 -4
  32. package/dist/types.d.ts.map +1 -1
  33. package/package.json +2 -2
  34. package/src/api-client.test.ts +122 -0
  35. package/src/api-client.ts +107 -116
  36. package/src/atomic-operations.test.ts +56 -16
  37. package/src/atomic-operations.ts +55 -19
  38. package/src/critical-paths.test.ts +51 -1
  39. package/src/email-relay-crypto.test.ts +87 -0
  40. package/src/email-relay-crypto.ts +293 -0
  41. package/src/escrow-attestation.test.ts +85 -0
  42. package/src/escrow-attestation.ts +64 -0
  43. package/src/escrow-crypto.test.ts +381 -0
  44. package/src/escrow-crypto.ts +319 -0
  45. package/src/escrow-pin.test.ts +119 -0
  46. package/src/escrow-pin.ts +83 -0
  47. package/src/index.ts +63 -1
  48. package/src/key-manager.ts +4 -9
  49. package/src/qr-login.ts +22 -15
  50. package/src/recovery-phrase.ts +40 -0
  51. package/src/sss-session-writes.test.ts +109 -0
  52. package/src/sss-strategy.test.ts +2642 -110
  53. package/src/sss-strategy.ts +2186 -224
  54. package/src/storage.test.ts +66 -8
  55. package/src/storage.ts +41 -29
  56. package/src/types.ts +107 -6
@@ -12,28 +12,42 @@
12
12
  * - Recovery method execution and setup
13
13
  * - Storage cleanup knowledge
14
14
  */
15
- import type { SSSKeyDerivationStrategy } from './types';
15
+ import type { SSSKeyDerivationStrategy, EscrowAttestationPolicy } from './types';
16
+ import type { EmailRelayBranding } from './email-relay-crypto';
16
17
  export interface SSSStorageFunctions {
17
18
  storeDeviceShare: (share: string, id?: string) => Promise<void>;
18
19
  getDeviceShare: (id?: string) => Promise<string | null>;
19
20
  hasDeviceShare: (id?: string) => Promise<boolean>;
20
21
  clearAllShares: (id?: string) => Promise<void>;
22
+ deleteDeviceShare: (id?: string) => Promise<void>;
21
23
  storeShareVersion: (version: number, id?: string) => Promise<void>;
22
24
  getShareVersion: (id?: string) => Promise<number | null>;
23
25
  }
24
26
  export interface SSSStrategyConfig {
27
+ /** Enable automatic enrollment under an explicit enclave trust policy. */
28
+ escrow?: {
29
+ enabled: boolean;
30
+ attestation: EscrowAttestationPolicy;
31
+ };
32
+ /** Report enrollment failures without logging recovery material. */
33
+ onEscrowError?: (err: unknown) => void;
25
34
  /** Server URL for key share operations */
26
35
  serverUrl: string;
27
36
  /** Custom storage functions (defaults to IndexedDB) */
28
37
  storage?: SSSStorageFunctions;
29
38
  /**
30
- * Whether to automatically send a backup share to the user's email
31
- * during key setup and recovery. The share is relayed through the server
32
- * but never persisted — fire-and-forget.
39
+ * Whether email recovery enrollment is enabled. Delivery is synchronous
40
+ * and must be confirmed with the code included in the recovery email.
33
41
  *
34
42
  * Defaults to false. Controlled by VITE_ENABLE_EMAIL_BACKUP_SHARE env var.
35
43
  */
36
44
  enableEmailBackupShare?: boolean;
45
+ /** Base64 DER/SPKI P-256 public key pinned for the isolated email relay. */
46
+ escrowRelayPublicKey?: string;
47
+ /** Identifier selecting the matching relay private key during rotation. */
48
+ escrowRelayKeyId?: string;
49
+ /** Tenant branding encrypted into the relay payload with the recovery key. */
50
+ emailBranding?: EmailRelayBranding;
37
51
  /**
38
52
  * Tenant identifier forwarded as `X-Tenant-Id` on every server request.
39
53
  * The lca-api uses this to brand recovery / OTP emails for the active
@@ -41,6 +55,22 @@ export interface SSSStrategyConfig {
41
55
  */
42
56
  tenantId?: string;
43
57
  }
58
+ export declare const SERVER_REQUEST_TIMEOUT_MS = 30000;
59
+ /** HTTP failure metadata without potentially sensitive server response text. */
60
+ export declare class EscrowRequestError extends Error {
61
+ readonly status: number;
62
+ constructor(status: number);
63
+ }
64
+ /**
65
+ * Signals that an identity-recovery attempt failed after the one-shot server
66
+ * session was submitted and must be restarted with a new verification code.
67
+ */
68
+ export declare class IdentityRecoverySessionConsumedError extends Error {
69
+ constructor(message: string);
70
+ }
71
+ /** Two tap-to-confirm questions with six choices each: a 1-in-36 guess. */
72
+ export declare const RECOVERY_PHRASE_CHALLENGE_COUNT = 2;
73
+ export declare const selectRecoveryPhraseChallengeIndices: (wordCount: number, challengeCount?: number) => number[];
44
74
  /**
45
75
  * Format an email share with a 4-character hex version prefix.
46
76
  *
@@ -61,6 +91,46 @@ export declare const parseVersionedEmailShare: (input: string) => {
61
91
  share: string;
62
92
  version: number | undefined;
63
93
  };
94
+ /**
95
+ * Serialize every share rotation (device + server write pair). Two rotations
96
+ * interleaving would leave the device share and the server auth share on
97
+ * different polynomials, which locks the account out on the next reconstruct.
98
+ */
99
+ export declare const withRotationLock: <T>(operation: () => Promise<T>) => Promise<T>;
100
+ /** DID_CHALLENGE_TTL_SECS (5 minutes) plus a processing margin for auth-share PUTs. */
101
+ export declare const PENDING_WRITE_EXPIRY_MS: number;
102
+ export interface PendingShareCandidate {
103
+ share: string;
104
+ createdAt: number;
105
+ }
106
+ /**
107
+ * Read device-only candidates from independent splits; never persist an auth,
108
+ * recovery, or email share here (two shares from one split reveal the key).
109
+ * Legacy raw shares have unknown age, but must still be checked before expiry.
110
+ * Mutating helpers must run under the account's share-update lock.
111
+ */
112
+ export declare const readPendingShareCandidates: (storage: SSSStorageFunctions, storageId?: string) => Promise<PendingShareCandidate[]>;
113
+ /** Clear only an empty/resolved queue or when explicitly forgetting this device. */
114
+ export declare const clearPendingShareCandidates: (storage: SSSStorageFunctions, storageId?: string) => Promise<void>;
115
+ /** Persist the versioned device-only queue without storing another share of any split. */
116
+ export declare const writePendingShareCandidates: (storage: SSSStorageFunctions, candidates: PendingShareCandidate[], storageId?: string) => Promise<void>;
117
+ /** Append a candidate; never evict a live write to make room for another one. */
118
+ export declare const addPendingShareCandidate: (storage: SSSStorageFunctions, candidate: PendingShareCandidate, storageId?: string) => Promise<void>;
119
+ /** Roll back only the definitively rejected operation, preserving earlier in-flight writes. */
120
+ export declare const removePendingShareCandidate: (storage: SSSStorageFunctions, share: string, storageId?: string) => Promise<void>;
121
+ interface CurrentShareSnapshot {
122
+ currentVersion: number | null;
123
+ authShare: string | null;
124
+ }
125
+ /**
126
+ * Check current and retained history before expiry: an expired nonce does not
127
+ * prove a write never committed. Keep unrelated live writes even after promotion,
128
+ * since older servers may still commit them after this read.
129
+ */
130
+ export declare const resolvePendingShareCandidates: (storage: SSSStorageFunctions, storageId: string | undefined, fetchCurrent: () => Promise<CurrentShareSnapshot>, expectedDid: string, didFromPrivateKey: (key: string) => Promise<string>, assertActiveUser?: () => void, onPromoted?: (snapshot: CurrentShareSnapshot) => void, fetchHistorical?: (version: number) => Promise<string | null>) => Promise<{
131
+ snapshot: CurrentShareSnapshot;
132
+ privateKey: string | null;
133
+ }>;
64
134
  /**
65
135
  * Create an SSS key derivation strategy.
66
136
  *
@@ -1 +1 @@
1
- {"version":3,"file":"sss-strategy.d.ts","sourceRoot":"","sources":["../src/sss-strategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACR,wBAAwB,EAU3B,MAAM,SAAS,CAAC;AA4BjB,MAAM,WAAW,mBAAmB;IAChC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,cAAc,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,iBAAiB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,eAAe,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,iBAAiB;IAC9B,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAElB,uDAAuD;IACvD,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAE9B;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAmID;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,eAAO,MAAM,yBAAyB,GAAI,YAAY,MAAM,EAAE,cAAc,MAAM,KAAG,MACT,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACjC,OAAO,MAAM,KACd;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;CAY9C,CAAC;AAqGF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,wBAAwB,CA8uBrF;AAED,YAAY,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"sss-strategy.d.ts","sourceRoot":"","sources":["../src/sss-strategy.ts"],"names":[],"mappings":"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"}
package/dist/storage.d.ts CHANGED
@@ -39,6 +39,7 @@ export declare function createAdaptiveStorage(): {
39
39
  getDeviceShare: (id?: string) => Promise<string | null>;
40
40
  hasDeviceShare: (id?: string) => Promise<boolean>;
41
41
  clearAllShares: (id?: string) => Promise<void>;
42
+ deleteDeviceShare: (id?: string) => Promise<void>;
42
43
  storeShareVersion: (version: number, id?: string) => Promise<void>;
43
44
  getShareVersion: (id?: string) => Promise<number | null>;
44
45
  };
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgJH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CASzG;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ5G;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYlG;AAED,wBAAsB,cAAc,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqCjG;AAED,wBAAsB,cAAc,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,OAAO,CAAC,CAG3F;AAED,wBAAsB,iBAAiB,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CAU3F;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAoDvE;AAYD,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAU5D;AAiDD;;;;GAIG;AACH,wBAAgB,qBAAqB;8BAEH,MAAM,OAAO,MAAM;0BAKvB,MAAM;0BAKN,MAAM;0BAKN,MAAM;iCAKC,MAAM,OAAO,MAAM;2BAKzB,MAAM;EAKpC;AAED,wBAAsB,cAAc,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC/D"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+IH,wBAAsB,gBAAgB,CAClC,KAAK,EAAE,MAAM,EACb,EAAE,GAAE,MAAgC,GACrC,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACnC,OAAO,EAAE,MAAM,EACf,EAAE,GAAE,MAAgC,GACrC,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACjC,EAAE,GAAE,MAAgC,GACrC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB;AAED,wBAAsB,cAAc,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCjG;AAED,wBAAsB,cAAc,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,OAAO,CAAC,CAG3F;AAED,wBAAsB,iBAAiB,CAAC,EAAE,GAAE,MAAgC,GAAG,OAAO,CAAC,IAAI,CAAC,CAU3F;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAsDvE;AAYD,wBAAgB,oBAAoB,IAAI,OAAO,CAS9C;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAU5D;AAyDD;;;;GAIG;AACH,wBAAgB,qBAAqB;8BAEH,MAAM,OAAO,MAAM;0BAKvB,MAAM;0BAGN,MAAM;0BAGN,MAAM;6BAGH,MAAM;iCAGF,MAAM,OAAO,MAAM;2BAKzB,MAAM;EAGpC;AAED,wBAAsB,cAAc,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsC/D"}
package/dist/types.d.ts CHANGED
@@ -4,8 +4,8 @@
4
4
  * Re-exports provider-agnostic interfaces from @learncard/types
5
5
  * and defines SSS-specific types (recovery shapes, backup files, etc.).
6
6
  */
7
- export { AuthSessionError, type AuthProviderType, type AuthUser, type AuthProvider, type RecoveryMethodInfo, type RecoveryResult, type ServerKeyStatus, type KeyDerivationStrategy, } from '@learncard/types';
8
- import type { AuthProvider, AuthProviderType, KeyDerivationStrategy, RecoveryMethodInfo } from '@learncard/types';
7
+ export { AuthSessionError, type AuthProviderType, type AuthUser, type AuthProvider, type RecoveryMethodInfo, type RecoveryResult, type IdentityRecoverySession, type ServerKeyStatus, type SssActivationState, type KeyDerivationStrategy, type DidAuthVpSigner, type EscrowEnrollmentOptions, type EscrowEnrollmentState, type EscrowPinStatus, } from '@learncard/types';
8
+ import type { AuthProvider, AuthProviderType, KeyDerivationStrategy, RecoveryMethodInfo, SssActivationState } from '@learncard/types';
9
9
  export type ContactMethodType = 'email' | 'phone';
10
10
  export interface ContactMethod {
11
11
  type: ContactMethodType;
@@ -21,7 +21,56 @@ export declare const SecurityLevels: readonly SecurityLevel[];
21
21
  * SSS recovery method type identifiers.
22
22
  * These are the specific recovery methods supported by the SSS strategy.
23
23
  */
24
- export type RecoveryMethodType = 'passkey' | 'backup' | 'phrase' | 'email';
24
+ export type RecoveryMethodType = 'passkey' | 'backup' | 'phrase' | 'email' | 'escrow';
25
+ /** Trust policy for the enclave that receives recovery material. */
26
+ export type EscrowAttestationPolicy = {
27
+ mode: 'software';
28
+ pinnedPublicKeys: string[];
29
+ } | {
30
+ mode: 'nitro';
31
+ pinnedMeasurements: {
32
+ imageSha384: string;
33
+ }[];
34
+ rootCertificatePem?: string;
35
+ };
36
+ /** Public status of an escrow recovery waiting period. */
37
+ export interface EscrowHoldStatus {
38
+ holdId: string;
39
+ releasePolicy: 'hold' | 'pin';
40
+ status: 'pending' | 'cancelled' | 'completed' | 'expired';
41
+ requestedAt: string;
42
+ releaseAfter: string;
43
+ cancelledAt?: string;
44
+ completedAt?: string;
45
+ }
46
+ /** Persist these secrets securely until completion; a null token means an existing hold. */
47
+ export type EscrowRecoveryStart = EscrowHoldStatus & {
48
+ resumeToken: string | null;
49
+ clientEphemeralPrivateKey: string;
50
+ pinSalt?: string;
51
+ };
52
+ /** The account has no available PIN release policy. */
53
+ export declare class EscrowPinUnavailableError extends Error {
54
+ constructor();
55
+ }
56
+ /** A failed PIN attempt consumes its hold; another attempt must start a fresh hold. */
57
+ export declare class EscrowPinMismatchError extends Error {
58
+ readonly attemptsRemaining: number;
59
+ constructor(attemptsRemaining: number);
60
+ }
61
+ /** Temporary throttle: retry after cooldown with a fresh hold, never retry /complete. */
62
+ export declare class EscrowPinThrottledError extends Error {
63
+ constructor();
64
+ }
65
+ /** A pending waiting-period request is too recent to restart. */
66
+ export declare class EscrowHoldRestartThrottledError extends Error {
67
+ readonly retryAfter?: string | undefined;
68
+ constructor(retryAfter?: string | undefined);
69
+ }
70
+ /** PIN recovery is exhausted; delayed escrow recovery remains available. */
71
+ export declare class EscrowPinLockedError extends Error {
72
+ constructor();
73
+ }
25
74
  export interface PasskeyRecoveryMethod {
26
75
  type: 'passkey';
27
76
  credentialId?: string;
@@ -41,6 +90,14 @@ export type RecoveryMethod = PasskeyRecoveryMethod | BackupFileRecoveryMethod |
41
90
  * SSS-specific recovery input — what the user provides to recover their key.
42
91
  */
43
92
  export type RecoveryInput = {
93
+ method: 'escrow-pin';
94
+ pin: string;
95
+ } | {
96
+ method: 'escrow';
97
+ holdId: string;
98
+ resumeToken: string;
99
+ clientEphemeralPrivateKey: string;
100
+ } | {
44
101
  method: 'passkey';
45
102
  credentialId: string;
46
103
  } | {
@@ -58,6 +115,9 @@ export type RecoveryInput = {
58
115
  * SSS-specific recovery setup input — what the user provides to set up a method.
59
116
  */
60
117
  export type RecoverySetupInput = {
118
+ method: 'escrow';
119
+ pin?: string;
120
+ } | {
61
121
  method: 'passkey';
62
122
  } | {
63
123
  method: 'phrase';
@@ -67,22 +127,41 @@ export type RecoverySetupInput = {
67
127
  did: string;
68
128
  } | {
69
129
  method: 'email';
130
+ email: string;
70
131
  };
71
132
  /**
72
133
  * SSS-specific recovery setup result.
73
134
  */
74
135
  export type RecoverySetupResult = {
136
+ method: 'escrow';
137
+ shareVersion: number;
138
+ } | {
75
139
  method: 'passkey';
76
140
  credentialId: string;
77
141
  } | {
78
142
  method: 'phrase';
79
143
  phrase: string;
144
+ challengeWordIndices: number[];
145
+ /** Shuffled choices per challenged word (the answer plus decoys not in the phrase). */
146
+ challengeWordOptions: string[][];
80
147
  } | {
81
148
  method: 'backup';
82
149
  backupFile: BackupFile;
83
150
  } | {
84
151
  method: 'email';
85
152
  };
153
+ /** Proof supplied after a pending recovery method has been created. */
154
+ export type RecoveryConfirmationInput = {
155
+ method: 'phrase';
156
+ challengeWords: string[];
157
+ } | {
158
+ method: 'backup';
159
+ fileContents: string;
160
+ password: string;
161
+ } | {
162
+ method: 'email';
163
+ code: string;
164
+ };
86
165
  export interface EncryptedShare {
87
166
  encryptedData: string;
88
167
  iv: string;
@@ -104,6 +183,8 @@ export interface UserKeyRecord {
104
183
  recoveryMethods: RecoveryMethodInfo[];
105
184
  migratedFromWeb3Auth: boolean;
106
185
  migratedAt?: Date;
186
+ sssActivationState?: SssActivationState;
187
+ provisionalCreatedAt?: Date;
107
188
  createdAt: Date;
108
189
  updatedAt: Date;
109
190
  }
@@ -112,6 +193,8 @@ export interface BackupFile {
112
193
  createdAt: string;
113
194
  primaryDid: string;
114
195
  shareVersion?: number;
196
+ /** SHA-256 checksum of the decrypted share, used to verify a just-written file. */
197
+ shareChecksum?: string;
115
198
  encryptedShare: {
116
199
  ciphertext: string;
117
200
  iv: string;
@@ -133,7 +216,7 @@ export interface SSSKeyManagerConfig {
133
216
  * The SSS key derivation strategy — a KeyDerivationStrategy narrowed
134
217
  * with SSS-specific recovery input/output types.
135
218
  */
136
- export type SSSKeyDerivationStrategy = KeyDerivationStrategy<RecoveryInput, RecoverySetupInput, RecoverySetupResult>;
219
+ export type SSSKeyDerivationStrategy = KeyDerivationStrategy<RecoveryInput, RecoverySetupInput, RecoverySetupResult, RecoveryConfirmationInput>;
137
220
  /** @deprecated Use KeyDerivationStrategy instead. Kept for legacy SSSKeyManager class. */
138
221
  export interface KeyDerivationProvider {
139
222
  readonly name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@learncard/sss-key-manager",
3
- "version": "0.1.24",
3
+ "version": "0.2.0",
4
4
  "description": "Shamir Secret Sharing key manager for LearnCard - replaces Web3Auth SFA",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/sss-key-manager.esm.js",
@@ -38,7 +38,7 @@
38
38
  "vitest": "4.1.11"
39
39
  },
40
40
  "dependencies": {
41
- "@learncard/types": "5.21.0",
41
+ "@learncard/types": "5.22.0",
42
42
  "@noble/ed25519": "^2.0.0",
43
43
  "@scure/bip39": "^1.2.1",
44
44
  "hash-wasm": "^4.11.0",
@@ -0,0 +1,122 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+
3
+ import { SSSApiClient } from './api-client';
4
+
5
+ import type { AuthProvider } from './types';
6
+
7
+ const SENTINEL_TOKEN = 'SENTINEL_TOKEN_XYZ';
8
+ const DID_CHALLENGE_ERROR = 'This operation requires the DID-challenge flow; use createSSSStrategy';
9
+
10
+ const createMockAuthProvider = (): AuthProvider => ({
11
+ getIdToken: vi.fn().mockResolvedValue(SENTINEL_TOKEN),
12
+ getCurrentUser: vi.fn().mockResolvedValue({
13
+ id: 'user-123',
14
+ email: 'sentinel-user@example.com',
15
+ providerType: 'firebase' as const,
16
+ }),
17
+ getProviderType: vi.fn().mockReturnValue('firebase' as const),
18
+ signOut: vi.fn().mockResolvedValue(undefined),
19
+ });
20
+
21
+ describe('SSSApiClient', () => {
22
+ let client: SSSApiClient;
23
+ let calls: { url: string; init?: RequestInit }[];
24
+
25
+ beforeEach(() => {
26
+ calls = [];
27
+
28
+ vi.spyOn(globalThis, 'fetch').mockImplementation(async (url, init) => {
29
+ calls.push({ url: url.toString(), init });
30
+ return new Response(
31
+ JSON.stringify({
32
+ authShare: null,
33
+ primaryDid: null,
34
+ securityLevel: 'basic',
35
+ recoveryMethods: [],
36
+ keyProvider: 'sss',
37
+ shareVersion: 1,
38
+ sssActivationState: 'active',
39
+ recoverySessionToken: 'recovery-session-token',
40
+ rebindSessionToken: 'rebind-session-token',
41
+ recoveryMethodsRequireConfirmation: [],
42
+ }),
43
+ { status: 200 }
44
+ );
45
+ });
46
+
47
+ client = new SSSApiClient({
48
+ serverUrl: 'http://test-server:5100/api',
49
+ authProvider: createMockAuthProvider(),
50
+ });
51
+ });
52
+
53
+ afterEach(() => {
54
+ vi.restoreAllMocks();
55
+ });
56
+
57
+ it('uses X-Auth-Token rather than Authorization for provider-authenticated reads', async () => {
58
+ await client.getAuthShare();
59
+
60
+ const headers = calls[0]!.init?.headers as Record<string, string>;
61
+ expect(headers['X-Auth-Token']).toBe(SENTINEL_TOKEN);
62
+ expect(headers.Authorization).toBeUndefined();
63
+ expect(calls[0]!.url).not.toContain(SENTINEL_TOKEN);
64
+ });
65
+
66
+ it('keeps recovery read credentials out of the URL', async () => {
67
+ await client.getRecoveryShare('passkey', 'credential-1');
68
+
69
+ const headers = calls[0]!.init?.headers as Record<string, string>;
70
+ expect(headers['X-Auth-Token']).toBe(SENTINEL_TOKEN);
71
+ expect(calls[0]!.url).not.toContain(SENTINEL_TOKEN);
72
+ expect(calls[0]!.url).not.toMatch(/[?&](token|share)=/i);
73
+ });
74
+
75
+ it('retains the valid unauthenticated identity-recovery helpers', async () => {
76
+ await client.startIdentityRecovery('recovery@example.com');
77
+ await client.verifyIdentityRecovery('recovery@example.com', '123456');
78
+ await client.useIdentityRecoverySession('recovery-session-token', 'phrase');
79
+
80
+ expect(calls.map(call => call.url)).toEqual([
81
+ 'http://test-server:5100/api/keys/recovery-session/start',
82
+ 'http://test-server:5100/api/keys/recovery-session/verify',
83
+ 'http://test-server:5100/api/keys/recovery-session/recover',
84
+ ]);
85
+ });
86
+
87
+ it('retains identity rebind because it supplies both DID proof and the auth token', async () => {
88
+ await client.completeIdentityRecoveryRebind({
89
+ recoverySessionToken: 'rebind-session-token',
90
+ newAuthToken: SENTINEL_TOKEN,
91
+ providerType: 'firebase',
92
+ primaryDid: 'did:key:zTest',
93
+ authShare: { encryptedData: 'encrypted-share', encryptedDek: '', iv: '' },
94
+ didAuthVp: 'did-auth-vp',
95
+ });
96
+
97
+ const headers = calls[0]!.init?.headers as Record<string, string>;
98
+ expect(headers.Authorization).toBe('Bearer did-auth-vp');
99
+ expect(headers['X-Auth-Token']).toBe(SENTINEL_TOKEN);
100
+ });
101
+
102
+ it.each([
103
+ [
104
+ 'storeAuthShare',
105
+ () =>
106
+ client.storeAuthShare({
107
+ authShare: { encryptedData: 'share', encryptedDek: '', iv: '' },
108
+ primaryDid: 'did:key:zTest',
109
+ }),
110
+ ],
111
+ ['addRecoveryMethod', () => client.addRecoveryMethod({ type: 'phrase' })],
112
+ ['markMigrated', () => client.markMigrated()],
113
+ ['activate', () => client.activate()],
114
+ ['sendEmailBackupShare', () => client.sendEmailBackupShare('email-share')],
115
+ ['addRecoveryEmail', () => client.addRecoveryEmail('recovery@example.com')],
116
+ ['verifyRecoveryEmail', () => client.verifyRecoveryEmail('123456')],
117
+ ['deleteUserKey', () => client.deleteUserKey()],
118
+ ])('%s fails closed instead of calling a route without DID proof', async (_name, call) => {
119
+ await expect(call()).rejects.toThrow(DID_CHALLENGE_ERROR);
120
+ expect(calls).toHaveLength(0);
121
+ });
122
+ });