@cubist-labs/cubesigner-sdk 0.1.23

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 (64) hide show
  1. package/LICENSE-APACHE +177 -0
  2. package/LICENSE-MIT +25 -0
  3. package/NOTICE +13 -0
  4. package/README.md +470 -0
  5. package/dist/examples/ethers.d.ts +1 -0
  6. package/dist/examples/ethers.js +142 -0
  7. package/dist/spec/env/beta.json +9 -0
  8. package/dist/spec/env/gamma.json +9 -0
  9. package/dist/spec/env/prod.json +9 -0
  10. package/dist/src/client.d.ts +10 -0
  11. package/dist/src/client.js +21 -0
  12. package/dist/src/env.d.ts +15 -0
  13. package/dist/src/env.js +35 -0
  14. package/dist/src/ethers/index.d.ts +50 -0
  15. package/dist/src/ethers/index.js +122 -0
  16. package/dist/src/index.d.ts +114 -0
  17. package/dist/src/index.js +205 -0
  18. package/dist/src/key.d.ts +114 -0
  19. package/dist/src/key.js +201 -0
  20. package/dist/src/mfa.d.ts +23 -0
  21. package/dist/src/mfa.js +63 -0
  22. package/dist/src/org.d.ts +161 -0
  23. package/dist/src/org.js +264 -0
  24. package/dist/src/role.d.ts +224 -0
  25. package/dist/src/role.js +256 -0
  26. package/dist/src/schema.d.ts +3049 -0
  27. package/dist/src/schema.js +7 -0
  28. package/dist/src/session/generic.d.ts +47 -0
  29. package/dist/src/session/generic.js +3 -0
  30. package/dist/src/session/management_session_manager.d.ts +59 -0
  31. package/dist/src/session/management_session_manager.js +111 -0
  32. package/dist/src/session/oidc_session_manager.d.ts +78 -0
  33. package/dist/src/session/oidc_session_manager.js +142 -0
  34. package/dist/src/session/session_manager.d.ts +74 -0
  35. package/dist/src/session/session_manager.js +79 -0
  36. package/dist/src/session/session_storage.d.ts +47 -0
  37. package/dist/src/session/session_storage.js +76 -0
  38. package/dist/src/session/signer_session_manager.d.ts +88 -0
  39. package/dist/src/session/signer_session_manager.js +159 -0
  40. package/dist/src/sign.d.ts +114 -0
  41. package/dist/src/sign.js +248 -0
  42. package/dist/src/signer_session.d.ts +180 -0
  43. package/dist/src/signer_session.js +369 -0
  44. package/dist/src/util.d.ts +35 -0
  45. package/dist/src/util.js +75 -0
  46. package/dist/test/sessions.d.ts +35 -0
  47. package/dist/test/sessions.js +56 -0
  48. package/package.json +61 -0
  49. package/src/client.ts +12 -0
  50. package/src/env.ts +25 -0
  51. package/src/ethers/index.ts +131 -0
  52. package/src/index.ts +220 -0
  53. package/src/key.ts +249 -0
  54. package/src/org.ts +333 -0
  55. package/src/role.ts +385 -0
  56. package/src/schema.ts +3054 -0
  57. package/src/session/management_session_manager.ts +136 -0
  58. package/src/session/oidc_session_manager.ts +193 -0
  59. package/src/session/session_manager.ts +114 -0
  60. package/src/session/session_storage.ts +73 -0
  61. package/src/session/signer_session_manager.ts +211 -0
  62. package/src/signer_session.ts +464 -0
  63. package/src/util.ts +58 -0
  64. package/tsconfig.json +32 -0
@@ -0,0 +1,211 @@
1
+ import { CubeSigner } from "..";
2
+ import { assertOk } from "../util";
3
+ import { components, paths, Client } from "../client";
4
+ import { HasEnv, OrgSessionManager } from "./session_manager";
5
+ import { SessionStorage } from "./session_storage";
6
+
7
+ export type ClientSessionInfo = components["schemas"]["ClientSessionInfo"];
8
+
9
+ export type CreateSignerSessionRequest =
10
+ paths["/v0/org/{org_id}/roles/{role_id}/tokens"]["post"]["requestBody"]["content"]["application/json"];
11
+ export type RefreshSignerSessionRequest =
12
+ paths["/v1/org/{org_id}/token/refresh"]["patch"]["requestBody"]["content"]["application/json"];
13
+
14
+ /** JSON representation of our "signer session" file format */
15
+ export interface SignerSessionObject {
16
+ /** The organization ID */
17
+ org_id: string;
18
+ /** The role ID */
19
+ role_id: string;
20
+ /** The purpose of the session token */
21
+ purpose: string;
22
+ /** The token to include in Authorization header */
23
+ token: string;
24
+ /** Session info */
25
+ session_info: ClientSessionInfo;
26
+ }
27
+
28
+ export interface SignerSessionData extends SignerSessionObject, HasEnv {}
29
+
30
+ /** Type of storage required for signer sessions */
31
+ export type SignerSessionStorage = SessionStorage<SignerSessionData>;
32
+
33
+ export interface SignerSessionLifetime {
34
+ /** Session lifetime (in seconds). Defaults to one week (604800). */
35
+ session?: number;
36
+ /** Auth token lifetime (in seconds). Defaults to five minutes (300). */
37
+ auth: number;
38
+ /** Refresh token lifetime (in seconds). Defaults to one day (86400). */
39
+ refresh?: number;
40
+ }
41
+
42
+ const defaultSignerSessionLifetime: SignerSessionLifetime = {
43
+ session: 604800,
44
+ auth: 300,
45
+ refresh: 86400,
46
+ };
47
+
48
+ /** Manager for signer sessions. */
49
+ export class SignerSessionManager extends OrgSessionManager<SignerSessionData> {
50
+ readonly cs?: CubeSigner;
51
+ readonly roleId: string;
52
+ #client: Client;
53
+
54
+ /**
55
+ * @return {string} The current auth token.
56
+ * @internal
57
+ */
58
+ async token(): Promise<string> {
59
+ const session = await this.storage.retrieve();
60
+ return session.token;
61
+ }
62
+
63
+ /**
64
+ * Returns a client with the current session and refreshes the current
65
+ * session. May **UPDATE/MUTATE** self.
66
+ */
67
+ async client(): Promise<Client> {
68
+ await this.refreshIfNeeded();
69
+ return this.#client;
70
+ }
71
+
72
+ /** Revokes the session. */
73
+ async revoke(): Promise<void> {
74
+ if (!this.cs) {
75
+ throw new Error("No management session available");
76
+ }
77
+ const session = await this.storage.retrieve();
78
+ const resp = await (
79
+ await this.cs.management()
80
+ ).del("/v0/org/{org_id}/roles/{role_id}/tokens/{session_id}", {
81
+ params: {
82
+ path: {
83
+ org_id: session.org_id,
84
+ role_id: session.role_id,
85
+ session_id: session.session_info.session_id,
86
+ },
87
+ },
88
+ parseAs: "json",
89
+ });
90
+ assertOk(resp);
91
+ }
92
+
93
+ /**
94
+ * Returns whether it's time to refresh this token.
95
+ * @return {boolean} Whether it's time to refresh this token.
96
+ * @internal
97
+ */
98
+ async isStale(): Promise<boolean> {
99
+ const session = await this.storage.retrieve();
100
+ return this.hasExpired(session.session_info.auth_token_exp);
101
+ }
102
+
103
+ /**
104
+ * Refreshes the session and **UPDATES/MUTATES** self.
105
+ */
106
+ async refresh(): Promise<void> {
107
+ const session = await this.storage.retrieve();
108
+ const csi = session.session_info;
109
+ const resp = await this.#client.patch("/v1/org/{org_id}/token/refresh", {
110
+ params: { path: { org_id: session.org_id } },
111
+ body: <RefreshSignerSessionRequest>{
112
+ epoch_num: csi.epoch,
113
+ epoch_token: csi.epoch_token,
114
+ other_token: csi.refresh_token,
115
+ },
116
+ parseAs: "json",
117
+ });
118
+ const data = assertOk(resp);
119
+ await this.storage.save(<SignerSessionData>{
120
+ ...session,
121
+ session_info: data.session_info,
122
+ token: data.token,
123
+ });
124
+ this.#client = this.createClient(data.token);
125
+ }
126
+
127
+ /**
128
+ * Create a new signer session.
129
+ * @param {CubeSigner} cs The CubeSigner instance
130
+ * @param {SessionStorage<SignerSessionObject>} storage The session storage to use
131
+ * @param {string} orgId Org ID
132
+ * @param {string} roleId Role ID
133
+ * @param {string} purpose The purpose of the session
134
+ * @param {SignerSessionLifetime} ttl Lifetime settings
135
+ * @return {Promise<SignerSessionManager>} New signer session
136
+ */
137
+ static async create(
138
+ cs: CubeSigner,
139
+ storage: SignerSessionStorage,
140
+ orgId: string,
141
+ roleId: string,
142
+ purpose: string,
143
+ ttl?: SignerSessionLifetime,
144
+ ): Promise<SignerSessionManager> {
145
+ const resp = await (
146
+ await cs.management()
147
+ ).post("/v0/org/{org_id}/roles/{role_id}/tokens", {
148
+ params: { path: { org_id: orgId, role_id: roleId } },
149
+ body: {
150
+ purpose,
151
+ auth_lifetime: ttl?.auth || defaultSignerSessionLifetime.auth,
152
+ refresh_lifetime: ttl?.refresh || defaultSignerSessionLifetime.refresh,
153
+ session_lifetime: ttl?.session || defaultSignerSessionLifetime.session,
154
+ },
155
+ parseAs: "json",
156
+ });
157
+ const data = assertOk(resp);
158
+ const session_info = data.session_info;
159
+ if (!session_info) {
160
+ throw new Error("Signer session info missing");
161
+ }
162
+ await storage.save({
163
+ org_id: orgId,
164
+ role_id: roleId,
165
+ purpose,
166
+ token: data.token,
167
+ session_info,
168
+ // Keep compatibility with tokens produced by CLI
169
+ env: {
170
+ ["Dev-CubeSignerStack"]: cs.env,
171
+ },
172
+ });
173
+ return new SignerSessionManager(cs, orgId, roleId, data.token, storage);
174
+ }
175
+
176
+ /**
177
+ * Uses an existing session to create a new signer session manager.
178
+ * @param {CubeSigner} cs The CubeSigner instance
179
+ * @param {SessionStorage<SignerSessionObject>} storage The session storage to use
180
+ * @return {Promise<SingerSession>} New signer session manager
181
+ */
182
+ static async loadFromStorage(
183
+ cs: CubeSigner,
184
+ storage: SignerSessionStorage,
185
+ ): Promise<SignerSessionManager> {
186
+ const session = await storage.retrieve();
187
+ return new SignerSessionManager(cs, session.org_id, session.role_id, session.token, storage);
188
+ }
189
+
190
+ /**
191
+ * Constructor.
192
+ * @param {CubeSigner} cs CubeSigner
193
+ * @param {string} orgId The id of the org associated with this session
194
+ * @param {string} roleId The id of the role that this session assumes
195
+ * @param {string} token The authorization token to use
196
+ * @param {SignerSessionStorage} storage The session storage to use
197
+ * @internal
198
+ */
199
+ private constructor(
200
+ cs: CubeSigner,
201
+ orgId: string,
202
+ roleId: string,
203
+ token: string,
204
+ storage: SignerSessionStorage,
205
+ ) {
206
+ super(cs.env, orgId, storage);
207
+ this.cs = cs;
208
+ this.roleId = roleId;
209
+ this.#client = this.createClient(token);
210
+ }
211
+ }
@@ -0,0 +1,464 @@
1
+ import assert from "assert";
2
+ import { CubeSigner, Key, OidcSessionManager, OidcSessionStorage, Org } from ".";
3
+ import { components, paths } from "./client";
4
+ import { assertOk } from "./util";
5
+ import { SignerSessionManager, SignerSessionStorage } from "./session/signer_session_manager";
6
+
7
+ export type KeyInfo = components["schemas"]["KeyInfo"];
8
+
9
+ /* eslint-disable */
10
+ export type EvmSignRequest =
11
+ paths["/v1/org/{org_id}/eth1/sign/{pubkey}"]["post"]["requestBody"]["content"]["application/json"];
12
+ export type Eth2SignRequest =
13
+ paths["/v1/org/{org_id}/eth2/sign/{pubkey}"]["post"]["requestBody"]["content"]["application/json"];
14
+ export type Eth2StakeRequest =
15
+ paths["/v1/org/{org_id}/eth2/stake"]["post"]["requestBody"]["content"]["application/json"];
16
+ export type Eth2UnstakeRequest =
17
+ paths["/v1/org/{org_id}/eth2/unstake/{pubkey}"]["post"]["requestBody"]["content"]["application/json"];
18
+ export type BlobSignRequest =
19
+ paths["/v1/org/{org_id}/blob/sign/{key_id}"]["post"]["requestBody"]["content"]["application/json"];
20
+ export type BtcSignRequest =
21
+ paths["/v0/org/{org_id}/btc/sign/{pubkey}"]["post"]["requestBody"]["content"]["application/json"];
22
+ export type SolanaSignRequest =
23
+ paths["/v1/org/{org_id}/solana/sign/{pubkey}"]["post"]["requestBody"]["content"]["application/json"];
24
+
25
+ export type EvmSignResponse =
26
+ components["responses"]["Eth1SignResponse"]["content"]["application/json"];
27
+ export type Eth2SignResponse =
28
+ components["responses"]["Eth2SignResponse"]["content"]["application/json"];
29
+ export type Eth2StakeResponse =
30
+ components["responses"]["StakeResponse"]["content"]["application/json"];
31
+ export type Eth2UnstakeResponse =
32
+ components["responses"]["UnstakeResponse"]["content"]["application/json"];
33
+ export type BlobSignResponse =
34
+ components["responses"]["BlobSignResponse"]["content"]["application/json"];
35
+ export type BtcSignResponse =
36
+ components["responses"]["BtcSignResponse"]["content"]["application/json"];
37
+ export type SolanaSignResponse =
38
+ components["responses"]["SolanaSignResponse"]["content"]["application/json"];
39
+ export type MfaRequestInfo =
40
+ components["responses"]["MfaRequestInfo"]["content"]["application/json"];
41
+
42
+ export type AcceptedResponse = components["schemas"]["AcceptedResponse"];
43
+ export type ErrorResponse = components["schemas"]["ErrorResponse"];
44
+ export type BtcSignatureKind = components["schemas"]["BtcSignatureKind"];
45
+ /* eslint-enable */
46
+
47
+ /** MFA request kind */
48
+ export type MfaType = components["schemas"]["MfaType"];
49
+
50
+ type SignFn<U> = (headers?: HeadersInit) => Promise<U | AcceptedResponse>;
51
+
52
+ /**
53
+ * A response of a signing request.
54
+ */
55
+ export class SignResponse<U> {
56
+ readonly #cs: CubeSigner;
57
+ readonly #orgId: string;
58
+ readonly #signFn: SignFn<U>;
59
+ readonly #resp: U | AcceptedResponse;
60
+
61
+ /** @return {boolean} True if this signing request requires an MFA approval */
62
+ requiresMfa(): boolean {
63
+ return (this.#resp as AcceptedResponse).accepted?.MfaRequired !== undefined;
64
+ }
65
+
66
+ /** @return {U} The signed data */
67
+ data(): U {
68
+ return this.#resp as U;
69
+ }
70
+
71
+ /**
72
+ * Approves the MFA request using a given signer session and a TOTP code.
73
+ *
74
+ * Note: This only works for MFA requests that require a single approval.
75
+ *
76
+ * @param {SignerSession} session Signer session to use
77
+ * @param {string} code 6-digit TOTP code
78
+ * @return {SignResponse<U>} The result of signing with the approval
79
+ */
80
+ async approveTotp(session: SignerSession, code: string): Promise<SignResponse<U>> {
81
+ const mfaId = this.#mfaId();
82
+
83
+ const mfaApproval = await session.totpApprove(mfaId, code);
84
+ assert(mfaApproval.id === mfaId);
85
+ const mfaConf = mfaApproval.receipt?.confirmation;
86
+
87
+ if (!mfaConf) {
88
+ throw new Error("MfaRequest has not been approved yet");
89
+ }
90
+
91
+ return await this.#signWithMfaApproval(mfaConf!);
92
+ }
93
+
94
+ /**
95
+ * Approves the MFA request using CubeSigner's management session.
96
+ *
97
+ * Note: This only works for MFA requests that require a single approval.
98
+ *
99
+ * @return {SignResponse<U>} The result of signing with the approval
100
+ */
101
+ async approve(): Promise<SignResponse<U>> {
102
+ const mfaId = this.#mfaId();
103
+
104
+ const mfaApproval = await Org.mfaApprove(this.#cs, this.#orgId, mfaId);
105
+ assert(mfaApproval.id === mfaId);
106
+ const mfaConf = mfaApproval.receipt?.confirmation;
107
+
108
+ if (!mfaConf) {
109
+ throw new Error("MfaRequest has not been approved yet");
110
+ }
111
+
112
+ return await this.#signWithMfaApproval(mfaConf);
113
+ }
114
+
115
+ // --------------------------------------------------------------------------
116
+ // -- INTERNAL --------------------------------------------------------------
117
+ // --------------------------------------------------------------------------
118
+
119
+ /**
120
+ * Constructor.
121
+ *
122
+ * @param {CubeSigner} cs The CubeSigner instance to use for requests
123
+ * @param {string} orgId The org id of the corresponding signing request
124
+ * @param {SignFn} signFn The signing function that this response is from.
125
+ * This argument is used to resend requests with
126
+ * different headers if needed.
127
+ * @param {U | AcceptedResponse} resp The response as returned by the OpenAPI
128
+ * client.
129
+ */
130
+ constructor(cs: CubeSigner, orgId: string, signFn: SignFn<U>, resp: U | AcceptedResponse) {
131
+ this.#cs = cs;
132
+ this.#orgId = orgId;
133
+ this.#signFn = signFn;
134
+ this.#resp = resp;
135
+ }
136
+
137
+ /**
138
+ * @param {string} mfaConf MFA request approval confirmation code
139
+ * @return {Promise<SignResponse<U>>} The result of signing after MFA approval
140
+ */
141
+ async #signWithMfaApproval(mfaConf: string): Promise<SignResponse<U>> {
142
+ const mfaId = this.#mfaId();
143
+
144
+ const headers = {
145
+ "x-cubist-mfa-id": mfaId,
146
+ "x-cubist-mfa-confirmation": mfaConf,
147
+ };
148
+ return new SignResponse(this.#cs, this.#orgId, this.#signFn, await this.#signFn(headers));
149
+ }
150
+
151
+ /**
152
+ * @return {string} MFA id if MFA is required for this response; throws otherwise.
153
+ */
154
+ #mfaId(): string {
155
+ const mfaRequired = (this.#resp as AcceptedResponse).accepted?.MfaRequired;
156
+ if (!mfaRequired) {
157
+ throw new Error("Request does not require MFA approval");
158
+ }
159
+ return mfaRequired.id;
160
+ }
161
+ }
162
+
163
+ /** Signer session info. Can only be used to revoke a token, but not for authentication. */
164
+ export class SignerSessionInfo {
165
+ readonly #cs: CubeSigner;
166
+ readonly #orgId: string;
167
+ readonly #roleId: string;
168
+ readonly #sessionId: string;
169
+ public readonly purpose: string;
170
+
171
+ /** Revoke this token */
172
+ async revoke() {
173
+ await SignerSession.revoke(this.#cs, this.#orgId, this.#roleId, this.#sessionId);
174
+ }
175
+
176
+ // --------------------------------------------------------------------------
177
+ // -- INTERNAL --------------------------------------------------------------
178
+ // --------------------------------------------------------------------------
179
+
180
+ /**
181
+ * Internal constructor.
182
+ * @param {CubeSigner} cs CubeSigner instance to use when calling `revoke`
183
+ * @param {string} orgId Organization ID
184
+ * @param {string} roleId Role ID
185
+ * @param {string} hash The hash of the token; can be used for revocation but not for auth
186
+ * @param {string} purpose Session purpose
187
+ * @internal
188
+ */
189
+ constructor(cs: CubeSigner, orgId: string, roleId: string, hash: string, purpose: string) {
190
+ this.#cs = cs;
191
+ this.#orgId = orgId;
192
+ this.#roleId = roleId;
193
+ this.#sessionId = hash;
194
+ this.purpose = purpose;
195
+ }
196
+ }
197
+
198
+ /** Signer session. */
199
+ export class SignerSession {
200
+ readonly cs: CubeSigner;
201
+ sessionMgr: OidcSessionManager | SignerSessionManager;
202
+ readonly #orgId: string;
203
+
204
+ /**
205
+ * Returns the list of keys that this token grants access to.
206
+ * @return {Key[]} The list of keys.
207
+ */
208
+ async keys(): Promise<Key[]> {
209
+ const resp = await (
210
+ await this.sessionMgr.client()
211
+ ).get("/v0/org/{org_id}/token/keys", {
212
+ params: { path: { org_id: this.#orgId } },
213
+ parseAs: "json",
214
+ });
215
+ const data = assertOk(resp);
216
+ return data.keys.map((k: KeyInfo) => new Key(this.cs, this.#orgId, k));
217
+ }
218
+
219
+ /**
220
+ * Approve a pending MFA request using TOTP.
221
+ *
222
+ * @param {string} mfaId The MFA request to approve
223
+ * @param {string} code The TOTP code
224
+ * @return {Promise<MfaRequestInfo>} The current status of the MFA request
225
+ */
226
+ async totpApprove(mfaId: string, code: string): Promise<MfaRequestInfo> {
227
+ const resp = await (
228
+ await this.sessionMgr.client()
229
+ ).patch("/v0/org/{org_id}/mfa/{mfa_id}/totp", {
230
+ params: { path: { org_id: this.#orgId, mfa_id: mfaId } },
231
+ body: { code },
232
+ parseAs: "json",
233
+ });
234
+ return assertOk(resp);
235
+ }
236
+
237
+ /**
238
+ * Submit an EVM sign request.
239
+ * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
240
+ * @param {EvmSignRequest} req What to sign.
241
+ * @return {Promise<EvmSignResponse | AcceptedResponse>} Signature
242
+ */
243
+ async signEvm(key: Key | string, req: EvmSignRequest): Promise<SignResponse<EvmSignResponse>> {
244
+ const pubkey = typeof key === "string" ? (key as string) : key.materialId;
245
+ const sign = async (headers?: HeadersInit) => {
246
+ const resp = await (
247
+ await this.sessionMgr.client()
248
+ ).post("/v1/org/{org_id}/eth1/sign/{pubkey}", {
249
+ params: { path: { org_id: this.#orgId, pubkey } },
250
+ body: req,
251
+ headers,
252
+ parseAs: "json",
253
+ });
254
+ return assertOk(resp);
255
+ };
256
+ return new SignResponse(this.cs, this.#orgId, sign, await sign());
257
+ }
258
+
259
+ /**
260
+ * Submit an 'eth2' sign request.
261
+ * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
262
+ * @param {Eth2SignRequest} req What to sign.
263
+ * @return {Promise<Eth2SignResponse | AcceptedResponse>} Signature
264
+ */
265
+ async signEth2(key: Key | string, req: Eth2SignRequest): Promise<SignResponse<Eth2SignResponse>> {
266
+ const pubkey = typeof key === "string" ? (key as string) : key.materialId;
267
+ const sign = async (headers?: HeadersInit) => {
268
+ const resp = await (
269
+ await this.sessionMgr.client()
270
+ ).post("/v1/org/{org_id}/eth2/sign/{pubkey}", {
271
+ params: { path: { org_id: this.#orgId, pubkey } },
272
+ body: req,
273
+ headers,
274
+ parseAs: "json",
275
+ });
276
+ return assertOk(resp);
277
+ };
278
+ return new SignResponse(this.cs, this.#orgId, sign, await sign());
279
+ }
280
+
281
+ /**
282
+ * Sign a stake request.
283
+ * @param {Eth2StakeRequest} req The request to sign.
284
+ * @return {Promise<Eth2StakeResponse | AcceptedResponse>} The response.
285
+ */
286
+ async stake(req: Eth2StakeRequest): Promise<SignResponse<Eth2StakeResponse>> {
287
+ const sign = async (headers?: HeadersInit) => {
288
+ const resp = await (
289
+ await this.sessionMgr.client()
290
+ ).post("/v1/org/{org_id}/eth2/stake", {
291
+ params: { path: { org_id: this.#orgId } },
292
+ body: req,
293
+ headers,
294
+ parseAs: "json",
295
+ });
296
+ return assertOk(resp);
297
+ };
298
+ return new SignResponse(this.cs, this.#orgId, sign, await sign());
299
+ }
300
+
301
+ /**
302
+ * Sign an unstake request.
303
+ * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
304
+ * @param {Eth2UnstakeRequest} req The request to sign.
305
+ * @return {Promise<Eth2UnstakeResponse | AcceptedResponse>} The response.
306
+ */
307
+ async unstake(
308
+ key: Key | string,
309
+ req: Eth2UnstakeRequest,
310
+ ): Promise<SignResponse<Eth2UnstakeResponse>> {
311
+ const pubkey = typeof key === "string" ? (key as string) : key.materialId;
312
+ const sign = async (headers?: HeadersInit) => {
313
+ const resp = await (
314
+ await this.sessionMgr.client()
315
+ ).post("/v1/org/{org_id}/eth2/unstake/{pubkey}", {
316
+ params: { path: { org_id: this.#orgId, pubkey } },
317
+ body: req,
318
+ headers,
319
+ parseAs: "json",
320
+ });
321
+ return assertOk(resp);
322
+ };
323
+ return new SignResponse(this.cs, this.#orgId, sign, await sign());
324
+ }
325
+
326
+ /**
327
+ * Sign a raw blob.
328
+ * @param {Key | string} key The key to sign with (either {@link Key} or its ID).
329
+ * @param {BlobSignRequest} req What to sign
330
+ * @return {Promise<BlobSignResponse | AcceptedResponse>} The response.
331
+ */
332
+ async signBlob(key: Key | string, req: BlobSignRequest): Promise<SignResponse<BlobSignResponse>> {
333
+ const key_id = typeof key === "string" ? (key as string) : key.id;
334
+ const sign = async (headers?: HeadersInit) => {
335
+ const resp = await (
336
+ await this.sessionMgr.client()
337
+ ).post("/v1/org/{org_id}/blob/sign/{key_id}", {
338
+ params: {
339
+ path: { org_id: this.#orgId, key_id },
340
+ },
341
+ body: req,
342
+ headers,
343
+ parseAs: "json",
344
+ });
345
+ return assertOk(resp);
346
+ };
347
+ return new SignResponse(this.cs, this.#orgId, sign, await sign());
348
+ }
349
+
350
+ /**
351
+ * Sign a bitcoin message.
352
+ * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
353
+ * @param {BtcSignRequest} req What to sign
354
+ * @return {Promise<BtcSignResponse | AcceptedResponse>} The response.
355
+ */
356
+ async signBtc(key: Key | string, req: BtcSignRequest): Promise<SignResponse<BtcSignResponse>> {
357
+ const pubkey = typeof key === "string" ? (key as string) : key.materialId;
358
+ const sign = async (headers?: HeadersInit) => {
359
+ const resp = await (
360
+ await this.sessionMgr.client()
361
+ ).post("/v0/org/{org_id}/btc/sign/{pubkey}", {
362
+ params: {
363
+ path: { org_id: this.#orgId, pubkey },
364
+ },
365
+ body: req,
366
+ headers: headers,
367
+ parseAs: "json",
368
+ });
369
+ return assertOk(resp);
370
+ };
371
+ return new SignResponse(this.cs, this.#orgId, sign, await sign());
372
+ }
373
+
374
+ /**
375
+ * Sign a solana message.
376
+ * @param {Key | string} key The key to sign with (either {@link Key} or its material ID).
377
+ * @param {SolanaSignRequest} req What to sign
378
+ * @return {Promise<SolanaSignResponse | AcceptedResponse>} The response.
379
+ */
380
+ async signSolana(
381
+ key: Key | string,
382
+ req: SolanaSignRequest,
383
+ ): Promise<SignResponse<SolanaSignResponse>> {
384
+ const pubkey = typeof key === "string" ? (key as string) : key.materialId;
385
+ const sign = async (headers?: HeadersInit) => {
386
+ const resp = await (
387
+ await this.sessionMgr.client()
388
+ ).post("/v1/org/{org_id}/solana/sign/{pubkey}", {
389
+ params: { path: { org_id: this.#orgId, pubkey } },
390
+ body: req,
391
+ headers,
392
+ parseAs: "json",
393
+ });
394
+ return assertOk(resp);
395
+ };
396
+ return new SignResponse(this.cs, this.#orgId, sign, await sign());
397
+ }
398
+
399
+ /**
400
+ * Loads an existing signer session from storage.
401
+ * @param {CubeSigner} cs The CubeSigner instance
402
+ * @param {SignerSessionStorage} storage The session storage to use
403
+ * @return {Promise<SingerSession>} New signer session
404
+ */
405
+ static async loadSignerSession(
406
+ cs: CubeSigner,
407
+ storage: SignerSessionStorage,
408
+ ): Promise<SignerSession> {
409
+ const manager = await SignerSessionManager.loadFromStorage(cs, storage);
410
+ return new SignerSession(cs, manager);
411
+ }
412
+
413
+ /**
414
+ * Loads an existing OIDC session from storage
415
+ * @param {CubeSigner} cs The CubeSigner instance
416
+ * @param {OidcSessionStorage} storage The storage to use
417
+ * @return {Promise<SignerSession>} New signer session
418
+ */
419
+ static async loadOidcSession(
420
+ cs: CubeSigner,
421
+ storage: OidcSessionStorage,
422
+ ): Promise<SignerSession> {
423
+ const manager = await OidcSessionManager.loadFromStorage(storage);
424
+ return new SignerSession(cs, manager);
425
+ }
426
+
427
+ /**
428
+ * Constructor.
429
+ * @param {CubeSigner} cs The CubeSigner instance to use for requests
430
+ * @param {OidcSessionManager | SignerSessionManager} sessionMgr The session manager to use
431
+ * @internal
432
+ */
433
+ constructor(cs: CubeSigner, sessionMgr: OidcSessionManager | SignerSessionManager) {
434
+ this.cs = cs;
435
+ this.sessionMgr = sessionMgr;
436
+ this.#orgId = sessionMgr.orgId;
437
+ }
438
+
439
+ // --------------------------------------------------------------------------
440
+ // -- INTERNAL --------------------------------------------------------------
441
+ // --------------------------------------------------------------------------
442
+
443
+ /* eslint-disable require-jsdoc */
444
+
445
+ /**
446
+ * Static method for revoking a token (used both from {SignerSession} and {SignerSessionInfo}).
447
+ * @param {CubeSigner} cs CubeSigner instance
448
+ * @param {string} orgId Organization ID
449
+ * @param {string} roleId Role ID
450
+ * @param {string} sessionId Signer session ID
451
+ * @internal
452
+ */
453
+ static async revoke(cs: CubeSigner, orgId: string, roleId: string, sessionId: string) {
454
+ const resp = await (
455
+ await cs.management()
456
+ ).del("/v0/org/{org_id}/roles/{role_id}/tokens/{session_id}", {
457
+ params: {
458
+ path: { org_id: orgId, role_id: roleId, session_id: sessionId },
459
+ },
460
+ parseAs: "json",
461
+ });
462
+ assertOk(resp);
463
+ }
464
+ }