@getpara/core-sdk 3.4.0 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ParaCore.js +98 -35
- package/dist/cjs/constants.js +1 -1
- package/dist/cjs/errors.js +12 -0
- package/dist/cjs/services/AuthService.js +42 -1
- package/dist/cjs/state/CoreStateManager.js +33 -6
- package/dist/cjs/state/machines/authStateMachine.js +105 -8
- package/dist/cjs/state/machines/coreStateMachine.js +8 -0
- package/dist/cjs/types/coreApi.js +2 -0
- package/dist/esm/ParaCore.js +99 -36
- package/dist/esm/constants.js +1 -1
- package/dist/esm/errors.js +11 -0
- package/dist/esm/services/AuthService.js +42 -1
- package/dist/esm/state/CoreStateManager.js +33 -6
- package/dist/esm/state/machines/authStateMachine.js +105 -8
- package/dist/esm/state/machines/coreStateMachine.js +8 -0
- package/dist/esm/types/coreApi.js +2 -0
- package/dist/types/ParaCore.d.ts +24 -2
- package/dist/types/errors.d.ts +13 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/services/AuthService.d.ts +10 -1
- package/dist/types/services/types/AuthServiceTypes.d.ts +6 -3
- package/dist/types/state/CoreStateManager.d.ts +1 -0
- package/dist/types/state/machines/authStateMachine.d.ts +77 -1
- package/dist/types/state/machines/coreStateMachine.d.ts +465 -6
- package/dist/types/state/types/auth.d.ts +4 -1
- package/dist/types/state/types/core.d.ts +23 -1
- package/dist/types/types/authState.d.ts +9 -3
- package/dist/types/types/coreApi.d.ts +17 -2
- package/package.json +3 -3
package/dist/esm/ParaCore.js
CHANGED
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
import { waitForAuthStateChange } from "./utils/stateListener.js";
|
|
55
55
|
import { warnOnce } from "./utils/deprecation.js";
|
|
56
56
|
import { assertConfigAllowed } from "./utils/partnerConfigGating.js";
|
|
57
|
-
import { TransactionReviewDenied, TransactionReviewTimeout } from "./errors.js";
|
|
57
|
+
import { SigningResultError, TransactionReviewDenied, TransactionReviewTimeout } from "./errors.js";
|
|
58
58
|
import * as constants from "./constants.js";
|
|
59
59
|
import { EnclaveClient } from "./shares/enclave.js";
|
|
60
60
|
import { AuthService } from "./services/AuthService.js";
|
|
@@ -69,6 +69,24 @@ import { wrapWithSpan } from "./telemetry/tracer.js";
|
|
|
69
69
|
import { setCurrentUserId } from "./telemetry/uxStateSpanProcessor.js";
|
|
70
70
|
import { initTelemetry } from "./telemetry/init.js";
|
|
71
71
|
import { recordActionOnSpan } from "./telemetry/uxAction.js";
|
|
72
|
+
const DEFAULT_SIGNING_RESULT_ERROR_MESSAGE = "Signing failed before a signature was produced.";
|
|
73
|
+
function getPendingTransactionId(signRes) {
|
|
74
|
+
return typeof signRes.pendingTransactionId === "string" && signRes.pendingTransactionId.length > 0 ? signRes.pendingTransactionId : void 0;
|
|
75
|
+
}
|
|
76
|
+
function requireSuccessfulSignatureResult(signRes) {
|
|
77
|
+
if (typeof signRes.signature === "string" && signRes.signature.length > 0) {
|
|
78
|
+
return { signature: signRes.signature };
|
|
79
|
+
}
|
|
80
|
+
throw new SigningResultError(
|
|
81
|
+
typeof signRes.message === "string" && signRes.message.length > 0 ? signRes.message : DEFAULT_SIGNING_RESULT_ERROR_MESSAGE,
|
|
82
|
+
{
|
|
83
|
+
code: signRes.code,
|
|
84
|
+
status: signRes.status,
|
|
85
|
+
responseURL: signRes.responseURL,
|
|
86
|
+
data: signRes.data
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
72
90
|
const _ParaCore = class _ParaCore {
|
|
73
91
|
constructor(envOrApiKey, apiKeyOrOpts, opts) {
|
|
74
92
|
__privateAdd(this, _ParaCore_instances);
|
|
@@ -1770,6 +1788,37 @@ const _ParaCore = class _ParaCore {
|
|
|
1770
1788
|
yield this.ctx.client.enable2FA(userId, verificationCode);
|
|
1771
1789
|
});
|
|
1772
1790
|
}
|
|
1791
|
+
/**
|
|
1792
|
+
* Login-time 2FA (ENG-6906): enroll a TOTP second factor for the current session.
|
|
1793
|
+
* Distinct from setup2fa/enable2fa, which configure the recovery-gating 2FA. This
|
|
1794
|
+
* is authenticated by the active session (no recovery config gate); the backend
|
|
1795
|
+
* 404s the surface when the login-MFA flag is off.
|
|
1796
|
+
*
|
|
1797
|
+
* @returns {Object} `{ uri, backupCodes }` — otpauth URI to render as a QR, plus
|
|
1798
|
+
* one-time backup codes to show the user exactly once.
|
|
1799
|
+
*/
|
|
1800
|
+
enrollMfa() {
|
|
1801
|
+
return __async(this, null, function* () {
|
|
1802
|
+
yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
|
|
1803
|
+
return yield __privateGet(this, _authService).enrollMfa();
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
/**
|
|
1807
|
+
* Login-time 2FA (ENG-6906): verify the second factor for the current login. On
|
|
1808
|
+
* success the backend stamps the session and this re-polls the login status so the
|
|
1809
|
+
* flow advances toward `done`; a wrong code resolves to `{ ok:false, attemptsRemaining }`
|
|
1810
|
+
* so the UI can re-prompt without treating it as a hard error.
|
|
1811
|
+
*
|
|
1812
|
+
* @param {Object} opts the options object.
|
|
1813
|
+
* @param {string} opts.code the TOTP or backup code entered by the user.
|
|
1814
|
+
* @returns {Object} `{ ok: true } | { ok: false; attemptsRemaining? }`
|
|
1815
|
+
*/
|
|
1816
|
+
verifyMfa(_0) {
|
|
1817
|
+
return __async(this, arguments, function* ({ code }) {
|
|
1818
|
+
yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
|
|
1819
|
+
return yield __privateGet(this, _authService).verifyMfa({ code });
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1773
1822
|
/**
|
|
1774
1823
|
* Resend a verification email for the current user.
|
|
1775
1824
|
*/
|
|
@@ -2331,6 +2380,14 @@ const _ParaCore = class _ParaCore {
|
|
|
2331
2380
|
return result.url;
|
|
2332
2381
|
});
|
|
2333
2382
|
}
|
|
2383
|
+
getDeniedSignatureResultWithUrl(pendingTransactionId) {
|
|
2384
|
+
return __async(this, null, function* () {
|
|
2385
|
+
return {
|
|
2386
|
+
pendingTransactionId,
|
|
2387
|
+
transactionReviewUrl: yield this.getTransactionReviewUrl(pendingTransactionId)
|
|
2388
|
+
};
|
|
2389
|
+
});
|
|
2390
|
+
}
|
|
2334
2391
|
getOnRampTransactionUrl(_0) {
|
|
2335
2392
|
return __async(this, arguments, function* ({
|
|
2336
2393
|
purchaseId
|
|
@@ -2393,11 +2450,9 @@ const _ParaCore = class _ParaCore {
|
|
|
2393
2450
|
);
|
|
2394
2451
|
let timeStart = Date.now();
|
|
2395
2452
|
const effectiveTimeoutMs = Math.max(timeoutMs, constants.TRANSACTION_REVIEW_TIMEOUT_MS);
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
effectiveTimeoutMs
|
|
2400
|
-
);
|
|
2453
|
+
let pendingTransactionId = getPendingTransactionId(signRes);
|
|
2454
|
+
if (pendingTransactionId) {
|
|
2455
|
+
const reviewUrl = yield this.getTransactionReviewUrl(pendingTransactionId, effectiveTimeoutMs);
|
|
2401
2456
|
if (onTransactionReviewUrl) {
|
|
2402
2457
|
onTransactionReviewUrl(reviewUrl);
|
|
2403
2458
|
} else {
|
|
@@ -2406,8 +2461,9 @@ const _ParaCore = class _ParaCore {
|
|
|
2406
2461
|
});
|
|
2407
2462
|
}
|
|
2408
2463
|
} else {
|
|
2409
|
-
|
|
2410
|
-
|
|
2464
|
+
const successfulSignRes2 = requireSuccessfulSignatureResult(signRes);
|
|
2465
|
+
dispatchEvent(ParaEvent.SIGN_MESSAGE_EVENT, successfulSignRes2);
|
|
2466
|
+
return successfulSignRes2;
|
|
2411
2467
|
}
|
|
2412
2468
|
while (true) {
|
|
2413
2469
|
if (isCanceled() || Date.now() - timeStart > effectiveTimeoutMs) {
|
|
@@ -2421,15 +2477,19 @@ const _ParaCore = class _ParaCore {
|
|
|
2421
2477
|
"tx.review.poll",
|
|
2422
2478
|
(span) => __async(this, null, function* () {
|
|
2423
2479
|
var _a;
|
|
2424
|
-
const res = (_a = (yield this.ctx.client.getPendingTransaction(this.userId,
|
|
2480
|
+
const res = (_a = (yield this.ctx.client.getPendingTransaction(this.userId, pendingTransactionId)).data) == null ? void 0 : _a.pendingTransaction;
|
|
2425
2481
|
span.setAttribute("polling.status", (res == null ? void 0 : res.approvedAt) ? "approved" : "pending");
|
|
2426
2482
|
return res;
|
|
2427
2483
|
}),
|
|
2428
|
-
{ "pending_transaction.id":
|
|
2484
|
+
{ "pending_transaction.id": pendingTransactionId }
|
|
2429
2485
|
);
|
|
2430
2486
|
} catch (e) {
|
|
2431
2487
|
const error = new TransactionReviewDenied();
|
|
2432
|
-
dispatchEvent(
|
|
2488
|
+
dispatchEvent(
|
|
2489
|
+
ParaEvent.SIGN_MESSAGE_EVENT,
|
|
2490
|
+
yield this.getDeniedSignatureResultWithUrl(pendingTransactionId),
|
|
2491
|
+
error.message
|
|
2492
|
+
);
|
|
2433
2493
|
throw error;
|
|
2434
2494
|
}
|
|
2435
2495
|
if (!(pendingTransaction == null ? void 0 : pendingTransaction.approvedAt)) {
|
|
@@ -2444,16 +2504,16 @@ const _ParaCore = class _ParaCore {
|
|
|
2444
2504
|
break;
|
|
2445
2505
|
}
|
|
2446
2506
|
}
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
);
|
|
2452
|
-
dispatchEvent(ParaEvent.SIGN_MESSAGE_EVENT, signRes, error.message);
|
|
2507
|
+
pendingTransactionId = getPendingTransactionId(signRes);
|
|
2508
|
+
if (pendingTransactionId) {
|
|
2509
|
+
const deniedSignRes = yield this.getDeniedSignatureResultWithUrl(pendingTransactionId);
|
|
2510
|
+
const error = new TransactionReviewTimeout(deniedSignRes.transactionReviewUrl, pendingTransactionId);
|
|
2511
|
+
dispatchEvent(ParaEvent.SIGN_MESSAGE_EVENT, deniedSignRes, error.message);
|
|
2453
2512
|
throw error;
|
|
2454
2513
|
}
|
|
2455
|
-
|
|
2456
|
-
|
|
2514
|
+
const successfulSignRes = requireSuccessfulSignatureResult(signRes);
|
|
2515
|
+
dispatchEvent(ParaEvent.SIGN_MESSAGE_EVENT, successfulSignRes);
|
|
2516
|
+
return successfulSignRes;
|
|
2457
2517
|
});
|
|
2458
2518
|
}
|
|
2459
2519
|
signMessageInner(_0) {
|
|
@@ -2532,19 +2592,18 @@ const _ParaCore = class _ParaCore {
|
|
|
2532
2592
|
);
|
|
2533
2593
|
let timeStart = Date.now();
|
|
2534
2594
|
const effectiveTimeoutMs = Math.max(timeoutMs, constants.TRANSACTION_REVIEW_TIMEOUT_MS);
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
effectiveTimeoutMs
|
|
2539
|
-
);
|
|
2595
|
+
let pendingTransactionId = getPendingTransactionId(signRes);
|
|
2596
|
+
if (pendingTransactionId) {
|
|
2597
|
+
const reviewUrl = yield this.getTransactionReviewUrl(pendingTransactionId, effectiveTimeoutMs);
|
|
2540
2598
|
if (onTransactionReviewUrl) {
|
|
2541
2599
|
onTransactionReviewUrl(reviewUrl);
|
|
2542
2600
|
} else {
|
|
2543
2601
|
yield this.platformUtils.openPopup(reviewUrl, { type: PopupType.SIGN_TRANSACTION_REVIEW });
|
|
2544
2602
|
}
|
|
2545
2603
|
} else {
|
|
2546
|
-
|
|
2547
|
-
|
|
2604
|
+
const successfulSignRes2 = requireSuccessfulSignatureResult(signRes);
|
|
2605
|
+
dispatchEvent(ParaEvent.SIGN_TRANSACTION_EVENT, successfulSignRes2);
|
|
2606
|
+
return successfulSignRes2;
|
|
2548
2607
|
}
|
|
2549
2608
|
while (true) {
|
|
2550
2609
|
if (isCanceled() || Date.now() - timeStart > effectiveTimeoutMs) {
|
|
@@ -2552,7 +2611,7 @@ const _ParaCore = class _ParaCore {
|
|
|
2552
2611
|
break;
|
|
2553
2612
|
}
|
|
2554
2613
|
yield new Promise((resolve) => setTimeout(resolve, constants.POLLING_INTERVAL_MS));
|
|
2555
|
-
const pendingTxId =
|
|
2614
|
+
const pendingTxId = pendingTransactionId;
|
|
2556
2615
|
let pendingTransaction;
|
|
2557
2616
|
try {
|
|
2558
2617
|
pendingTransaction = yield wrapWithSpan(
|
|
@@ -2567,7 +2626,11 @@ const _ParaCore = class _ParaCore {
|
|
|
2567
2626
|
);
|
|
2568
2627
|
} catch (e) {
|
|
2569
2628
|
const error = new TransactionReviewDenied();
|
|
2570
|
-
dispatchEvent(
|
|
2629
|
+
dispatchEvent(
|
|
2630
|
+
ParaEvent.SIGN_TRANSACTION_EVENT,
|
|
2631
|
+
yield this.getDeniedSignatureResultWithUrl(pendingTxId),
|
|
2632
|
+
error.message
|
|
2633
|
+
);
|
|
2571
2634
|
throw error;
|
|
2572
2635
|
}
|
|
2573
2636
|
if (!(pendingTransaction == null ? void 0 : pendingTransaction.approvedAt)) {
|
|
@@ -2591,16 +2654,16 @@ const _ParaCore = class _ParaCore {
|
|
|
2591
2654
|
break;
|
|
2592
2655
|
}
|
|
2593
2656
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
);
|
|
2599
|
-
dispatchEvent(ParaEvent.SIGN_TRANSACTION_EVENT, signRes, error.message);
|
|
2657
|
+
pendingTransactionId = getPendingTransactionId(signRes);
|
|
2658
|
+
if (pendingTransactionId) {
|
|
2659
|
+
const deniedSignRes = yield this.getDeniedSignatureResultWithUrl(pendingTransactionId);
|
|
2660
|
+
const error = new TransactionReviewTimeout(deniedSignRes.transactionReviewUrl, pendingTransactionId);
|
|
2661
|
+
dispatchEvent(ParaEvent.SIGN_TRANSACTION_EVENT, deniedSignRes, error.message);
|
|
2600
2662
|
throw error;
|
|
2601
2663
|
}
|
|
2602
|
-
|
|
2603
|
-
|
|
2664
|
+
const successfulSignRes = requireSuccessfulSignatureResult(signRes);
|
|
2665
|
+
dispatchEvent(ParaEvent.SIGN_TRANSACTION_EVENT, successfulSignRes);
|
|
2666
|
+
return successfulSignRes;
|
|
2604
2667
|
});
|
|
2605
2668
|
}
|
|
2606
2669
|
isProviderModalDisabled() {
|
package/dist/esm/constants.js
CHANGED
package/dist/esm/errors.js
CHANGED
|
@@ -20,6 +20,16 @@ class TransactionReviewTimeout extends Error {
|
|
|
20
20
|
this.pendingTransactionId = pendingTransactionId;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
class SigningResultError extends Error {
|
|
24
|
+
constructor(message, options = {}) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "SigningResultError";
|
|
27
|
+
this.code = options.code;
|
|
28
|
+
this.status = options.status;
|
|
29
|
+
this.responseURL = options.responseURL;
|
|
30
|
+
this.data = options.data;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
23
33
|
class PartnerConfigError extends Error {
|
|
24
34
|
constructor(code, message, detail) {
|
|
25
35
|
super(message);
|
|
@@ -30,6 +40,7 @@ class PartnerConfigError extends Error {
|
|
|
30
40
|
}
|
|
31
41
|
export {
|
|
32
42
|
PartnerConfigError,
|
|
43
|
+
SigningResultError,
|
|
33
44
|
TransactionReviewDenied,
|
|
34
45
|
TransactionReviewError,
|
|
35
46
|
TransactionReviewTimeout
|
|
@@ -169,6 +169,11 @@ class AuthService {
|
|
|
169
169
|
JSON.stringify(isSLOPossible)
|
|
170
170
|
);
|
|
171
171
|
return serverAuthState;
|
|
172
|
+
// No preparation needed
|
|
173
|
+
case "mfa":
|
|
174
|
+
return serverAuthState;
|
|
175
|
+
default:
|
|
176
|
+
return serverAuthState;
|
|
172
177
|
}
|
|
173
178
|
});
|
|
174
179
|
this.prepareLoginState = (_0, _1) => __async(this, [_0, _1], function* (loginState, { useShortUrls: shorten = false, portalTheme, sessionLookupId }) {
|
|
@@ -420,10 +425,46 @@ class AuthService {
|
|
|
420
425
|
return yield waitForAuthStateChange({
|
|
421
426
|
stateManager: __privateGet(this, _stateManager),
|
|
422
427
|
resolvePhases: [
|
|
423
|
-
{ phase: "awaiting_session_start", onPhase: (state) => state.authStateResult }
|
|
428
|
+
{ phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
|
|
429
|
+
// Login-time 2FA (ENG-6906): the OAuth poll surfaced an mfa challenge instead
|
|
430
|
+
// of completing. Resolve here so the caller stops blocking; the challenge is
|
|
431
|
+
// read from the consumer auth state (AuthStateInfo.mfa) and satisfied via the
|
|
432
|
+
// enroll/verify hooks, which fire RESOLVE_2FA to continue the flow.
|
|
433
|
+
{ phase: "awaiting_2fa", onPhase: (state) => state.authStateResult },
|
|
434
|
+
{ phase: "awaiting_2fa_enrollment", onPhase: (state) => state.authStateResult }
|
|
424
435
|
]
|
|
425
436
|
});
|
|
426
437
|
});
|
|
438
|
+
/**
|
|
439
|
+
* Login-time 2FA (ENG-6906): after the second factor has been satisfied/enrolled
|
|
440
|
+
* server-side, re-poll the login status to advance the flow. Fires RESOLVE_2FA,
|
|
441
|
+
* which re-enters verify-oauth polling (now returning stage:'done') and routes
|
|
442
|
+
* onward to awaiting_session_start / authenticated.
|
|
443
|
+
*/
|
|
444
|
+
this.resolveMfa = (pollingCallbacks) => __async(this, null, function* () {
|
|
445
|
+
__privateGet(this, _stateManager).send({ type: "RESOLVE_2FA", data: pollingCallbacks });
|
|
446
|
+
return yield waitForAuthStateChange({
|
|
447
|
+
stateManager: __privateGet(this, _stateManager),
|
|
448
|
+
resolvePhases: [
|
|
449
|
+
{ phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
|
|
450
|
+
{ phase: "authenticated", onPhase: (state) => state.authStateResult }
|
|
451
|
+
],
|
|
452
|
+
// If re-polling after the second factor lands in the auth error phase, reject fast
|
|
453
|
+
// with a clear message instead of stalling until the listener's default timeout. The
|
|
454
|
+
// caller stays parked at awaiting_2fa and can re-prompt/retry. (ENG-6906)
|
|
455
|
+
rejectPhases: [{ phase: "error", onPhase: () => new Error("Login 2FA resolution failed") }]
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
this.enrollMfa = () => __async(this, null, function* () {
|
|
459
|
+
return yield __privateGet(this, _paraCoreInterface).ctx.client.enrollMfa();
|
|
460
|
+
});
|
|
461
|
+
this.verifyMfa = (_0) => __async(this, [_0], function* ({ code }) {
|
|
462
|
+
const result = yield __privateGet(this, _paraCoreInterface).ctx.client.verifyMfa(code);
|
|
463
|
+
if (result.ok) {
|
|
464
|
+
yield this.resolveMfa();
|
|
465
|
+
}
|
|
466
|
+
return result;
|
|
467
|
+
});
|
|
427
468
|
this.authenticateWithOAuth = (params) => __async(this, null, function* () {
|
|
428
469
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
429
470
|
switch (params.method) {
|
|
@@ -80,7 +80,7 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
80
80
|
* Extracts all data needed by UI consumers from authStateResult.
|
|
81
81
|
*/
|
|
82
82
|
computeAuthStateInfo(authContext, walletContext) {
|
|
83
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L;
|
|
83
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q;
|
|
84
84
|
const defaultAuthStateInfo = {
|
|
85
85
|
userId: null,
|
|
86
86
|
isPasskeySupported: false,
|
|
@@ -102,6 +102,7 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
102
102
|
fallbackUsed: false,
|
|
103
103
|
fallbackChannel: null,
|
|
104
104
|
externalWalletVerification: null,
|
|
105
|
+
mfa: null,
|
|
105
106
|
recoverySecret: null,
|
|
106
107
|
isNewUser: false
|
|
107
108
|
};
|
|
@@ -143,6 +144,7 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
143
144
|
let deliveryChannel = null;
|
|
144
145
|
let fallbackUsed = false;
|
|
145
146
|
let fallbackChannel = null;
|
|
147
|
+
let mfa = null;
|
|
146
148
|
if (stage === "login") {
|
|
147
149
|
const loginState = authStateResult;
|
|
148
150
|
const authMethods = (_j = loginState.loginAuthMethods) != null ? _j : [];
|
|
@@ -179,6 +181,17 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
179
181
|
deliveryChannel = (_E = verifyState.deliveryChannel) != null ? _E : null;
|
|
180
182
|
fallbackUsed = (_F = verifyState.fallbackUsed) != null ? _F : false;
|
|
181
183
|
fallbackChannel = (_G = verifyState.fallbackChannel) != null ? _G : null;
|
|
184
|
+
} else if (stage === "mfa") {
|
|
185
|
+
const { mfa: challenge } = authStateResult;
|
|
186
|
+
mfa = {
|
|
187
|
+
mode: challenge.mode,
|
|
188
|
+
step: challenge.step,
|
|
189
|
+
methods: (_H = challenge.methods) != null ? _H : null,
|
|
190
|
+
attemptsRemaining: (_I = challenge.attemptsRemaining) != null ? _I : null,
|
|
191
|
+
lockedUntil: (_J = challenge.lockedUntil) != null ? _J : null,
|
|
192
|
+
secretUri: (_K = challenge.secretUri) != null ? _K : null,
|
|
193
|
+
backupCodes: (_L = challenge.backupCodes) != null ? _L : null
|
|
194
|
+
};
|
|
182
195
|
}
|
|
183
196
|
return {
|
|
184
197
|
userId,
|
|
@@ -201,10 +214,11 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
201
214
|
fallbackUsed,
|
|
202
215
|
fallbackChannel,
|
|
203
216
|
externalWalletVerification: externalWalletVerification ? {
|
|
204
|
-
signatureVerificationMessage: (
|
|
205
|
-
walletAddress: (
|
|
206
|
-
walletType: (
|
|
217
|
+
signatureVerificationMessage: (_M = externalWalletVerification.signatureVerificationMessage) != null ? _M : "",
|
|
218
|
+
walletAddress: (_O = (_N = externalWalletVerification.externalWallet) == null ? void 0 : _N.address) != null ? _O : "",
|
|
219
|
+
walletType: (_Q = (_P = externalWalletVerification.externalWallet) == null ? void 0 : _P.type) != null ? _Q : ""
|
|
207
220
|
} : null,
|
|
221
|
+
mfa,
|
|
208
222
|
recoverySecret,
|
|
209
223
|
isNewUser
|
|
210
224
|
};
|
|
@@ -265,10 +279,19 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
265
279
|
}
|
|
266
280
|
authStateInfoEqual(a, b) {
|
|
267
281
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
268
|
-
return a.userId === b.userId && a.isPasskeySupported === b.isPasskeySupported && a.hasPasskey === b.hasPasskey && a.hasPassword === b.hasPassword && a.hasPin === b.hasPin && a.passkeyUrl === b.passkeyUrl && a.passkeyFullUrl === b.passkeyFullUrl && a.passkeyKnownDeviceUrl === b.passkeyKnownDeviceUrl && a.passwordUrl === b.passwordUrl && a.passwordFullUrl === b.passwordFullUrl && a.pinUrl === b.pinUrl && a.pinFullUrl === b.pinFullUrl && a.passkeyId === b.passkeyId && a.verificationUrl === b.verificationUrl && a.verificationFullUrl === b.verificationFullUrl && a.deliveryChannel === b.deliveryChannel && a.fallbackUsed === b.fallbackUsed && a.fallbackChannel === b.fallbackChannel && a.recoverySecret === b.recoverySecret && a.isNewUser === b.isNewUser && ((_a = a.externalWalletVerification) == null ? void 0 : _a.signatureVerificationMessage) === ((_b = b.externalWalletVerification) == null ? void 0 : _b.signatureVerificationMessage) && ((_c = a.externalWalletVerification) == null ? void 0 : _c.walletAddress) === ((_d = b.externalWalletVerification) == null ? void 0 : _d.walletAddress) && ((_e = a.externalWalletVerification) == null ? void 0 : _e.walletType) === ((_f = b.externalWalletVerification) == null ? void 0 : _f.walletType) && ((_g = a.passkeyHints) == null ? void 0 : _g.length) === ((_h = b.passkeyHints) == null ? void 0 : _h.length) && ((_i = a.passkeyHints) != null ? _i : []).every(
|
|
282
|
+
return a.userId === b.userId && a.isPasskeySupported === b.isPasskeySupported && a.hasPasskey === b.hasPasskey && a.hasPassword === b.hasPassword && a.hasPin === b.hasPin && a.passkeyUrl === b.passkeyUrl && a.passkeyFullUrl === b.passkeyFullUrl && a.passkeyKnownDeviceUrl === b.passkeyKnownDeviceUrl && a.passwordUrl === b.passwordUrl && a.passwordFullUrl === b.passwordFullUrl && a.pinUrl === b.pinUrl && a.pinFullUrl === b.pinFullUrl && a.passkeyId === b.passkeyId && a.verificationUrl === b.verificationUrl && a.verificationFullUrl === b.verificationFullUrl && a.deliveryChannel === b.deliveryChannel && a.fallbackUsed === b.fallbackUsed && a.fallbackChannel === b.fallbackChannel && a.recoverySecret === b.recoverySecret && a.isNewUser === b.isNewUser && ((_a = a.externalWalletVerification) == null ? void 0 : _a.signatureVerificationMessage) === ((_b = b.externalWalletVerification) == null ? void 0 : _b.signatureVerificationMessage) && ((_c = a.externalWalletVerification) == null ? void 0 : _c.walletAddress) === ((_d = b.externalWalletVerification) == null ? void 0 : _d.walletAddress) && ((_e = a.externalWalletVerification) == null ? void 0 : _e.walletType) === ((_f = b.externalWalletVerification) == null ? void 0 : _f.walletType) && this.mfaEqual(a.mfa, b.mfa) && ((_g = a.passkeyHints) == null ? void 0 : _g.length) === ((_h = b.passkeyHints) == null ? void 0 : _h.length) && ((_i = a.passkeyHints) != null ? _i : []).every(
|
|
269
283
|
(hint, i) => hint.useragent === b.passkeyHints[i].useragent && hint.aaguid === b.passkeyHints[i].aaguid
|
|
270
284
|
);
|
|
271
285
|
}
|
|
286
|
+
mfaEqual(a, b) {
|
|
287
|
+
if (a === b) return true;
|
|
288
|
+
if (!a || !b) return false;
|
|
289
|
+
const sameStringArray = (x, y) => {
|
|
290
|
+
var _a, _b;
|
|
291
|
+
return ((_a = x == null ? void 0 : x.length) != null ? _a : -1) === ((_b = y == null ? void 0 : y.length) != null ? _b : -1) && (x != null ? x : []).every((v, i) => v === y[i]);
|
|
292
|
+
};
|
|
293
|
+
return a.mode === b.mode && a.step === b.step && a.attemptsRemaining === b.attemptsRemaining && a.lockedUntil === b.lockedUntil && a.secretUri === b.secretUri && sameStringArray(a.methods, b.methods) && sameStringArray(a.backupCodes, b.backupCodes);
|
|
294
|
+
}
|
|
272
295
|
};
|
|
273
296
|
_CoreStateManager.CORE_LOADING_STATES = /* @__PURE__ */ new Set([
|
|
274
297
|
"setting_up",
|
|
@@ -282,7 +305,11 @@ _CoreStateManager.AUTH_LOADING_STATES = /* @__PURE__ */ new Set([
|
|
|
282
305
|
"authenticating_farcaster",
|
|
283
306
|
"processing_authentication",
|
|
284
307
|
"authenticating_telegram",
|
|
285
|
-
"checking_state"
|
|
308
|
+
"checking_state",
|
|
309
|
+
// Re-polling the login status after the second factor is satisfied (ENG-6906).
|
|
310
|
+
// awaiting_2fa / awaiting_2fa_enrollment are deliberately NOT loading — they are
|
|
311
|
+
// user-input holds where the UI shows the MFA prompt.
|
|
312
|
+
"resolving_2fa"
|
|
286
313
|
]);
|
|
287
314
|
_CoreStateManager.WALLET_LOADING_STATES = /* @__PURE__ */ new Set([
|
|
288
315
|
"checking_wallet_state",
|
|
@@ -712,18 +712,18 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
712
712
|
guard: and([
|
|
713
713
|
({ event }) => {
|
|
714
714
|
const output = event.output;
|
|
715
|
-
return !!output.externalWallet;
|
|
715
|
+
return !!(output == null ? void 0 : output.externalWallet);
|
|
716
716
|
},
|
|
717
717
|
or([
|
|
718
718
|
({ event }) => {
|
|
719
719
|
var _a;
|
|
720
720
|
const output = event.output;
|
|
721
|
-
return output.stage === "done" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
721
|
+
return (output == null ? void 0 : output.stage) === "done" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
722
722
|
},
|
|
723
723
|
({ event }) => {
|
|
724
724
|
var _a, _b;
|
|
725
725
|
const output = event.output;
|
|
726
|
-
return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && !((_b = output.externalWallet) == null ? void 0 : _b.withVerification);
|
|
726
|
+
return (output == null ? void 0 : output.stage) === "verify" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && !((_b = output == null ? void 0 : output.externalWallet) == null ? void 0 : _b.withVerification);
|
|
727
727
|
}
|
|
728
728
|
])
|
|
729
729
|
])
|
|
@@ -740,12 +740,12 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
740
740
|
guard: and([
|
|
741
741
|
({ event }) => {
|
|
742
742
|
const output = event.output;
|
|
743
|
-
return !!output.externalWallet;
|
|
743
|
+
return !!(output == null ? void 0 : output.externalWallet);
|
|
744
744
|
},
|
|
745
745
|
({ event }) => {
|
|
746
746
|
var _a, _b;
|
|
747
747
|
const output = event.output;
|
|
748
|
-
return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && ((_b = output.externalWallet) == null ? void 0 : _b.withVerification);
|
|
748
|
+
return (output == null ? void 0 : output.stage) === "verify" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && ((_b = output == null ? void 0 : output.externalWallet) == null ? void 0 : _b.withVerification);
|
|
749
749
|
}
|
|
750
750
|
])
|
|
751
751
|
},
|
|
@@ -761,12 +761,12 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
761
761
|
guard: and([
|
|
762
762
|
({ event }) => {
|
|
763
763
|
const output = event.output;
|
|
764
|
-
return !!output.externalWallet;
|
|
764
|
+
return !!(output == null ? void 0 : output.externalWallet);
|
|
765
765
|
},
|
|
766
766
|
({ event }) => {
|
|
767
767
|
var _a;
|
|
768
768
|
const output = event.output;
|
|
769
|
-
return output.stage === "verify" && !!((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
769
|
+
return (output == null ? void 0 : output.stage) === "verify" && !!((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
770
770
|
}
|
|
771
771
|
])
|
|
772
772
|
},
|
|
@@ -780,11 +780,37 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
780
780
|
({ event }) => {
|
|
781
781
|
var _a;
|
|
782
782
|
const output = event.output;
|
|
783
|
-
return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
783
|
+
return (output == null ? void 0 : output.stage) === "verify" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
784
784
|
},
|
|
785
785
|
() => !paraCoreInterface.authService.isEnclaveUser
|
|
786
786
|
])
|
|
787
787
|
},
|
|
788
|
+
// Login-time 2FA (ENG-6906): the server gated the login behind a second
|
|
789
|
+
// factor. Enrollment (no factor yet) and verification (existing factor)
|
|
790
|
+
// are surfaced as distinct phases so a custom UI can show the right step.
|
|
791
|
+
{
|
|
792
|
+
target: "awaiting_2fa_enrollment",
|
|
793
|
+
actions: [
|
|
794
|
+
"storeAuthStateResult",
|
|
795
|
+
{ type: "logTransition", params: { to: "awaiting_2fa_enrollment", detail: "mfa enroll" } }
|
|
796
|
+
],
|
|
797
|
+
guard: ({ event }) => {
|
|
798
|
+
var _a;
|
|
799
|
+
const output = event.output;
|
|
800
|
+
return (output == null ? void 0 : output.stage) === "mfa" && ((_a = output == null ? void 0 : output.mfa) == null ? void 0 : _a.mode) === "enroll";
|
|
801
|
+
}
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
target: "awaiting_2fa",
|
|
805
|
+
actions: [
|
|
806
|
+
"storeAuthStateResult",
|
|
807
|
+
{ type: "logTransition", params: { to: "awaiting_2fa", detail: "mfa verify" } }
|
|
808
|
+
],
|
|
809
|
+
guard: ({ event }) => {
|
|
810
|
+
const output = event.output;
|
|
811
|
+
return (output == null ? void 0 : output.stage) === "mfa";
|
|
812
|
+
}
|
|
813
|
+
},
|
|
788
814
|
{
|
|
789
815
|
target: "awaiting_session_start",
|
|
790
816
|
actions: [
|
|
@@ -827,6 +853,77 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
827
853
|
CANCEL: { target: "unauthenticated", actions: ["resetState"] }
|
|
828
854
|
}
|
|
829
855
|
},
|
|
856
|
+
// Login-time 2FA hold states (ENG-6906). The SDK satisfies the second factor
|
|
857
|
+
// out-of-band (enrollMfa/verifyMfa against /internal/v1/auth/2fa/*); once the
|
|
858
|
+
// backend has stamped the session, a RESOLVE_2FA event re-polls the login
|
|
859
|
+
// status, which now returns stage:'done'.
|
|
860
|
+
awaiting_2fa: {
|
|
861
|
+
on: {
|
|
862
|
+
RESOLVE_2FA: { target: "resolving_2fa", actions: ["setPollingCallbacks", "resetError"] },
|
|
863
|
+
CANCEL: { target: "unauthenticated", actions: ["resetState"] }
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
awaiting_2fa_enrollment: {
|
|
867
|
+
on: {
|
|
868
|
+
RESOLVE_2FA: { target: "resolving_2fa", actions: ["setPollingCallbacks", "resetError"] },
|
|
869
|
+
CANCEL: { target: "unauthenticated", actions: ["resetState"] }
|
|
870
|
+
}
|
|
871
|
+
},
|
|
872
|
+
resolving_2fa: {
|
|
873
|
+
entry: [{ type: "logTransition", params: { to: "resolving_2fa" } }],
|
|
874
|
+
invoke: {
|
|
875
|
+
src: "polling",
|
|
876
|
+
input: ({ context }) => {
|
|
877
|
+
var _a;
|
|
878
|
+
let resolvedAuthState = null;
|
|
879
|
+
return {
|
|
880
|
+
checkCondition: () => __async(this, null, function* () {
|
|
881
|
+
try {
|
|
882
|
+
const result = yield paraCoreInterface.pollingService.waitForOAuth({
|
|
883
|
+
onSuccess: (serverAuthState) => {
|
|
884
|
+
resolvedAuthState = serverAuthState;
|
|
885
|
+
}
|
|
886
|
+
})();
|
|
887
|
+
return { finished: result.finished && !!resolvedAuthState, data: { authState: resolvedAuthState } };
|
|
888
|
+
} catch (error) {
|
|
889
|
+
throw new Error(`2FA resolution polling failed: ${extractErrorMessage(error, "Unknown error")}`);
|
|
890
|
+
}
|
|
891
|
+
}),
|
|
892
|
+
onPoll: () => {
|
|
893
|
+
var _a2, _b;
|
|
894
|
+
return (_b = (_a2 = context.pollingCallbacks) == null ? void 0 : _a2.onPoll) == null ? void 0 : _b.call(_a2);
|
|
895
|
+
},
|
|
896
|
+
onCancel: () => {
|
|
897
|
+
var _a2, _b;
|
|
898
|
+
return (_b = (_a2 = context.pollingCallbacks) == null ? void 0 : _a2.onCancel) == null ? void 0 : _b.call(_a2);
|
|
899
|
+
},
|
|
900
|
+
isCanceled: ((_a = context.pollingCallbacks) == null ? void 0 : _a.isCanceled) || (() => false),
|
|
901
|
+
id: "resolving2fa"
|
|
902
|
+
};
|
|
903
|
+
},
|
|
904
|
+
onError: {
|
|
905
|
+
target: "error",
|
|
906
|
+
actions: setAuthErrorAssign("2FA resolution failed")
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
on: makePollingOnHandlers("processing_authentication", "2FA resolution failed", [
|
|
910
|
+
assign({
|
|
911
|
+
serverAuthStateResult: ({ event }) => {
|
|
912
|
+
var _a;
|
|
913
|
+
const authState = ((_a = event.data) == null ? void 0 : _a.authState) || null;
|
|
914
|
+
return {
|
|
915
|
+
authState,
|
|
916
|
+
opts: DEFAULT_AUTH_OPTS
|
|
917
|
+
};
|
|
918
|
+
},
|
|
919
|
+
isNewUser: ({ event }) => {
|
|
920
|
+
var _a;
|
|
921
|
+
const authState = (_a = event.data) == null ? void 0 : _a.authState;
|
|
922
|
+
return authState ? computeIsNewUser(authState) : false;
|
|
923
|
+
}
|
|
924
|
+
})
|
|
925
|
+
])
|
|
926
|
+
},
|
|
830
927
|
awaiting_session_start: {
|
|
831
928
|
on: {
|
|
832
929
|
WAIT_FOR_SESSION: {
|
|
@@ -180,6 +180,14 @@ function createCoreStateMachine(paraCoreInterface) {
|
|
|
180
180
|
"WAIT_FOR_WALLET_CREATION": {
|
|
181
181
|
actions: ({ context, event }) => context.authMachineRef.send(event)
|
|
182
182
|
},
|
|
183
|
+
// Login-time 2FA (ENG-6906): after the second factor is satisfied, verifyMfa
|
|
184
|
+
// fires RESOLVE_2FA so the auth machine re-polls verify-oauth and advances the
|
|
185
|
+
// login. Without forwarding it here the parent silently drops the event, the
|
|
186
|
+
// auth child stays parked at awaiting_2fa[_enrollment], and the user never gets
|
|
187
|
+
// a wallet.
|
|
188
|
+
"RESOLVE_2FA": {
|
|
189
|
+
actions: ({ context, event }) => context.authMachineRef.send(event)
|
|
190
|
+
},
|
|
183
191
|
"INITIALIZE_GUEST_MODE": {
|
|
184
192
|
actions: ({ context, event }) => context.authMachineRef.send(event)
|
|
185
193
|
},
|