@learncard/lca-api-service 1.3.1 → 1.4.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 (99) hide show
  1. package/.env.example +26 -2
  2. package/AGENTS.md +59 -44
  3. package/CHANGELOG.md +57 -0
  4. package/compose.env +5 -0
  5. package/dist/accesslayer/signing-authority/index.d.ts +8 -2
  6. package/dist/app.d.ts +297 -8
  7. package/dist/cache/challenges.d.ts +2 -0
  8. package/dist/cache/recoverySessions.d.ts +42 -0
  9. package/dist/config/environment.d.ts +152 -2
  10. package/dist/config/environment.test.d.ts +1 -0
  11. package/dist/helpers/learnCard.signingAuthority.test.d.ts +1 -0
  12. package/dist/helpers/rateLimit.helpers.d.ts +4 -0
  13. package/dist/helpers/seedEncryption.helpers.d.ts +23 -0
  14. package/dist/helpers/seedEncryption.helpers.test.d.ts +1 -0
  15. package/dist/index.js +2 -2
  16. package/dist/migrations/signingAuthoritySeeds.d.ts +13 -0
  17. package/dist/migrations/signingAuthoritySeedsCli.test.d.ts +1 -0
  18. package/dist/models/EscrowHold.d.ts +75 -0
  19. package/dist/models/SigningAuthority.d.ts +7 -1
  20. package/dist/models/UserKey.d.ts +316 -3
  21. package/dist/models/UserKey.escrowPin.test.d.ts +1 -0
  22. package/dist/models/index.d.ts +1 -0
  23. package/dist/routes/escrow.d.ts +150 -0
  24. package/dist/routes/firebase.test.d.ts +1 -0
  25. package/dist/routes/index.d.ts +6 -0
  26. package/dist/routes/keys.d.ts +181 -7
  27. package/dist/routes/qr-login.d.ts +1 -1
  28. package/dist/services/escrow-enclave/index.d.ts +9 -0
  29. package/dist/services/escrow-enclave/notifications.d.ts +9 -0
  30. package/dist/services/escrow-enclave/softwareEnclave.d.ts +17 -0
  31. package/dist/services/escrow-enclave/softwareEnclave.test.d.ts +1 -0
  32. package/dist/services/escrow-enclave/types.d.ts +67 -0
  33. package/dist/types/seed-encryption.d.ts +31 -0
  34. package/dist/types/seed-migration.d.ts +49 -0
  35. package/lambda.ts +8 -3
  36. package/package.json +17 -11
  37. package/scripts/check-seed-encryption-infrastructure.mjs +123 -0
  38. package/scripts/check-signing-authority-redis.mjs +93 -0
  39. package/scripts/migrate-signing-authority-seeds-local.sh +51 -0
  40. package/scripts/migrate-signing-authority-seeds.mjs +105 -0
  41. package/seedMigrationLambda.test.ts +145 -0
  42. package/seedMigrationLambda.ts +50 -0
  43. package/serverless-local.yml +3 -0
  44. package/serverless.escrow-env.cjs +20 -0
  45. package/serverless.yml +133 -0
  46. package/src/accesslayer/signing-authority/create.ts +11 -7
  47. package/src/app.ts +2 -0
  48. package/src/cache/challenges.ts +12 -2
  49. package/src/cache/in-memory-lru.ts +1 -0
  50. package/src/cache/recoverySessions.ts +252 -0
  51. package/src/config/environment.test.ts +116 -0
  52. package/src/config/environment.ts +97 -0
  53. package/src/docker-entry.ts +4 -0
  54. package/src/helpers/learnCard.helpers.test.ts +11 -1
  55. package/src/helpers/learnCard.helpers.ts +57 -45
  56. package/src/helpers/learnCard.signingAuthority.test.ts +194 -0
  57. package/src/helpers/rateLimit.helpers.ts +112 -0
  58. package/src/helpers/seedEncryption.helpers.test.ts +427 -0
  59. package/src/helpers/seedEncryption.helpers.ts +372 -0
  60. package/src/helpers/signingAuthority.helpers.ts +4 -1
  61. package/src/migrations/signingAuthoritySeeds.ts +430 -0
  62. package/src/migrations/signingAuthoritySeedsCli.test.ts +70 -0
  63. package/src/models/EscrowHold.ts +225 -0
  64. package/src/models/SigningAuthority.ts +14 -3
  65. package/src/models/UserKey.escrowPin.test.ts +49 -0
  66. package/src/models/UserKey.ts +1024 -40
  67. package/src/models/index.ts +1 -0
  68. package/src/models/pruneOrphanedRecoveryMethods.ts +3 -1
  69. package/src/routes/credentials.ts +8 -0
  70. package/src/routes/escrow.ts +826 -0
  71. package/src/routes/firebase.test.ts +94 -0
  72. package/src/routes/firebase.ts +99 -56
  73. package/src/routes/index.ts +98 -5
  74. package/src/routes/keys.ts +1017 -174
  75. package/src/routes/qr-login.ts +51 -53
  76. package/src/services/delivery/adapters/postmark.adapter.ts +5 -0
  77. package/src/services/escrow-enclave/README.md +51 -0
  78. package/src/services/escrow-enclave/index.ts +36 -0
  79. package/src/services/escrow-enclave/notifications.ts +14 -0
  80. package/src/services/escrow-enclave/softwareEnclave.test.ts +249 -0
  81. package/src/services/escrow-enclave/softwareEnclave.ts +168 -0
  82. package/src/services/escrow-enclave/types.ts +76 -0
  83. package/src/types/seed-encryption.ts +51 -0
  84. package/src/types/seed-migration.ts +61 -0
  85. package/test/credentials.spec.ts +2 -0
  86. package/test/keys-escrow.spec.ts +1389 -0
  87. package/test/keys-identity-rebind.spec.ts +456 -0
  88. package/test/keys-lifecycle-invariants.spec.ts +785 -0
  89. package/test/keys-recovery-confirmation.spec.ts +586 -0
  90. package/test/keys-recovery-rate-limit.spec.ts +123 -0
  91. package/test/keys-secret-leakage.spec.ts +265 -0
  92. package/test/models/escrow.spec.ts +210 -0
  93. package/test/signing-authority-http.spec.ts +161 -0
  94. package/test/signing-authority-seed-migration.spec.ts +414 -0
  95. package/test/signing-authority.spec.ts +40 -0
  96. package/vitest.config.ts +1 -1
  97. package/vitest.integration.config.ts +5 -0
  98. package/dist/cache/signing-authority.d.ts +0 -6
  99. package/src/cache/signing-authority.ts +0 -37
@@ -0,0 +1,23 @@
1
+ import { KMSClient } from '@aws-sdk/client-kms';
2
+ import type { EncryptedSigningAuthoritySeed, SeedEncryptionConfig, SeedEncryption, SeedEncryptionFailure, SigningAuthoritySeedIdentity, SigningAuthoritySeedRecord } from 'types/seed-encryption';
3
+ export declare const SA_SEED_ENCRYPTION_PURPOSE = "lca-signing-authority-seed";
4
+ export declare class SeedEncryptionError extends Error {
5
+ readonly category: SeedEncryptionFailure;
6
+ readonly awsRequestId?: string | undefined;
7
+ constructor(category: SeedEncryptionFailure, awsRequestId?: string | undefined);
8
+ }
9
+ export declare const logSeedEncryptionFailure: (error: unknown, operation: string, record?: {
10
+ _id?: unknown;
11
+ keyVersion?: unknown;
12
+ }) => void;
13
+ export declare const getSeedIdentity: (record: {
14
+ _id?: unknown;
15
+ ownerDid: string;
16
+ name: string;
17
+ did?: string;
18
+ }) => SigningAuthoritySeedIdentity;
19
+ export declare const parseSeedEnvelope: (record: object) => EncryptedSigningAuthoritySeed | undefined;
20
+ export declare const createSeedEncryption: (config: SeedEncryptionConfig, kms?: KMSClient) => SeedEncryption;
21
+ export declare const seedEncryption: SeedEncryption;
22
+ export declare const decryptSigningAuthoritySeed: (record: SigningAuthoritySeedRecord) => Promise<string>;
23
+ export declare const getSeedCacheFingerprint: (record: SigningAuthoritySeedRecord) => string;
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/dist/index.js
3
- size: 119986604 bytes
4
- sha256: c5d3d194d7bde48502ddfc43d0513c741a79d171dce75b507c5479e20ca22585
3
+ size: 130294880 bytes
4
+ sha256: a1011a859d7a6b8f2f80b736401ec8e590ef34af0167e08e979d2a8ad252801a
@@ -0,0 +1,13 @@
1
+ import type { Db } from 'mongodb';
2
+ import type { SeedMigrationCounts, SeedMigrationRequest, SeedMigrationResult } from 'types/seed-migration';
3
+ export declare const SEED_MIGRATION_STATE_COLLECTION = "signingauthorityseedmigration";
4
+ export declare const SEED_MIGRATION_RECEIPTS_COLLECTION = "signingauthorityseedverification";
5
+ export declare class SeedMigrationError extends Error {
6
+ readonly category: string;
7
+ constructor(category: string);
8
+ }
9
+ export declare const countSeedMigrationDocuments: (db: Db) => Promise<SeedMigrationCounts>;
10
+ export declare const runSeedMigrationBatch: (db: Db, request: SeedMigrationRequest, options: {
11
+ encryptedWritesEnabled: boolean;
12
+ remainingTime?: () => number;
13
+ }) => Promise<SeedMigrationResult>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,75 @@
1
+ import { z } from 'zod';
2
+ import type { Collection } from 'mongodb';
3
+ import { type AuthProviderMapping } from './UserKey';
4
+ export declare const ESCROW_HOLDS_COLLECTION = "escrowholds";
5
+ export declare const ESCROW_HOLD_STALE_WINDOW_MS: number;
6
+ export declare const ESCROW_HOLD_RESTART_MIN_AGE_MS: number;
7
+ export declare const EscrowHoldValidator: z.ZodObject<{
8
+ _id: z.ZodString;
9
+ authProvider: z.ZodObject<{
10
+ type: z.ZodEnum<{
11
+ firebase: "firebase";
12
+ supertokens: "supertokens";
13
+ keycloak: "keycloak";
14
+ oidc: "oidc";
15
+ }>;
16
+ id: z.ZodString;
17
+ }, z.core.$strip>;
18
+ primaryDid: z.ZodString;
19
+ shareVersion: z.ZodNumber;
20
+ status: z.ZodEnum<{
21
+ pending: "pending";
22
+ cancelled: "cancelled";
23
+ completed: "completed";
24
+ expired: "expired";
25
+ }>;
26
+ identityProofType: z.ZodEnum<{
27
+ "auth-token": "auth-token";
28
+ "recovery-session": "recovery-session";
29
+ }>;
30
+ requestedAt: z.ZodDate;
31
+ releaseAfter: z.ZodDate;
32
+ releasePolicy: z.ZodDefault<z.ZodEnum<{
33
+ pin: "pin";
34
+ hold: "hold";
35
+ }>>;
36
+ cancelReason: z.ZodOptional<z.ZodEnum<{
37
+ "pin-mismatch": "pin-mismatch";
38
+ "pin-locked": "pin-locked";
39
+ superseded: "superseded";
40
+ "release-failed": "release-failed";
41
+ }>>;
42
+ cancelledAt: z.ZodOptional<z.ZodDate>;
43
+ cancelledBy: z.ZodOptional<z.ZodEnum<{
44
+ did: "did";
45
+ system: "system";
46
+ }>>;
47
+ completedAt: z.ZodOptional<z.ZodDate>;
48
+ clientEphemeralPublicKey: z.ZodString;
49
+ resumeTokenHash: z.ZodString;
50
+ notifications: z.ZodDefault<z.ZodArray<z.ZodObject<{
51
+ kind: z.ZodEnum<{
52
+ cancelled: "cancelled";
53
+ completed: "completed";
54
+ started: "started";
55
+ }>;
56
+ sentAt: z.ZodDate;
57
+ }, z.core.$strip>>>;
58
+ requestIp: z.ZodOptional<z.ZodString>;
59
+ createdAt: z.ZodDate;
60
+ updatedAt: z.ZodDate;
61
+ }, z.core.$strip>;
62
+ export type EscrowHold = z.infer<typeof EscrowHoldValidator>;
63
+ export type CreateEscrowHoldInput = Omit<z.input<typeof EscrowHoldValidator>, '_id' | 'status' | 'createdAt' | 'updatedAt' | 'notifications' | 'cancelledAt' | 'cancelledBy' | 'completedAt' | 'cancelReason'>;
64
+ export declare const getEscrowHoldsCollection: () => Collection<EscrowHold>;
65
+ export declare const createEscrowHoldsIndexes: () => Promise<void>;
66
+ export declare const createEscrowHold: (input: CreateEscrowHoldInput) => Promise<EscrowHold>;
67
+ export declare const findPendingEscrowHoldByAuthProvider: (authProvider: AuthProviderMapping, releasePolicy?: EscrowHold["releasePolicy"]) => Promise<EscrowHold | null>;
68
+ export declare const findEscrowHoldById: (id: string) => Promise<EscrowHold | null>;
69
+ export declare const cancelEscrowHold: (id: string, cancelledBy: "did" | "system", cancelReason?: EscrowHold["cancelReason"]) => Promise<EscrowHold | null>;
70
+ export declare const completeEscrowHold: (id: string) => Promise<EscrowHold | null>;
71
+ export declare const hasCompletedEscrowHoldForVersion: (authProvider: AuthProviderMapping, shareVersion: number) => Promise<boolean>;
72
+ export declare const expireStaleEscrowHolds: (now: Date) => Promise<number>;
73
+ export declare const markClaimedEscrowHoldFailed: (id: string, reason: "pin-mismatch" | "pin-locked" | "release-failed", completedAt: Date) => Promise<void>;
74
+ export declare const hashEscrowResumeToken: (token: string) => string;
75
+ export declare const generateEscrowResumeToken: () => string;
@@ -4,7 +4,13 @@ export declare const MongoSigningAuthorityValidator: z.ZodObject<{
4
4
  _id: z.ZodOptional<z.ZodString>;
5
5
  ownerDid: z.ZodString;
6
6
  name: z.ZodString;
7
- seed: z.ZodString;
7
+ seed: z.ZodOptional<z.ZodString>;
8
+ encryptedSeed: z.ZodOptional<z.ZodString>;
9
+ encryptedDek: z.ZodOptional<z.ZodString>;
10
+ keyVersion: z.ZodOptional<z.ZodEnum<{
11
+ "kms-v1": "kms-v1";
12
+ "local-v1": "local-v1";
13
+ }>>;
8
14
  did: z.ZodOptional<z.ZodString>;
9
15
  endpoint: z.ZodOptional<z.ZodString>;
10
16
  }, z.core.$strip>;
@@ -33,8 +33,14 @@ export declare const RecoveryMethodValidator: z.ZodObject<{
33
33
  passkey: "passkey";
34
34
  backup: "backup";
35
35
  phrase: "phrase";
36
+ escrow: "escrow";
36
37
  }>;
37
38
  createdAt: z.ZodDate;
39
+ confirmationStatus: z.ZodOptional<z.ZodEnum<{
40
+ pending: "pending";
41
+ confirmed: "confirmed";
42
+ }>>;
43
+ confirmedAt: z.ZodOptional<z.ZodDate>;
38
44
  credentialId: z.ZodOptional<z.ZodString>;
39
45
  encryptedShare: z.ZodOptional<z.ZodObject<{
40
46
  encryptedData: z.ZodString;
@@ -42,6 +48,10 @@ export declare const RecoveryMethodValidator: z.ZodObject<{
42
48
  salt: z.ZodOptional<z.ZodString>;
43
49
  }, z.core.$strip>>;
44
50
  shareVersion: z.ZodOptional<z.ZodNumber>;
51
+ confirmationCodeHash: z.ZodOptional<z.ZodString>;
52
+ confirmationCodeExpiresAt: z.ZodOptional<z.ZodDate>;
53
+ confirmationAttempts: z.ZodOptional<z.ZodNumber>;
54
+ confirmationEmail: z.ZodOptional<z.ZodString>;
45
55
  }, z.core.$strip>;
46
56
  export declare const PreviousAuthShareValidator: z.ZodObject<{
47
57
  authShare: z.ZodObject<{
@@ -52,7 +62,95 @@ export declare const PreviousAuthShareValidator: z.ZodObject<{
52
62
  shareVersion: z.ZodNumber;
53
63
  createdAt: z.ZodDate;
54
64
  }, z.core.$strip>;
55
- export declare const MongoUserKeyValidator: z.ZodObject<{
65
+ export declare const EscrowEnvelopeValidator: z.ZodObject<{
66
+ version: z.ZodLiteral<1>;
67
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
68
+ keyId: z.ZodString;
69
+ ephemeralPublicKey: z.ZodString;
70
+ salt: z.ZodString;
71
+ iv: z.ZodString;
72
+ ciphertext: z.ZodString;
73
+ }, z.core.$strict>;
74
+ export declare const EscrowBlobValidator: z.ZodObject<{
75
+ envelope: z.ZodObject<{
76
+ version: z.ZodLiteral<1>;
77
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
78
+ keyId: z.ZodString;
79
+ ephemeralPublicKey: z.ZodString;
80
+ salt: z.ZodString;
81
+ iv: z.ZodString;
82
+ ciphertext: z.ZodString;
83
+ }, z.core.$strict>;
84
+ enclaveKeyId: z.ZodString;
85
+ enclaveMode: z.ZodEnum<{
86
+ software: "software";
87
+ nitro: "nitro";
88
+ }>;
89
+ measurements: z.ZodObject<{
90
+ imageSha384: z.ZodOptional<z.ZodString>;
91
+ pcr0: z.ZodOptional<z.ZodString>;
92
+ pcr1: z.ZodOptional<z.ZodString>;
93
+ pcr2: z.ZodOptional<z.ZodString>;
94
+ }, z.core.$strip>;
95
+ shareVersion: z.ZodNumber;
96
+ createdAt: z.ZodDate;
97
+ }, z.core.$strip>;
98
+ export type EscrowBlob = z.infer<typeof EscrowBlobValidator>;
99
+ export declare const EscrowPinSaltValidator: z.ZodString;
100
+ export declare const EscrowPinValidator: z.ZodObject<{
101
+ salt: z.ZodString;
102
+ failedAttempts: z.ZodNumber;
103
+ verifiedFailedAttempts: z.ZodOptional<z.ZodNumber>;
104
+ enabledAt: z.ZodDate;
105
+ disabledAt: z.ZodOptional<z.ZodDate>;
106
+ shareVersion: z.ZodNumber;
107
+ }, z.core.$strip>;
108
+ export declare const EscrowPinStatusValidator: z.ZodObject<{
109
+ state: z.ZodEnum<{
110
+ none: "none";
111
+ enabled: "enabled";
112
+ locked: "locked";
113
+ stale: "stale";
114
+ }>;
115
+ enabled: z.ZodBoolean;
116
+ attemptsRemaining: z.ZodNumber;
117
+ salt: z.ZodOptional<z.ZodString>;
118
+ }, z.core.$strip>;
119
+ export declare const getEscrowPinStatus: (userKey: MongoUserKeyType) => z.infer<typeof EscrowPinStatusValidator>;
120
+ declare const MongoUserKeyBaseValidator: z.ZodObject<{
121
+ escrowBlob: z.ZodOptional<z.ZodObject<{
122
+ envelope: z.ZodObject<{
123
+ version: z.ZodLiteral<1>;
124
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
125
+ keyId: z.ZodString;
126
+ ephemeralPublicKey: z.ZodString;
127
+ salt: z.ZodString;
128
+ iv: z.ZodString;
129
+ ciphertext: z.ZodString;
130
+ }, z.core.$strict>;
131
+ enclaveKeyId: z.ZodString;
132
+ enclaveMode: z.ZodEnum<{
133
+ software: "software";
134
+ nitro: "nitro";
135
+ }>;
136
+ measurements: z.ZodObject<{
137
+ imageSha384: z.ZodOptional<z.ZodString>;
138
+ pcr0: z.ZodOptional<z.ZodString>;
139
+ pcr1: z.ZodOptional<z.ZodString>;
140
+ pcr2: z.ZodOptional<z.ZodString>;
141
+ }, z.core.$strip>;
142
+ shareVersion: z.ZodNumber;
143
+ createdAt: z.ZodDate;
144
+ }, z.core.$strip>>;
145
+ escrowPin: z.ZodOptional<z.ZodObject<{
146
+ salt: z.ZodString;
147
+ failedAttempts: z.ZodNumber;
148
+ verifiedFailedAttempts: z.ZodOptional<z.ZodNumber>;
149
+ enabledAt: z.ZodDate;
150
+ disabledAt: z.ZodOptional<z.ZodDate>;
151
+ shareVersion: z.ZodNumber;
152
+ }, z.core.$strip>>;
153
+ escrowOptedOutAt: z.ZodOptional<z.ZodDate>;
56
154
  _id: z.ZodOptional<z.ZodString>;
57
155
  contactMethod: z.ZodObject<{
58
156
  type: z.ZodEnum<{
@@ -103,8 +201,14 @@ export declare const MongoUserKeyValidator: z.ZodObject<{
103
201
  passkey: "passkey";
104
202
  backup: "backup";
105
203
  phrase: "phrase";
204
+ escrow: "escrow";
106
205
  }>;
107
206
  createdAt: z.ZodDate;
207
+ confirmationStatus: z.ZodOptional<z.ZodEnum<{
208
+ pending: "pending";
209
+ confirmed: "confirmed";
210
+ }>>;
211
+ confirmedAt: z.ZodOptional<z.ZodDate>;
108
212
  credentialId: z.ZodOptional<z.ZodString>;
109
213
  encryptedShare: z.ZodOptional<z.ZodObject<{
110
214
  encryptedData: z.ZodString;
@@ -112,15 +216,140 @@ export declare const MongoUserKeyValidator: z.ZodObject<{
112
216
  salt: z.ZodOptional<z.ZodString>;
113
217
  }, z.core.$strip>>;
114
218
  shareVersion: z.ZodOptional<z.ZodNumber>;
219
+ confirmationCodeHash: z.ZodOptional<z.ZodString>;
220
+ confirmationCodeExpiresAt: z.ZodOptional<z.ZodDate>;
221
+ confirmationAttempts: z.ZodOptional<z.ZodNumber>;
222
+ confirmationEmail: z.ZodOptional<z.ZodString>;
115
223
  }, z.core.$strip>>>;
116
224
  recoveryEmail: z.ZodOptional<z.ZodString>;
117
225
  recoveryEmailVerifiedAt: z.ZodOptional<z.ZodDate>;
118
226
  migratedFromWeb3Auth: z.ZodDefault<z.ZodBoolean>;
119
227
  migratedAt: z.ZodOptional<z.ZodDate>;
228
+ sssActivationState: z.ZodOptional<z.ZodEnum<{
229
+ provisional: "provisional";
230
+ active: "active";
231
+ }>>;
232
+ provisionalCreatedAt: z.ZodOptional<z.ZodDate>;
120
233
  createdAt: z.ZodDate;
121
234
  updatedAt: z.ZodDate;
122
235
  }, z.core.$strip>;
123
- export type MongoUserKeyType = z.infer<typeof MongoUserKeyValidator>;
236
+ export declare const MongoUserKeyValidator: z.ZodObject<{
237
+ escrowBlob: z.ZodOptional<z.ZodObject<{
238
+ envelope: z.ZodObject<{
239
+ version: z.ZodLiteral<1>;
240
+ algorithm: z.ZodLiteral<"P-256-HKDF-SHA256-AES-256-GCM">;
241
+ keyId: z.ZodString;
242
+ ephemeralPublicKey: z.ZodString;
243
+ salt: z.ZodString;
244
+ iv: z.ZodString;
245
+ ciphertext: z.ZodString;
246
+ }, z.core.$strict>;
247
+ enclaveKeyId: z.ZodString;
248
+ enclaveMode: z.ZodEnum<{
249
+ software: "software";
250
+ nitro: "nitro";
251
+ }>;
252
+ measurements: z.ZodObject<{
253
+ imageSha384: z.ZodOptional<z.ZodString>;
254
+ pcr0: z.ZodOptional<z.ZodString>;
255
+ pcr1: z.ZodOptional<z.ZodString>;
256
+ pcr2: z.ZodOptional<z.ZodString>;
257
+ }, z.core.$strip>;
258
+ shareVersion: z.ZodNumber;
259
+ createdAt: z.ZodDate;
260
+ }, z.core.$strip>>;
261
+ escrowPin: z.ZodOptional<z.ZodObject<{
262
+ salt: z.ZodString;
263
+ failedAttempts: z.ZodNumber;
264
+ verifiedFailedAttempts: z.ZodOptional<z.ZodNumber>;
265
+ enabledAt: z.ZodDate;
266
+ disabledAt: z.ZodOptional<z.ZodDate>;
267
+ shareVersion: z.ZodNumber;
268
+ }, z.core.$strip>>;
269
+ escrowOptedOutAt: z.ZodOptional<z.ZodDate>;
270
+ _id: z.ZodOptional<z.ZodString>;
271
+ contactMethod: z.ZodObject<{
272
+ type: z.ZodEnum<{
273
+ email: "email";
274
+ phone: "phone";
275
+ }>;
276
+ value: z.ZodString;
277
+ }, z.core.$strip>;
278
+ authProviders: z.ZodDefault<z.ZodArray<z.ZodObject<{
279
+ type: z.ZodEnum<{
280
+ firebase: "firebase";
281
+ supertokens: "supertokens";
282
+ keycloak: "keycloak";
283
+ oidc: "oidc";
284
+ }>;
285
+ id: z.ZodString;
286
+ }, z.core.$strip>>>;
287
+ primaryDid: z.ZodString;
288
+ linkedDids: z.ZodDefault<z.ZodArray<z.ZodString>>;
289
+ keyProvider: z.ZodDefault<z.ZodEnum<{
290
+ web3auth: "web3auth";
291
+ sss: "sss";
292
+ }>>;
293
+ authShare: z.ZodOptional<z.ZodObject<{
294
+ encryptedData: z.ZodString;
295
+ encryptedDek: z.ZodString;
296
+ iv: z.ZodString;
297
+ }, z.core.$strip>>;
298
+ shareVersion: z.ZodDefault<z.ZodNumber>;
299
+ shareUpdatedAt: z.ZodOptional<z.ZodDate>;
300
+ previousAuthShares: z.ZodDefault<z.ZodArray<z.ZodObject<{
301
+ authShare: z.ZodObject<{
302
+ encryptedData: z.ZodString;
303
+ encryptedDek: z.ZodString;
304
+ iv: z.ZodString;
305
+ }, z.core.$strip>;
306
+ shareVersion: z.ZodNumber;
307
+ createdAt: z.ZodDate;
308
+ }, z.core.$strip>>>;
309
+ securityLevel: z.ZodDefault<z.ZodEnum<{
310
+ basic: "basic";
311
+ enhanced: "enhanced";
312
+ advanced: "advanced";
313
+ }>>;
314
+ recoveryMethods: z.ZodDefault<z.ZodArray<z.ZodObject<{
315
+ type: z.ZodEnum<{
316
+ email: "email";
317
+ passkey: "passkey";
318
+ backup: "backup";
319
+ phrase: "phrase";
320
+ escrow: "escrow";
321
+ }>;
322
+ createdAt: z.ZodDate;
323
+ confirmationStatus: z.ZodOptional<z.ZodEnum<{
324
+ pending: "pending";
325
+ confirmed: "confirmed";
326
+ }>>;
327
+ confirmedAt: z.ZodOptional<z.ZodDate>;
328
+ credentialId: z.ZodOptional<z.ZodString>;
329
+ encryptedShare: z.ZodOptional<z.ZodObject<{
330
+ encryptedData: z.ZodString;
331
+ iv: z.ZodString;
332
+ salt: z.ZodOptional<z.ZodString>;
333
+ }, z.core.$strip>>;
334
+ shareVersion: z.ZodOptional<z.ZodNumber>;
335
+ confirmationCodeHash: z.ZodOptional<z.ZodString>;
336
+ confirmationCodeExpiresAt: z.ZodOptional<z.ZodDate>;
337
+ confirmationAttempts: z.ZodOptional<z.ZodNumber>;
338
+ confirmationEmail: z.ZodOptional<z.ZodString>;
339
+ }, z.core.$strip>>>;
340
+ recoveryEmail: z.ZodOptional<z.ZodString>;
341
+ recoveryEmailVerifiedAt: z.ZodOptional<z.ZodDate>;
342
+ migratedFromWeb3Auth: z.ZodDefault<z.ZodBoolean>;
343
+ migratedAt: z.ZodOptional<z.ZodDate>;
344
+ sssActivationState: z.ZodOptional<z.ZodEnum<{
345
+ provisional: "provisional";
346
+ active: "active";
347
+ }>>;
348
+ provisionalCreatedAt: z.ZodOptional<z.ZodDate>;
349
+ createdAt: z.ZodDate;
350
+ updatedAt: z.ZodDate;
351
+ }, z.core.$loose>;
352
+ export type MongoUserKeyType = z.infer<typeof MongoUserKeyBaseValidator>;
124
353
  export type ContactMethod = z.infer<typeof ContactMethodValidator>;
125
354
  export type AuthProviderMapping = z.infer<typeof AuthProviderMappingValidator>;
126
355
  export type ServerEncryptedShare = z.infer<typeof ServerEncryptedShareValidator>;
@@ -128,6 +357,13 @@ export type EncryptedShare = z.infer<typeof EncryptedShareValidator>;
128
357
  export type RecoveryMethod = z.infer<typeof RecoveryMethodValidator>;
129
358
  export type PreviousAuthShare = z.infer<typeof PreviousAuthShareValidator>;
130
359
  export declare const MAX_PREVIOUS_AUTH_SHARES = 5;
360
+ export declare const PROVISIONAL_MIGRATION_TTL_MS: number;
361
+ export declare class UserKeyVersionConflictError extends Error {
362
+ constructor();
363
+ }
364
+ export declare const getSssActivationState: (userKey: MongoUserKeyType) => "provisional" | "active";
365
+ export declare const isRecoveryMethodConfirmed: (userKey: MongoUserKeyType, method: RecoveryMethod) => boolean;
366
+ export declare const hasActivatableRecoveryMethod: (userKey: MongoUserKeyType) => boolean;
131
367
  export { pruneOrphanedRecoveryMethods };
132
368
  export declare const getUserKeysCollection: () => import("mongodb").Collection<{
133
369
  contactMethod: {
@@ -153,8 +389,10 @@ export declare const getUserKeysCollection: () => import("mongodb").Collection<{
153
389
  }[];
154
390
  securityLevel: "basic" | "enhanced" | "advanced";
155
391
  recoveryMethods: {
156
- type: "email" | "passkey" | "backup" | "phrase";
392
+ type: "email" | "passkey" | "backup" | "phrase" | "escrow";
157
393
  createdAt: Date;
394
+ confirmationStatus?: "pending" | "confirmed" | undefined;
395
+ confirmedAt?: Date | undefined;
158
396
  credentialId?: string | undefined;
159
397
  encryptedShare?: {
160
398
  encryptedData: string;
@@ -162,10 +400,44 @@ export declare const getUserKeysCollection: () => import("mongodb").Collection<{
162
400
  salt?: string | undefined;
163
401
  } | undefined;
164
402
  shareVersion?: number | undefined;
403
+ confirmationCodeHash?: string | undefined;
404
+ confirmationCodeExpiresAt?: Date | undefined;
405
+ confirmationAttempts?: number | undefined;
406
+ confirmationEmail?: string | undefined;
165
407
  }[];
166
408
  migratedFromWeb3Auth: boolean;
167
409
  createdAt: Date;
168
410
  updatedAt: Date;
411
+ escrowBlob?: {
412
+ envelope: {
413
+ version: 1;
414
+ algorithm: "P-256-HKDF-SHA256-AES-256-GCM";
415
+ keyId: string;
416
+ ephemeralPublicKey: string;
417
+ salt: string;
418
+ iv: string;
419
+ ciphertext: string;
420
+ };
421
+ enclaveKeyId: string;
422
+ enclaveMode: "software" | "nitro";
423
+ measurements: {
424
+ imageSha384?: string | undefined;
425
+ pcr0?: string | undefined;
426
+ pcr1?: string | undefined;
427
+ pcr2?: string | undefined;
428
+ };
429
+ shareVersion: number;
430
+ createdAt: Date;
431
+ } | undefined;
432
+ escrowPin?: {
433
+ salt: string;
434
+ failedAttempts: number;
435
+ enabledAt: Date;
436
+ shareVersion: number;
437
+ verifiedFailedAttempts?: number | undefined;
438
+ disabledAt?: Date | undefined;
439
+ } | undefined;
440
+ escrowOptedOutAt?: Date | undefined;
169
441
  _id?: string | undefined;
170
442
  authShare?: {
171
443
  encryptedData: string;
@@ -176,16 +448,57 @@ export declare const getUserKeysCollection: () => import("mongodb").Collection<{
176
448
  recoveryEmail?: string | undefined;
177
449
  recoveryEmailVerifiedAt?: Date | undefined;
178
450
  migratedAt?: Date | undefined;
451
+ sssActivationState?: "provisional" | "active" | undefined;
452
+ provisionalCreatedAt?: Date | undefined;
179
453
  }>;
180
454
  export declare const createUserKeysIndexes: () => Promise<void>;
455
+ export declare const ensureUserKeysIndexes: () => Promise<void>;
181
456
  export declare const findUserKeyByContactMethod: (contactMethod: ContactMethod) => Promise<MongoUserKeyType | null>;
182
457
  export declare const findUserKeyByAuthProvider: (providerType: string, providerId: string) => Promise<MongoUserKeyType | null>;
183
458
  export declare const findUserKeyByDid: (did: string) => Promise<MongoUserKeyType | null>;
459
+ export declare const findUniqueUserKeyByVerifiedRecoveryEmail: (email: string) => Promise<MongoUserKeyType | null>;
184
460
  export declare const findAuthShareByVersion: (userKey: MongoUserKeyType, version: number) => ServerEncryptedShare | null;
185
461
  export declare const upsertUserKey: (contactMethod: ContactMethod, data: Partial<Omit<MongoUserKeyType, "_id" | "contactMethod" | "createdAt">>) => Promise<MongoUserKeyType>;
462
+ export declare const upsertUserKeyByAuthProvider: (contactMethod: ContactMethod, authProvider: AuthProviderMapping, data: Partial<Omit<MongoUserKeyType, "_id" | "contactMethod" | "createdAt" | "authProviders">>, expectedVersion?: number) => Promise<MongoUserKeyType>;
186
463
  export declare const addAuthProviderToUserKey: (contactMethod: ContactMethod, authProvider: AuthProviderMapping) => Promise<void>;
187
464
  export declare const addRecoveryMethodToUserKey: (contactMethod: ContactMethod, recoveryMethod: RecoveryMethod) => Promise<void>;
465
+ export declare const setEscrowBlobByAuthProvider: (authProvider: AuthProviderMapping, blob: EscrowBlob, expectedShareVersion: number, pin?: {
466
+ salt: string;
467
+ }, carryFrom?: {
468
+ blob: EscrowBlob;
469
+ pin: NonNullable<MongoUserKeyType["escrowPin"]>;
470
+ }) => Promise<MongoUserKeyType | null>;
471
+ export declare const clearEscrowByAuthProvider: (authProvider: AuthProviderMapping, { optOut }: {
472
+ optOut: boolean;
473
+ }) => Promise<MongoUserKeyType | null>;
474
+ export declare const setEscrowOptInByAuthProvider: (authProvider: AuthProviderMapping) => Promise<MongoUserKeyType | null>;
475
+ export declare const reserveEscrowPinAttempt: (authProvider: AuthProviderMapping, shareVersion: number, expectedCiphertext?: string) => Promise<MongoUserKeyType | null>;
476
+ export declare const refundEscrowPinAttempt: (authProvider: AuthProviderMapping, shareVersion: number, expectedCiphertext: string) => Promise<void>;
477
+ export declare const recordEscrowPinFailure: (authProvider: AuthProviderMapping, shareVersion: number, expectedCiphertext: string) => Promise<MongoUserKeyType | null>;
478
+ export declare const disableEscrowPin: (authProvider: AuthProviderMapping, shareVersion?: number, expectedCiphertext?: string) => Promise<boolean>;
479
+ export declare const addRecoveryMethodToUserKeyByAuthProvider: (authProvider: AuthProviderMapping, recoveryMethod: RecoveryMethod) => Promise<void>;
480
+ export declare const removeRecoveryMethodFromUserKeyByAuthProvider: (authProvider: AuthProviderMapping, type: RecoveryMethod["type"], credentialId?: string) => Promise<void>;
481
+ export declare const incrementRecoveryConfirmationAttemptsByAuthProvider: (authProvider: AuthProviderMapping, shareVersion: number) => Promise<boolean>;
482
+ export declare const confirmRecoveryMethodByAuthProvider: (authProvider: AuthProviderMapping, type: RecoveryMethod["type"], shareVersion: number, credentialId?: string) => Promise<boolean>;
188
483
  export declare const markUserKeyMigrated: (contactMethod: ContactMethod) => Promise<void>;
484
+ export declare const markUserKeyMigratedByAuthProvider: (authProvider: AuthProviderMapping) => Promise<void>;
485
+ export declare const markUserKeyMigrationProvisionalByAuthProvider: (authProvider: AuthProviderMapping, provisionalCreatedAt: Date) => Promise<boolean>;
486
+ export declare const activateUserKeyByAuthProvider: (authProvider: AuthProviderMapping, shareVersion: number, isMigration: boolean) => Promise<boolean>;
487
+ export declare const purgeExpiredProvisionalMigrationByAuthProvider: (authProvider: AuthProviderMapping, now?: Date) => Promise<boolean>;
189
488
  export declare const setRecoveryEmail: (contactMethod: ContactMethod, email: string) => Promise<void>;
489
+ export declare const setRecoveryEmailByAuthProvider: (authProvider: AuthProviderMapping, email: string) => Promise<void>;
190
490
  export declare const upgradeContactMethod: (oldContactMethod: ContactMethod, newContactMethod: ContactMethod) => Promise<boolean>;
491
+ export declare const upgradeContactMethodByAuthProvider: (authProvider: AuthProviderMapping, expectedOldContactMethod: ContactMethod, newContactMethod: ContactMethod) => Promise<boolean>;
191
492
  export declare const deleteUserKey: (contactMethod: ContactMethod) => Promise<void>;
493
+ export declare const deleteUserKeyByAuthProvider: (authProvider: AuthProviderMapping) => Promise<void>;
494
+ export interface CompleteIdentityRebindInput {
495
+ oldAuthProvider: AuthProviderMapping;
496
+ newAuthProvider: AuthProviderMapping;
497
+ newContactMethod: ContactMethod;
498
+ primaryDid: string;
499
+ authShare: ServerEncryptedShare;
500
+ }
501
+ export declare const completeIdentityRebind: (input: CompleteIdentityRebindInput) => Promise<{
502
+ shareVersion: number;
503
+ methodsRequiringConfirmation: RecoveryMethod["type"][];
504
+ } | null>;
@@ -0,0 +1 @@
1
+ export {};
@@ -5,3 +5,4 @@ export * from './SigningAuthority';
5
5
  export * from './Pins';
6
6
  export * from './Preferences';
7
7
  export * from './UserKey';
8
+ export * from './EscrowHold';