@cubist-labs/cubesigner-sdk 0.2.2 → 0.2.17

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 (55) hide show
  1. package/dist/package.json +68 -0
  2. package/dist/src/api.d.ts +493 -0
  3. package/dist/src/api.js +1166 -0
  4. package/dist/src/client.d.ts +432 -335
  5. package/dist/src/client.js +195 -863
  6. package/dist/src/ethers/index.d.ts +33 -6
  7. package/dist/src/ethers/index.js +59 -12
  8. package/dist/src/index.d.ts +31 -26
  9. package/dist/src/index.js +51 -32
  10. package/dist/src/key.d.ts +28 -21
  11. package/dist/src/key.js +17 -10
  12. package/dist/src/mfa.d.ts +7 -7
  13. package/dist/src/mfa.js +20 -32
  14. package/dist/src/org.d.ts +37 -279
  15. package/dist/src/org.js +48 -194
  16. package/dist/src/paginator.js +1 -1
  17. package/dist/src/response.d.ts +101 -0
  18. package/dist/src/response.js +164 -0
  19. package/dist/src/role.d.ts +11 -9
  20. package/dist/src/role.js +1 -1
  21. package/dist/src/schema.d.ts +586 -10
  22. package/dist/src/schema.js +1 -1
  23. package/dist/src/schema_types.d.ts +6 -0
  24. package/dist/src/schema_types.js +1 -1
  25. package/dist/src/session/cognito_manager.d.ts +15 -3
  26. package/dist/src/session/cognito_manager.js +23 -5
  27. package/dist/src/session/session_manager.d.ts +1 -1
  28. package/dist/src/session/session_manager.js +3 -11
  29. package/dist/src/session/session_storage.js +1 -1
  30. package/dist/src/session/signer_session_manager.d.ts +3 -7
  31. package/dist/src/session/signer_session_manager.js +2 -8
  32. package/dist/src/signer_session.d.ts +8 -266
  33. package/dist/src/signer_session.js +15 -221
  34. package/dist/src/user_export.d.ts +52 -0
  35. package/dist/src/user_export.js +129 -0
  36. package/dist/src/util.d.ts +15 -0
  37. package/dist/src/util.js +33 -11
  38. package/package.json +12 -10
  39. package/src/api.ts +1395 -0
  40. package/src/client.ts +216 -1025
  41. package/src/ethers/index.ts +70 -12
  42. package/src/index.ts +59 -43
  43. package/src/key.ts +19 -12
  44. package/src/mfa.ts +16 -28
  45. package/src/org.ts +49 -204
  46. package/src/response.ts +196 -0
  47. package/src/role.ts +5 -3
  48. package/src/schema.ts +586 -10
  49. package/src/schema_types.ts +7 -0
  50. package/src/session/cognito_manager.ts +33 -6
  51. package/src/session/session_manager.ts +2 -8
  52. package/src/session/signer_session_manager.ts +3 -10
  53. package/src/signer_session.ts +13 -261
  54. package/src/user_export.ts +116 -0
  55. package/src/util.ts +29 -10
package/src/client.ts CHANGED
@@ -1,88 +1,39 @@
1
- import createClient from "openapi-fetch";
2
- import { paths } from "./schema";
3
- import {
4
- SignerSessionData,
5
- SignerSessionLifetime,
6
- SignerSessionManager,
7
- } from "./session/signer_session_manager";
8
- import {
9
- CreateOidcUserOptions,
10
- IdentityProof,
11
- KeyInRoleInfo,
12
- KeyInfoApi,
13
- ListKeysResponse,
14
- ListRoleKeysResponse,
15
- ListRoleUsersResponse,
16
- ListRolesResponse,
17
- OidcIdentity,
18
- SessionsResponse,
19
- PublicKeyCredential,
20
- RoleInfo,
21
- UpdateKeyRequest,
22
- UpdateOrgRequest,
23
- UpdateOrgResponse,
24
- UpdateRoleRequest,
25
- UserIdInfo,
26
- UserInRoleInfo,
27
- UserInfo,
28
- SessionInfo,
29
- OrgInfo,
30
- RatchetConfig,
31
- OidcAuthResponse,
32
- EvmSignRequest,
33
- EvmSignResponse,
34
- Eth2SignRequest,
35
- Eth2SignResponse,
36
- Eth2StakeRequest,
37
- Eth2StakeResponse,
38
- Eth2UnstakeRequest,
39
- Eth2UnstakeResponse,
40
- BlobSignRequest,
41
- BlobSignResponse,
42
- BtcSignResponse,
43
- BtcSignRequest,
44
- SolanaSignRequest,
45
- SolanaSignResponse,
46
- AvaSignResponse,
47
- AvaSignRequest,
48
- AvaTx,
49
- MfaRequestInfo,
50
- MemberRole,
51
- } from "./schema_types";
52
- import { assertOk } from "./util";
53
- import { AddFidoChallenge, MfaFidoChallenge, MfaReceipt, TotpChallenge } from "./mfa";
54
- import { CubeSignerResponse, mapResponse } from "./signer_session";
55
- import { Key, KeyType } from "./key";
56
- import { Page, PageOpts, PageQueryArgs, Paginator } from "./paginator";
57
- import { KeyPolicy } from "./role";
58
- import { EnvInterface } from "./env";
59
-
60
- /** @internal */
61
- export type Client = ReturnType<typeof createClient<paths>>;
62
-
63
- export { paths };
1
+ import { SignerSessionManager, SignerSessionStorage } from "./session/signer_session_manager";
2
+ import { CognitoSessionManager } from "./session/cognito_manager";
3
+ import { CubeSignerApi, OidcClient } from "./api";
4
+ import { KeyType, Key } from "./key";
5
+ import { OrgInfo, RatchetConfig } from "./schema_types";
6
+ import { MfaReceipt } from "./mfa";
7
+ import { PageOpts } from "./paginator";
8
+ import { Role } from "./role";
9
+
10
+ // used in doc comments
11
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
12
+ import { AddFidoChallenge, MfaFidoChallenge, TotpChallenge } from "./mfa";
13
+ import { MemorySessionStorage } from "./session/session_storage";
14
+
15
+ /** Options for logging in with OIDC token */
16
+ export interface OidcAuthOptions {
17
+ /** Optional token lifetimes */
18
+ lifetimes?: RatchetConfig;
19
+ /** Optional MFA receipt */
20
+ mfaReceipt?: MfaReceipt;
21
+ /** Optional storage to use for the returned session (defaults to {@link MemorySessionStorage}) */
22
+ storage?: SignerSessionStorage;
23
+ }
64
24
 
65
25
  /**
66
26
  * Client to use to send requests to CubeSigner services
67
27
  * when authenticating using a CubeSigner session token.
68
28
  */
69
- export class CubeSignerClient {
70
- readonly #orgId: string;
71
- readonly #sessionMgr: SignerSessionManager;
72
-
73
- /** Underlying session manager */
74
- get sessionMgr(): SignerSessionManager {
75
- return this.#sessionMgr;
76
- }
77
-
29
+ export class CubeSignerClient extends CubeSignerApi {
78
30
  /**
79
31
  * Constructor.
80
32
  * @param {SignerSessionManager} sessionMgr The session manager to use
81
33
  * @param {string?} orgId Optional organization ID; if omitted, uses the org ID from the session manager.
82
34
  */
83
35
  constructor(sessionMgr: SignerSessionManager, orgId?: string) {
84
- this.#sessionMgr = sessionMgr;
85
- this.#orgId = orgId ?? sessionMgr.orgId;
36
+ super(sessionMgr, orgId);
86
37
  }
87
38
 
88
39
  /**
@@ -92,1131 +43,371 @@ export class CubeSignerClient {
92
43
  * @return {CubeSignerClient} A new instance of this class using the same session manager but targeting different organization.
93
44
  */
94
45
  withOrg(orgId?: string): CubeSignerClient {
95
- return orgId ? new CubeSignerClient(this.#sessionMgr, orgId) : this;
96
- }
97
-
98
- /** Org id */
99
- get orgId() {
100
- return this.#orgId;
101
- }
102
-
103
- // #region USERS: userGet, userResetTotp(Init|Complete), userVerifyTotp, userRegisterFido(Init|Complete)
104
-
105
- /**
106
- * Obtain information about the current user.
107
- *
108
- * @return {Promise<UserInfo>} Retrieves information about the current user.
109
- */
110
- async userGet(): Promise<UserInfo> {
111
- const client = await this.client();
112
- const resp =
113
- `${this.orgId}` !== "undefined"
114
- ? await client.get("/v0/org/{org_id}/user/me", {
115
- params: { path: { org_id: this.orgId } },
116
- parseAs: "json",
117
- })
118
- : await client.get("/v0/about_me", { parseAs: "json" });
119
- return assertOk(resp);
120
- }
121
-
122
- /**
123
- * Creates a request to change user's TOTP. This request returns a new TOTP challenge
124
- * that must be answered by calling `userResetTotpComplete`
125
- *
126
- * @param {MfaReceipt} mfaReceipt MFA receipt to include in HTTP headers
127
- */
128
- async userResetTotpInit(mfaReceipt?: MfaReceipt): Promise<CubeSignerResponse<TotpChallenge>> {
129
- const resetTotpFn = async (headers?: HeadersInit) => {
130
- const client = await this.client();
131
- const resp = await client.post("/v0/org/{org_id}/user/me/totp", {
132
- headers,
133
- params: { path: { org_id: this.orgId } },
134
- body: null,
135
- parseAs: "json",
136
- });
137
- const data = assertOk(resp);
138
- return mapResponse(data, (totpInfo) => new TotpChallenge(this, totpInfo));
139
- };
140
- return await CubeSignerResponse.create(resetTotpFn, mfaReceipt);
141
- }
142
-
143
- /**
144
- * Answer the TOTP challenge issued by `userResetTotpInit`. If successful, user's
145
- * TOTP configuration will be updated to that of the TOTP challenge.
146
- *
147
- * @param {string} totpId - The ID of the TOTP challenge
148
- * @param {string} code - The TOTP code that should verify against the TOTP configuration from the challenge.
149
- */
150
- async userResetTotpComplete(totpId: string, code: string): Promise<void> {
151
- const client = await this.client();
152
- const resp = await client.patch("/v0/org/{org_id}/user/me/totp", {
153
- parseAs: "json",
154
- params: { path: { org_id: this.orgId } },
155
- body: { totp_id: totpId, code },
156
- });
157
- assertOk(resp);
158
- }
159
-
160
- /**
161
- * Verifies a given TOTP code against the current user's TOTP configuration.
162
- * Throws an error if the verification fails.
163
- *
164
- * @param {string} code Current TOTP code
165
- */
166
- async userVerifyTotp(code: string) {
167
- const client = await this.client();
168
- const resp = await client.post("/v0/org/{org_id}/user/me/totp/verify", {
169
- params: { path: { org_id: this.orgId } },
170
- body: { code },
171
- parseAs: "json",
172
- });
173
- assertOk(resp);
174
- }
175
-
176
- /**
177
- * Initiate adding a new FIDO device. MFA may be required. This returns a challenge that must
178
- * be answered with `userRegisterFidoComplete` (after MFA approvals).
179
- *
180
- * @param {string} name The name of the new device.
181
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt to include in HTTP headers
182
- * @return {Promise<CubeSignerResponse<AddFidoChallenge>>} A challenge that must be answered in order to complete FIDO registration.
183
- */
184
- async userRegisterFidoInit(
185
- name: string,
186
- mfaReceipt?: MfaReceipt,
187
- ): Promise<CubeSignerResponse<AddFidoChallenge>> {
188
- const addFidoFn = async (headers?: HeadersInit) => {
189
- const client = await this.client();
190
- const resp = await client.post("/v0/org/{org_id}/user/me/fido", {
191
- headers,
192
- params: { path: { org_id: this.orgId } },
193
- body: { name },
194
- parseAs: "json",
195
- });
196
- const data = assertOk(resp);
197
- return mapResponse(data, (c) => new AddFidoChallenge(this, c));
198
- };
199
- return await CubeSignerResponse.create(addFidoFn, mfaReceipt);
200
- }
201
-
202
- /**
203
- * Complete a previously initiated request to add a new FIDO device.
204
- * @param {string} challengeId The ID of the challenge returned by the remote end.
205
- * @param {PublicKeyCredential} credential The answer to the challenge.
206
- */
207
- async userRegisterFidoComplete(challengeId: string, credential: PublicKeyCredential) {
208
- const client = await this.client();
209
- const resp = await client.patch("/v0/org/{org_id}/user/me/fido", {
210
- params: { path: { org_id: this.orgId } },
211
- body: {
212
- challenge_id: challengeId,
213
- credential,
214
- },
215
- parseAs: "json",
216
- });
217
- assertOk(resp);
218
- }
219
-
220
- // #endregion
221
-
222
- // #region ORGS: orgGet, orgUpdate
223
-
224
- /**
225
- * Obtain information about the current organization.
226
- * @return {Org} Information about the organization.
227
- */
228
- async orgGet(): Promise<OrgInfo> {
229
- const client = await this.client();
230
- const resp = await client.get("/v0/org/{org_id}", {
231
- params: { path: { org_id: this.orgId } },
232
- parseAs: "json",
233
- });
234
- return assertOk(resp);
235
- }
236
-
237
- /**
238
- * Update the org.
239
- * @param {UpdateOrgRequest} request The JSON request to send to the API server.
240
- * @return {UpdateOrgResponse} Updated org information.
241
- */
242
- async orgUpdate(request: UpdateOrgRequest): Promise<UpdateOrgResponse> {
243
- const client = await this.client();
244
- const resp = await client.patch("/v0/org/{org_id}", {
245
- params: { path: { org_id: this.orgId } },
246
- body: request,
247
- parseAs: "json",
248
- });
249
- return assertOk(resp);
250
- }
251
-
252
- // #endregion
253
-
254
- // #region ORG USERS: orgUserInvite, orgUsersList, orgUserCreateOidc, orgUserDeleteOidc
255
-
256
- /**
257
- * Create a new (first-party) user in the organization and send an email invitation to that user.
258
- *
259
- * @param {string} email Email of the user
260
- * @param {string} name The full name of the user
261
- * @param {MemberRole} role Optional role. Defaults to "alien.
262
- */
263
- async orgUserInvite(email: string, name: string, role?: MemberRole): Promise<void> {
264
- const client = await this.client();
265
- const resp = await client.post("/v0/org/{org_id}/invite", {
266
- params: { path: { org_id: this.orgId } },
267
- body: {
268
- email,
269
- name,
270
- role,
271
- skip_email: false,
272
- },
273
- parseAs: "json",
274
- });
275
- assertOk(resp);
276
- }
277
-
278
- /**
279
- * List users.
280
- * @return {User[]} Org users.
281
- */
282
- async orgUsersList(): Promise<UserIdInfo[]> {
283
- const client = await this.client();
284
- const resp = await client.get("/v0/org/{org_id}/users", {
285
- params: { path: { org_id: this.orgId } },
286
- parseAs: "json",
287
- });
288
- const data = assertOk(resp);
289
- return data.users;
46
+ return orgId ? new CubeSignerClient(this.sessionMgr, orgId) : this;
290
47
  }
291
48
 
292
49
  /**
293
- * Create a new OIDC user. This can be a first-party "Member" or third-party "Alien".
294
- * @param {OidcIdentity} identity The identity of the OIDC user
295
- * @param {string} email Email of the OIDC user
296
- * @param {CreateOidcUserOptions} opts Additional options for new OIDC users
297
- * @return {string} User id of the new user
298
- */
299
- async orgUserCreateOidc(
300
- identity: OidcIdentity,
301
- email: string,
302
- opts: CreateOidcUserOptions = {},
303
- ): Promise<string> {
304
- const client = await this.client();
305
- const resp = await client.post("/v0/org/{org_id}/users", {
306
- params: { path: { org_id: this.orgId } },
307
- body: {
308
- identity,
309
- role: opts.memberRole ?? "Alien",
310
- email: email,
311
- mfa_policy: opts.mfaPolicy ?? null,
312
- },
313
- parseAs: "json",
314
- });
315
- return assertOk(resp).user_id;
316
- }
317
-
318
- /**
319
- * Delete an existing OIDC user.
320
- * @param {OidcIdentity} identity The identity of the OIDC user
321
- */
322
- async orgUserDeleteOidc(identity: OidcIdentity) {
323
- const client = await this.client();
324
- const resp = await client.del("/v0/org/{org_id}/users/oidc", {
325
- params: { path: { org_id: this.orgId } },
326
- body: identity,
327
- parseAs: "json",
328
- });
329
- return assertOk(resp);
330
- }
331
-
332
- // #endregion
333
-
334
- // #region KEYS: keyGet, keyUpdate, keyDelete, keysCreate, keysDerive, keysList
335
-
336
- /**
337
- * Get a key by its id.
50
+ * Loads an existing management session and creates a {@link CubeSignerClient} instance.
338
51
  *
339
- * @param {string} keyId The id of the key to get.
340
- * @return {KeyInfoApi} The key information.
341
- */
342
- async keyGet(keyId: string): Promise<KeyInfoApi> {
343
- const client = await this.client();
344
- const resp = await client.get("/v0/org/{org_id}/keys/{key_id}", {
345
- params: { path: { org_id: this.orgId, key_id: keyId } },
346
- parseAs: "json",
347
- });
348
- return assertOk(resp);
349
- }
350
-
351
- /**
352
- * Update key.
353
- * @param {string} keyId The ID of the key to update.
354
- * @param {UpdateKeyRequest} request The JSON request to send to the API server.
355
- * @return {KeyInfoApi} The JSON response from the API server.
52
+ * @return {Promise<CubeSignerClient>} New CubeSigner instance
356
53
  */
357
- async keyUpdate(keyId: string, request: UpdateKeyRequest): Promise<KeyInfoApi> {
358
- const client = await this.client();
359
- const resp = await client.patch("/v0/org/{org_id}/keys/{key_id}", {
360
- params: { path: { org_id: this.orgId, key_id: keyId } },
361
- body: request,
362
- parseAs: "json",
363
- });
364
- return assertOk(resp);
54
+ static async loadManagementSession(): Promise<CubeSignerClient> {
55
+ const mgr = await CognitoSessionManager.loadManagementSession();
56
+ // HACK: Ignore that sessionMgr may be a CognitoSessionManager and pretend that it
57
+ // is a SignerSessionManager; that's fine because the CubeSignerClient will
58
+ // almost always just call `await token()` on it, which works in both cases.
59
+ // NOTE: This will go away once `cs login` starts producing signer sessions.
60
+ return new CubeSignerClient(mgr as unknown as SignerSessionManager);
365
61
  }
366
62
 
367
63
  /**
368
- * Deletes a key.
369
- *
370
- * @param {string} keyId - Key id
64
+ * Create a new signing key.
65
+ * @param {KeyType} type The type of key to create.
66
+ * @param {string?} ownerId The owner of the key. Defaults to the session's user.
67
+ * @return {Key[]} The new keys.
371
68
  */
372
- async keyDelete(keyId: string) {
373
- const client = await this.client();
374
- const resp = await client.del("/v0/org/{org_id}/keys/{key_id}", {
375
- params: { path: { org_id: this.orgId, key_id: keyId } },
376
- parseAs: "json",
377
- });
378
- assertOk(resp);
69
+ async createKey(type: KeyType, ownerId?: string): Promise<Key> {
70
+ return (await this.createKeys(type, 1, ownerId))[0];
379
71
  }
380
72
 
381
73
  /**
382
74
  * Create new signing keys.
383
- *
384
- * @param {KeyType} keyType The type of key to create.
75
+ * @param {KeyType} type The type of key to create.
385
76
  * @param {number} count The number of keys to create.
386
77
  * @param {string?} ownerId The owner of the keys. Defaults to the session's user.
387
- * @return {KeyInfoApi[]} The new keys.
78
+ * @return {Key[]} The new keys.
388
79
  */
389
- async keysCreate(keyType: KeyType, count: number, ownerId?: string): Promise<KeyInfoApi[]> {
390
- const chain_id = 0; // not used anymore
391
- const client = await this.client();
392
- const resp = await client.post("/v0/org/{org_id}/keys", {
393
- params: { path: { org_id: this.orgId } },
394
- body: {
395
- count,
396
- chain_id,
397
- key_type: keyType,
398
- owner: ownerId || null,
399
- },
400
- parseAs: "json",
401
- });
402
- const data = assertOk(resp);
403
- return data.keys;
80
+ async createKeys(type: KeyType, count: number, ownerId?: string): Promise<Key[]> {
81
+ const keys = await this.keysCreate(type, count, ownerId);
82
+ return keys.map((k) => new Key(this, k));
404
83
  }
405
84
 
406
85
  /**
407
- * Derive a set of keys of a specified type using a supplied derivation path and an existing long-lived mnemonic.
408
- *
86
+ * Derive a key of the given type using the given derivation path and mnemonic.
409
87
  * The owner of the derived key will be the owner of the mnemonic.
410
88
  *
411
- * @param {KeyType} keyType The type of key to create.
412
- * @param {string[]} derivationPaths Derivation paths from which to derive new keys.
89
+ * @param {KeyType} type Type of key to derive from the mnemonic.
90
+ * @param {string} derivationPath Mnemonic derivation path used to generate new key.
413
91
  * @param {string} mnemonicId materialId of mnemonic key used to derive the new key.
414
92
  *
415
- * @return {KeyInfoApi[]} The newly derived keys.
93
+ * @return {Key} newly derived key or undefined if it already exists.
416
94
  */
417
- async keysDerive(
418
- keyType: KeyType,
419
- derivationPaths: string[],
95
+ async deriveKey(
96
+ type: KeyType,
97
+ derivationPath: string,
420
98
  mnemonicId: string,
421
- ): Promise<KeyInfoApi[]> {
422
- const client = await this.client();
423
- const resp = await client.put("/v0/org/{org_id}/derive_key", {
424
- params: { path: { org_id: this.orgId } },
425
- body: {
426
- derivation_path: derivationPaths,
427
- mnemonic_id: mnemonicId,
428
- key_type: keyType,
429
- },
430
- parseAs: "json",
431
- });
432
- return assertOk(resp).keys;
99
+ ): Promise<Key | undefined> {
100
+ return (await this.deriveKeys(type, [derivationPath], mnemonicId))[0];
433
101
  }
434
102
 
435
103
  /**
436
- * List all keys in the org.
437
- * @param {KeyType?} type Optional key type to filter list for.
438
- * @param {PageOpts?} page Pagination options. Defaults to fetching the entire result set.
439
- * @return {Paginator<ListKeysResponse, KeyInfoApi>} Paginator for iterating over keys.
440
- */
441
- keysList(type?: KeyType, page?: PageOpts): Paginator<ListKeysResponse, KeyInfoApi> {
442
- const listFn = async (query: PageQueryArgs) => {
443
- const client = await this.client();
444
- const resp = await client.get("/v0/org/{org_id}/keys", {
445
- params: {
446
- path: { org_id: this.orgId },
447
- query: {
448
- key_type: type,
449
- ...query,
450
- },
451
- },
452
- parseAs: "json",
453
- });
454
- return assertOk(resp);
455
- };
456
- return new Paginator(
457
- page ?? Page.default(),
458
- listFn,
459
- (r) => r.keys,
460
- (r) => r.last_evaluated_key,
461
- );
462
- }
463
- // #endregion
464
-
465
- // #region ROLES: roleCreate, roleRead, roleUpdate, roleDelete, rolesList
466
-
467
- /**
468
- * Create a new role.
104
+ * Derive a set of keys of the given type using the given derivation paths and mnemonic.
469
105
  *
470
- * @param {string?} name The optional name of the role.
471
- * @return {string} The ID of the new role.
472
- */
473
- async roleCreate(name?: string): Promise<string> {
474
- const client = await this.client();
475
- const resp = await client.post("/v0/org/{org_id}/roles", {
476
- params: { path: { org_id: this.orgId } },
477
- body: name ? { name } : undefined,
478
- parseAs: "json",
479
- });
480
- return assertOk(resp).role_id;
481
- }
482
-
483
- /**
484
- * Get a role by its id (or name).
485
- * @param {string} roleId The id of the role to get.
486
- * @return {RoleInfo} The role.
487
- */
488
- async roleGet(roleId: string): Promise<RoleInfo> {
489
- const client = await this.client();
490
- const resp = await client.get("/v0/org/{org_id}/roles/{role_id}", {
491
- params: { path: { org_id: this.orgId, role_id: roleId } },
492
- parseAs: "json",
493
- });
494
- return assertOk(resp);
495
- }
496
-
497
- /**
498
- * Update a role.
106
+ * The owner of the derived keys will be the owner of the mnemonic.
107
+ *
108
+ * @param {KeyType} type Type of key to derive from the mnemonic.
109
+ * @param {string[]} derivationPaths Mnemonic derivation paths used to generate new key.
110
+ * @param {string} mnemonicId materialId of mnemonic key used to derive the new key.
499
111
  *
500
- * @param {string} roleId The ID of the role to update.
501
- * @param {UpdateRoleRequest} request The update request.
502
- * @return {Promise<RoleInfo>} The updated role information.
112
+ * @return {Key[]} newly derived keys.
503
113
  */
504
- async roleUpdate(roleId: string, request: UpdateRoleRequest): Promise<RoleInfo> {
505
- const client = await this.client();
506
- const resp = await client.patch("/v0/org/{org_id}/roles/{role_id}", {
507
- params: { path: { org_id: this.orgId, role_id: roleId } },
508
- body: request,
509
- parseAs: "json",
510
- });
511
- return assertOk(resp);
114
+ async deriveKeys(type: KeyType, derivationPaths: string[], mnemonicId: string): Promise<Key[]> {
115
+ const keys = await this.keysDerive(type, derivationPaths, mnemonicId);
116
+ return keys.map((k) => new Key(this, k));
512
117
  }
513
118
 
514
119
  /**
515
- * Delete a role by its ID.
516
- *
517
- * @param {string} roleId The ID of the role to delete.
120
+ * Create a new {@link OidcClient} that will use a given OIDC token for auth.
121
+ * @param {string} oidcToken The authentication token to use
122
+ * @return {OidcClient} New OIDC client.
518
123
  */
519
- async roleDelete(roleId: string): Promise<void> {
520
- const client = await this.client();
521
- const resp = await client.del("/v0/org/{org_id}/roles/{role_id}", {
522
- params: { path: { org_id: this.orgId, role_id: roleId } },
523
- parseAs: "json",
524
- });
525
- assertOk(resp);
124
+ newOidcClient(oidcToken: string): OidcClient {
125
+ return new OidcClient(this.sessionMgr.env, this.orgId, oidcToken);
526
126
  }
527
127
 
528
128
  /**
529
- * List all roles in the org.
129
+ * Authenticate an OIDC user and create a new session manager for them.
530
130
  *
531
- * @param {PageOpts} page Pagination options. Defaults to fetching the entire result set.
532
- * @return {RoleInfo} Paginator for iterating over roles.
131
+ * @param {string} oidcToken The OIDC token
132
+ * @param {List<string>} scopes The scopes of the resulting session
133
+ * @param {OidcAuthOptions} options Options.
134
+ * @return {Promise<SignerSessionManager>} The signer session manager
533
135
  */
534
- rolesList(page?: PageOpts): Paginator<ListRolesResponse, RoleInfo> {
535
- const listFn = async (query: PageQueryArgs) => {
536
- const client = await this.client();
537
- const resp = await client.get("/v0/org/{org_id}/roles", {
538
- params: {
539
- path: { org_id: this.orgId },
540
- query,
541
- },
542
- parseAs: "json",
543
- });
544
- return assertOk(resp);
545
- };
546
- return new Paginator(
547
- page ?? Page.default(),
548
- listFn,
549
- (r) => r.roles,
550
- (r) => r.last_evaluated_key,
551
- );
136
+ async oidcAuth(
137
+ oidcToken: string,
138
+ scopes: Array<string>,
139
+ options?: OidcAuthOptions,
140
+ ): Promise<SignerSessionManager> {
141
+ const oidcClient = this.newOidcClient(oidcToken);
142
+ const resp = await oidcClient.sessionCreate(scopes, options?.lifetimes, options?.mfaReceipt);
143
+ return await SignerSessionManager.loadFromStorage(new MemorySessionStorage(resp.data()));
552
144
  }
553
145
 
554
- // #endregion
555
-
556
- // #region ROLE KEYS: roleKeysAdd, roleKeysDelete, roleKeysList
557
-
558
146
  /**
559
- * Add existing keys to an existing role.
147
+ * Create a new user in the organization and sends an invitation to that user.
560
148
  *
561
- * @param {string} roleId The ID of the role
562
- * @param {string[]} keyIds The IDs of the keys to add to the role.
563
- * @param {KeyPolicy?} policy The optional policy to apply to each key.
149
+ * Same as {@link orgUserInvite}.
564
150
  */
565
- async roleKeysAdd(roleId: string, keyIds: string[], policy?: KeyPolicy) {
566
- const client = await this.client();
567
- const resp = await client.put("/v0/org/{org_id}/roles/{role_id}/add_keys", {
568
- params: { path: { org_id: this.#orgId, role_id: roleId } },
569
- body: {
570
- key_ids: keyIds,
571
- policy: (policy ?? null) as Record<string, never>[] | null,
572
- },
573
- parseAs: "json",
574
- });
575
- assertOk(resp, "Failed to add keys to role");
151
+ get createUser() {
152
+ return this.orgUserInvite.bind(this);
576
153
  }
577
154
 
578
155
  /**
579
- * Remove an existing key from an existing role.
156
+ * Create a new OIDC user.
580
157
  *
581
- * @param {string} roleId The ID of the role
582
- * @param {string} keyId The ID of the key to remove from the role
158
+ * Same as {@link orgUserCreateOidc}.
583
159
  */
584
- async roleKeysRemove(roleId: string, keyId: string) {
585
- const client = await this.client();
586
- const resp = await client.del("/v0/org/{org_id}/roles/{role_id}/keys/{key_id}", {
587
- params: { path: { org_id: this.#orgId, role_id: roleId, key_id: keyId } },
588
- parseAs: "json",
589
- });
590
- assertOk(resp, "Failed to remove key from a role");
160
+ get createOidcUser() {
161
+ return this.orgUserCreateOidc.bind(this);
591
162
  }
592
163
 
593
164
  /**
594
- * List all keys in a role.
165
+ * Delete an existing OIDC user.
595
166
  *
596
- * @param {string} roleId The ID of the role whose keys to retrieve.
597
- * @param {PageOpts} page Pagination options. Defaults to fetching the entire result set.
598
- * @return {Paginator<ListRoleKeysResponse, KeyInRoleInfo>} Paginator for iterating over the keys in the role.
167
+ * Same as {@link orgUserDeleteOidc}.
599
168
  */
600
- roleKeysList(roleId: string, page?: PageOpts): Paginator<ListRoleKeysResponse, KeyInRoleInfo> {
601
- const listFn = async (query: PageQueryArgs) => {
602
- const client = await this.client();
603
- const resp = await client.get("/v0/org/{org_id}/roles/{role_id}/keys", {
604
- params: {
605
- path: { org_id: this.orgId, role_id: roleId },
606
- query,
607
- },
608
- parseAs: "json",
609
- });
610
- return assertOk(resp);
611
- };
612
- return new Paginator(
613
- page ?? Page.default(),
614
- listFn,
615
- (r) => r.keys,
616
- (r) => r.last_evaluated_key,
617
- );
169
+ get deleteOidcUser() {
170
+ return this.orgUserDeleteOidc.bind(this);
618
171
  }
619
172
 
620
- // #endregion
621
-
622
- // #region ROLE USERS: roleUserAdd, roleUsersList
623
-
624
173
  /**
625
- * Add an existing user to an existing role.
174
+ * List users in the organization.
626
175
  *
627
- * @param {string} roleId The ID of the role.
628
- * @param {string} userId The ID of the user to add to the role.
176
+ * Same as {@link orgUsersList}
629
177
  */
630
- async roleUserAdd(roleId: string, userId: string) {
631
- const client = await this.client();
632
- const resp = await client.put("/v0/org/{org_id}/roles/{role_id}/add_user/{user_id}", {
633
- params: { path: { org_id: this.#orgId, role_id: roleId, user_id: userId } },
634
- parseAs: "json",
635
- });
636
- assertOk(resp, "Failed to add user to role");
178
+ get users() {
179
+ return this.orgUsersList.bind(this);
637
180
  }
638
181
 
639
182
  /**
640
- * List all users in a role.
183
+ * Obtain information about the current user.
641
184
  *
642
- * @param {string} roleId The ID of the role whose users to retrieve.
643
- * @param {PageOpts} page Pagination options. Defaults to fetching the entire result set.
644
- * @return {Paginator<ListRoleUsersResponse, UserInRoleInfo>} Paginator for iterating over the users in the role.
185
+ * Same as {@link userGet}
645
186
  */
646
- roleUsersList(roleId: string, page?: PageOpts): Paginator<ListRoleUsersResponse, UserInRoleInfo> {
647
- const listFn = async (query: PageQueryArgs) => {
648
- const client = await this.client();
649
- const resp = await client.get("/v0/org/{org_id}/roles/{role_id}/users", {
650
- params: {
651
- path: { org_id: this.orgId, role_id: roleId },
652
- query,
653
- },
654
- parseAs: "json",
655
- });
656
- return assertOk(resp);
657
- };
658
- return new Paginator(
659
- page ?? Page.default(),
660
- listFn,
661
- (r) => r.users,
662
- (r) => r.last_evaluated_key,
663
- );
187
+ get user() {
188
+ return this.userGet.bind(this);
664
189
  }
665
190
 
666
- // #endregion
667
-
668
- // #region SESSIONS: sessionCreateForRole, sessionRefresh, sessionRevoke, sessionsList, sessionKeysList
669
-
670
191
  /**
671
- * Create a new signer session for a given role.
192
+ * Get information about a specific org.
672
193
  *
673
- * @param {string} roleId Role ID
674
- * @param {string} purpose The purpose of the session
675
- * @param {string[]} scopes Session scopes. Only `sign:*` scopes are allowed.
676
- * @param {SignerSessionLifetime} lifetimes Lifetime settings
677
- * @return {Promise<SignerSessionData>} New signer session info.
194
+ * @param {string?} orgId The ID or name of the org
195
+ * @return {Promise<OrgInfo>} CubeSigner client for the requested org.
678
196
  */
679
- async sessionCreateForRole(
680
- roleId: string,
681
- purpose: string,
682
- scopes?: string[],
683
- lifetimes?: SignerSessionLifetime,
684
- ): Promise<SignerSessionData> {
685
- lifetimes ??= defaultSignerSessionLifetime;
686
- const invalidScopes = (scopes || []).filter((s) => !s.startsWith("sign:"));
687
- if (invalidScopes.length > 0) {
688
- throw new Error(`Role scopes must start with 'sign:'; invalid scopes: ${invalidScopes}`);
689
- }
690
-
691
- const client = await this.client();
692
- const resp = await client.post("/v0/org/{org_id}/roles/{role_id}/tokens", {
693
- params: { path: { org_id: this.orgId, role_id: roleId } },
694
- body: {
695
- purpose,
696
- scopes,
697
- auth_lifetime: lifetimes.auth,
698
- refresh_lifetime: lifetimes.refresh,
699
- session_lifetime: lifetimes.session,
700
- grace_lifetime: lifetimes.grace,
701
- },
702
- parseAs: "json",
703
- });
704
- const data = assertOk(resp);
705
- return {
706
- org_id: this.orgId,
707
- role_id: roleId,
708
- purpose,
709
- token: data.token,
710
- session_info: data.session_info,
711
- // Keep compatibility with tokens produced by CLI
712
- env: {
713
- ["Dev-CubeSignerStack"]: this.#sessionMgr.env,
714
- },
715
- };
197
+ async org(orgId?: string): Promise<OrgInfo> {
198
+ return await this.withOrg(orgId).orgGet();
716
199
  }
717
200
 
718
201
  /**
719
- * Revoke a session.
202
+ * Obtain information about the current user.
720
203
  *
721
- * @param {string} sessionId The ID of the session to revoke.
204
+ * Same as {@link userGet}
722
205
  */
723
- async sessionRevoke(sessionId: string) {
724
- const client = await this.client();
725
- const resp = await client.del("/v0/org/{org_id}/session/{session_id}", {
726
- params: { path: { org_id: this.orgId, session_id: sessionId } },
727
- parseAs: "json",
728
- });
729
- assertOk(resp);
206
+ get aboutMe() {
207
+ return this.userGet.bind(this);
730
208
  }
731
209
 
732
210
  /**
733
- * Returns a paginator for iterating over all signer sessions optionally filtered by a role.
211
+ * Get a key by id.
734
212
  *
735
- * @param {string?} roleId If set, limit to sessions for this role only.
736
- * @param {PageOpts?} page Pagination options. Defaults to fetching the entire result set.
737
- * @return {Promise<SignerSessionInfo[]>} Signer sessions for this role.
213
+ * @param {string} keyId The id of the key to get.
214
+ * @return {Key} The key.
738
215
  */
739
- sessionsList(roleId?: string, page?: PageOpts): Paginator<SessionsResponse, SessionInfo> {
740
- const listFn = async (query: PageQueryArgs) => {
741
- const client = await this.client();
742
- const resp = await client.get("/v0/org/{org_id}/session", {
743
- params: {
744
- path: { org_id: this.#orgId },
745
- query: { role: roleId, ...query },
746
- },
747
- parseAs: "json",
748
- });
749
- return assertOk(resp);
750
- };
751
- return new Paginator(
752
- page ?? Page.default(),
753
- listFn,
754
- (r) => r.sessions,
755
- (r) => r.last_evaluated_key,
756
- );
216
+ async getKey(keyId: string): Promise<Key> {
217
+ const keyInfo = await this.keyGet(keyId);
218
+ return new Key(this, keyInfo);
757
219
  }
758
220
 
759
221
  /**
760
- * Returns the list of keys that this session has access to.
761
- * @return {Key[]} The list of keys.
222
+ * Get all keys in the org.
223
+ *
224
+ * @param {KeyType?} type Optional key type to filter list for.
225
+ * @param {PageOpts} page Pagination options. Defaults to fetching the entire result set.
226
+ * @return {Promise<Key[]>} The keys.
762
227
  */
763
- async sessionKeysList(): Promise<KeyInfoApi[]> {
764
- const client = await this.client();
765
- const resp = await client.get("/v0/org/{org_id}/token/keys", {
766
- params: { path: { org_id: this.orgId } },
767
- parseAs: "json",
768
- });
769
- return assertOk(resp).keys;
228
+ async orgKeys(type?: KeyType, page?: PageOpts): Promise<Key[]> {
229
+ const paginator = this.keysList(type, page);
230
+ const keys = await paginator.fetch();
231
+ return keys.map((k) => new Key(this, k));
770
232
  }
771
233
 
772
- // #endregion
773
-
774
- // #region IDENTITY: identityProve, identityVerify
775
-
776
234
  /**
777
- * Obtain proof of authentication using the current CubeSigner session.
235
+ * Create a new role.
778
236
  *
779
- * @return {Promise<IdentityProof>} Proof of authentication
237
+ * @param {string?} name The name of the role.
238
+ * @return {Role} The new role.
780
239
  */
781
- async identityProve(): Promise<IdentityProof> {
782
- const client = await this.client();
783
- const resp = await client.post("/v0/org/{org_id}/identity/prove", {
784
- params: { path: { org_id: this.orgId } },
785
- parseAs: "json",
786
- });
787
- return assertOk(resp);
240
+ async createRole(name?: string): Promise<Role> {
241
+ const roleId = await this.roleCreate(name);
242
+ const roleInfo = await this.roleGet(roleId);
243
+ return new Role(this, roleInfo);
788
244
  }
789
245
 
790
246
  /**
791
- * Checks if a given identity proof is valid.
247
+ * Get a role by id or name.
792
248
  *
793
- * @param {IdentityProof} proof The proof of authentication.
249
+ * @param {string} roleId The id or name of the role to get.
250
+ * @return {Role} The role.
794
251
  */
795
- async identityVerify(proof: IdentityProof) {
796
- const client = await this.client();
797
- const resp = await client.post("/v0/org/{org_id}/identity/verify", {
798
- params: { path: { org_id: this.orgId } },
799
- body: proof,
800
- parseAs: "json",
801
- });
802
- assertOk(resp);
252
+ async getRole(roleId: string): Promise<Role> {
253
+ const roleInfo = await this.roleGet(roleId);
254
+ return new Role(this, roleInfo);
803
255
  }
804
256
 
805
- // #endregion
806
-
807
- // #region MFA: mfaGet, mfaList, mfaApprove, mfaList, mfaApprove, mfaApproveTotp, mfaApproveFido(Init|Complete)
808
-
809
257
  /**
810
- * Retrieves existing MFA request.
258
+ * List all roles in the org.
811
259
  *
812
- * @param {string} mfaId MFA request ID
813
- * @return {Promise<MfaRequestInfo>} MFA request information
260
+ * @param {PageOpts} page Pagination options. Defaults to fetching the entire result set.
261
+ * @return {Role[]} The roles.
814
262
  */
815
- async mfaGet(mfaId: string): Promise<MfaRequestInfo> {
816
- const client = await this.client();
817
- const resp = await client.get("/v0/org/{org_id}/mfa/{mfa_id}", {
818
- params: { path: { org_id: this.orgId, mfa_id: mfaId } },
819
- });
820
- return assertOk(resp);
263
+ async listRoles(page?: PageOpts): Promise<Role[]> {
264
+ const roles = await this.rolesList(page).fetch();
265
+ return roles.map((r) => new Role(this, r));
821
266
  }
822
267
 
823
268
  /**
824
- * List pending MFA requests accessible to the current user.
269
+ * List all users in the org.
825
270
  *
826
- * @return {Promise<MfaRequestInfo[]>} The MFA requests.
271
+ * Same as {@link orgUsersList}
827
272
  */
828
- async mfaList(): Promise<MfaRequestInfo[]> {
829
- const client = await this.client();
830
- const resp = await client.get("/v0/org/{org_id}/mfa", {
831
- params: { path: { org_id: this.orgId } },
832
- });
833
- return assertOk(resp).mfa_requests;
273
+ get listUsers() {
274
+ return this.orgUsersList.bind(this);
834
275
  }
835
276
 
836
277
  /**
837
- * Approve a pending MFA request using the current session.
278
+ * Approve a pending MFA request.
838
279
  *
839
- * @param {string} mfaId The id of the MFA request
840
- * @return {Promise<MfaRequestInfo>} The result of the MFA request
280
+ * Same as {@link mfaApprove}
841
281
  */
842
- async mfaApprove(mfaId: string): Promise<MfaRequestInfo> {
843
- const client = await this.client();
844
- const resp = await client.patch("/v0/org/{org_id}/mfa/{mfa_id}", {
845
- params: { path: { org_id: this.orgId, mfa_id: mfaId } },
846
- });
847
- return assertOk(resp);
282
+ get approveMfaRequest() {
283
+ return this.mfaApprove.bind(this);
848
284
  }
849
285
 
850
286
  /**
851
287
  * Approve a pending MFA request using TOTP.
852
288
  *
853
- * @param {string} mfaId The MFA request to approve
854
- * @param {string} code The TOTP code
855
- * @return {Promise<MfaRequestInfo>} The current status of the MFA request
289
+ * Same as {@link mfaApproveTotp}
856
290
  */
857
- async mfaApproveTotp(mfaId: string, code: string): Promise<MfaRequestInfo> {
858
- const client = await this.client();
859
- const resp = await client.patch("/v0/org/{org_id}/mfa/{mfa_id}/totp", {
860
- params: { path: { org_id: this.#orgId, mfa_id: mfaId } },
861
- body: { code },
862
- parseAs: "json",
863
- });
864
- return assertOk(resp);
291
+ get totpApprove() {
292
+ return this.mfaApproveTotp.bind(this);
865
293
  }
866
294
 
867
295
  /**
868
296
  * Initiate approval of an existing MFA request using FIDO.
869
297
  *
870
- * @param {string} mfaId The MFA request ID.
871
- * @return {Promise<MfaFidoChallenge>} A challenge that needs to be answered to complete the approval.
872
- */
873
- async mfaApproveFidoInit(mfaId: string): Promise<MfaFidoChallenge> {
874
- const client = await this.client();
875
- const resp = await client.post("/v0/org/{org_id}/mfa/{mfa_id}/fido", {
876
- params: { path: { org_id: this.orgId, mfa_id: mfaId } },
877
- parseAs: "json",
878
- });
879
- const challenge = assertOk(resp);
880
- return new MfaFidoChallenge(this, mfaId, challenge);
881
- }
882
-
883
- /**
884
- * Complete a previously initiated MFA request approval using FIDO.
298
+ * Returns a {@link MfaFidoChallenge} that must be answered by calling
299
+ * {@link MfaFidoChallenge.answer} or {@link fidoApproveComplete}.
885
300
  *
886
- * @param {string} mfaId The MFA request ID
887
- * @param {string} challengeId The challenge ID
888
- * @param {PublicKeyCredential} credential The answer to the challenge
889
- * @return {Promise<MfaRequestInfo>} The current status of the MFA request.
301
+ * Same as {@link mfaApproveFidoInit}
890
302
  */
891
- async mfaApproveFidoComplete(
892
- mfaId: string,
893
- challengeId: string,
894
- credential: PublicKeyCredential,
895
- ): Promise<MfaRequestInfo> {
896
- const client = await this.client();
897
- const resp = await client.patch("/v0/org/{org_id}/mfa/{mfa_id}/fido", {
898
- params: { path: { org_id: this.orgId, mfa_id: mfaId } },
899
- body: {
900
- challenge_id: challengeId,
901
- credential,
902
- },
903
- parseAs: "json",
904
- });
905
- return assertOk(resp);
303
+ get fidoApproveStart() {
304
+ return this.mfaApproveFidoInit.bind(this);
906
305
  }
907
306
 
908
- // #endregion
909
-
910
- // #region SIGN: signEvm, signEth2, signStake, signUnstake, signAva, signBlob, signBtc, signSolana
911
-
912
307
  /**
913
- * Sign an EVM transaction.
914
- * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
915
- * @param {EvmSignRequest} req What to sign.
916
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt.
917
- * @return {Promise<EvmSignResponse | AcceptedResponse>} Signature (or MFA approval request).
308
+ * Answer the MFA approval with FIDO challenge issued by {@link fidoApproveStart}.
309
+ *
310
+ * Same as {@link mfaApproveFidoComplete}
918
311
  */
919
- async signEvm(
920
- key: Key | string,
921
- req: EvmSignRequest,
922
- mfaReceipt?: MfaReceipt,
923
- ): Promise<CubeSignerResponse<EvmSignResponse>> {
924
- const pubkey = typeof key === "string" ? (key as string) : key.materialId;
925
- const sign = async (headers?: HeadersInit) => {
926
- const client = await this.client();
927
- const resp = await client.post("/v1/org/{org_id}/eth1/sign/{pubkey}", {
928
- params: { path: { org_id: this.orgId, pubkey } },
929
- body: req,
930
- headers,
931
- parseAs: "json",
932
- });
933
- return assertOk(resp);
934
- };
935
- return await CubeSignerResponse.create(sign, mfaReceipt);
312
+ get fidoApproveComplete() {
313
+ return this.mfaApproveFidoComplete.bind(this);
936
314
  }
937
315
 
938
316
  /**
939
- * Sign an Eth2/Beacon-chain validation message.
317
+ * Get a pending MFA request by its id.
940
318
  *
941
- * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
942
- * @param {Eth2SignRequest} req What to sign.
943
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt
944
- * @return {Promise<Eth2SignResponse | AcceptedResponse>} Signature
319
+ * Same as {@link CubeSignerClient.getMfaInfo}
945
320
  */
946
- async signEth2(
947
- key: Key | string,
948
- req: Eth2SignRequest,
949
- mfaReceipt?: MfaReceipt,
950
- ): Promise<CubeSignerResponse<Eth2SignResponse>> {
951
- const pubkey = typeof key === "string" ? (key as string) : key.materialId;
952
- const sign = async (headers?: HeadersInit) => {
953
- const client = await this.client();
954
- const resp = await client.post("/v1/org/{org_id}/eth2/sign/{pubkey}", {
955
- params: { path: { org_id: this.orgId, pubkey } },
956
- body: req,
957
- headers,
958
- parseAs: "json",
959
- });
960
- return assertOk(resp);
961
- };
962
- return await CubeSignerResponse.create(sign, mfaReceipt);
321
+ get getMfaInfo() {
322
+ return this.mfaGet.bind(this);
963
323
  }
964
324
 
965
325
  /**
966
- * Sign an Eth2/Beacon-chain deposit (or staking) message.
326
+ * List pending MFA requests accessible to the current user.
967
327
  *
968
- * @param {Eth2StakeRequest} req The request to sign.
969
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt
970
- * @return {Promise<Eth2StakeResponse | AcceptedResponse>} The response.
328
+ * Same as {@link CubeSignerClient.mfaList}
971
329
  */
972
- async signStake(
973
- req: Eth2StakeRequest,
974
- mfaReceipt?: MfaReceipt,
975
- ): Promise<CubeSignerResponse<Eth2StakeResponse>> {
976
- const sign = async (headers?: HeadersInit) => {
977
- const client = await this.client();
978
- const resp = await client.post("/v1/org/{org_id}/eth2/stake", {
979
- params: { path: { org_id: this.orgId } },
980
- body: req,
981
- headers,
982
- parseAs: "json",
983
- });
984
- return assertOk(resp);
985
- };
986
- return await CubeSignerResponse.create(sign, mfaReceipt);
330
+ get listMfaInfos() {
331
+ return this.mfaList.bind(this);
987
332
  }
988
333
 
989
334
  /**
990
- * Sign an Eth2/Beacon-chain unstake/exit request.
335
+ * Obtain a proof of authentication.
991
336
  *
992
- * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
993
- * @param {Eth2UnstakeRequest} req The request to sign.
994
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt
995
- * @return {Promise<Eth2UnstakeResponse | AcceptedResponse>} The response.
337
+ * Same as {@link CubeSignerClient.identityProve}
996
338
  */
997
- async signUnstake(
998
- key: Key | string,
999
- req: Eth2UnstakeRequest,
1000
- mfaReceipt?: MfaReceipt,
1001
- ): Promise<CubeSignerResponse<Eth2UnstakeResponse>> {
1002
- const pubkey = typeof key === "string" ? (key as string) : key.materialId;
1003
- const sign = async (headers?: HeadersInit) => {
1004
- const client = await this.client();
1005
- const resp = await client.post("/v1/org/{org_id}/eth2/unstake/{pubkey}", {
1006
- params: { path: { org_id: this.orgId, pubkey } },
1007
- body: req,
1008
- headers,
1009
- parseAs: "json",
1010
- });
1011
- return assertOk(resp);
1012
- };
1013
- return await CubeSignerResponse.create(sign, mfaReceipt);
339
+ get proveIdentity() {
340
+ return this.identityProve.bind(this);
1014
341
  }
1015
342
 
1016
343
  /**
1017
- * Sign an Avalanche P- or X-chain message.
1018
- * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
1019
- * @param {AvaTx} tx Avalanche message (transaction) to sign
1020
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt
1021
- * @return {Promise<AvaSignResponse | AcceptedResponse>} The response.
344
+ * Check if a given proof of OIDC authentication is valid.
345
+ *
346
+ * Same as {@link CubeSignerClient.identityVerify}
1022
347
  */
1023
- async signAva(
1024
- key: Key | string,
1025
- tx: AvaTx,
1026
- mfaReceipt?: MfaReceipt,
1027
- ): Promise<CubeSignerResponse<AvaSignResponse>> {
1028
- const pubkey = typeof key === "string" ? (key as string) : key.materialId;
1029
- const sign = async (headers?: HeadersInit) => {
1030
- const req = <AvaSignRequest>{
1031
- tx: tx as unknown,
1032
- };
1033
- const client = await this.client();
1034
- const resp = await client.post("/v0/org/{org_id}/ava/sign/{pubkey}", {
1035
- params: { path: { org_id: this.orgId, pubkey } },
1036
- body: req,
1037
- headers,
1038
- parseAs: "json",
1039
- });
1040
- return assertOk(resp);
1041
- };
1042
- return await CubeSignerResponse.create(sign, mfaReceipt);
348
+ get verifyIdentity() {
349
+ return this.identityVerify.bind(this);
1043
350
  }
1044
351
 
1045
352
  /**
1046
- * Sign a raw blob.
1047
- *
1048
- * This requires the key to have a '"AllowRawBlobSigning"' policy. This is because
1049
- * signing arbitrary messages is, in general, dangerous (and you should instead
1050
- * prefer typed end-points as used by, for example, `signEvm`). For Secp256k1 keys,
1051
- * for example, you **must** call this function with a message that is 32 bytes long and
1052
- * the output of a secure hash function.
1053
- *
1054
- * This function returns signatures serialized as;
1055
- *
1056
- * - ECDSA signatures are serialized as big-endian r and s plus recovery-id
1057
- * byte v, which can in general take any of the values 0, 1, 2, or 3.
353
+ * Creates a request to add a new FIDO device.
1058
354
  *
1059
- * - EdDSA signatures are serialized in the standard format.
355
+ * Returns a {@link AddFidoChallenge} that must be answered by calling {@link AddFidoChallenge.answer}.
1060
356
  *
1061
- * - BLS signatures are not supported on the blob-sign endpoint.
357
+ * MFA may be required.
1062
358
  *
1063
- * @param {Key | string} key The key to sign with (either {@link Key} or its ID).
1064
- * @param {BlobSignRequest} req What to sign
1065
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt
1066
- * @return {Promise<BlobSignResponse | AcceptedResponse>} The response.
359
+ * Same as {@link CubeSignerClient.userRegisterFidoInit}
1067
360
  */
1068
- async signBlob(
1069
- key: Key | string,
1070
- req: BlobSignRequest,
1071
- mfaReceipt?: MfaReceipt,
1072
- ): Promise<CubeSignerResponse<BlobSignResponse>> {
1073
- const key_id = typeof key === "string" ? (key as string) : key.id;
1074
- const sign = async (headers?: HeadersInit) => {
1075
- const client = await this.client();
1076
- const resp = await client.post("/v1/org/{org_id}/blob/sign/{key_id}", {
1077
- params: {
1078
- path: { org_id: this.orgId, key_id },
1079
- },
1080
- body: req,
1081
- headers,
1082
- parseAs: "json",
1083
- });
1084
- return assertOk(resp);
1085
- };
1086
- return await CubeSignerResponse.create(sign, mfaReceipt);
361
+ get addFidoStart() {
362
+ return this.userRegisterFidoInit.bind(this);
1087
363
  }
1088
364
 
1089
365
  /**
1090
- * Sign a Bitcoin message.
366
+ * Creates a request to change user's TOTP. Returns a {@link TotpChallenge}
367
+ * that must be answered by calling {@link TotpChallenge.answer} or
368
+ * {@link resetTotpComplete}.
1091
369
  *
1092
- * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
1093
- * @param {BtcSignRequest} req What to sign
1094
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt
1095
- * @return {Promise<BtcSignResponse | AcceptedResponse>} The response.
370
+ * Same as {@link userResetTotpInit}
1096
371
  */
1097
- async signBtc(
1098
- key: Key | string,
1099
- req: BtcSignRequest,
1100
- mfaReceipt?: MfaReceipt,
1101
- ): Promise<CubeSignerResponse<BtcSignResponse>> {
1102
- const pubkey = typeof key === "string" ? (key as string) : key.materialId;
1103
- const sign = async (headers?: HeadersInit) => {
1104
- const client = await this.client();
1105
- const resp = await client.post("/v0/org/{org_id}/btc/sign/{pubkey}", {
1106
- params: {
1107
- path: { org_id: this.orgId, pubkey },
1108
- },
1109
- body: req,
1110
- headers: headers,
1111
- parseAs: "json",
1112
- });
1113
- return assertOk(resp);
1114
- };
1115
- return await CubeSignerResponse.create(sign, mfaReceipt);
372
+ get resetTotpStart() {
373
+ return this.userResetTotpInit.bind(this);
1116
374
  }
1117
375
 
1118
376
  /**
1119
- * Sign a Solana message.
377
+ * Answer the TOTP challenge issued by {@link resetTotpStart}. If successful,
378
+ * user's TOTP configuration will be updated to that of the TOTP challenge.
1120
379
  *
1121
- * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
1122
- * @param {SolanaSignRequest} req What to sign
1123
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt
1124
- * @return {Promise<SolanaSignResponse | AcceptedResponse>} The response.
380
+ * Same as {@link userResetTotpComplete}
1125
381
  */
1126
- async signSolana(
1127
- key: Key | string,
1128
- req: SolanaSignRequest,
1129
- mfaReceipt?: MfaReceipt,
1130
- ): Promise<CubeSignerResponse<SolanaSignResponse>> {
1131
- const pubkey = typeof key === "string" ? (key as string) : key.materialId;
1132
- const sign = async (headers?: HeadersInit) => {
1133
- const client = await this.client();
1134
- const resp = await client.post("/v0/org/{org_id}/solana/sign/{pubkey}", {
1135
- params: { path: { org_id: this.orgId, pubkey } },
1136
- body: req,
1137
- headers,
1138
- parseAs: "json",
1139
- });
1140
- return assertOk(resp);
1141
- };
1142
- return await CubeSignerResponse.create(sign, mfaReceipt);
382
+ get resetTotpComplete() {
383
+ return this.userResetTotpComplete.bind(this);
1143
384
  }
1144
- // #endregion
1145
-
1146
- /** HTTPS client */
1147
- private async client(): Promise<Client> {
1148
- return await this.#sessionMgr.client();
1149
- }
1150
- }
1151
-
1152
- /**
1153
- * Client to use to send requests to CubeSigner services
1154
- * when authenticating using an OIDC token.
1155
- */
1156
- export class OidcClient {
1157
- readonly #orgId: string;
1158
- readonly #client: Client;
1159
385
 
1160
386
  /**
1161
- * @param {EnvInterface} env CubeSigner deployment
1162
- * @param {string} orgId Target organization ID
1163
- * @param {string} oidcToken User's OIDC token
387
+ * Verifies a given TOTP code against the current user's TOTP configuration.
388
+ * Throws an error if the verification fails.
389
+ *
390
+ * Same as {@link userVerifyTotp}
1164
391
  */
1165
- constructor(env: EnvInterface, orgId: string, oidcToken: string) {
1166
- this.#orgId = orgId;
1167
- this.#client = createClient<paths>({
1168
- baseUrl: env.SignerApiRoot,
1169
- headers: {
1170
- Authorization: oidcToken,
1171
- },
1172
- });
392
+ get verifyTotp() {
393
+ return this.userVerifyTotp.bind(this);
1173
394
  }
1174
395
 
1175
396
  /**
1176
- * Exchange an OIDC token for a CubeSigner session token.
1177
- * @param {List<string>} scopes The scopes for the new session
1178
- * @param {RatchetConfig} lifetimes Lifetimes of the new session.
1179
- * @param {MfaReceipt} mfaReceipt Optional MFA receipt (id + confirmation code)
1180
- * @return {Promise<CubeSignerResponse<OidcAuthResponse>>} The session data.
397
+ * Sign a stake request.
398
+ *
399
+ * Same as {@link signStake}
1181
400
  */
1182
- async sessionCreate(
1183
- scopes: Array<string>,
1184
- lifetimes?: RatchetConfig,
1185
- mfaReceipt?: MfaReceipt,
1186
- ): Promise<CubeSignerResponse<OidcAuthResponse>> {
1187
- const loginFn = async (headers?: HeadersInit) => {
1188
- const resp = await this.#client.post("/v0/org/{org_id}/oidc", {
1189
- params: { path: { org_id: this.#orgId } },
1190
- headers,
1191
- body: {
1192
- scopes,
1193
- tokens: lifetimes,
1194
- },
1195
- parseAs: "json",
1196
- });
1197
- return assertOk(resp);
1198
- };
1199
-
1200
- return await CubeSignerResponse.create(loginFn, mfaReceipt);
401
+ get stake() {
402
+ return this.signStake.bind(this);
1201
403
  }
1202
404
 
1203
405
  /**
1204
- * Exchange an OIDC token for a proof of authentication.
406
+ * Sign an unstake request.
1205
407
  *
1206
- * @return {Promise<IdentityProof>} Proof of authentication
408
+ * Same as {@link signUnstake}
1207
409
  */
1208
- async identityProve(): Promise<IdentityProof> {
1209
- const resp = await this.#client.post("/v0/org/{org_id}/identity/prove/oidc", {
1210
- params: { path: { org_id: this.#orgId } },
1211
- parseAs: "json",
1212
- });
1213
- return assertOk(resp);
410
+ get unstake() {
411
+ return this.signUnstake.bind(this);
1214
412
  }
1215
413
  }
1216
-
1217
- const defaultSignerSessionLifetime: SignerSessionLifetime = {
1218
- session: 604800, // 1 week
1219
- auth: 300, // 5 min
1220
- refresh: 86400, // 1 day
1221
- grace: 30, // seconds
1222
- };