@tomo-inc/cubist-wallet-sdk 0.0.5 → 0.0.7
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.
- package/dist/index.cjs +1271 -0
- package/dist/index.d.cts +422 -0
- package/dist/index.d.ts +422 -0
- package/dist/index.js +1250 -0
- package/package.json +3 -3
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1271 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var walletUtils = require('@tomo-inc/wallet-utils');
|
|
4
|
+
var cubesignerSdk = require('@cubist-labs/cubesigner-sdk');
|
|
5
|
+
var cubistSigSdk = require('@tomo-inc/cubist-sig-sdk');
|
|
6
|
+
var axios = require('axios');
|
|
7
|
+
var CryptoJS = require('crypto-js');
|
|
8
|
+
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
12
|
+
var CryptoJS__default = /*#__PURE__*/_interopDefault(CryptoJS);
|
|
13
|
+
|
|
14
|
+
// src/cube-account.ts
|
|
15
|
+
|
|
16
|
+
// src/const.ts
|
|
17
|
+
var SEED_PHRASE_EXPORT_DURATION = 48;
|
|
18
|
+
var EXPORT_TIME_FORMAT = "yyyy-MM-dd hh:mm:ss";
|
|
19
|
+
var OIDC_TOKEN_LIFETIME = 30 * 24 * 60 * 60;
|
|
20
|
+
var CUBE_LIFETIME = {
|
|
21
|
+
auth: OIDC_TOKEN_LIFETIME,
|
|
22
|
+
refresh: OIDC_TOKEN_LIFETIME * 2
|
|
23
|
+
};
|
|
24
|
+
var CUBE_SCOPES = [
|
|
25
|
+
"sign:*",
|
|
26
|
+
"export:*",
|
|
27
|
+
"manage:session:extend",
|
|
28
|
+
"manage:mfa:*",
|
|
29
|
+
"manage:mfa:register:email",
|
|
30
|
+
"manage:mfa:register:fido",
|
|
31
|
+
"manage:mfa:unregister:fido",
|
|
32
|
+
"manage:mfa:register:totp",
|
|
33
|
+
"manage:mfa:unregister:totp",
|
|
34
|
+
"manage:export:user:delete",
|
|
35
|
+
"manage:export:user:list"
|
|
36
|
+
];
|
|
37
|
+
var EXPORT_KEY_PREFIX = "Key#Mnemonic_";
|
|
38
|
+
var ISS_MAP = {
|
|
39
|
+
"https://accounts.google.com": "google",
|
|
40
|
+
"https://shim.oauth2.cubist.dev/twitter": "x"
|
|
41
|
+
};
|
|
42
|
+
var CUBE_SALTS = {
|
|
43
|
+
prod: "xnPWRJT5XG2WyevuydMjMpZq",
|
|
44
|
+
pre: "xnPWRJT5XG2WyevuydMjMpZq",
|
|
45
|
+
dev: "dev@tomo"
|
|
46
|
+
};
|
|
47
|
+
var getMfaInfoConfig = (cubeStage) => {
|
|
48
|
+
const lastTime = cubeStage === "prod" ? 172800 : 300;
|
|
49
|
+
const AllowedMfaTypes = {
|
|
50
|
+
Login: ["Fido", "EmailOtp", "Totp"],
|
|
51
|
+
RegisterMfa: ["Fido", `EmailOtp#${lastTime}`, "Totp"],
|
|
52
|
+
Export: ["Fido", "Totp"]
|
|
53
|
+
};
|
|
54
|
+
const MfaRequestConfig = {
|
|
55
|
+
createSession: {
|
|
56
|
+
method: "POST",
|
|
57
|
+
path: "/session/",
|
|
58
|
+
_allowed_mfa_types: AllowedMfaTypes.Login
|
|
59
|
+
},
|
|
60
|
+
addFido: {
|
|
61
|
+
method: "POST",
|
|
62
|
+
path: "/user/me/fido/",
|
|
63
|
+
_allowed_mfa_types: AllowedMfaTypes.RegisterMfa
|
|
64
|
+
},
|
|
65
|
+
deleteFido: {
|
|
66
|
+
method: "DELETE",
|
|
67
|
+
path: "/user/me/fido/",
|
|
68
|
+
_allowed_mfa_types: AllowedMfaTypes.RegisterMfa
|
|
69
|
+
},
|
|
70
|
+
registerTotp: {
|
|
71
|
+
method: "POST",
|
|
72
|
+
path: "/user/me/totp/",
|
|
73
|
+
_allowed_mfa_types: AllowedMfaTypes.RegisterMfa
|
|
74
|
+
},
|
|
75
|
+
deleteTotp: {
|
|
76
|
+
method: "DELETE",
|
|
77
|
+
path: "/user/me/totp/",
|
|
78
|
+
_allowed_mfa_types: AllowedMfaTypes.RegisterMfa
|
|
79
|
+
},
|
|
80
|
+
registerEmailOtp: {
|
|
81
|
+
method: "POST",
|
|
82
|
+
path: "/user/me/email/",
|
|
83
|
+
_allowed_mfa_types: AllowedMfaTypes.RegisterMfa
|
|
84
|
+
},
|
|
85
|
+
initExport: {
|
|
86
|
+
method: "POST",
|
|
87
|
+
path: "/user/me/export/",
|
|
88
|
+
_allowed_mfa_types: AllowedMfaTypes.Export
|
|
89
|
+
},
|
|
90
|
+
completeExport: {
|
|
91
|
+
method: "PATCH",
|
|
92
|
+
path: "/user/me/export/",
|
|
93
|
+
_allowed_mfa_types: AllowedMfaTypes.Export
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
return MfaRequestConfig;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// src/cube-export.ts
|
|
100
|
+
var CubeExportService = class _CubeExportService {
|
|
101
|
+
constructor() {
|
|
102
|
+
this.seedPhraseKey = "";
|
|
103
|
+
this.cubeAccountService = null;
|
|
104
|
+
this.cubeSignerClient = null;
|
|
105
|
+
this.exportKey = null;
|
|
106
|
+
cubesignerSdk.userExportKeygen().then((key) => {
|
|
107
|
+
this.exportKey = key;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
static getInstance() {
|
|
111
|
+
if (!_CubeExportService.instance) {
|
|
112
|
+
_CubeExportService.instance = new _CubeExportService();
|
|
113
|
+
}
|
|
114
|
+
return _CubeExportService.instance;
|
|
115
|
+
}
|
|
116
|
+
init(cubeAccountService) {
|
|
117
|
+
this.cubeAccountService = cubeAccountService;
|
|
118
|
+
this.cubeSignerClient = cubeAccountService.cubeSignerClient;
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
async getExportKey() {
|
|
122
|
+
if (this.seedPhraseKey) {
|
|
123
|
+
return this.seedPhraseKey;
|
|
124
|
+
}
|
|
125
|
+
const sessionKeys = await this.cubeSignerClient?.sessionKeys() || [];
|
|
126
|
+
const key = sessionKeys.find((key2) => key2?.id.indexOf(EXPORT_KEY_PREFIX) === 0);
|
|
127
|
+
this.seedPhraseKey = key?.id || "";
|
|
128
|
+
return this.seedPhraseKey;
|
|
129
|
+
}
|
|
130
|
+
async getExportInfo() {
|
|
131
|
+
if (!this.cubeSignerClient) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const keyId = await this.getExportKey();
|
|
135
|
+
const exports$1 = this.cubeSignerClient?.org()?.exports(keyId);
|
|
136
|
+
const exportData = await exports$1?.fetch();
|
|
137
|
+
if (exportData?.length === 0) {
|
|
138
|
+
return { ready: true };
|
|
139
|
+
}
|
|
140
|
+
const { valid_epoch = 0, exp_epoch = 0 } = exportData[0];
|
|
141
|
+
let lastTime = valid_epoch - Date.now() / 1e3;
|
|
142
|
+
lastTime = Math.max(Math.ceil(lastTime), 0);
|
|
143
|
+
const duration = exp_epoch - valid_epoch;
|
|
144
|
+
return {
|
|
145
|
+
ready: true,
|
|
146
|
+
keyId,
|
|
147
|
+
lastTime,
|
|
148
|
+
duration,
|
|
149
|
+
valid_epoch,
|
|
150
|
+
exp_epoch
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async initExport(receipt) {
|
|
154
|
+
if (!this.cubeSignerClient || !this.cubeAccountService) {
|
|
155
|
+
throw new Error("cubeSignerClient is not initialized");
|
|
156
|
+
}
|
|
157
|
+
const keyId = await this.getExportKey();
|
|
158
|
+
const initExportResp = await this.cubeSignerClient.org().initExport(keyId, receipt);
|
|
159
|
+
if (initExportResp.requiresMfa()) {
|
|
160
|
+
return await this.cubeAccountService?.cubeMfaService?.getMfaInfo("initExport") || null;
|
|
161
|
+
}
|
|
162
|
+
return initExportResp.data();
|
|
163
|
+
}
|
|
164
|
+
async completeExport(receipt) {
|
|
165
|
+
if (!this.cubeSignerClient || !this.cubeAccountService) {
|
|
166
|
+
throw new Error("cubeSignerClient is not initialized");
|
|
167
|
+
}
|
|
168
|
+
const keyId = await this.getExportKey();
|
|
169
|
+
const exportResp = await this.cubeSignerClient.org().completeExport(keyId, this.exportKey.publicKey, receipt);
|
|
170
|
+
if (exportResp.requiresMfa()) {
|
|
171
|
+
return await this.cubeAccountService?.cubeMfaService?.getMfaInfo("completeExport") || null;
|
|
172
|
+
}
|
|
173
|
+
const encryptedData = exportResp.data();
|
|
174
|
+
const seedPhrase = await cubesignerSdk.userExportDecrypt(this.exportKey.privateKey, encryptedData);
|
|
175
|
+
return seedPhrase;
|
|
176
|
+
}
|
|
177
|
+
async deleteExport() {
|
|
178
|
+
if (!this.cubeSignerClient || !this.cubeAccountService) {
|
|
179
|
+
throw new Error("cubeSignerClient is not initialized");
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const keyId = await this.getExportKey();
|
|
183
|
+
const res = await this.cubeSignerClient.org().deleteExport(keyId);
|
|
184
|
+
return {
|
|
185
|
+
success: true,
|
|
186
|
+
data: res
|
|
187
|
+
};
|
|
188
|
+
} catch (error) {
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
message: error?.message || "delete export error",
|
|
192
|
+
error
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
var RELAY_NAME = "passkey-relay";
|
|
198
|
+
var SENDER_NAME = "cubist-sdk";
|
|
199
|
+
var passkeyRelayWindow = null;
|
|
200
|
+
var openWindow = ({ url, name, width, height }) => {
|
|
201
|
+
const RN = window.ReactNativeWebView;
|
|
202
|
+
if (RN) {
|
|
203
|
+
const message = {
|
|
204
|
+
url,
|
|
205
|
+
name
|
|
206
|
+
};
|
|
207
|
+
RN.postMessage(
|
|
208
|
+
JSON.stringify({
|
|
209
|
+
type: "OPEN_PASSKEY_RELAY",
|
|
210
|
+
message
|
|
211
|
+
})
|
|
212
|
+
);
|
|
213
|
+
return {
|
|
214
|
+
closed: false,
|
|
215
|
+
postMessage: (message2) => {
|
|
216
|
+
RN.postMessage(
|
|
217
|
+
JSON.stringify({
|
|
218
|
+
type: "PASSKEY_RELAY_MESSAGE",
|
|
219
|
+
message: message2
|
|
220
|
+
})
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const top = (window.innerHeight - (height)) / 2 + window.screenY;
|
|
226
|
+
const left = (window.innerWidth - (width)) / 2 + window.screenX;
|
|
227
|
+
try {
|
|
228
|
+
const relyWindow = window.open(
|
|
229
|
+
url,
|
|
230
|
+
name,
|
|
231
|
+
`dialog=yes,top=${top}px,left=${left},width=${width !== void 0 ? width : 400}px,height=${height !== void 0 ? height : 600}px`
|
|
232
|
+
);
|
|
233
|
+
if (!relyWindow) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
return relyWindow;
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error("Failed to open window:", error);
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var closeWindow = () => {
|
|
243
|
+
try {
|
|
244
|
+
if (passkeyRelayWindow && !passkeyRelayWindow.closed) {
|
|
245
|
+
passkeyRelayWindow.close();
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error("Failed to close window:", error);
|
|
249
|
+
} finally {
|
|
250
|
+
passkeyRelayWindow = null;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
var sendPasskeyMessage = async (message, tomoStage) => {
|
|
254
|
+
if (passkeyRelayWindow === null) {
|
|
255
|
+
throw new Error("Failed to open relay window");
|
|
256
|
+
}
|
|
257
|
+
const origin = walletUtils.RelayOrigins[tomoStage] || walletUtils.RelayOrigins["dev"];
|
|
258
|
+
passkeyRelayWindow.postMessage({ ...message, from: SENDER_NAME }, origin);
|
|
259
|
+
};
|
|
260
|
+
var initPasskeyPage = async (config) => {
|
|
261
|
+
return new Promise((resolve, reject) => {
|
|
262
|
+
config = config || walletUtils.cache.get("cubeConfig");
|
|
263
|
+
if (!config.oidcToken || !config.tomoClientId) {
|
|
264
|
+
reject({ message: "oidcToken/tomoClientId is required" });
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const PASSKEY_ORIGIN = walletUtils.RelayOrigins[config.tomoStage];
|
|
268
|
+
if (!PASSKEY_ORIGIN) {
|
|
269
|
+
reject({ message: "tomoStage must be dev/pre/prod." });
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
passkeyRelayWindow = openWindow({
|
|
273
|
+
url: `${PASSKEY_ORIGIN}/passkey?origin=${window.location.origin}`,
|
|
274
|
+
name: "relay-passkey",
|
|
275
|
+
width: 400,
|
|
276
|
+
height: 600
|
|
277
|
+
});
|
|
278
|
+
const handleMessage = (event) => {
|
|
279
|
+
const { type, data, from, error } = event.data;
|
|
280
|
+
if (type === "passkey-relay-loaded" && from === RELAY_NAME) {
|
|
281
|
+
sendPasskeyMessage({ type: "init", params: config }, config.tomoStage);
|
|
282
|
+
}
|
|
283
|
+
if (type === "passkey-relay-init" && from === RELAY_NAME) {
|
|
284
|
+
window.removeEventListener("message", handleMessage);
|
|
285
|
+
resolve(data);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
window.addEventListener("message", handleMessage);
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
var addPasskey = async (params, config) => {
|
|
292
|
+
if (!passkeyRelayWindow) {
|
|
293
|
+
await initPasskeyPage(config);
|
|
294
|
+
}
|
|
295
|
+
return new Promise((resolve, reject) => {
|
|
296
|
+
const handleMessage = (event) => {
|
|
297
|
+
const { type, data, from, error } = event.data;
|
|
298
|
+
if (type === "passkey-relay-addFido" && from === RELAY_NAME) {
|
|
299
|
+
window.removeEventListener("message", handleMessage);
|
|
300
|
+
resolve(data);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
window.addEventListener("message", handleMessage);
|
|
304
|
+
sendPasskeyMessage({ type: "addFido", params }, config.tomoStage);
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
var verifyPasskey = async (params, config) => {
|
|
308
|
+
if (!passkeyRelayWindow) {
|
|
309
|
+
await initPasskeyPage(config);
|
|
310
|
+
}
|
|
311
|
+
return new Promise((resolve, reject) => {
|
|
312
|
+
const handleMessage = (event) => {
|
|
313
|
+
const { type, data: receipt, from, error } = event.data;
|
|
314
|
+
if (type === "passkey-relay-verify" && from === RELAY_NAME) {
|
|
315
|
+
window.removeEventListener("message", handleMessage);
|
|
316
|
+
resolve(receipt);
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
window.addEventListener("message", handleMessage);
|
|
320
|
+
sendPasskeyMessage({ type: "verify", params }, config.tomoStage);
|
|
321
|
+
});
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/utils.ts
|
|
325
|
+
var applyLocalDevFixes = (type, challenge, { userId, rpId, fidoName }) => {
|
|
326
|
+
rpId = rpId || window.location.hostname;
|
|
327
|
+
const { host, protocol } = window.location;
|
|
328
|
+
const isNotHttp = protocol !== "https:" && protocol !== "http:";
|
|
329
|
+
const isLocal = host.indexOf("localhost:") === 0;
|
|
330
|
+
challenge.options = challenge?.options || {};
|
|
331
|
+
challenge.options.rp = challenge.options.rp || {};
|
|
332
|
+
challenge.options.rp.id = rpId;
|
|
333
|
+
challenge.options.rpId = rpId;
|
|
334
|
+
if (isNotHttp || isLocal) {
|
|
335
|
+
if (challenge?.options?.rp?.id) {
|
|
336
|
+
delete challenge.options.rp.id;
|
|
337
|
+
}
|
|
338
|
+
if (challenge?.options?.rpId) {
|
|
339
|
+
delete challenge.options.rpId;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
challenge.options.timeout = 6e4;
|
|
343
|
+
challenge.options.attestation = "none";
|
|
344
|
+
const user = challenge.options?.user || {};
|
|
345
|
+
if (type === "add") {
|
|
346
|
+
user.id = user.id || new TextEncoder().encode(userId);
|
|
347
|
+
user.name = fidoName;
|
|
348
|
+
user.displayName = fidoName;
|
|
349
|
+
}
|
|
350
|
+
challenge.options.user = user;
|
|
351
|
+
return challenge;
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// src/cube-mfa.ts
|
|
355
|
+
var CubeMfaService = class _CubeMfaService {
|
|
356
|
+
constructor() {
|
|
357
|
+
this.mfaType = "fido";
|
|
358
|
+
this.cubeAccountService = null;
|
|
359
|
+
this.cubeSignerClient = null;
|
|
360
|
+
this.apiClient = null;
|
|
361
|
+
this.mfaAnswer = null;
|
|
362
|
+
this.mfaChallenge = null;
|
|
363
|
+
this.registerChallenge = null;
|
|
364
|
+
}
|
|
365
|
+
static getInstance() {
|
|
366
|
+
if (!_CubeMfaService.instance) {
|
|
367
|
+
_CubeMfaService.instance = new _CubeMfaService();
|
|
368
|
+
}
|
|
369
|
+
return _CubeMfaService.instance;
|
|
370
|
+
}
|
|
371
|
+
init(cubeAccountService) {
|
|
372
|
+
this.cubeSignerClient = cubeAccountService.cubeSignerClient;
|
|
373
|
+
this.apiClient = cubeAccountService.apiClient;
|
|
374
|
+
this.cubeAccountService = cubeAccountService;
|
|
375
|
+
return this;
|
|
376
|
+
}
|
|
377
|
+
setMfaType(mfaType) {
|
|
378
|
+
if (!mfaType) {
|
|
379
|
+
throw new Error("mfaType is required");
|
|
380
|
+
}
|
|
381
|
+
this.mfaType = mfaType;
|
|
382
|
+
}
|
|
383
|
+
setMfaAnswer(mfaAnswer) {
|
|
384
|
+
this.mfaAnswer = mfaAnswer;
|
|
385
|
+
}
|
|
386
|
+
async getMfaInfo(bizType) {
|
|
387
|
+
if (!bizType) {
|
|
388
|
+
throw new Error("mfaRequestType is required");
|
|
389
|
+
}
|
|
390
|
+
const MfaInfoConfig = getMfaInfoConfig(this.cubeAccountService?.config?.cubeStage || "gamma");
|
|
391
|
+
const config = MfaInfoConfig[bizType];
|
|
392
|
+
if (!config) {
|
|
393
|
+
throw new Error("mfaRequestType is not supported");
|
|
394
|
+
}
|
|
395
|
+
const { method, path } = config;
|
|
396
|
+
const mfaList = await this.apiClient.mfaList();
|
|
397
|
+
const mfaInfo = mfaList.find((mfa) => {
|
|
398
|
+
const _method = mfa?.request.method;
|
|
399
|
+
const _path = mfa?.request.path + "/";
|
|
400
|
+
return _method === method && _path.indexOf(path) > -1;
|
|
401
|
+
});
|
|
402
|
+
if (!mfaInfo) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
let mfaRequired = null;
|
|
406
|
+
const allowed_mfa_types = mfaInfo?.status?.allowed_mfa_types || [];
|
|
407
|
+
for (const type of allowed_mfa_types) {
|
|
408
|
+
mfaRequired = mfaRequired || {};
|
|
409
|
+
const types = type.toLowerCase().split("#");
|
|
410
|
+
mfaRequired[types[0]] = types[1] ? Number(types[1]) : true;
|
|
411
|
+
}
|
|
412
|
+
const { receipt, created_at } = mfaInfo;
|
|
413
|
+
let emailOtpRemainTime = 0;
|
|
414
|
+
if (typeof mfaRequired.emailOtp === "number") {
|
|
415
|
+
const remainTime = mfaRequired.emailOtp - (Date.now() / 1e3 - created_at);
|
|
416
|
+
emailOtpRemainTime = Math.max(0, Math.ceil(remainTime));
|
|
417
|
+
}
|
|
418
|
+
if (mfaRequired.emailOtp) {
|
|
419
|
+
mfaRequired.emailOtpRemainTime = emailOtpRemainTime;
|
|
420
|
+
}
|
|
421
|
+
const verifyStatus = receipt !== null ? "approved" : "pending";
|
|
422
|
+
return { ...mfaInfo, verifyStatus, mfaRequired };
|
|
423
|
+
}
|
|
424
|
+
async answerRegister(code) {
|
|
425
|
+
const challenge = this.registerChallenge;
|
|
426
|
+
if (!challenge) {
|
|
427
|
+
throw new Error("challenge is required");
|
|
428
|
+
}
|
|
429
|
+
try {
|
|
430
|
+
const receipt = await challenge.answer(code) || null;
|
|
431
|
+
this.registerChallenge = null;
|
|
432
|
+
return {
|
|
433
|
+
success: true,
|
|
434
|
+
data: receipt
|
|
435
|
+
};
|
|
436
|
+
} catch (error) {
|
|
437
|
+
return {
|
|
438
|
+
success: false,
|
|
439
|
+
message: error?.message || "answer error",
|
|
440
|
+
error
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
async executeBizWithMfa(bizType, mfaInfo) {
|
|
445
|
+
if (!bizType) {
|
|
446
|
+
throw new Error("bizType is required");
|
|
447
|
+
}
|
|
448
|
+
if (!mfaInfo) {
|
|
449
|
+
mfaInfo = await this.getMfaInfo(bizType) || null;
|
|
450
|
+
}
|
|
451
|
+
if (!mfaInfo?.id) {
|
|
452
|
+
throw new Error("mfa not exists, please create mfa first");
|
|
453
|
+
}
|
|
454
|
+
const { success, data: receipt } = await this.approvalMfa(mfaInfo?.id || "") || {};
|
|
455
|
+
if (!success) {
|
|
456
|
+
return {
|
|
457
|
+
success: false,
|
|
458
|
+
message: `approval with ${this.mfaType} error.`
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
if (bizType === "createSession") {
|
|
462
|
+
const result = await this.cubeAccountService?.createSession(receipt);
|
|
463
|
+
return {
|
|
464
|
+
success: !!result,
|
|
465
|
+
message: !result ? "create session error" : "",
|
|
466
|
+
data: result
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
if (bizType === "addFido") {
|
|
470
|
+
const name = mfaInfo.request?.body?.name;
|
|
471
|
+
const res = await this.addFido(name, receipt);
|
|
472
|
+
return {
|
|
473
|
+
success: !!res,
|
|
474
|
+
message: !res ? "addFido error" : "",
|
|
475
|
+
data: res
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
if (bizType === "deleteFido") {
|
|
479
|
+
const path = mfaInfo?.request?.path || "";
|
|
480
|
+
const fidoId = path.split("/user/me/fido/")[1] || "";
|
|
481
|
+
if (!fidoId) {
|
|
482
|
+
throw new Error("fidoId is required");
|
|
483
|
+
}
|
|
484
|
+
const res = await this.deleteFido(decodeURIComponent(fidoId), receipt);
|
|
485
|
+
return {
|
|
486
|
+
success: !!res,
|
|
487
|
+
message: !res ? "deleteFido error" : "",
|
|
488
|
+
data: res
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
if (bizType === "registerTotp") {
|
|
492
|
+
const issuer = mfaInfo.request?.body?.issuer;
|
|
493
|
+
const res = await this.registerTotp(issuer, receipt);
|
|
494
|
+
return {
|
|
495
|
+
success: !!res,
|
|
496
|
+
message: !res ? "registerTotp error" : "",
|
|
497
|
+
data: res
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
if (bizType === "deleteTotp") {
|
|
501
|
+
const res = await this.deleteTotp(receipt);
|
|
502
|
+
return {
|
|
503
|
+
success: !!res,
|
|
504
|
+
message: !res ? "deleteTotp error" : "",
|
|
505
|
+
data: res
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (bizType === "registerEmailOtp") {
|
|
509
|
+
const email = mfaInfo.request?.body?.email;
|
|
510
|
+
const res = await this.registerEmailOtp(email, receipt);
|
|
511
|
+
return {
|
|
512
|
+
success: !!res,
|
|
513
|
+
message: !res ? "registerEmailOtp error" : "",
|
|
514
|
+
data: res
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
const cubeExportService = this.cubeAccountService?.cubeExportService;
|
|
518
|
+
if (bizType === "initExport") {
|
|
519
|
+
const res = await cubeExportService?.initExport(receipt);
|
|
520
|
+
return {
|
|
521
|
+
success: !!res,
|
|
522
|
+
message: !res ? "init export error" : "",
|
|
523
|
+
data: res
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
if (bizType === "completeExport") {
|
|
527
|
+
const res = await cubeExportService?.completeExport(receipt);
|
|
528
|
+
return {
|
|
529
|
+
success: !!res,
|
|
530
|
+
message: !res ? "complete export error" : "",
|
|
531
|
+
data: res
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
return {
|
|
535
|
+
success: false,
|
|
536
|
+
message: "bizType is not supported"
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
async approvalMfa(mfaId) {
|
|
540
|
+
const apis = {
|
|
541
|
+
totp: "approvalTotp",
|
|
542
|
+
emailOtp: "approvalEmailOtp",
|
|
543
|
+
fido: "approvalFido"
|
|
544
|
+
};
|
|
545
|
+
const mfaType = this.mfaType;
|
|
546
|
+
if (!mfaType || !apis[mfaType]) {
|
|
547
|
+
return {
|
|
548
|
+
success: false,
|
|
549
|
+
message: "mfaType is required"
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
let receipt = null;
|
|
553
|
+
try {
|
|
554
|
+
switch (mfaType) {
|
|
555
|
+
case "totp":
|
|
556
|
+
receipt = await this.approvalTotp(mfaId);
|
|
557
|
+
break;
|
|
558
|
+
case "emailOtp":
|
|
559
|
+
receipt = await this.approvalEmailOtp(mfaId);
|
|
560
|
+
break;
|
|
561
|
+
case "fido":
|
|
562
|
+
receipt = await this.approvalFido(mfaId);
|
|
563
|
+
break;
|
|
564
|
+
default:
|
|
565
|
+
return {
|
|
566
|
+
success: false,
|
|
567
|
+
message: "Unsupported MFA type"
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
} catch (error) {
|
|
571
|
+
return {
|
|
572
|
+
success: false,
|
|
573
|
+
message: `approval ${mfaType} error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
if (!receipt) {
|
|
577
|
+
return {
|
|
578
|
+
success: false,
|
|
579
|
+
message: `approval ${mfaType} error.`
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
success: true,
|
|
584
|
+
data: receipt
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
getPasskeyConfig() {
|
|
588
|
+
const { config } = this.cubeAccountService || {};
|
|
589
|
+
delete config?.cubeSalt;
|
|
590
|
+
delete config?.jwtToken;
|
|
591
|
+
return config;
|
|
592
|
+
}
|
|
593
|
+
passkeyClear() {
|
|
594
|
+
closeWindow();
|
|
595
|
+
}
|
|
596
|
+
async addFido(fidoName, receipt) {
|
|
597
|
+
const config = this.getPasskeyConfig();
|
|
598
|
+
return await addPasskey({ fidoName, receipt }, config);
|
|
599
|
+
}
|
|
600
|
+
async addFidoLocal(fidoName, receipt) {
|
|
601
|
+
if (!fidoName || typeof fidoName !== "string") {
|
|
602
|
+
throw new Error("name is required");
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
const mfaConfig = await this.cubeAccountService?.getMfaConfig();
|
|
606
|
+
const fidos = mfaConfig?.fido?.data || [];
|
|
607
|
+
const existingFido = fidos.find((fido) => fido?.name === fidoName);
|
|
608
|
+
if (existingFido) {
|
|
609
|
+
throw new Error(`FIDO key with name "${fidoName}" already exists`);
|
|
610
|
+
}
|
|
611
|
+
const cubeSignerClient = this.cubeSignerClient;
|
|
612
|
+
const addFidoResp = await cubeSignerClient?.addFido(fidoName, receipt);
|
|
613
|
+
if (addFidoResp.requiresMfa()) {
|
|
614
|
+
return await this.getMfaInfo("addFido");
|
|
615
|
+
}
|
|
616
|
+
const config = {
|
|
617
|
+
userId: mfaConfig?.account?.userId,
|
|
618
|
+
rpId: this.cubeAccountService?.config?.rpId || window.location.hostname,
|
|
619
|
+
fidoName
|
|
620
|
+
};
|
|
621
|
+
const challenge = applyLocalDevFixes("add", addFidoResp.data(), config);
|
|
622
|
+
await challenge.createCredentialAndAnswer();
|
|
623
|
+
return true;
|
|
624
|
+
} catch (error) {
|
|
625
|
+
console.error("addFido error", error);
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
async deleteFido(fidoId, receipt) {
|
|
630
|
+
try {
|
|
631
|
+
const cubeSignerClient = this.cubeSignerClient;
|
|
632
|
+
const deleteFidoResp = await cubeSignerClient?.deleteFido(fidoId, receipt);
|
|
633
|
+
if (deleteFidoResp.requiresMfa()) {
|
|
634
|
+
return await this.getMfaInfo("deleteFido");
|
|
635
|
+
}
|
|
636
|
+
return deleteFidoResp.data();
|
|
637
|
+
} catch (error) {
|
|
638
|
+
return null;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
async approvalFido(mfaId) {
|
|
642
|
+
const config = this.getPasskeyConfig();
|
|
643
|
+
const receipt = await verifyPasskey({ mfaId }, config);
|
|
644
|
+
return receipt;
|
|
645
|
+
}
|
|
646
|
+
async approvalFidoLocal(mfaId) {
|
|
647
|
+
const apiClient = this.apiClient;
|
|
648
|
+
const mfaConfig = await this.cubeAccountService?.getMfaConfig();
|
|
649
|
+
let challenge = await apiClient.mfaFidoInit(mfaId);
|
|
650
|
+
const config = {
|
|
651
|
+
userId: mfaConfig?.account?.userId,
|
|
652
|
+
rpId: this.cubeAccountService?.config?.rpId || window.location.hostname,
|
|
653
|
+
fidoName: ""
|
|
654
|
+
};
|
|
655
|
+
challenge = applyLocalDevFixes("approval", challenge, config);
|
|
656
|
+
const mfa = await challenge.createCredentialAndAnswer("approve");
|
|
657
|
+
const receipt = await mfa.receipt();
|
|
658
|
+
return receipt;
|
|
659
|
+
}
|
|
660
|
+
async registerTotp(issuer, receipt) {
|
|
661
|
+
if (issuer === "") {
|
|
662
|
+
throw new Error("issuer are required");
|
|
663
|
+
}
|
|
664
|
+
const totpResp = await this.apiClient.userTotpResetInit(issuer, receipt);
|
|
665
|
+
if (totpResp.requiresMfa()) {
|
|
666
|
+
return await this.getMfaInfo("registerTotp");
|
|
667
|
+
}
|
|
668
|
+
const challenge = totpResp.data();
|
|
669
|
+
this.registerChallenge = challenge;
|
|
670
|
+
const searchParams = new URL(challenge?.url).searchParams;
|
|
671
|
+
const totpInfo = {
|
|
672
|
+
id: challenge?.id,
|
|
673
|
+
url: challenge?.url,
|
|
674
|
+
secret: searchParams.get("secret") || "",
|
|
675
|
+
issuer: searchParams.get("issuer") || issuer
|
|
676
|
+
};
|
|
677
|
+
return totpInfo;
|
|
678
|
+
}
|
|
679
|
+
async deleteTotp(receipt) {
|
|
680
|
+
const deleteTotpResp = await this.apiClient.userTotpDelete(receipt);
|
|
681
|
+
if (deleteTotpResp.requiresMfa()) {
|
|
682
|
+
return await this.getMfaInfo("deleteTotp");
|
|
683
|
+
}
|
|
684
|
+
return deleteTotpResp.data();
|
|
685
|
+
}
|
|
686
|
+
async approvalTotp(mfaId) {
|
|
687
|
+
if (!mfaId) {
|
|
688
|
+
throw new Error("MFA ID not found");
|
|
689
|
+
}
|
|
690
|
+
const totpCode = this.mfaAnswer?.totpCode;
|
|
691
|
+
if (!totpCode || !/^\d{6}$/.test(totpCode)) {
|
|
692
|
+
console.error("TOTP code is required");
|
|
693
|
+
throw new Error("TOTP code is required");
|
|
694
|
+
}
|
|
695
|
+
const mfa = await this.apiClient.mfaVoteTotp(mfaId, totpCode, "approve");
|
|
696
|
+
const mfaOrgId = this.cubeSignerClient?.org()?.id || this.cubeAccountService?.cubeOrgId || "";
|
|
697
|
+
const receipt = {
|
|
698
|
+
mfaId: mfa.id,
|
|
699
|
+
mfaConf: mfa?.receipt?.confirmation,
|
|
700
|
+
mfaOrgId
|
|
701
|
+
};
|
|
702
|
+
return receipt;
|
|
703
|
+
}
|
|
704
|
+
async registerEmailOtp(email, receipt) {
|
|
705
|
+
if (!email || !walletUtils.isEmail(email)) {
|
|
706
|
+
throw new Error("email is required");
|
|
707
|
+
}
|
|
708
|
+
const cubeSignerClient = await this.cubeAccountService?.getOidcClient();
|
|
709
|
+
const apiClient = cubeSignerClient.apiClient;
|
|
710
|
+
const params = {
|
|
711
|
+
email,
|
|
712
|
+
allow_otp_login: true
|
|
713
|
+
};
|
|
714
|
+
const registerEmailOtpResp = await apiClient.userEmailResetInit(params, receipt);
|
|
715
|
+
if (registerEmailOtpResp.requiresMfa()) {
|
|
716
|
+
return await this.getMfaInfo("registerEmailOtp");
|
|
717
|
+
}
|
|
718
|
+
this.registerChallenge = registerEmailOtpResp.data();
|
|
719
|
+
return this.registerChallenge;
|
|
720
|
+
}
|
|
721
|
+
//48hour countdown
|
|
722
|
+
//mfaVoteEmailComplete
|
|
723
|
+
async approvalEmailOtp(mfaId) {
|
|
724
|
+
if (!mfaId) {
|
|
725
|
+
throw new Error("MFA ID not found");
|
|
726
|
+
}
|
|
727
|
+
if (!this.mfaChallenge) {
|
|
728
|
+
const mfaChallenge = await this.apiClient.mfaVoteEmailInit(mfaId, "approve");
|
|
729
|
+
this.mfaChallenge = mfaChallenge;
|
|
730
|
+
return null;
|
|
731
|
+
}
|
|
732
|
+
let emailCode = this.mfaAnswer?.emailCode || "";
|
|
733
|
+
emailCode = emailCode.split(/\s/).join("");
|
|
734
|
+
if (!emailCode) {
|
|
735
|
+
throw new Error("emailCode is required");
|
|
736
|
+
}
|
|
737
|
+
try {
|
|
738
|
+
const mfa = await this.mfaChallenge.answer(emailCode);
|
|
739
|
+
const mfaOrgId = this.cubeSignerClient?.org()?.id || this.cubeAccountService?.cubeOrgId || "";
|
|
740
|
+
const receipt = {
|
|
741
|
+
mfaId: mfa.id,
|
|
742
|
+
mfaConf: mfa?.receipt?.confirmation,
|
|
743
|
+
mfaOrgId
|
|
744
|
+
};
|
|
745
|
+
this.mfaChallenge = null;
|
|
746
|
+
return receipt;
|
|
747
|
+
} catch (error) {
|
|
748
|
+
console.warn("approvalEmailOtp error", error);
|
|
749
|
+
return null;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
async sendEmailCode(mfaId) {
|
|
753
|
+
if (!mfaId) {
|
|
754
|
+
throw new Error("mfaId is required");
|
|
755
|
+
}
|
|
756
|
+
try {
|
|
757
|
+
const mfaChallenge = await this.apiClient.mfaVoteEmailInit(mfaId, "approve");
|
|
758
|
+
this.mfaChallenge = mfaChallenge;
|
|
759
|
+
return true;
|
|
760
|
+
} catch (error) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
var recoverEVMTxData = (unsignedTx, numberType) => {
|
|
766
|
+
try {
|
|
767
|
+
const { data, types } = JSON.parse(unsignedTx);
|
|
768
|
+
for (const prop in types) {
|
|
769
|
+
if (types[prop] === "bigint") {
|
|
770
|
+
data[prop] = BigInt(data[prop]);
|
|
771
|
+
if (numberType === "string") {
|
|
772
|
+
data[prop] = data[prop].toString();
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
return data;
|
|
777
|
+
} catch (error) {
|
|
778
|
+
throw new Error("Invalid unsigned transaction");
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
var CubeSignService = class _CubeSignService {
|
|
782
|
+
async init({ cubeSession }) {
|
|
783
|
+
this.cubeSession = cubeSession;
|
|
784
|
+
if (!this.services) {
|
|
785
|
+
this.services = await cubistSigSdk.getKeys(cubeSession);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
static getInstance() {
|
|
789
|
+
if (!_CubeSignService.instance) {
|
|
790
|
+
_CubeSignService.instance = new _CubeSignService();
|
|
791
|
+
}
|
|
792
|
+
return _CubeSignService.instance;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Get specific services by chainType and address
|
|
796
|
+
* @param chainType Chain type (EVM, TRON, SOL, DOGE)
|
|
797
|
+
* @param address Wallet address
|
|
798
|
+
* @returns The matching services object or null if not found
|
|
799
|
+
*/
|
|
800
|
+
async getServiceByChainAndAddress(chainType, address) {
|
|
801
|
+
if (!this.services) {
|
|
802
|
+
this.services = await cubistSigSdk.getKeys(this.cubeSession);
|
|
803
|
+
}
|
|
804
|
+
const keyId = this.buildKeyId(chainType, address);
|
|
805
|
+
const service = this.services.find((k) => k.id === keyId);
|
|
806
|
+
if (!service) {
|
|
807
|
+
console.warn(`service not found for chainType: ${chainType}`);
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
return service;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Build key ID from chainType and address following the pattern in the services data
|
|
814
|
+
* @param chainType Chain type
|
|
815
|
+
* @param address Wallet address
|
|
816
|
+
* @returns Key ID string
|
|
817
|
+
*/
|
|
818
|
+
buildKeyId(chainType, address) {
|
|
819
|
+
switch (chainType) {
|
|
820
|
+
case walletUtils.ChainTypes.EVM:
|
|
821
|
+
return `Key#${address}`;
|
|
822
|
+
case walletUtils.ChainTypes.TRON:
|
|
823
|
+
return `Key#Tron_${address}`;
|
|
824
|
+
case walletUtils.ChainTypes.SOL:
|
|
825
|
+
return `Key#Solana_${address}`;
|
|
826
|
+
case walletUtils.ChainTypes.DOGE:
|
|
827
|
+
return `Key#Doge_${address}`;
|
|
828
|
+
default:
|
|
829
|
+
return `Key#${address}`;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Unified transaction signing method for all supported chains
|
|
834
|
+
* @param chainType Chain type (EVM, SOL, DOGE, TRON, BTC)
|
|
835
|
+
* @param address User's wallet address
|
|
836
|
+
* @param params Signing parameters specific to each chain (always JSON stringified from social account)
|
|
837
|
+
* @returns Signed transaction
|
|
838
|
+
*/
|
|
839
|
+
async signTransaction(chainType, address, params) {
|
|
840
|
+
const sessionInfo = this?.cubeSession;
|
|
841
|
+
const service = await this.getServiceByChainAndAddress(chainType, address);
|
|
842
|
+
if (!service) {
|
|
843
|
+
throw new Error(`service not found for chain ${chainType}`);
|
|
844
|
+
}
|
|
845
|
+
const parsedParams = typeof params === "string" ? JSON.parse(params) : params;
|
|
846
|
+
switch (chainType) {
|
|
847
|
+
case walletUtils.ChainTypes.EVM: {
|
|
848
|
+
const transaction = recoverEVMTxData(params, "string");
|
|
849
|
+
return await cubistSigSdk.signEvmTransaction(service, transaction, transaction.chainId, sessionInfo);
|
|
850
|
+
}
|
|
851
|
+
case walletUtils.ChainTypes.SOL: {
|
|
852
|
+
return await cubistSigSdk.signSolanaTransaction(service, parsedParams.rawTransaction, sessionInfo);
|
|
853
|
+
}
|
|
854
|
+
case walletUtils.ChainTypes.DOGE: {
|
|
855
|
+
return await cubistSigSdk.signDogePsbt(service, parsedParams.psbtBase64, sessionInfo);
|
|
856
|
+
}
|
|
857
|
+
case walletUtils.ChainTypes.TRON: {
|
|
858
|
+
const rawTransaction = parsedParams.data?.rawTransaction || parsedParams.rawTransaction;
|
|
859
|
+
return await cubistSigSdk.signTronRawTransaction(service, rawTransaction, sessionInfo);
|
|
860
|
+
}
|
|
861
|
+
default:
|
|
862
|
+
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Unified message signing method for all supported chains
|
|
867
|
+
* @param chainType Chain type (EVM, SOL, DOGE, TRON)
|
|
868
|
+
* @param address User's wallet address
|
|
869
|
+
* @param message Message to be signed
|
|
870
|
+
* @returns Message signature
|
|
871
|
+
*/
|
|
872
|
+
async signMessage(chainType, address, message) {
|
|
873
|
+
const sessionInfo = this?.cubeSession;
|
|
874
|
+
const service = await this.getServiceByChainAndAddress(chainType, address);
|
|
875
|
+
if (!service) {
|
|
876
|
+
throw new Error(`service not found for chain ${chainType}`);
|
|
877
|
+
}
|
|
878
|
+
switch (chainType) {
|
|
879
|
+
case walletUtils.ChainTypes.EVM:
|
|
880
|
+
return await cubistSigSdk.signEvmMessage(service, message, sessionInfo);
|
|
881
|
+
case walletUtils.ChainTypes.SOL:
|
|
882
|
+
return await cubistSigSdk.signSolanaMessage(service, message, sessionInfo);
|
|
883
|
+
case walletUtils.ChainTypes.DOGE:
|
|
884
|
+
return (await cubistSigSdk.signDogeMessage(service, message, sessionInfo)).signature;
|
|
885
|
+
case walletUtils.ChainTypes.TRON:
|
|
886
|
+
return await cubistSigSdk.signTronMessage(service, message, sessionInfo);
|
|
887
|
+
default:
|
|
888
|
+
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Unified typed data signing method (supports EVM and TRON)
|
|
893
|
+
* @param chainType Chain type (EVM, TRON)
|
|
894
|
+
* @param address User's wallet address
|
|
895
|
+
* @param typedData Typed data to be signed
|
|
896
|
+
* @returns Typed data signature
|
|
897
|
+
*/
|
|
898
|
+
async signTypedData(chainType, address, typedData) {
|
|
899
|
+
const sessionInfo = this?.cubeSession;
|
|
900
|
+
const service = await this.getServiceByChainAndAddress(chainType, address);
|
|
901
|
+
if (!service) {
|
|
902
|
+
throw new Error(`service not found for chain ${chainType}`);
|
|
903
|
+
}
|
|
904
|
+
switch (chainType) {
|
|
905
|
+
case walletUtils.ChainTypes.EVM:
|
|
906
|
+
return await cubistSigSdk.signEvmTypedData(service, typedData, sessionInfo);
|
|
907
|
+
case walletUtils.ChainTypes.TRON: {
|
|
908
|
+
return await cubistSigSdk.signTronTypeDaya(service, typedData.message, sessionInfo);
|
|
909
|
+
}
|
|
910
|
+
default:
|
|
911
|
+
throw new Error(`Unsupported chain type: ${chainType}`);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
var generateCubeSignature = async (data, salt) => {
|
|
916
|
+
if (!salt) {
|
|
917
|
+
throw new Error("salt is required");
|
|
918
|
+
}
|
|
919
|
+
const timestamp = Date.now().toString();
|
|
920
|
+
const req = {
|
|
921
|
+
...data,
|
|
922
|
+
timestamp
|
|
923
|
+
};
|
|
924
|
+
const reqString = JSON.stringify(req);
|
|
925
|
+
const signature = CryptoJS__default.default.SHA256(reqString + salt).toString();
|
|
926
|
+
return { timestamp, signature };
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
// src/api.ts
|
|
930
|
+
function getTomoApi(config) {
|
|
931
|
+
const { tomoStage = "dev", tomoClientId, jwtToken } = config;
|
|
932
|
+
const tomoApi = axios__default.default.create({
|
|
933
|
+
baseURL: `${walletUtils.TomoApiDomains[tomoStage] || walletUtils.TomoApiDomains.dev}/user`,
|
|
934
|
+
timeout: 2e4
|
|
935
|
+
});
|
|
936
|
+
tomoApi.interceptors.request.use(
|
|
937
|
+
async (config2) => {
|
|
938
|
+
config2.headers["client-id"] = tomoClientId;
|
|
939
|
+
if (jwtToken) {
|
|
940
|
+
config2.headers["Authorization"] = `Bearer ${jwtToken}`;
|
|
941
|
+
}
|
|
942
|
+
return config2;
|
|
943
|
+
},
|
|
944
|
+
(error) => {
|
|
945
|
+
if (error?.response?.status === 401) {
|
|
946
|
+
return Promise.reject(error);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
);
|
|
950
|
+
return tomoApi;
|
|
951
|
+
}
|
|
952
|
+
var addUserToCube = async (req, config) => {
|
|
953
|
+
const { iss, sub } = req;
|
|
954
|
+
const cubeSalt = config.cubeSalt || "";
|
|
955
|
+
if (!cubeSalt) {
|
|
956
|
+
throw new Error("tomoStage error.");
|
|
957
|
+
}
|
|
958
|
+
const { timestamp, signature } = await generateCubeSignature({ iss, sub }, cubeSalt);
|
|
959
|
+
const signedReq = { ...req, timestamp, signature };
|
|
960
|
+
const tomoApi = getTomoApi(config);
|
|
961
|
+
const res = await tomoApi.post("/api/login/loginByCubistV2", signedReq);
|
|
962
|
+
return res?.data?.data || {};
|
|
963
|
+
};
|
|
964
|
+
var updateUserInfo = async (userInfo, config) => {
|
|
965
|
+
const tomoApi = getTomoApi(config);
|
|
966
|
+
const res = await tomoApi.post("/api/user/getUserInfo");
|
|
967
|
+
const userInfoBefore = res?.data?.data.user || {};
|
|
968
|
+
const nickname = userInfo.nickname.trim();
|
|
969
|
+
userInfo = { ...userInfoBefore, ...userInfo, nickname, username: nickname };
|
|
970
|
+
const result = await tomoApi.post("/api/setting/updateUserInfo", userInfo, {
|
|
971
|
+
headers: {}
|
|
972
|
+
});
|
|
973
|
+
return !!result?.data?.success;
|
|
974
|
+
};
|
|
975
|
+
var CubeAccountService = class _CubeAccountService {
|
|
976
|
+
constructor(config) {
|
|
977
|
+
this.jwtToken = "";
|
|
978
|
+
this.accountData = null;
|
|
979
|
+
this.cubeUserInfo = null;
|
|
980
|
+
this.cubeIdentity = null;
|
|
981
|
+
this.cubeSession = null;
|
|
982
|
+
this.cubeSignerClient = null;
|
|
983
|
+
this.apiClient = null;
|
|
984
|
+
this.cubeMfaService = null;
|
|
985
|
+
this.cubeExportService = null;
|
|
986
|
+
this.cubeOrgId = "";
|
|
987
|
+
this.config = config;
|
|
988
|
+
this.cubeEnv = null;
|
|
989
|
+
}
|
|
990
|
+
static getInstance(config) {
|
|
991
|
+
if (_CubeAccountService.instance) {
|
|
992
|
+
return _CubeAccountService.instance;
|
|
993
|
+
}
|
|
994
|
+
if (!config?.tomoStage || !walletUtils.CubeStages[config?.tomoStage]) {
|
|
995
|
+
throw new Error("tomoStage not 'dev' or 'pre' or 'prod'");
|
|
996
|
+
}
|
|
997
|
+
const cubeSalt = CUBE_SALTS[config?.tomoStage];
|
|
998
|
+
if (!cubeSalt) {
|
|
999
|
+
throw new Error("cubeSalt is required");
|
|
1000
|
+
}
|
|
1001
|
+
const cubeStage = walletUtils.CubeStages[config?.tomoStage];
|
|
1002
|
+
const env = cubesignerSdk.envs[cubeStage];
|
|
1003
|
+
const cubeOrgId = walletUtils.CubeOrgIds[config?.tomoStage];
|
|
1004
|
+
_CubeAccountService.instance = new _CubeAccountService({ ...config, cubeSalt, cubeStage });
|
|
1005
|
+
_CubeAccountService.instance.cubeEnv = env;
|
|
1006
|
+
_CubeAccountService.instance.cubeOrgId = cubeOrgId;
|
|
1007
|
+
return _CubeAccountService.instance;
|
|
1008
|
+
}
|
|
1009
|
+
//no api dependency
|
|
1010
|
+
async getCubeIdentity() {
|
|
1011
|
+
const oidcToken = this?.config?.oidcToken;
|
|
1012
|
+
if (!oidcToken) {
|
|
1013
|
+
const cubeIdentityCache = await walletUtils.cache.get("cubeIdentity");
|
|
1014
|
+
if (cubeIdentityCache) {
|
|
1015
|
+
this.cubeIdentity = cubeIdentityCache;
|
|
1016
|
+
return this.cubeIdentity;
|
|
1017
|
+
}
|
|
1018
|
+
console.warn("oidcToken is required");
|
|
1019
|
+
return null;
|
|
1020
|
+
}
|
|
1021
|
+
const cubeOrgId = this.cubeOrgId;
|
|
1022
|
+
const cubeIdentity = await cubistSigSdk.proof(oidcToken, this.cubeEnv, cubeOrgId);
|
|
1023
|
+
await walletUtils.cache.set("cubeIdentity", cubeIdentity, false);
|
|
1024
|
+
this.cubeIdentity = cubeIdentity;
|
|
1025
|
+
return cubeIdentity;
|
|
1026
|
+
}
|
|
1027
|
+
//login + reg new user by wallet-api
|
|
1028
|
+
async loginOrRegister(oidcToken, options) {
|
|
1029
|
+
this.config = { ...this.config, oidcToken };
|
|
1030
|
+
const cubeIdentity = await this.getCubeIdentity();
|
|
1031
|
+
const req = {
|
|
1032
|
+
cubistUserID: cubeIdentity?.user_info?.user_id,
|
|
1033
|
+
aud: cubeIdentity?.aud,
|
|
1034
|
+
email: cubeIdentity?.email || options?.email || null,
|
|
1035
|
+
//must null
|
|
1036
|
+
iss: cubeIdentity?.identity?.iss,
|
|
1037
|
+
sub: cubeIdentity?.identity?.sub,
|
|
1038
|
+
initialized: cubeIdentity?.user_info?.initialized
|
|
1039
|
+
};
|
|
1040
|
+
const accountData = await addUserToCube(req, this.config);
|
|
1041
|
+
const { userToken, user, accountBaseInfo, accountWallet } = accountData;
|
|
1042
|
+
this.accountData = accountData;
|
|
1043
|
+
this.accountWallet = accountWallet;
|
|
1044
|
+
this.jwtToken = userToken.accessToken;
|
|
1045
|
+
return {
|
|
1046
|
+
user: { userId: user.userID, nickname: user.nickname, avatar: user.avatar },
|
|
1047
|
+
accountBaseInfo,
|
|
1048
|
+
accountWallet,
|
|
1049
|
+
walletId: accountWallet?.walletID
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
async updateUserInfo(userInfo) {
|
|
1053
|
+
const nickname = userInfo.nickname.trim();
|
|
1054
|
+
if (nickname.length < 6 || nickname.length > 20) {
|
|
1055
|
+
throw new Error("name length 6~20");
|
|
1056
|
+
}
|
|
1057
|
+
const config = { ...this.config, jwtToken: this.jwtToken };
|
|
1058
|
+
const result = await updateUserInfo(userInfo, config);
|
|
1059
|
+
return result;
|
|
1060
|
+
}
|
|
1061
|
+
/*
|
|
1062
|
+
all functions below must after loginOrRegister
|
|
1063
|
+
user only can user cube apis after added by org manager with loginOrRegister
|
|
1064
|
+
cube session = loginOrRegister + cube connected
|
|
1065
|
+
*/
|
|
1066
|
+
async createSessionByOidcToken(oidcToken) {
|
|
1067
|
+
oidcToken = oidcToken || this?.config?.oidcToken || "";
|
|
1068
|
+
if (!oidcToken) {
|
|
1069
|
+
console.warn("oidcToken is required");
|
|
1070
|
+
return false;
|
|
1071
|
+
}
|
|
1072
|
+
const scopes = CUBE_SCOPES;
|
|
1073
|
+
const oidcSessionResp = await cubistSigSdk.getOidcResp(oidcToken, this.cubeEnv, this.cubeOrgId, OIDC_TOKEN_LIFETIME, scopes);
|
|
1074
|
+
const cubeSession = oidcSessionResp.data();
|
|
1075
|
+
this.setCubeSession(cubeSession);
|
|
1076
|
+
return !!cubeSession;
|
|
1077
|
+
}
|
|
1078
|
+
//with mfa
|
|
1079
|
+
async createSession(receipt) {
|
|
1080
|
+
const purpose = "wallet_operations";
|
|
1081
|
+
const oidcSessionResp = await this.apiClient.sessionCreateExtended(purpose, CUBE_SCOPES, CUBE_LIFETIME, receipt);
|
|
1082
|
+
if (oidcSessionResp.requiresMfa()) {
|
|
1083
|
+
return await this.cubeMfaService?.getMfaInfo("createSession") || null;
|
|
1084
|
+
}
|
|
1085
|
+
const cubeSession = oidcSessionResp.data();
|
|
1086
|
+
this.setCubeSession(cubeSession);
|
|
1087
|
+
return cubeSession;
|
|
1088
|
+
}
|
|
1089
|
+
async refreshSession() {
|
|
1090
|
+
const purpose = "wallet_operations";
|
|
1091
|
+
const oidcSessionResp = await this.apiClient.sessionCreate(purpose, CUBE_SCOPES, CUBE_LIFETIME);
|
|
1092
|
+
const cubeSession = oidcSessionResp.data();
|
|
1093
|
+
this.setCubeSession(cubeSession);
|
|
1094
|
+
return !!cubeSession;
|
|
1095
|
+
}
|
|
1096
|
+
getCubeSession() {
|
|
1097
|
+
return this.cubeSession;
|
|
1098
|
+
}
|
|
1099
|
+
setCubeSession(cubeSession) {
|
|
1100
|
+
this.cubeSession = cubeSession;
|
|
1101
|
+
}
|
|
1102
|
+
sessionRevoke() {
|
|
1103
|
+
const apiClient = this.apiClient;
|
|
1104
|
+
this.cubeSession = null;
|
|
1105
|
+
apiClient?.sessionRevoke();
|
|
1106
|
+
}
|
|
1107
|
+
async refreshCubeClient(cubeSession) {
|
|
1108
|
+
try {
|
|
1109
|
+
await this.createCubeSignerClient(cubeSession);
|
|
1110
|
+
this.initSubServices();
|
|
1111
|
+
} catch (error) {
|
|
1112
|
+
console.error("refreshCubeClient error", error);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
async createCubeSignerClient(session) {
|
|
1116
|
+
const cubeSignerClient = await cubesignerSdk.CubeSignerClient.create(session);
|
|
1117
|
+
this.cubeSignerClient = cubeSignerClient;
|
|
1118
|
+
this.apiClient = this.cubeSignerClient.apiClient;
|
|
1119
|
+
return cubeSignerClient;
|
|
1120
|
+
}
|
|
1121
|
+
async getOidcClient(receipt) {
|
|
1122
|
+
const oidcToken = this?.config?.oidcToken || "";
|
|
1123
|
+
if (!oidcToken) {
|
|
1124
|
+
console.warn("oidcToken is required");
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
const scopes = CUBE_SCOPES;
|
|
1128
|
+
const cubeSignerClient = await cubistSigSdk.getOidcClient(
|
|
1129
|
+
oidcToken,
|
|
1130
|
+
this.cubeEnv,
|
|
1131
|
+
this.cubeOrgId,
|
|
1132
|
+
OIDC_TOKEN_LIFETIME,
|
|
1133
|
+
scopes,
|
|
1134
|
+
receipt
|
|
1135
|
+
);
|
|
1136
|
+
return cubeSignerClient;
|
|
1137
|
+
}
|
|
1138
|
+
async autoLogin(session) {
|
|
1139
|
+
await this.refreshCubeClient(session);
|
|
1140
|
+
await this.setCubeSession(session);
|
|
1141
|
+
}
|
|
1142
|
+
async init(oidcToken) {
|
|
1143
|
+
oidcToken = oidcToken || this?.config?.oidcToken || "";
|
|
1144
|
+
if (!oidcToken) {
|
|
1145
|
+
console.warn("oidcToken is required");
|
|
1146
|
+
return false;
|
|
1147
|
+
}
|
|
1148
|
+
try {
|
|
1149
|
+
this.config = { ...this.config, oidcToken };
|
|
1150
|
+
const cubeSignerClient = await this.getOidcClient();
|
|
1151
|
+
this.cubeSignerClient = cubeSignerClient;
|
|
1152
|
+
this.apiClient = this.cubeSignerClient.apiClient;
|
|
1153
|
+
const result = await this.createSessionByOidcToken(oidcToken);
|
|
1154
|
+
if (!result) {
|
|
1155
|
+
throw new Error("create session by oidc token failed");
|
|
1156
|
+
}
|
|
1157
|
+
this.initSubServices();
|
|
1158
|
+
return true;
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
console.error("init error", error);
|
|
1161
|
+
throw error;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
async initSubServices() {
|
|
1165
|
+
const cubeMfaService = CubeMfaService.getInstance();
|
|
1166
|
+
this.cubeMfaService = cubeMfaService.init(this);
|
|
1167
|
+
const cubeExportService = CubeExportService.getInstance();
|
|
1168
|
+
this.cubeExportService = cubeExportService.init(this);
|
|
1169
|
+
}
|
|
1170
|
+
async initCubeSignService() {
|
|
1171
|
+
const cubeSession = this.getCubeSession();
|
|
1172
|
+
const cubeSignService = CubeSignService.getInstance();
|
|
1173
|
+
await cubeSignService.init({ cubeSession });
|
|
1174
|
+
return cubeSignService;
|
|
1175
|
+
}
|
|
1176
|
+
async getCubeUserInfo() {
|
|
1177
|
+
try {
|
|
1178
|
+
const cubeUserInfo = await this.apiClient?.userGet();
|
|
1179
|
+
this.cubeUserInfo = cubeUserInfo;
|
|
1180
|
+
return cubeUserInfo;
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
return null;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
async getMfaConfig() {
|
|
1186
|
+
const [cubeUserInfo, cubeIdentity] = await Promise.all([
|
|
1187
|
+
this.getCubeUserInfo(),
|
|
1188
|
+
this.getCubeIdentity()
|
|
1189
|
+
]);
|
|
1190
|
+
const name = cubeUserInfo?.name || cubeIdentity?.preferred_username || "";
|
|
1191
|
+
const iss = cubeIdentity?.identity?.iss || "";
|
|
1192
|
+
const accountType = ISS_MAP?.[iss] || "email";
|
|
1193
|
+
const verifiedEmail = cubeUserInfo?.verified_email?.email || "";
|
|
1194
|
+
const email = cubeUserInfo?.email || "";
|
|
1195
|
+
const emailOtpEnabled = verifiedEmail !== "" || email !== "";
|
|
1196
|
+
const configuredMfa = cubeUserInfo?.mfa || [];
|
|
1197
|
+
const fidos = configuredMfa.filter((item) => item.type === "fido");
|
|
1198
|
+
const totp = configuredMfa.filter((item) => item.type === "totp");
|
|
1199
|
+
return {
|
|
1200
|
+
noMfa: !emailOtpEnabled && fidos.length === 0 && totp.length === 0,
|
|
1201
|
+
hasMfa: emailOtpEnabled || fidos.length > 0 || totp.length > 0,
|
|
1202
|
+
account: {
|
|
1203
|
+
name,
|
|
1204
|
+
email,
|
|
1205
|
+
otpEmail: verifiedEmail,
|
|
1206
|
+
accountType,
|
|
1207
|
+
userId: cubeUserInfo?.user_id || ""
|
|
1208
|
+
},
|
|
1209
|
+
emailOtp: {
|
|
1210
|
+
data: email || verifiedEmail,
|
|
1211
|
+
enabled: emailOtpEnabled
|
|
1212
|
+
},
|
|
1213
|
+
fido: {
|
|
1214
|
+
data: fidos,
|
|
1215
|
+
enabled: fidos.length > 0
|
|
1216
|
+
},
|
|
1217
|
+
totp: {
|
|
1218
|
+
data: totp[0],
|
|
1219
|
+
enabled: totp.length > 0
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
// src/cube-connect.ts
|
|
1226
|
+
var CubeConnect = async (config) => {
|
|
1227
|
+
const cubeAccount = CubeAccountService.getInstance(config);
|
|
1228
|
+
if (!config.oidcToken) {
|
|
1229
|
+
throw new Error("oidcToken is required");
|
|
1230
|
+
}
|
|
1231
|
+
await cubeAccount.loginOrRegister(config.oidcToken);
|
|
1232
|
+
await cubeAccount.init(config.oidcToken);
|
|
1233
|
+
const cubeMfaService = cubeAccount.cubeMfaService;
|
|
1234
|
+
const cubeExportService = cubeAccount.cubeExportService;
|
|
1235
|
+
return {
|
|
1236
|
+
cubeAccount,
|
|
1237
|
+
cubeMfa: cubeMfaService,
|
|
1238
|
+
cubeExport: cubeExportService
|
|
1239
|
+
};
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
// src/types.ts
|
|
1243
|
+
var LoginError = /* @__PURE__ */ ((LoginError2) => {
|
|
1244
|
+
LoginError2["FIDO_NOT_ALLOWED"] = "NotAllowedError";
|
|
1245
|
+
LoginError2["MFA_NOT_APPROVED"] = "MFA not approved yet";
|
|
1246
|
+
LoginError2["MFA_REQUIRED"] = "MFA should not be required after approval";
|
|
1247
|
+
LoginError2["OIDC_TOKEN_NOT_FOUND"] = "Oidc token not found";
|
|
1248
|
+
LoginError2["CUBE_IDENTITY_NOT_FOUND"] = "Cube identity not found";
|
|
1249
|
+
LoginError2["CUBE_USER_INFO_NOT_FOUND"] = "Cube user info not found";
|
|
1250
|
+
LoginError2["OIDC_TOKEN_EXPIRED"] = "ExpiredSignature";
|
|
1251
|
+
LoginError2["FAILED_OPEN_POPUP"] = "Failed to open popup window";
|
|
1252
|
+
LoginError2["OAUTH_LOGIN_TIMEOUT"] = "OAuth login timeout";
|
|
1253
|
+
LoginError2["USER_CANCELLED_LOGIN"] = "User cancelled login";
|
|
1254
|
+
return LoginError2;
|
|
1255
|
+
})(LoginError || {});
|
|
1256
|
+
|
|
1257
|
+
exports.CUBE_LIFETIME = CUBE_LIFETIME;
|
|
1258
|
+
exports.CUBE_SALTS = CUBE_SALTS;
|
|
1259
|
+
exports.CUBE_SCOPES = CUBE_SCOPES;
|
|
1260
|
+
exports.CubeAccountService = CubeAccountService;
|
|
1261
|
+
exports.CubeConnect = CubeConnect;
|
|
1262
|
+
exports.CubeExportService = CubeExportService;
|
|
1263
|
+
exports.CubeMfaService = CubeMfaService;
|
|
1264
|
+
exports.CubeSignService = CubeSignService;
|
|
1265
|
+
exports.EXPORT_KEY_PREFIX = EXPORT_KEY_PREFIX;
|
|
1266
|
+
exports.EXPORT_TIME_FORMAT = EXPORT_TIME_FORMAT;
|
|
1267
|
+
exports.ISS_MAP = ISS_MAP;
|
|
1268
|
+
exports.LoginError = LoginError;
|
|
1269
|
+
exports.OIDC_TOKEN_LIFETIME = OIDC_TOKEN_LIFETIME;
|
|
1270
|
+
exports.SEED_PHRASE_EXPORT_DURATION = SEED_PHRASE_EXPORT_DURATION;
|
|
1271
|
+
exports.getMfaInfoConfig = getMfaInfoConfig;
|