@inkbox/sdk 0.1.4 → 0.2.1

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 (65) hide show
  1. package/README.md +31 -35
  2. package/dist/_http.d.ts +7 -1
  3. package/dist/_http.d.ts.map +1 -1
  4. package/dist/_http.js +13 -1
  5. package/dist/_http.js.map +1 -1
  6. package/dist/agent_identity.d.ts +89 -71
  7. package/dist/agent_identity.d.ts.map +1 -1
  8. package/dist/agent_identity.js +145 -113
  9. package/dist/agent_identity.js.map +1 -1
  10. package/dist/credentials.d.ts +97 -0
  11. package/dist/credentials.d.ts.map +1 -0
  12. package/dist/credentials.js +147 -0
  13. package/dist/credentials.js.map +1 -0
  14. package/dist/identities/resources/identities.d.ts +1 -16
  15. package/dist/identities/resources/identities.d.ts.map +1 -1
  16. package/dist/identities/resources/identities.js +1 -19
  17. package/dist/identities/resources/identities.js.map +1 -1
  18. package/dist/identities/types.d.ts +0 -21
  19. package/dist/identities/types.d.ts.map +1 -1
  20. package/dist/identities/types.js +0 -11
  21. package/dist/identities/types.js.map +1 -1
  22. package/dist/index.d.ts +11 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +7 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/inkbox.d.ts +42 -6
  27. package/dist/inkbox.d.ts.map +1 -1
  28. package/dist/inkbox.js +59 -10
  29. package/dist/inkbox.js.map +1 -1
  30. package/dist/mail/resources/messages.d.ts +2 -2
  31. package/dist/mail/resources/messages.d.ts.map +1 -1
  32. package/dist/mail/resources/messages.js.map +1 -1
  33. package/dist/mail/types.d.ts +8 -1
  34. package/dist/mail/types.d.ts.map +1 -1
  35. package/dist/mail/types.js +8 -0
  36. package/dist/mail/types.js.map +1 -1
  37. package/dist/vault/crypto.d.ts +138 -0
  38. package/dist/vault/crypto.d.ts.map +1 -0
  39. package/dist/vault/crypto.js +273 -0
  40. package/dist/vault/crypto.js.map +1 -0
  41. package/dist/vault/resources/vault.d.ts +183 -0
  42. package/dist/vault/resources/vault.d.ts.map +1 -0
  43. package/dist/vault/resources/vault.js +396 -0
  44. package/dist/vault/resources/vault.js.map +1 -0
  45. package/dist/vault/totp.d.ts +73 -0
  46. package/dist/vault/totp.d.ts.map +1 -0
  47. package/dist/vault/totp.js +230 -0
  48. package/dist/vault/totp.js.map +1 -0
  49. package/dist/vault/types.d.ts +239 -0
  50. package/dist/vault/types.d.ts.map +1 -0
  51. package/dist/vault/types.js +229 -0
  52. package/dist/vault/types.js.map +1 -0
  53. package/package.json +5 -1
  54. package/dist/authenticator/resources/accounts.d.ts +0 -70
  55. package/dist/authenticator/resources/accounts.d.ts.map +0 -1
  56. package/dist/authenticator/resources/accounts.js +0 -91
  57. package/dist/authenticator/resources/accounts.js.map +0 -1
  58. package/dist/authenticator/resources/apps.d.ts +0 -38
  59. package/dist/authenticator/resources/apps.d.ts.map +0 -1
  60. package/dist/authenticator/resources/apps.js +0 -52
  61. package/dist/authenticator/resources/apps.js.map +0 -1
  62. package/dist/authenticator/types.d.ts +0 -83
  63. package/dist/authenticator/types.d.ts.map +0 -1
  64. package/dist/authenticator/types.js +0 -43
  65. package/dist/authenticator/types.js.map +0 -1
@@ -0,0 +1,396 @@
1
+ /**
2
+ * inkbox-vault/resources/vault.ts
3
+ *
4
+ * VaultResource — org-level vault operations.
5
+ * UnlockedVault — crypto-enabled wrapper for secret CRUD after unlock.
6
+ */
7
+ import { generateTotp, parseTotpUri } from "../totp.js";
8
+ import { computeAuthHash, decryptPayload, deriveMasterKey, deriveSalt, encryptPayload, unwrapOrgKey, } from "../crypto.js";
9
+ import { VaultSecretType, inferSecretType, parseAccessRule, parsePayload, parseVaultInfo, parseVaultKey, parseVaultSecret, parseVaultSecretDetail, serializePayload, } from "../types.js";
10
+ /**
11
+ * Org-level vault operations.
12
+ *
13
+ * Access via `inkbox.vault`. Most read-only operations work without
14
+ * unlocking. To create, read, or update secret payloads, call
15
+ * {@link unlock} first.
16
+ */
17
+ export class VaultResource {
18
+ /** @internal */
19
+ http;
20
+ /** @internal */
21
+ _unlocked = null;
22
+ /** @internal */
23
+ constructor(http) {
24
+ this.http = http;
25
+ }
26
+ // ------------------------------------------------------------------
27
+ // Vault metadata
28
+ // ------------------------------------------------------------------
29
+ /** Get vault metadata for the caller's organisation. */
30
+ async info() {
31
+ const data = await this.http.get("/info");
32
+ return parseVaultInfo(data);
33
+ }
34
+ // ------------------------------------------------------------------
35
+ // Keys (read-only via API key)
36
+ // ------------------------------------------------------------------
37
+ /**
38
+ * List vault keys (metadata only — no wrapped key material).
39
+ *
40
+ * @param options.keyType - Optional filter: `"primary"` or `"recovery"`.
41
+ */
42
+ async listKeys(options = {}) {
43
+ const params = {};
44
+ if (options.keyType !== undefined)
45
+ params["type"] = options.keyType;
46
+ const data = await this.http.get("/keys", params);
47
+ return data.map(parseVaultKey);
48
+ }
49
+ // ------------------------------------------------------------------
50
+ // Secrets (metadata-only operations)
51
+ // ------------------------------------------------------------------
52
+ /**
53
+ * List vault secrets (metadata only, no encrypted payload).
54
+ *
55
+ * @param options.secretType - Optional filter: `"login"`, `"ssh_key"`,
56
+ * `"api_key"`, or `"other"`.
57
+ */
58
+ async listSecrets(options = {}) {
59
+ const params = {};
60
+ if (options.secretType !== undefined)
61
+ params["secret_type"] = options.secretType;
62
+ const data = await this.http.get("/secrets", params);
63
+ return data.map(parseVaultSecret);
64
+ }
65
+ /**
66
+ * Delete a vault secret.
67
+ *
68
+ * @param secretId - UUID of the secret to delete.
69
+ */
70
+ async deleteSecret(secretId) {
71
+ await this.http.delete(`/secrets/${secretId}`);
72
+ }
73
+ // ------------------------------------------------------------------
74
+ // Access rules
75
+ // ------------------------------------------------------------------
76
+ /**
77
+ * List identity access rules for a vault secret.
78
+ *
79
+ * @param secretId - UUID of the secret.
80
+ */
81
+ async listAccessRules(secretId) {
82
+ const data = await this.http.get(`/secrets/${secretId}/access`);
83
+ return data.map(parseAccessRule);
84
+ }
85
+ /**
86
+ * Grant an identity access to a vault secret.
87
+ *
88
+ * @param secretId - UUID of the secret.
89
+ * @param identityId - UUID of the identity to grant access to.
90
+ */
91
+ async grantAccess(secretId, identityId) {
92
+ const data = await this.http.post(`/secrets/${secretId}/access`, { identity_id: identityId });
93
+ return parseAccessRule(data);
94
+ }
95
+ /**
96
+ * Revoke an identity's access to a vault secret.
97
+ *
98
+ * @param secretId - UUID of the secret.
99
+ * @param identityId - UUID of the identity to revoke access from.
100
+ */
101
+ async revokeAccess(secretId, identityId) {
102
+ await this.http.delete(`/secrets/${secretId}/access/${identityId}`);
103
+ }
104
+ // ------------------------------------------------------------------
105
+ // Unlock
106
+ // ------------------------------------------------------------------
107
+ /**
108
+ * Unlock the vault with a vault key.
109
+ *
110
+ * Derives the encryption key from the provided vault key, fetches
111
+ * and decrypts all vault secrets.
112
+ *
113
+ * @param vaultKey - Vault key or recovery code.
114
+ * @param options.identityId - Optional agent identity UUID. When
115
+ * provided, only secrets that this identity has been granted access
116
+ * to are included in {@link UnlockedVault.secrets}.
117
+ * @returns {@link UnlockedVault} with decrypted secrets and methods for
118
+ * secret CRUD.
119
+ * @throws If the vault key is incorrect or the vault key has been deleted.
120
+ */
121
+ async unlock(vaultKey, options = {}) {
122
+ // Step 1: get org_id for salt derivation
123
+ const vaultInfo = await this.info();
124
+ const salt = deriveSalt(vaultInfo.organizationId);
125
+ // Step 2: derive master key → auth hash
126
+ const masterKey = await deriveMasterKey(vaultKey, salt);
127
+ const authHash = computeAuthHash(masterKey);
128
+ // Step 3: fetch wrapped key + encrypted secrets
129
+ // We always send auth_hash, so the server returns the singular
130
+ // wrapped_org_encryption_key for the matching vault key. The
131
+ // plural wrapped_org_encryption_keys is only returned when
132
+ // auth_hash is omitted (a recovery flow this SDK does not use,
133
+ // since recovery codes are derived the same way as vault keys).
134
+ const data = await this.http.get("/unlock", {
135
+ auth_hash: authHash,
136
+ });
137
+ const wrapped = data.wrapped_org_encryption_key;
138
+ if (!wrapped) {
139
+ throw new Error("No vault key matched. " +
140
+ "Check that the vault key is correct and has not been deleted.");
141
+ }
142
+ // Step 4: unwrap the org encryption key.
143
+ // The wrapped key was encrypted with the vault key UUID as AAD.
144
+ // Fetch all key IDs and try each as AAD until one works.
145
+ const keysData = await this.http.get("/keys");
146
+ const allKeyIds = keysData
147
+ .filter((k) => k.status === "active")
148
+ .map((k) => k.id);
149
+ let orgKey = null;
150
+ for (const keyId of allKeyIds) {
151
+ try {
152
+ orgKey = unwrapOrgKey(masterKey, wrapped, keyId);
153
+ break;
154
+ }
155
+ catch {
156
+ continue;
157
+ }
158
+ }
159
+ if (!orgKey) {
160
+ throw new Error("Failed to unwrap org encryption key. Check that the vault key is correct.");
161
+ }
162
+ // Step 5: decrypt all secrets from the unlock bundle
163
+ const decrypted = [];
164
+ for (const raw of data.encrypted_secrets ?? []) {
165
+ const detail = parseVaultSecretDetail(raw);
166
+ const payloadDict = decryptPayload(orgKey, detail.encryptedPayload, detail.id);
167
+ const payload = parsePayload(detail.secretType, payloadDict);
168
+ decrypted.push({
169
+ id: detail.id,
170
+ name: detail.name,
171
+ description: detail.description,
172
+ secretType: detail.secretType,
173
+ status: detail.status,
174
+ createdAt: detail.createdAt,
175
+ updatedAt: detail.updatedAt,
176
+ payload,
177
+ });
178
+ }
179
+ // Always store the unfiltered vault so identity.getCredentials()
180
+ // has the full set to filter from, even when identityId is provided.
181
+ this._unlocked = new UnlockedVault(this.http, orgKey, [...decrypted]);
182
+ // Step 6 (optional): filter by identity access rules
183
+ if (options.identityId !== undefined) {
184
+ const idStr = options.identityId;
185
+ const filtered = [];
186
+ for (const secret of decrypted) {
187
+ const rules = await this.http.get(`/secrets/${secret.id}/access`);
188
+ if (rules.some((r) => r.identity_id === idStr)) {
189
+ filtered.push(secret);
190
+ }
191
+ }
192
+ return new UnlockedVault(this.http, orgKey, filtered);
193
+ }
194
+ return this._unlocked;
195
+ }
196
+ }
197
+ /**
198
+ * A vault unlocked with a valid vault key.
199
+ *
200
+ * Provides transparent encrypt/decrypt for secret CRUD operations.
201
+ *
202
+ * Obtain via {@link VaultResource.unlock}.
203
+ */
204
+ export class UnlockedVault {
205
+ http;
206
+ orgKey;
207
+ secretsCache;
208
+ constructor(http, orgKey, secretsCache) {
209
+ this.http = http;
210
+ this.orgKey = orgKey;
211
+ this.secretsCache = secretsCache;
212
+ }
213
+ /** All vault secrets decrypted from the unlock response. */
214
+ get secrets() {
215
+ return [...this.secretsCache];
216
+ }
217
+ /**
218
+ * Re-fetch, decrypt, and update a single secret in the cache.
219
+ *
220
+ * Best-effort — if the re-fetch fails the cache is left unchanged.
221
+ */
222
+ async refreshCachedSecret(secretId) {
223
+ try {
224
+ const updated = await this.getSecret(secretId);
225
+ this.secretsCache = this.secretsCache.map((s) => s.id === secretId ? updated : s);
226
+ }
227
+ catch {
228
+ // Cache refresh is best-effort.
229
+ }
230
+ }
231
+ // ------------------------------------------------------------------
232
+ // Encrypted CRUD
233
+ // ------------------------------------------------------------------
234
+ /**
235
+ * Fetch and decrypt a single vault secret.
236
+ *
237
+ * @param secretId - UUID of the secret.
238
+ */
239
+ async getSecret(secretId) {
240
+ const data = await this.http.get(`/secrets/${secretId}`);
241
+ const detail = parseVaultSecretDetail(data);
242
+ const payloadDict = decryptPayload(this.orgKey, detail.encryptedPayload, detail.id);
243
+ const payload = parsePayload(detail.secretType, payloadDict);
244
+ return {
245
+ id: detail.id,
246
+ name: detail.name,
247
+ description: detail.description,
248
+ secretType: detail.secretType,
249
+ status: detail.status,
250
+ createdAt: detail.createdAt,
251
+ updatedAt: detail.updatedAt,
252
+ payload,
253
+ };
254
+ }
255
+ /**
256
+ * Encrypt and store a new secret.
257
+ *
258
+ * The `secretType` is inferred from the payload shape.
259
+ *
260
+ * @param options.name - Display name (max 255 characters).
261
+ * @param options.description - Optional description.
262
+ * @param options.payload - One of {@link LoginPayload}, {@link SSHKeyPayload},
263
+ * {@link APIKeyPayload}, or {@link OtherPayload}.
264
+ */
265
+ async createSecret(options) {
266
+ const secretType = inferSecretType(options.payload);
267
+ const serialized = serializePayload(secretType, options.payload);
268
+ // Generate the UUID client-side so we can use it as AAD for
269
+ // encryption in the same request.
270
+ const secretId = crypto.randomUUID();
271
+ const encrypted = encryptPayload(this.orgKey, serialized, secretId);
272
+ const body = {
273
+ id: secretId,
274
+ name: options.name,
275
+ secret_type: secretType,
276
+ encrypted_payload: encrypted,
277
+ };
278
+ if (options.description !== undefined)
279
+ body["description"] = options.description;
280
+ const data = await this.http.post("/secrets", body);
281
+ const result = parseVaultSecret(data);
282
+ // Append the new secret to the cache so it's immediately visible.
283
+ try {
284
+ const decrypted = await this.getSecret(result.id);
285
+ this.secretsCache.push(decrypted);
286
+ }
287
+ catch {
288
+ // best-effort
289
+ }
290
+ return result;
291
+ }
292
+ /**
293
+ * Update a vault secret's name, description, and/or encrypted payload.
294
+ *
295
+ * Only provided fields are sent to the server.
296
+ *
297
+ * **Note:** The `secretType` is immutable after creation. If a payload
298
+ * is provided it must be the **same type** as the original (e.g. update
299
+ * a `login` secret with a new {@link LoginPayload}). To change the
300
+ * type, delete the secret and create a new one.
301
+ *
302
+ * @param secretId - UUID of the secret to update.
303
+ * @param options.name - New display name.
304
+ * @param options.description - New description.
305
+ * @param options.payload - New payload of the **same type** as the
306
+ * original (will be re-encrypted).
307
+ */
308
+ async updateSecret(secretId, options) {
309
+ const body = {};
310
+ if ("name" in options)
311
+ body["name"] = options.name;
312
+ if ("description" in options)
313
+ body["description"] = options.description;
314
+ if (options.payload !== undefined) {
315
+ // Enforce secret_type immutability — the server treats the
316
+ // payload as opaque ciphertext and cannot check this itself.
317
+ const current = parseVaultSecret(await this.http.get(`/secrets/${secretId}`));
318
+ const newType = inferSecretType(options.payload);
319
+ if (newType !== current.secretType) {
320
+ throw new TypeError(`Cannot update a '${current.secretType}' secret with a '${newType}' payload. Delete and recreate instead.`);
321
+ }
322
+ const serialized = serializePayload(newType, options.payload);
323
+ body["encrypted_payload"] = encryptPayload(this.orgKey, serialized, secretId);
324
+ }
325
+ const data = await this.http.patch(`/secrets/${secretId}`, body);
326
+ // Refresh the cache so subsequent reads are consistent.
327
+ await this.refreshCachedSecret(secretId);
328
+ return parseVaultSecret(data);
329
+ }
330
+ /**
331
+ * Delete a vault secret.
332
+ *
333
+ * @param secretId - UUID of the secret to delete.
334
+ */
335
+ async deleteSecret(secretId) {
336
+ await this.http.delete(`/secrets/${secretId}`);
337
+ this.secretsCache = this.secretsCache.filter((s) => s.id !== secretId);
338
+ }
339
+ // ------------------------------------------------------------------
340
+ // TOTP helpers
341
+ // ------------------------------------------------------------------
342
+ /**
343
+ * Add or replace the TOTP configuration on a login secret.
344
+ *
345
+ * @param secretId - UUID of the login secret.
346
+ * @param totp - A {@link TOTPConfig} object or an `otpauth://totp/...` URI string.
347
+ * @returns Updated {@link VaultSecret} metadata.
348
+ * @throws TypeError if the secret is not a login type.
349
+ * @throws Error if a URI string is invalid or not TOTP.
350
+ */
351
+ async setTotp(secretId, totp) {
352
+ const config = typeof totp === "string" ? parseTotpUri(totp) : totp;
353
+ const secret = await this.getSecret(secretId);
354
+ if (secret.secretType !== VaultSecretType.LOGIN) {
355
+ throw new TypeError(`Cannot set TOTP on a '${secret.secretType}' secret — only login secrets support TOTP`);
356
+ }
357
+ const payload = { ...secret.payload, totp: config };
358
+ return this.updateSecret(secretId, { payload });
359
+ }
360
+ /**
361
+ * Remove TOTP configuration from a login secret.
362
+ *
363
+ * @param secretId - UUID of the login secret.
364
+ * @returns Updated {@link VaultSecret} metadata.
365
+ * @throws TypeError if the secret is not a login type.
366
+ */
367
+ async removeTotp(secretId) {
368
+ const secret = await this.getSecret(secretId);
369
+ if (secret.secretType !== VaultSecretType.LOGIN) {
370
+ throw new TypeError(`Cannot remove TOTP from a '${secret.secretType}' secret — only login secrets support TOTP`);
371
+ }
372
+ const loginPayload = secret.payload;
373
+ const { totp: _, ...rest } = loginPayload;
374
+ return this.updateSecret(secretId, { payload: rest });
375
+ }
376
+ /**
377
+ * Generate the current TOTP code for a login secret.
378
+ *
379
+ * @param secretId - UUID of the login secret.
380
+ * @returns A {@link TOTPCode}.
381
+ * @throws TypeError if the secret is not a login type.
382
+ * @throws Error if the login has no TOTP configured.
383
+ */
384
+ async getTotpCode(secretId) {
385
+ const secret = await this.getSecret(secretId);
386
+ if (secret.secretType !== VaultSecretType.LOGIN) {
387
+ throw new TypeError(`Cannot generate TOTP for a '${secret.secretType}' secret — only login secrets support TOTP`);
388
+ }
389
+ const loginPayload = secret.payload;
390
+ if (!loginPayload.totp) {
391
+ throw new Error(`Login secret '${secretId}' has no TOTP configured`);
392
+ }
393
+ return generateTotp(loginPayload.totp);
394
+ }
395
+ }
396
+ //# sourceMappingURL=vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../../src/vault/resources/vault.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EACL,eAAe,EACf,cAAc,EACd,eAAe,EACf,UAAU,EACV,cAAc,EACd,YAAY,GACb,MAAM,cAAc,CAAC;AAUtB,OAAO,EACL,eAAe,EACf,eAAe,EACf,eAAe,EACf,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAUrB;;;;;;GAMG;AACH,MAAM,OAAO,aAAa;IACxB,gBAAgB;IACP,IAAI,CAAgB;IAE7B,gBAAgB;IAChB,SAAS,GAAyB,IAAI,CAAC;IAEvC,gBAAgB;IAChB,YAAY,IAAmB;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,qEAAqE;IACrE,iBAAiB;IACjB,qEAAqE;IAErE,wDAAwD;IACxD,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAe,OAAO,CAAC,CAAC;QACxD,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,qEAAqE;IACrE,+BAA+B;IAC/B,qEAAqE;IAErE;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,UAAgC,EAAE;QAC/C,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;YAAE,MAAM,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;QACpE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAgB,OAAO,EAAE,MAAM,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED,qEAAqE;IACrE,qCAAqC;IACrC,qEAAqE;IAErE;;;;;OAKG;IACH,KAAK,CAAC,WAAW,CAAC,UAAmC,EAAE;QACrD,MAAM,MAAM,GAA2B,EAAE,CAAC;QAC1C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;YAAE,MAAM,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;QACjF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAmB,UAAU,EAAE,MAAM,CAAC,CAAC;QACvE,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,QAAgB;QACjC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,qEAAqE;IACrE,eAAe;IACf,qEAAqE;IAErE;;;;OAIG;IACH,KAAK,CAAC,eAAe,CAAC,QAAgB;QACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAC9B,YAAY,QAAQ,SAAS,CAC9B,CAAC;QACF,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,UAAkB;QACpD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAC/B,YAAY,QAAQ,SAAS,EAC7B,EAAE,WAAW,EAAE,UAAU,EAAE,CAC5B,CAAC;QACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAAC,QAAgB,EAAE,UAAkB;QACrD,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,QAAQ,WAAW,UAAU,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,qEAAqE;IACrE,SAAS;IACT,qEAAqE;IAErE;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,MAAM,CACV,QAAgB,EAChB,UAAmC,EAAE;QAErC,yCAAyC;QACzC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAElD,wCAAwC;QACxC,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;QAE5C,gDAAgD;QAChD,+DAA+D;QAC/D,8DAA8D;QAC9D,2DAA2D;QAC3D,+DAA+D;QAC/D,gEAAgE;QAChE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAyB,SAAS,EAAE;YAClE,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,IAAI,CAAC,0BAA0B,CAAC;QAChD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,wBAAwB;gBACtB,+DAA+D,CAClE,CAAC;QACJ,CAAC;QAED,yCAAyC;QACzC,gEAAgE;QAChE,yDAAyD;QACzD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAgB,OAAO,CAAC,CAAC;QAC7D,MAAM,SAAS,GAAG,QAAQ;aACvB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;aACpC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAEpB,IAAI,MAAM,GAAsB,IAAI,CAAC;QACrC,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;gBACjD,MAAM;YACR,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,MAAM,SAAS,GAA2B,EAAE,CAAC;QAC7C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,iBAAiB,IAAI,EAAE,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC3C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YAC/E,MAAM,OAAO,GAAG,YAAY,CAC1B,MAAM,CAAC,UAAU,EACjB,WAAsC,CACvC,CAAC;YACF,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,OAAO;aACR,CAAC,CAAC;QACL,CAAC;QAED,iEAAiE;QACjE,qEAAqE;QACrE,IAAI,CAAC,SAAS,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;QAEtE,qDAAqD;QACrD,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;YACjC,MAAM,QAAQ,GAA2B,EAAE,CAAC;YAC5C,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;gBAC/B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAE/B,YAAY,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC;gBAClC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,KAAK,CAAC,EAAE,CAAC;oBAC/C,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACxB,CAAC;YACH,CAAC;YACD,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,aAAa;IACP,IAAI,CAAgB;IACpB,MAAM,CAAa;IAC5B,YAAY,CAAyB;IAE7C,YACE,IAAmB,EACnB,MAAkB,EAClB,YAAoC;QAEpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;IAED,4DAA4D;IAC5D,IAAI,OAAO;QACT,OAAO,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,mBAAmB,CAAC,QAAgB;QAChD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC/C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9C,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAChC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,gCAAgC;QAClC,CAAC;IACH,CAAC;IAED,qEAAqE;IACrE,iBAAiB;IACjB,qEAAqE;IAErE;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,QAAgB;QAC9B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAC9B,YAAY,QAAQ,EAAE,CACvB,CAAC;QACF,MAAM,MAAM,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACpF,MAAM,OAAO,GAAG,YAAY,CAC1B,MAAM,CAAC,UAAU,EACjB,WAAsC,CACvC,CAAC;QACF,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,OAAO;SACR,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,YAAY,CAAC,OAIlB;QACC,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QACjE,4DAA4D;QAC5D,kCAAkC;QAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QACpE,MAAM,IAAI,GAA4B;YACpC,EAAE,EAAE,QAAQ;YACZ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,UAAU;YACvB,iBAAiB,EAAE,SAAS;SAC7B,CAAC;QACF,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS;YAAE,IAAI,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;QACjF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAiB,UAAU,EAAE,IAAI,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACtC,kEAAkE;QAClE,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,YAAY,CAChB,QAAgB,EAChB,OAIC;QAED,MAAM,IAAI,GAA4B,EAAE,CAAC;QACzC,IAAI,MAAM,IAAI,OAAO;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;QACnD,IAAI,aAAa,IAAI,OAAO;YAAE,IAAI,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;QACxE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,2DAA2D;YAC3D,6DAA6D;YAC7D,MAAM,OAAO,GAAG,gBAAgB,CAC9B,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAiB,YAAY,QAAQ,EAAE,CAAC,CAC5D,CAAC;YACF,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACjD,IAAI,OAAO,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;gBACnC,MAAM,IAAI,SAAS,CACjB,oBAAoB,OAAO,CAAC,UAAU,oBAAoB,OAAO,yCAAyC,CAC3G,CAAC;YACJ,CAAC;YACD,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;YAC9D,IAAI,CAAC,mBAAmB,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QAChF,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAChC,YAAY,QAAQ,EAAE,EACtB,IAAI,CACL,CAAC;QACF,wDAAwD;QACxD,MAAM,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,QAAgB;QACjC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IACzE,CAAC;IAED,qEAAqE;IACrE,eAAe;IACf,qEAAqE;IAErE;;;;;;;;OAQG;IACH,KAAK,CAAC,OAAO,CACX,QAAgB,EAChB,IAAyB;QAEzB,MAAM,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACpE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,UAAU,KAAK,eAAe,CAAC,KAAK,EAAE,CAAC;YAChD,MAAM,IAAI,SAAS,CACjB,yBAAyB,MAAM,CAAC,UAAU,4CAA4C,CACvF,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,QAAgB;QAC/B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,UAAU,KAAK,eAAe,CAAC,KAAK,EAAE,CAAC;YAChD,MAAM,IAAI,SAAS,CACjB,8BAA8B,MAAM,CAAC,UAAU,4CAA4C,CAC5F,CAAC;QACJ,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,CAAC,OAA6C,CAAC;QAC1E,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,YAAY,CAAC;QAC1C,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,WAAW,CAAC,QAAgB;QAChC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,MAAM,CAAC,UAAU,KAAK,eAAe,CAAC,KAAK,EAAE,CAAC;YAChD,MAAM,IAAI,SAAS,CACjB,+BAA+B,MAAM,CAAC,UAAU,4CAA4C,CAC7F,CAAC;QACJ,CAAC;QACD,MAAM,YAAY,GAAG,MAAM,CAAC,OAA6C,CAAC;QAC1E,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,iBAAiB,QAAQ,0BAA0B,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;CACF"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * inkbox-vault/totp.ts
3
+ *
4
+ * Client-side TOTP (RFC 6238) implementation.
5
+ */
6
+ /**
7
+ * Hash algorithm for TOTP code generation.
8
+ *
9
+ * Values are lowercase to match `otpauth://` URI convention.
10
+ */
11
+ export declare const TOTPAlgorithm: {
12
+ readonly SHA1: "sha1";
13
+ readonly SHA256: "sha256";
14
+ readonly SHA512: "sha512";
15
+ };
16
+ export type TOTPAlgorithm = (typeof TOTPAlgorithm)[keyof typeof TOTPAlgorithm];
17
+ /** A generated TOTP code with timing metadata. */
18
+ export interface TOTPCode {
19
+ /** The OTP code string (e.g. `"482901"`). */
20
+ code: string;
21
+ /** Unix timestamp when this code became valid. */
22
+ periodStart: number;
23
+ /** Unix timestamp when this code expires. */
24
+ periodEnd: number;
25
+ /** Seconds left until expiry. */
26
+ secondsRemaining: number;
27
+ }
28
+ /**
29
+ * TOTP configuration stored inside a {@link LoginPayload}.
30
+ */
31
+ export interface TOTPConfig {
32
+ /** Base32-encoded shared secret. */
33
+ secret: string;
34
+ /** Hash algorithm (default `"sha1"`). */
35
+ algorithm?: TOTPAlgorithm;
36
+ /** Number of digits in the OTP code (6 or 8, default 6). */
37
+ digits?: number;
38
+ /** Time step in seconds (30 or 60, default 30). */
39
+ period?: number;
40
+ /** Optional issuer name (e.g. `"GitHub"`). */
41
+ issuer?: string;
42
+ /** Optional account identifier (e.g. `"user@example.com"`). */
43
+ accountName?: string;
44
+ }
45
+ /**
46
+ * Validate a TOTPConfig's fields.
47
+ *
48
+ * @throws Error if any field is invalid.
49
+ */
50
+ export declare function validateTotpConfig(config: TOTPConfig): void;
51
+ /**
52
+ * Generate the current TOTP code per RFC 6238.
53
+ *
54
+ * @param config - TOTP configuration with the shared secret and parameters.
55
+ * @returns A {@link TOTPCode} with the code and timing metadata.
56
+ */
57
+ export declare function generateTotp(config: TOTPConfig): TOTPCode;
58
+ /**
59
+ * Parse an `otpauth://totp/...` URI into a {@link TOTPConfig}.
60
+ *
61
+ * Supports the Google Authenticator Key URI format.
62
+ * Rejects HOTP URIs with an error.
63
+ *
64
+ * @param uri - The full `otpauth://` URI string.
65
+ * @returns A validated {@link TOTPConfig}.
66
+ * @throws Error on invalid scheme, HOTP type, missing secret, or invalid parameters.
67
+ */
68
+ export declare function parseTotpUri(uri: string): TOTPConfig;
69
+ /** Serialize a TOTPConfig to the snake_case wire format. @internal */
70
+ export declare function serializeTotpConfig(config: TOTPConfig): Record<string, unknown>;
71
+ /** Parse a TOTPConfig from the snake_case wire format. @internal */
72
+ export declare function parseTotpConfig(raw: Record<string, unknown>): TOTPConfig;
73
+ //# sourceMappingURL=totp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"totp.d.ts","sourceRoot":"","sources":["../../src/vault/totp.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAI/E,kDAAkD;AAClD,MAAM,WAAW,QAAQ;IACvB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAQD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAiB3D;AA+DD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,CAgBzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAsFpD;AAID,sEAAsE;AACtE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,UAAU,CAWZ"}