@getpara/core-sdk 3.4.0 → 3.5.0
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 +31 -0
- package/dist/cjs/constants.js +1 -1
- 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 +31 -0
- package/dist/esm/constants.js +1 -1
- 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 +23 -2
- 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/cjs/ParaCore.js
CHANGED
|
@@ -1825,6 +1825,37 @@ const _ParaCore = class _ParaCore {
|
|
|
1825
1825
|
yield this.ctx.client.enable2FA(userId, verificationCode);
|
|
1826
1826
|
});
|
|
1827
1827
|
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Login-time 2FA (ENG-6906): enroll a TOTP second factor for the current session.
|
|
1830
|
+
* Distinct from setup2fa/enable2fa, which configure the recovery-gating 2FA. This
|
|
1831
|
+
* is authenticated by the active session (no recovery config gate); the backend
|
|
1832
|
+
* 404s the surface when the login-MFA flag is off.
|
|
1833
|
+
*
|
|
1834
|
+
* @returns {Object} `{ uri, backupCodes }` — otpauth URI to render as a QR, plus
|
|
1835
|
+
* one-time backup codes to show the user exactly once.
|
|
1836
|
+
*/
|
|
1837
|
+
enrollMfa() {
|
|
1838
|
+
return __async(this, null, function* () {
|
|
1839
|
+
yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
|
|
1840
|
+
return yield __privateGet(this, _authService).enrollMfa();
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Login-time 2FA (ENG-6906): verify the second factor for the current login. On
|
|
1845
|
+
* success the backend stamps the session and this re-polls the login status so the
|
|
1846
|
+
* flow advances toward `done`; a wrong code resolves to `{ ok:false, attemptsRemaining }`
|
|
1847
|
+
* so the UI can re-prompt without treating it as a hard error.
|
|
1848
|
+
*
|
|
1849
|
+
* @param {Object} opts the options object.
|
|
1850
|
+
* @param {string} opts.code the TOTP or backup code entered by the user.
|
|
1851
|
+
* @returns {Object} `{ ok: true } | { ok: false; attemptsRemaining? }`
|
|
1852
|
+
*/
|
|
1853
|
+
verifyMfa(_0) {
|
|
1854
|
+
return __async(this, arguments, function* ({ code }) {
|
|
1855
|
+
yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
|
|
1856
|
+
return yield __privateGet(this, _authService).verifyMfa({ code });
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1828
1859
|
/**
|
|
1829
1860
|
* Resend a verification email for the current user.
|
|
1830
1861
|
*/
|
package/dist/cjs/constants.js
CHANGED
|
@@ -46,7 +46,7 @@ __export(constants_exports, {
|
|
|
46
46
|
TRANSACTION_REVIEW_TIMEOUT_MS: () => TRANSACTION_REVIEW_TIMEOUT_MS
|
|
47
47
|
});
|
|
48
48
|
module.exports = __toCommonJS(constants_exports);
|
|
49
|
-
const PARA_CORE_VERSION = "3.
|
|
49
|
+
const PARA_CORE_VERSION = "3.5.0";
|
|
50
50
|
const PREFIX = "@CAPSULE/";
|
|
51
51
|
const PARA_PREFIX = "@PARA/";
|
|
52
52
|
const LOCAL_STORAGE_AUTH_INFO = `${PREFIX}authInfo`;
|
|
@@ -238,6 +238,11 @@ class AuthService {
|
|
|
238
238
|
JSON.stringify(isSLOPossible)
|
|
239
239
|
);
|
|
240
240
|
return serverAuthState;
|
|
241
|
+
// No preparation needed
|
|
242
|
+
case "mfa":
|
|
243
|
+
return serverAuthState;
|
|
244
|
+
default:
|
|
245
|
+
return serverAuthState;
|
|
241
246
|
}
|
|
242
247
|
});
|
|
243
248
|
this.prepareLoginState = (_0, _1) => __async(this, [_0, _1], function* (loginState, { useShortUrls: shorten = false, portalTheme, sessionLookupId }) {
|
|
@@ -489,10 +494,46 @@ class AuthService {
|
|
|
489
494
|
return yield (0, import_stateListener.waitForAuthStateChange)({
|
|
490
495
|
stateManager: __privateGet(this, _stateManager),
|
|
491
496
|
resolvePhases: [
|
|
492
|
-
{ phase: "awaiting_session_start", onPhase: (state) => state.authStateResult }
|
|
497
|
+
{ phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
|
|
498
|
+
// Login-time 2FA (ENG-6906): the OAuth poll surfaced an mfa challenge instead
|
|
499
|
+
// of completing. Resolve here so the caller stops blocking; the challenge is
|
|
500
|
+
// read from the consumer auth state (AuthStateInfo.mfa) and satisfied via the
|
|
501
|
+
// enroll/verify hooks, which fire RESOLVE_2FA to continue the flow.
|
|
502
|
+
{ phase: "awaiting_2fa", onPhase: (state) => state.authStateResult },
|
|
503
|
+
{ phase: "awaiting_2fa_enrollment", onPhase: (state) => state.authStateResult }
|
|
493
504
|
]
|
|
494
505
|
});
|
|
495
506
|
});
|
|
507
|
+
/**
|
|
508
|
+
* Login-time 2FA (ENG-6906): after the second factor has been satisfied/enrolled
|
|
509
|
+
* server-side, re-poll the login status to advance the flow. Fires RESOLVE_2FA,
|
|
510
|
+
* which re-enters verify-oauth polling (now returning stage:'done') and routes
|
|
511
|
+
* onward to awaiting_session_start / authenticated.
|
|
512
|
+
*/
|
|
513
|
+
this.resolveMfa = (pollingCallbacks) => __async(this, null, function* () {
|
|
514
|
+
__privateGet(this, _stateManager).send({ type: "RESOLVE_2FA", data: pollingCallbacks });
|
|
515
|
+
return yield (0, import_stateListener.waitForAuthStateChange)({
|
|
516
|
+
stateManager: __privateGet(this, _stateManager),
|
|
517
|
+
resolvePhases: [
|
|
518
|
+
{ phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
|
|
519
|
+
{ phase: "authenticated", onPhase: (state) => state.authStateResult }
|
|
520
|
+
],
|
|
521
|
+
// If re-polling after the second factor lands in the auth error phase, reject fast
|
|
522
|
+
// with a clear message instead of stalling until the listener's default timeout. The
|
|
523
|
+
// caller stays parked at awaiting_2fa and can re-prompt/retry. (ENG-6906)
|
|
524
|
+
rejectPhases: [{ phase: "error", onPhase: () => new Error("Login 2FA resolution failed") }]
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
this.enrollMfa = () => __async(this, null, function* () {
|
|
528
|
+
return yield __privateGet(this, _paraCoreInterface).ctx.client.enrollMfa();
|
|
529
|
+
});
|
|
530
|
+
this.verifyMfa = (_0) => __async(this, [_0], function* ({ code }) {
|
|
531
|
+
const result = yield __privateGet(this, _paraCoreInterface).ctx.client.verifyMfa(code);
|
|
532
|
+
if (result.ok) {
|
|
533
|
+
yield this.resolveMfa();
|
|
534
|
+
}
|
|
535
|
+
return result;
|
|
536
|
+
});
|
|
496
537
|
this.authenticateWithOAuth = (params) => __async(this, null, function* () {
|
|
497
538
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
498
539
|
switch (params.method) {
|
|
@@ -115,7 +115,7 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
115
115
|
* Extracts all data needed by UI consumers from authStateResult.
|
|
116
116
|
*/
|
|
117
117
|
computeAuthStateInfo(authContext, walletContext) {
|
|
118
|
-
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;
|
|
118
|
+
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;
|
|
119
119
|
const defaultAuthStateInfo = {
|
|
120
120
|
userId: null,
|
|
121
121
|
isPasskeySupported: false,
|
|
@@ -137,6 +137,7 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
137
137
|
fallbackUsed: false,
|
|
138
138
|
fallbackChannel: null,
|
|
139
139
|
externalWalletVerification: null,
|
|
140
|
+
mfa: null,
|
|
140
141
|
recoverySecret: null,
|
|
141
142
|
isNewUser: false
|
|
142
143
|
};
|
|
@@ -178,6 +179,7 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
178
179
|
let deliveryChannel = null;
|
|
179
180
|
let fallbackUsed = false;
|
|
180
181
|
let fallbackChannel = null;
|
|
182
|
+
let mfa = null;
|
|
181
183
|
if (stage === "login") {
|
|
182
184
|
const loginState = authStateResult;
|
|
183
185
|
const authMethods = (_j = loginState.loginAuthMethods) != null ? _j : [];
|
|
@@ -214,6 +216,17 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
214
216
|
deliveryChannel = (_E = verifyState.deliveryChannel) != null ? _E : null;
|
|
215
217
|
fallbackUsed = (_F = verifyState.fallbackUsed) != null ? _F : false;
|
|
216
218
|
fallbackChannel = (_G = verifyState.fallbackChannel) != null ? _G : null;
|
|
219
|
+
} else if (stage === "mfa") {
|
|
220
|
+
const { mfa: challenge } = authStateResult;
|
|
221
|
+
mfa = {
|
|
222
|
+
mode: challenge.mode,
|
|
223
|
+
step: challenge.step,
|
|
224
|
+
methods: (_H = challenge.methods) != null ? _H : null,
|
|
225
|
+
attemptsRemaining: (_I = challenge.attemptsRemaining) != null ? _I : null,
|
|
226
|
+
lockedUntil: (_J = challenge.lockedUntil) != null ? _J : null,
|
|
227
|
+
secretUri: (_K = challenge.secretUri) != null ? _K : null,
|
|
228
|
+
backupCodes: (_L = challenge.backupCodes) != null ? _L : null
|
|
229
|
+
};
|
|
217
230
|
}
|
|
218
231
|
return {
|
|
219
232
|
userId,
|
|
@@ -236,10 +249,11 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
236
249
|
fallbackUsed,
|
|
237
250
|
fallbackChannel,
|
|
238
251
|
externalWalletVerification: externalWalletVerification ? {
|
|
239
|
-
signatureVerificationMessage: (
|
|
240
|
-
walletAddress: (
|
|
241
|
-
walletType: (
|
|
252
|
+
signatureVerificationMessage: (_M = externalWalletVerification.signatureVerificationMessage) != null ? _M : "",
|
|
253
|
+
walletAddress: (_O = (_N = externalWalletVerification.externalWallet) == null ? void 0 : _N.address) != null ? _O : "",
|
|
254
|
+
walletType: (_Q = (_P = externalWalletVerification.externalWallet) == null ? void 0 : _P.type) != null ? _Q : ""
|
|
242
255
|
} : null,
|
|
256
|
+
mfa,
|
|
243
257
|
recoverySecret,
|
|
244
258
|
isNewUser
|
|
245
259
|
};
|
|
@@ -300,10 +314,19 @@ const _CoreStateManager = class _CoreStateManager {
|
|
|
300
314
|
}
|
|
301
315
|
authStateInfoEqual(a, b) {
|
|
302
316
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
303
|
-
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(
|
|
317
|
+
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(
|
|
304
318
|
(hint, i) => hint.useragent === b.passkeyHints[i].useragent && hint.aaguid === b.passkeyHints[i].aaguid
|
|
305
319
|
);
|
|
306
320
|
}
|
|
321
|
+
mfaEqual(a, b) {
|
|
322
|
+
if (a === b) return true;
|
|
323
|
+
if (!a || !b) return false;
|
|
324
|
+
const sameStringArray = (x, y) => {
|
|
325
|
+
var _a, _b;
|
|
326
|
+
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]);
|
|
327
|
+
};
|
|
328
|
+
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);
|
|
329
|
+
}
|
|
307
330
|
};
|
|
308
331
|
_CoreStateManager.CORE_LOADING_STATES = /* @__PURE__ */ new Set([
|
|
309
332
|
"setting_up",
|
|
@@ -317,7 +340,11 @@ _CoreStateManager.AUTH_LOADING_STATES = /* @__PURE__ */ new Set([
|
|
|
317
340
|
"authenticating_farcaster",
|
|
318
341
|
"processing_authentication",
|
|
319
342
|
"authenticating_telegram",
|
|
320
|
-
"checking_state"
|
|
343
|
+
"checking_state",
|
|
344
|
+
// Re-polling the login status after the second factor is satisfied (ENG-6906).
|
|
345
|
+
// awaiting_2fa / awaiting_2fa_enrollment are deliberately NOT loading — they are
|
|
346
|
+
// user-input holds where the UI shows the MFA prompt.
|
|
347
|
+
"resolving_2fa"
|
|
321
348
|
]);
|
|
322
349
|
_CoreStateManager.WALLET_LOADING_STATES = /* @__PURE__ */ new Set([
|
|
323
350
|
"checking_wallet_state",
|
|
@@ -756,18 +756,18 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
756
756
|
guard: (0, import_xstate.and)([
|
|
757
757
|
({ event }) => {
|
|
758
758
|
const output = event.output;
|
|
759
|
-
return !!output.externalWallet;
|
|
759
|
+
return !!(output == null ? void 0 : output.externalWallet);
|
|
760
760
|
},
|
|
761
761
|
(0, import_xstate.or)([
|
|
762
762
|
({ event }) => {
|
|
763
763
|
var _a;
|
|
764
764
|
const output = event.output;
|
|
765
|
-
return output.stage === "done" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
765
|
+
return (output == null ? void 0 : output.stage) === "done" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
766
766
|
},
|
|
767
767
|
({ event }) => {
|
|
768
768
|
var _a, _b;
|
|
769
769
|
const output = event.output;
|
|
770
|
-
return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && !((_b = output.externalWallet) == null ? void 0 : _b.withVerification);
|
|
770
|
+
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);
|
|
771
771
|
}
|
|
772
772
|
])
|
|
773
773
|
])
|
|
@@ -784,12 +784,12 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
784
784
|
guard: (0, import_xstate.and)([
|
|
785
785
|
({ event }) => {
|
|
786
786
|
const output = event.output;
|
|
787
|
-
return !!output.externalWallet;
|
|
787
|
+
return !!(output == null ? void 0 : output.externalWallet);
|
|
788
788
|
},
|
|
789
789
|
({ event }) => {
|
|
790
790
|
var _a, _b;
|
|
791
791
|
const output = event.output;
|
|
792
|
-
return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && ((_b = output.externalWallet) == null ? void 0 : _b.withVerification);
|
|
792
|
+
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);
|
|
793
793
|
}
|
|
794
794
|
])
|
|
795
795
|
},
|
|
@@ -805,12 +805,12 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
805
805
|
guard: (0, import_xstate.and)([
|
|
806
806
|
({ event }) => {
|
|
807
807
|
const output = event.output;
|
|
808
|
-
return !!output.externalWallet;
|
|
808
|
+
return !!(output == null ? void 0 : output.externalWallet);
|
|
809
809
|
},
|
|
810
810
|
({ event }) => {
|
|
811
811
|
var _a;
|
|
812
812
|
const output = event.output;
|
|
813
|
-
return output.stage === "verify" && !!((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
813
|
+
return (output == null ? void 0 : output.stage) === "verify" && !!((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
814
814
|
}
|
|
815
815
|
])
|
|
816
816
|
},
|
|
@@ -824,11 +824,37 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
824
824
|
({ event }) => {
|
|
825
825
|
var _a;
|
|
826
826
|
const output = event.output;
|
|
827
|
-
return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
827
|
+
return (output == null ? void 0 : output.stage) === "verify" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
|
|
828
828
|
},
|
|
829
829
|
() => !paraCoreInterface.authService.isEnclaveUser
|
|
830
830
|
])
|
|
831
831
|
},
|
|
832
|
+
// Login-time 2FA (ENG-6906): the server gated the login behind a second
|
|
833
|
+
// factor. Enrollment (no factor yet) and verification (existing factor)
|
|
834
|
+
// are surfaced as distinct phases so a custom UI can show the right step.
|
|
835
|
+
{
|
|
836
|
+
target: "awaiting_2fa_enrollment",
|
|
837
|
+
actions: [
|
|
838
|
+
"storeAuthStateResult",
|
|
839
|
+
{ type: "logTransition", params: { to: "awaiting_2fa_enrollment", detail: "mfa enroll" } }
|
|
840
|
+
],
|
|
841
|
+
guard: ({ event }) => {
|
|
842
|
+
var _a;
|
|
843
|
+
const output = event.output;
|
|
844
|
+
return (output == null ? void 0 : output.stage) === "mfa" && ((_a = output == null ? void 0 : output.mfa) == null ? void 0 : _a.mode) === "enroll";
|
|
845
|
+
}
|
|
846
|
+
},
|
|
847
|
+
{
|
|
848
|
+
target: "awaiting_2fa",
|
|
849
|
+
actions: [
|
|
850
|
+
"storeAuthStateResult",
|
|
851
|
+
{ type: "logTransition", params: { to: "awaiting_2fa", detail: "mfa verify" } }
|
|
852
|
+
],
|
|
853
|
+
guard: ({ event }) => {
|
|
854
|
+
const output = event.output;
|
|
855
|
+
return (output == null ? void 0 : output.stage) === "mfa";
|
|
856
|
+
}
|
|
857
|
+
},
|
|
832
858
|
{
|
|
833
859
|
target: "awaiting_session_start",
|
|
834
860
|
actions: [
|
|
@@ -871,6 +897,77 @@ function createAuthStateMachine(paraCoreInterface) {
|
|
|
871
897
|
CANCEL: { target: "unauthenticated", actions: ["resetState"] }
|
|
872
898
|
}
|
|
873
899
|
},
|
|
900
|
+
// Login-time 2FA hold states (ENG-6906). The SDK satisfies the second factor
|
|
901
|
+
// out-of-band (enrollMfa/verifyMfa against /internal/v1/auth/2fa/*); once the
|
|
902
|
+
// backend has stamped the session, a RESOLVE_2FA event re-polls the login
|
|
903
|
+
// status, which now returns stage:'done'.
|
|
904
|
+
awaiting_2fa: {
|
|
905
|
+
on: {
|
|
906
|
+
RESOLVE_2FA: { target: "resolving_2fa", actions: ["setPollingCallbacks", "resetError"] },
|
|
907
|
+
CANCEL: { target: "unauthenticated", actions: ["resetState"] }
|
|
908
|
+
}
|
|
909
|
+
},
|
|
910
|
+
awaiting_2fa_enrollment: {
|
|
911
|
+
on: {
|
|
912
|
+
RESOLVE_2FA: { target: "resolving_2fa", actions: ["setPollingCallbacks", "resetError"] },
|
|
913
|
+
CANCEL: { target: "unauthenticated", actions: ["resetState"] }
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
resolving_2fa: {
|
|
917
|
+
entry: [{ type: "logTransition", params: { to: "resolving_2fa" } }],
|
|
918
|
+
invoke: {
|
|
919
|
+
src: "polling",
|
|
920
|
+
input: ({ context }) => {
|
|
921
|
+
var _a;
|
|
922
|
+
let resolvedAuthState = null;
|
|
923
|
+
return {
|
|
924
|
+
checkCondition: () => __async(this, null, function* () {
|
|
925
|
+
try {
|
|
926
|
+
const result = yield paraCoreInterface.pollingService.waitForOAuth({
|
|
927
|
+
onSuccess: (serverAuthState) => {
|
|
928
|
+
resolvedAuthState = serverAuthState;
|
|
929
|
+
}
|
|
930
|
+
})();
|
|
931
|
+
return { finished: result.finished && !!resolvedAuthState, data: { authState: resolvedAuthState } };
|
|
932
|
+
} catch (error) {
|
|
933
|
+
throw new Error(`2FA resolution polling failed: ${(0, import_stateErrorHelpers.extractErrorMessage)(error, "Unknown error")}`);
|
|
934
|
+
}
|
|
935
|
+
}),
|
|
936
|
+
onPoll: () => {
|
|
937
|
+
var _a2, _b;
|
|
938
|
+
return (_b = (_a2 = context.pollingCallbacks) == null ? void 0 : _a2.onPoll) == null ? void 0 : _b.call(_a2);
|
|
939
|
+
},
|
|
940
|
+
onCancel: () => {
|
|
941
|
+
var _a2, _b;
|
|
942
|
+
return (_b = (_a2 = context.pollingCallbacks) == null ? void 0 : _a2.onCancel) == null ? void 0 : _b.call(_a2);
|
|
943
|
+
},
|
|
944
|
+
isCanceled: ((_a = context.pollingCallbacks) == null ? void 0 : _a.isCanceled) || (() => false),
|
|
945
|
+
id: "resolving2fa"
|
|
946
|
+
};
|
|
947
|
+
},
|
|
948
|
+
onError: {
|
|
949
|
+
target: "error",
|
|
950
|
+
actions: (0, import_authStateMachine_helpers.setAuthErrorAssign)("2FA resolution failed")
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
on: (0, import_authStateMachine_helpers.makePollingOnHandlers)("processing_authentication", "2FA resolution failed", [
|
|
954
|
+
(0, import_xstate.assign)({
|
|
955
|
+
serverAuthStateResult: ({ event }) => {
|
|
956
|
+
var _a;
|
|
957
|
+
const authState = ((_a = event.data) == null ? void 0 : _a.authState) || null;
|
|
958
|
+
return {
|
|
959
|
+
authState,
|
|
960
|
+
opts: import_authStateMachine_helpers.DEFAULT_AUTH_OPTS
|
|
961
|
+
};
|
|
962
|
+
},
|
|
963
|
+
isNewUser: ({ event }) => {
|
|
964
|
+
var _a;
|
|
965
|
+
const authState = (_a = event.data) == null ? void 0 : _a.authState;
|
|
966
|
+
return authState ? (0, import_authStateMachine_helpers.computeIsNewUser)(authState) : false;
|
|
967
|
+
}
|
|
968
|
+
})
|
|
969
|
+
])
|
|
970
|
+
},
|
|
874
971
|
awaiting_session_start: {
|
|
875
972
|
on: {
|
|
876
973
|
WAIT_FOR_SESSION: {
|
|
@@ -219,6 +219,14 @@ function createCoreStateMachine(paraCoreInterface) {
|
|
|
219
219
|
"WAIT_FOR_WALLET_CREATION": {
|
|
220
220
|
actions: ({ context, event }) => context.authMachineRef.send(event)
|
|
221
221
|
},
|
|
222
|
+
// Login-time 2FA (ENG-6906): after the second factor is satisfied, verifyMfa
|
|
223
|
+
// fires RESOLVE_2FA so the auth machine re-polls verify-oauth and advances the
|
|
224
|
+
// login. Without forwarding it here the parent silently drops the event, the
|
|
225
|
+
// auth child stays parked at awaiting_2fa[_enrollment], and the user never gets
|
|
226
|
+
// a wallet.
|
|
227
|
+
"RESOLVE_2FA": {
|
|
228
|
+
actions: ({ context, event }) => context.authMachineRef.send(event)
|
|
229
|
+
},
|
|
222
230
|
"INITIALIZE_GUEST_MODE": {
|
|
223
231
|
actions: ({ context, event }) => context.authMachineRef.send(event)
|
|
224
232
|
},
|
package/dist/esm/ParaCore.js
CHANGED
|
@@ -1770,6 +1770,37 @@ const _ParaCore = class _ParaCore {
|
|
|
1770
1770
|
yield this.ctx.client.enable2FA(userId, verificationCode);
|
|
1771
1771
|
});
|
|
1772
1772
|
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Login-time 2FA (ENG-6906): enroll a TOTP second factor for the current session.
|
|
1775
|
+
* Distinct from setup2fa/enable2fa, which configure the recovery-gating 2FA. This
|
|
1776
|
+
* is authenticated by the active session (no recovery config gate); the backend
|
|
1777
|
+
* 404s the surface when the login-MFA flag is off.
|
|
1778
|
+
*
|
|
1779
|
+
* @returns {Object} `{ uri, backupCodes }` — otpauth URI to render as a QR, plus
|
|
1780
|
+
* one-time backup codes to show the user exactly once.
|
|
1781
|
+
*/
|
|
1782
|
+
enrollMfa() {
|
|
1783
|
+
return __async(this, null, function* () {
|
|
1784
|
+
yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
|
|
1785
|
+
return yield __privateGet(this, _authService).enrollMfa();
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Login-time 2FA (ENG-6906): verify the second factor for the current login. On
|
|
1790
|
+
* success the backend stamps the session and this re-polls the login status so the
|
|
1791
|
+
* flow advances toward `done`; a wrong code resolves to `{ ok:false, attemptsRemaining }`
|
|
1792
|
+
* so the UI can re-prompt without treating it as a hard error.
|
|
1793
|
+
*
|
|
1794
|
+
* @param {Object} opts the options object.
|
|
1795
|
+
* @param {string} opts.code the TOTP or backup code entered by the user.
|
|
1796
|
+
* @returns {Object} `{ ok: true } | { ok: false; attemptsRemaining? }`
|
|
1797
|
+
*/
|
|
1798
|
+
verifyMfa(_0) {
|
|
1799
|
+
return __async(this, arguments, function* ({ code }) {
|
|
1800
|
+
yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
|
|
1801
|
+
return yield __privateGet(this, _authService).verifyMfa({ code });
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1773
1804
|
/**
|
|
1774
1805
|
* Resend a verification email for the current user.
|
|
1775
1806
|
*/
|
package/dist/esm/constants.js
CHANGED
|
@@ -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",
|