@tomo-inc/cubist-wallet-sdk 0.0.4

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.
@@ -0,0 +1,324 @@
1
+ import { CubeOrgIds, CubeStage, CubeStages } from "@tomo-inc/wallet-utils";
2
+ import { CubeExportService } from "./cube-export";
3
+ import { CubeSignerClient, SessionData, envs, getOidcClient, getOidcResp, proof } from "./cube-libs";
4
+ import { CubeMfaService } from "./cube-mfa";
5
+ import { CubeSignService } from "./cube-sign";
6
+
7
+ import { addUserToCube, updateUserInfo } from "./api";
8
+
9
+ import { CUBE_LIFETIME, CUBE_SALTS, CUBE_SCOPES, ISS_MAP, OIDC_TOKEN_LIFETIME } from "./const";
10
+ import {
11
+ AccountType,
12
+ ApiClient,
13
+ CubeConfig,
14
+ CubeIdentity,
15
+ CubeUserInfo,
16
+ FidoKey,
17
+ LoginRes,
18
+ MfaConfig,
19
+ MfaInfo,
20
+ MfaReceipt,
21
+ } from "./types";
22
+
23
+ import { cache } from "@tomo-inc/wallet-utils";
24
+
25
+ export class CubeAccountService {
26
+ public config: CubeConfig;
27
+ private static instance: CubeAccountService;
28
+ private jwtToken: string;
29
+ public accountData: any;
30
+
31
+ public cubeUserInfo: CubeUserInfo | null;
32
+ public cubeIdentity: CubeIdentity | null;
33
+ private cubeSession: SessionData | null;
34
+
35
+ public cubeSignerClient: CubeSignerClient | null;
36
+ public apiClient: ApiClient | null;
37
+
38
+ public cubeMfaService: CubeMfaService | null;
39
+ public cubeExportService: CubeExportService | null;
40
+
41
+ public accountWallet: any;
42
+ public cubeEnv: any;
43
+ public cubeOrgId: string;
44
+
45
+ public constructor(config: CubeConfig) {
46
+ this.jwtToken = "";
47
+ this.accountData = null;
48
+ this.cubeUserInfo = null;
49
+ this.cubeIdentity = null;
50
+ this.cubeSession = null;
51
+ this.cubeSignerClient = null;
52
+ this.apiClient = null;
53
+ this.cubeMfaService = null;
54
+ this.cubeExportService = null;
55
+ this.cubeOrgId = "";
56
+ this.config = config;
57
+ this.cubeEnv = null;
58
+ }
59
+
60
+ public static getInstance(config?: CubeConfig) {
61
+ if (CubeAccountService.instance) {
62
+ return CubeAccountService.instance;
63
+ }
64
+
65
+ if (!config?.tomoStage || !CubeStages[config?.tomoStage]) {
66
+ throw new Error("tomoStage not 'dev' or 'pre' or 'prod'");
67
+ }
68
+
69
+ const cubeSalt = CUBE_SALTS[config?.tomoStage];
70
+ if (!cubeSalt) {
71
+ throw new Error("cubeSalt is required");
72
+ }
73
+
74
+ const cubeStage = CubeStages[config?.tomoStage] as CubeStage;
75
+ const env = envs[cubeStage];
76
+ const cubeOrgId = CubeOrgIds[config?.tomoStage];
77
+
78
+ CubeAccountService.instance = new CubeAccountService({ ...config, cubeSalt, cubeStage });
79
+ CubeAccountService.instance.cubeEnv = env;
80
+ CubeAccountService.instance.cubeOrgId = cubeOrgId;
81
+ return CubeAccountService.instance;
82
+ }
83
+
84
+ //no api dependency
85
+ public async getCubeIdentity(): Promise<CubeIdentity | null> {
86
+ const oidcToken = this?.config?.oidcToken;
87
+ if (!oidcToken) {
88
+ const cubeIdentityCache = await cache.get("cubeIdentity");
89
+ if (cubeIdentityCache) {
90
+ this.cubeIdentity = cubeIdentityCache;
91
+ return this.cubeIdentity;
92
+ }
93
+ console.warn("oidcToken is required");
94
+ return null;
95
+ }
96
+ const cubeOrgId = this.cubeOrgId;
97
+ const cubeIdentity: any = await proof(oidcToken, this.cubeEnv, cubeOrgId);
98
+ await cache.set("cubeIdentity", cubeIdentity, false);
99
+ this.cubeIdentity = cubeIdentity;
100
+ return cubeIdentity;
101
+ }
102
+
103
+ //login + reg new user by wallet-api
104
+ public async loginOrRegister(oidcToken: string, options?: any): Promise<LoginRes> {
105
+ this.config = { ...this.config, oidcToken };
106
+ const cubeIdentity = await this.getCubeIdentity();
107
+
108
+ const req = {
109
+ cubistUserID: cubeIdentity?.user_info?.user_id,
110
+ aud: cubeIdentity?.aud,
111
+ email: cubeIdentity?.email || options?.email || null, //must null
112
+ iss: cubeIdentity?.identity?.iss,
113
+ sub: cubeIdentity?.identity?.sub,
114
+ initialized: cubeIdentity?.user_info?.initialized,
115
+ };
116
+
117
+ //add user by tomo api, return userInfo + tomo jwt token + all wallet address
118
+ const accountData = await addUserToCube(req, this.config);
119
+ const { userToken, user, accountBaseInfo, accountWallet } = accountData;
120
+ this.accountData = accountData;
121
+ this.accountWallet = accountWallet;
122
+ this.jwtToken = userToken.accessToken;
123
+ return {
124
+ user: { userId: user.userID, nickname: user.nickname, avatar: user.avatar },
125
+ accountBaseInfo,
126
+ accountWallet,
127
+ walletId: accountWallet?.walletID,
128
+ };
129
+ }
130
+
131
+ public async updateUserInfo(userInfo: { nickname: string; avatar: `https://${string}` }): Promise<boolean> {
132
+ const nickname = userInfo.nickname.trim();
133
+ if (nickname.length < 6 || nickname.length > 20) {
134
+ throw new Error("name length 6~20");
135
+ }
136
+ const config = { ...this.config, jwtToken: this.jwtToken };
137
+ const result = await updateUserInfo(userInfo, config);
138
+ return result;
139
+ }
140
+
141
+ /*
142
+ all functions below must after loginOrRegister
143
+ user only can user cube apis after added by org manager with loginOrRegister
144
+ cube session = loginOrRegister + cube connected
145
+ */
146
+ public async createSessionByOidcToken(oidcToken: string): Promise<boolean> {
147
+ oidcToken = oidcToken || this?.config?.oidcToken || "";
148
+ if (!oidcToken) {
149
+ console.warn("oidcToken is required");
150
+ return false;
151
+ }
152
+ const scopes = CUBE_SCOPES as any;
153
+ const oidcSessionResp = await getOidcResp(oidcToken, this.cubeEnv, this.cubeOrgId, OIDC_TOKEN_LIFETIME, scopes);
154
+ const cubeSession: any = oidcSessionResp.data();
155
+ this.setCubeSession(cubeSession as SessionData);
156
+ return !!cubeSession;
157
+ }
158
+
159
+ //with mfa
160
+ public async createSession(receipt?: MfaReceipt): Promise<MfaInfo | null | SessionData> {
161
+ const purpose = "wallet_operations";
162
+ const oidcSessionResp = await this.apiClient.sessionCreateExtended(purpose, CUBE_SCOPES, CUBE_LIFETIME, receipt);
163
+ if (oidcSessionResp.requiresMfa()) {
164
+ return (await this.cubeMfaService?.getMfaInfo("createSession")) || null;
165
+ }
166
+
167
+ const cubeSession: any = oidcSessionResp.data();
168
+ this.setCubeSession(cubeSession as SessionData);
169
+ return cubeSession;
170
+ }
171
+
172
+ public async refreshSession(): Promise<boolean> {
173
+ const purpose = "wallet_operations";
174
+ const oidcSessionResp = await this.apiClient.sessionCreate(purpose, CUBE_SCOPES, CUBE_LIFETIME);
175
+ const cubeSession: any = oidcSessionResp.data();
176
+ this.setCubeSession(cubeSession as SessionData);
177
+ return !!cubeSession;
178
+ }
179
+
180
+ public getCubeSession(): SessionData | null {
181
+ return this.cubeSession;
182
+ }
183
+
184
+ private setCubeSession(cubeSession: SessionData): void {
185
+ this.cubeSession = cubeSession;
186
+ }
187
+
188
+ public sessionRevoke(): void {
189
+ const apiClient = this.apiClient;
190
+ this.cubeSession = null;
191
+ apiClient?.sessionRevoke();
192
+ }
193
+
194
+ private async refreshCubeClient(cubeSession: SessionData): Promise<void> {
195
+ try {
196
+ await this.createCubeSignerClient(cubeSession);
197
+ this.initSubServices();
198
+ } catch (error) {
199
+ console.error("refreshCubeClient error", error);
200
+ }
201
+ }
202
+
203
+ private async createCubeSignerClient(session: SessionData): Promise<CubeSignerClient> {
204
+ const cubeSignerClient = await CubeSignerClient.create(session as any);
205
+ this.cubeSignerClient = cubeSignerClient;
206
+ this.apiClient = this.cubeSignerClient.apiClient;
207
+ return cubeSignerClient;
208
+ }
209
+
210
+ public async getOidcClient(receipt?: MfaReceipt): Promise<any> {
211
+ const oidcToken = this?.config?.oidcToken || "";
212
+ if (!oidcToken) {
213
+ console.warn("oidcToken is required");
214
+ return;
215
+ }
216
+ const scopes = CUBE_SCOPES as any;
217
+ const cubeSignerClient: any = await getOidcClient(
218
+ oidcToken,
219
+ this.cubeEnv,
220
+ this.cubeOrgId,
221
+ OIDC_TOKEN_LIFETIME,
222
+ scopes,
223
+ receipt,
224
+ );
225
+ return cubeSignerClient;
226
+ }
227
+
228
+ private async autoLogin(session: SessionData): Promise<void> {
229
+ await this.refreshCubeClient(session);
230
+ await this.setCubeSession(session);
231
+ }
232
+
233
+ public async init(oidcToken?: string): Promise<boolean> {
234
+ oidcToken = oidcToken || this?.config?.oidcToken || "";
235
+ if (!oidcToken) {
236
+ console.warn("oidcToken is required");
237
+ return false;
238
+ }
239
+ try {
240
+ this.config = { ...this.config, oidcToken };
241
+ const cubeSignerClient: CubeSignerClient = await this.getOidcClient();
242
+ this.cubeSignerClient = cubeSignerClient;
243
+ this.apiClient = this.cubeSignerClient.apiClient;
244
+
245
+ const result = await this.createSessionByOidcToken(oidcToken);
246
+ if (!result) {
247
+ throw new Error("create session by oidc token failed");
248
+ }
249
+ this.initSubServices();
250
+ return true;
251
+ } catch (error) {
252
+ console.error("init error", error);
253
+ throw error;
254
+ }
255
+ }
256
+
257
+ public async initSubServices(): Promise<void> {
258
+ const cubeMfaService = CubeMfaService.getInstance();
259
+ this.cubeMfaService = cubeMfaService.init(this);
260
+
261
+ const cubeExportService = CubeExportService.getInstance();
262
+ this.cubeExportService = cubeExportService.init(this);
263
+ }
264
+
265
+ public async initCubeSignService(): Promise<CubeSignService> {
266
+ const cubeSession = this.getCubeSession();
267
+ const cubeSignService = CubeSignService.getInstance();
268
+ await cubeSignService.init({ cubeSession });
269
+ return cubeSignService;
270
+ }
271
+
272
+ public async getCubeUserInfo(): Promise<CubeUserInfo | null> {
273
+ try {
274
+ const cubeUserInfo: CubeUserInfo = await this.apiClient?.userGet();
275
+ this.cubeUserInfo = cubeUserInfo;
276
+ return cubeUserInfo;
277
+ } catch (error) {
278
+ return null;
279
+ }
280
+ }
281
+
282
+ public async getMfaConfig(): Promise<MfaConfig> {
283
+ const [cubeUserInfo, cubeIdentity]: [CubeUserInfo | null, CubeIdentity | null] = await Promise.all([
284
+ this.getCubeUserInfo(),
285
+ this.getCubeIdentity(),
286
+ ]);
287
+
288
+ const name = cubeUserInfo?.name || cubeIdentity?.preferred_username || "";
289
+ const iss = cubeIdentity?.identity?.iss || "";
290
+ const accountType: AccountType = ISS_MAP?.[iss as keyof typeof ISS_MAP] || "email";
291
+
292
+ const verifiedEmail = cubeUserInfo?.verified_email?.email || "";
293
+ const email = cubeUserInfo?.email || "";
294
+ const emailOtpEnabled = verifiedEmail !== "" || email !== "";
295
+
296
+ const configuredMfa = cubeUserInfo?.mfa || [];
297
+ const fidos: FidoKey[] = configuredMfa.filter((item) => item.type === "fido");
298
+ const totp = configuredMfa.filter((item) => item.type === "totp");
299
+
300
+ return {
301
+ noMfa: !emailOtpEnabled && fidos.length === 0 && totp.length === 0,
302
+ hasMfa: emailOtpEnabled || fidos.length > 0 || totp.length > 0,
303
+ account: {
304
+ name,
305
+ email,
306
+ otpEmail: verifiedEmail,
307
+ accountType,
308
+ userId: cubeUserInfo?.user_id || "",
309
+ },
310
+ emailOtp: {
311
+ data: email || verifiedEmail,
312
+ enabled: emailOtpEnabled,
313
+ },
314
+ fido: {
315
+ data: fidos,
316
+ enabled: fidos.length > 0,
317
+ },
318
+ totp: {
319
+ data: totp[0],
320
+ enabled: totp.length > 0,
321
+ },
322
+ };
323
+ }
324
+ }
@@ -0,0 +1,22 @@
1
+ import { CubeConfig } from "types";
2
+ import { CubeAccountService } from "./cube-account";
3
+
4
+ export const CubeConnect = async (config: CubeConfig) => {
5
+ const cubeAccount = CubeAccountService.getInstance(config);
6
+
7
+ if (!config.oidcToken) {
8
+ throw new Error("oidcToken is required");
9
+ }
10
+
11
+ await cubeAccount.loginOrRegister(config.oidcToken);
12
+ await cubeAccount.init(config.oidcToken);
13
+
14
+ const cubeMfaService = cubeAccount.cubeMfaService;
15
+ const cubeExportService = cubeAccount.cubeExportService;
16
+
17
+ return {
18
+ cubeAccount,
19
+ cubeMfa: cubeMfaService,
20
+ cubeExport: cubeExportService,
21
+ };
22
+ };
@@ -0,0 +1,125 @@
1
+ import { EXPORT_KEY_PREFIX } from "./const";
2
+ import { CubeSignerClient, userExportDecrypt, userExportKeygen } from "./cube-libs";
3
+ import { CubeAccountService } from "./cube-account";
4
+
5
+ import { CubeRes, MfaInfo, MfaReceipt, SeedPhrase, SeedPhraseExportInfo } from "./types";
6
+
7
+ export class CubeExportService {
8
+ private static instance: CubeExportService;
9
+
10
+ private cubeAccountService: CubeAccountService | null;
11
+ private cubeSignerClient: CubeSignerClient | null;
12
+
13
+ private seedPhraseKey: string;
14
+ private exportKey: any;
15
+
16
+ public constructor() {
17
+ this.seedPhraseKey = "";
18
+ this.cubeAccountService = null;
19
+ this.cubeSignerClient = null;
20
+ this.exportKey = null;
21
+ userExportKeygen().then((key) => {
22
+ this.exportKey = key;
23
+ });
24
+ }
25
+
26
+ public static getInstance() {
27
+ if (!CubeExportService.instance) {
28
+ CubeExportService.instance = new CubeExportService();
29
+ }
30
+ return CubeExportService.instance;
31
+ }
32
+
33
+ public init(cubeAccountService: CubeAccountService) {
34
+ this.cubeAccountService = cubeAccountService;
35
+ this.cubeSignerClient = cubeAccountService.cubeSignerClient;
36
+ return this;
37
+ }
38
+
39
+ public async getExportKey(): Promise<string> {
40
+ if (this.seedPhraseKey) {
41
+ return this.seedPhraseKey;
42
+ }
43
+ const sessionKeys: any[] = (await this.cubeSignerClient?.sessionKeys()) || [];
44
+ const key: any = sessionKeys.find((key) => key?.id.indexOf(EXPORT_KEY_PREFIX) === 0);
45
+ this.seedPhraseKey = key?.id || "";
46
+ return this.seedPhraseKey;
47
+ }
48
+
49
+ public async getExportInfo(): Promise<SeedPhraseExportInfo | null> {
50
+ if (!this.cubeSignerClient) {
51
+ return null;
52
+ }
53
+ const keyId = await this.getExportKey();
54
+ const exports = this.cubeSignerClient?.org()?.exports(keyId);
55
+ const exportData = await exports?.fetch();
56
+
57
+ if (exportData?.length === 0) {
58
+ return { ready: true };
59
+ }
60
+
61
+ const { valid_epoch = 0, exp_epoch = 0 } = exportData[0];
62
+ let lastTime = valid_epoch - Date.now() / 1000;
63
+ lastTime = Math.max(Math.ceil(lastTime), 0);
64
+ const duration = exp_epoch - valid_epoch;
65
+ return {
66
+ ready: true,
67
+ keyId,
68
+ lastTime,
69
+ duration,
70
+ valid_epoch,
71
+ exp_epoch,
72
+ };
73
+ }
74
+
75
+ public async initExport(receipt?: MfaReceipt): Promise<MfaInfo | null> {
76
+ if (!this.cubeSignerClient || !this.cubeAccountService) {
77
+ throw new Error("cubeSignerClient is not initialized");
78
+ }
79
+ const keyId = await this.getExportKey();
80
+ const initExportResp: any = await this.cubeSignerClient.org().initExport(keyId, receipt);
81
+
82
+ if (initExportResp.requiresMfa()) {
83
+ return (await this.cubeAccountService?.cubeMfaService?.getMfaInfo("initExport")) || null;
84
+ }
85
+
86
+ return initExportResp.data();
87
+ }
88
+
89
+ public async completeExport(receipt?: MfaReceipt): Promise<MfaInfo | SeedPhrase | null> {
90
+ if (!this.cubeSignerClient || !this.cubeAccountService) {
91
+ throw new Error("cubeSignerClient is not initialized");
92
+ }
93
+ const keyId = await this.getExportKey();
94
+
95
+ const exportResp: any = await this.cubeSignerClient.org().completeExport(keyId, this.exportKey.publicKey, receipt);
96
+ if (exportResp.requiresMfa()) {
97
+ return (await this.cubeAccountService?.cubeMfaService?.getMfaInfo("completeExport")) || null;
98
+ }
99
+
100
+ const encryptedData = exportResp.data();
101
+ const seedPhrase: SeedPhrase = await userExportDecrypt(this.exportKey.privateKey, encryptedData);
102
+ return seedPhrase;
103
+ }
104
+
105
+ public async deleteExport(): Promise<CubeRes> {
106
+ if (!this.cubeSignerClient || !this.cubeAccountService) {
107
+ throw new Error("cubeSignerClient is not initialized");
108
+ }
109
+
110
+ try {
111
+ const keyId = await this.getExportKey();
112
+ const res = await this.cubeSignerClient.org().deleteExport(keyId);
113
+ return {
114
+ success: true,
115
+ data: res,
116
+ };
117
+ } catch (error: any) {
118
+ return {
119
+ success: false,
120
+ message: error?.message || "delete export error",
121
+ error,
122
+ };
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,29 @@
1
+ import { CubeSignerClient, SessionData, envs, userExportDecrypt, userExportKeygen } from "@cubist-labs/cubesigner-sdk";
2
+
3
+ export { CubeSignerClient, envs, userExportDecrypt, userExportKeygen };
4
+ export type { SessionData };
5
+
6
+ import {
7
+ getOidcClient,
8
+ getOidcResp,
9
+ getOidcUserInfoSession,
10
+ emailLogin as loginToCubeByEmail,
11
+ proof,
12
+ } from "@tomo-inc/cubist-sig-sdk";
13
+ export { getOidcClient, getOidcResp, getOidcUserInfoSession, loginToCubeByEmail, proof };
14
+
15
+ export {
16
+ getKeys,
17
+ signDogeMessage,
18
+ signDogePsbt,
19
+ signEvmMessage,
20
+ signEvmTransaction,
21
+ signEvmTypedData,
22
+ signSolanaMessage,
23
+ signSolanaTransaction,
24
+ signTronMessage,
25
+ signTronRawTransaction,
26
+ signTronTypeDaya,
27
+ } from "@tomo-inc/cubist-sig-sdk";
28
+
29
+ export type { TypedData } from "@tomo-inc/cubist-sig-sdk";