@frontegg/redux-store 6.155.0-alpha.0 → 6.155.0-alpha.2
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/auth/ActivateState/saga.js +3 -2
- package/auth/ApiTokensState/index.d.ts +0 -8
- package/auth/LoginState/index.d.ts +1 -1
- package/auth/LoginState/index.js +1 -1
- package/auth/LoginState/interfaces.d.ts +5 -0
- package/auth/LoginState/saga.d.ts +3 -17
- package/auth/LoginState/saga.js +19 -383
- package/auth/LoginState/saga.utils.d.ts +12 -0
- package/auth/LoginState/saga.utils.js +47 -0
- package/auth/LoginState/sagas/afterAuthNavigation.saga.d.ts +19 -0
- package/auth/LoginState/sagas/afterAuthNavigation.saga.js +82 -0
- package/auth/LoginState/sagas/handleVerifyMFAResponse.saga.d.ts +52 -0
- package/auth/LoginState/sagas/handleVerifyMFAResponse.saga.js +80 -0
- package/auth/LoginState/sagas/index.d.ts +7 -0
- package/auth/LoginState/sagas/index.js +7 -0
- package/auth/LoginState/{mfaRequiredState.saga.d.ts → sagas/mfaRequiredState.saga.d.ts} +3 -3
- package/auth/LoginState/{mfaRequiredState.saga.js → sagas/mfaRequiredState.saga.js} +3 -3
- package/auth/LoginState/sagas/mfaWithAuthenticator.saga.d.ts +40 -0
- package/auth/LoginState/sagas/mfaWithAuthenticator.saga.js +140 -0
- package/auth/LoginState/sagas/mfaWithEmailCode.saga.d.ts +71 -0
- package/auth/LoginState/sagas/mfaWithEmailCode.saga.js +96 -0
- package/auth/LoginState/sagas/mfaWithSMS.saga.d.ts +77 -0
- package/auth/LoginState/sagas/mfaWithSMS.saga.js +107 -0
- package/auth/LoginState/sagas/mfaWithWebAuthn.saga.d.ts +81 -0
- package/auth/LoginState/sagas/mfaWithWebAuthn.saga.js +119 -0
- package/auth/LoginState/utils.d.ts +2 -1
- package/auth/LoginState/utils.js +6 -1
- package/auth/MfaState/saga.js +1 -1
- package/auth/SignUp/saga.js +1 -1
- package/auth/StepUpState/index.d.ts +16 -3
- package/auth/StepUpState/index.js +22 -3
- package/auth/StepUpState/interfaces.d.ts +9 -0
- package/auth/StepUpState/saga.d.ts +131 -6
- package/auth/StepUpState/saga.js +110 -41
- package/auth/index.d.ts +6 -0
- package/auth/interfaces.d.ts +1 -0
- package/auth/reducer.d.ts +6 -0
- package/index.d.ts +1 -1
- package/index.js +2 -2
- package/node/auth/ActivateState/saga.js +3 -2
- package/node/auth/LoginState/index.js +6 -0
- package/node/auth/LoginState/saga.js +54 -410
- package/node/auth/LoginState/saga.utils.js +55 -0
- package/node/auth/LoginState/sagas/afterAuthNavigation.saga.js +89 -0
- package/node/auth/LoginState/sagas/handleVerifyMFAResponse.saga.js +87 -0
- package/node/auth/LoginState/sagas/index.js +82 -0
- package/node/auth/LoginState/{mfaRequiredState.saga.js → sagas/mfaRequiredState.saga.js} +3 -3
- package/node/auth/LoginState/sagas/mfaWithAuthenticator.saga.js +147 -0
- package/node/auth/LoginState/sagas/mfaWithEmailCode.saga.js +106 -0
- package/node/auth/LoginState/sagas/mfaWithSMS.saga.js +116 -0
- package/node/auth/LoginState/sagas/mfaWithWebAuthn.saga.js +128 -0
- package/node/auth/LoginState/utils.js +6 -1
- package/node/auth/MfaState/saga.js +1 -1
- package/node/auth/SignUp/saga.js +1 -1
- package/node/auth/StepUpState/index.js +21 -8
- package/node/auth/StepUpState/saga.js +115 -41
- package/node/index.js +5 -5
- package/package.json +1 -1
- package/auth/StepUpState/utils.d.ts +0 -3
- package/auth/StepUpState/utils.js +0 -10
- package/node/auth/StepUpState/utils.js +0 -19
|
@@ -7,13 +7,14 @@ const _excluded = ["callback", "events"],
|
|
|
7
7
|
import { call, delay, put, select, takeLeading } from 'redux-saga/effects';
|
|
8
8
|
import { api, ContextHolder } from '@frontegg/rest-api';
|
|
9
9
|
import { actions } from '../reducer';
|
|
10
|
-
import { afterAuthNavigation
|
|
11
|
-
import { getMfaRequiredState } from '../LoginState/mfaRequiredState.saga';
|
|
10
|
+
import { afterAuthNavigation } from '../LoginState/saga';
|
|
12
11
|
import { UserVeirifedOriginTypes } from '../interfaces';
|
|
13
12
|
import { ActivateAccountStep } from './interfaces';
|
|
14
13
|
import { TeamStateKeys } from '../TeamState/interfaces';
|
|
15
14
|
import { GTMEventAction, errorHandler, reportGTMEvent } from '../../utils';
|
|
16
15
|
import { isMfaRequired } from '../LoginState/utils';
|
|
16
|
+
import { afterAuthenticationStateUpdate } from '../LoginState/saga.utils';
|
|
17
|
+
import { getMfaRequiredState } from '../LoginState/sagas/mfaRequiredState.saga';
|
|
17
18
|
function* preActivateAccount({
|
|
18
19
|
payload: {
|
|
19
20
|
userId,
|
|
@@ -45,10 +45,6 @@ declare const reducers: {
|
|
|
45
45
|
resetPhoneNumberState: import("..").ResetPhoneNumberState;
|
|
46
46
|
ssoState: import("..").SSOState;
|
|
47
47
|
profileState: import("..").ProfileState;
|
|
48
|
-
/**
|
|
49
|
-
* if you see error in matcher that's mean the DispatchAction does not
|
|
50
|
-
* contains the same functions in reducers and actions
|
|
51
|
-
*/
|
|
52
48
|
mfaState: import("..").MFAState;
|
|
53
49
|
teamState: import("..").TeamState;
|
|
54
50
|
groupsState: import("..").GroupsState;
|
|
@@ -97,10 +93,6 @@ declare const reducers: {
|
|
|
97
93
|
resetPhoneNumberState: import("..").ResetPhoneNumberState;
|
|
98
94
|
ssoState: import("..").SSOState;
|
|
99
95
|
profileState: import("..").ProfileState;
|
|
100
|
-
/**
|
|
101
|
-
* if you see error in matcher that's mean the DispatchAction does not
|
|
102
|
-
* contains the same functions in reducers and actions
|
|
103
|
-
*/
|
|
104
96
|
mfaState: import("..").MFAState;
|
|
105
97
|
teamState: import("..").TeamState;
|
|
106
98
|
groupsState: import("..").GroupsState;
|
|
@@ -234,4 +234,4 @@ declare type DispatchedActions = {
|
|
|
234
234
|
};
|
|
235
235
|
export declare type LoginActions = DispatchedActions;
|
|
236
236
|
export { loginState, reducers as loginReducers, actions as loginActions };
|
|
237
|
-
export { getRedirectUrl } from './utils';
|
|
237
|
+
export { getRedirectUrl, getSearchParam } from './utils';
|
package/auth/LoginState/index.js
CHANGED
|
@@ -98,6 +98,11 @@ export declare type IVerifyMFAWebAuthnPayload = WithCallback<WithDeviceId<Omit<I
|
|
|
98
98
|
export interface IRecoverMFATokenPayload extends WithCallback<IRecoverMFAToken> {
|
|
99
99
|
recaptchaToken?: string;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Type for action to set the loading state
|
|
103
|
+
* @param options.loading - true if in loading state
|
|
104
|
+
* @param options.error - error if in error state
|
|
105
|
+
*/
|
|
101
106
|
export declare type SetLoadingAction = ({ loading, error }: {
|
|
102
107
|
loading?: boolean;
|
|
103
108
|
error?: unknown;
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import { CallEffect } from 'redux-saga/effects';
|
|
2
|
-
import { ISamlMetadata
|
|
2
|
+
import { ISamlMetadata } from '@frontegg/rest-api';
|
|
3
3
|
import { AuthState } from '../interfaces';
|
|
4
|
-
export declare function afterAuthenticationStateUpdate({ user, tenants, activeTenant }: ILoginResponseV3, additionalUpdate?: Partial<AuthState>): Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").PutEffect<{
|
|
5
|
-
payload: Partial<AuthState>;
|
|
6
|
-
type: string;
|
|
7
|
-
}>, void, AuthState>;
|
|
8
|
-
export declare function afterAuthNavigation(): Generator<import("redux-saga/effects").SelectEffect | Promise<unknown> | CallEffect<void>, void, {
|
|
9
|
-
routes: any;
|
|
10
|
-
includeQueryParam: any;
|
|
11
|
-
enforceRedirectToSameSite?: false | undefined;
|
|
12
|
-
allowedRedirectOrigins?: never[] | undefined;
|
|
13
|
-
} & string>;
|
|
14
4
|
export declare function refreshMetadata(): Generator<import("redux-saga/effects").PutEffect<{
|
|
15
5
|
payload: Partial<AuthState>;
|
|
16
6
|
type: string;
|
|
@@ -25,11 +15,7 @@ export declare function loadSSOPublicConfigurationFunction(): Generator<import("
|
|
|
25
15
|
}>;
|
|
26
16
|
export declare function refreshToken(): Generator<import("redux-saga/effects").SelectEffect | CallEffect<any>, void, AuthState>;
|
|
27
17
|
export declare function refreshTokenForSocialLogins(): Generator<import("redux-saga/effects").SelectEffect | CallEffect<any>, void, AuthState>;
|
|
28
|
-
export declare function shouldShowPromptPasskeys(): Generator<import("redux-saga/effects").SelectEffect | CallEffect<boolean[]> | CallEffect<IWebAuthnDevices> | import("redux-saga/effects").PutEffect<{
|
|
29
|
-
payload: Partial<import("../..").PasskeysState>;
|
|
30
|
-
type: string;
|
|
31
|
-
}>, boolean, {
|
|
32
|
-
publicAuthStrategyPolicy: any;
|
|
33
|
-
} & boolean[] & IWebAuthnDevices>;
|
|
34
18
|
export declare function loginSagas(): Generator<import("redux-saga/effects").ForkEffect<never>, void, unknown>;
|
|
19
|
+
export { afterAuthNavigation } from './sagas/afterAuthNavigation.saga';
|
|
20
|
+
export { mfaWithAuthenticator } from './sagas/mfaWithAuthenticator.saga';
|
|
35
21
|
export declare function loginSagasMock(): Generator<import("redux-saga/effects").ForkEffect<never>, void, unknown>;
|
package/auth/LoginState/saga.js
CHANGED
|
@@ -14,35 +14,38 @@ const _excluded = ["callback"],
|
|
|
14
14
|
_excluded12 = ["callback"],
|
|
15
15
|
_excluded13 = ["callback"],
|
|
16
16
|
_excluded14 = ["callback"],
|
|
17
|
-
_excluded15 = ["callback"]
|
|
18
|
-
_excluded16 = ["callback", "deviceId"],
|
|
19
|
-
_excluded17 = ["callback"],
|
|
20
|
-
_excluded18 = ["callback"],
|
|
21
|
-
_excluded19 = ["callback", "deviceId"],
|
|
22
|
-
_excluded20 = ["callback", "deviceId"],
|
|
23
|
-
_excluded21 = ["callback", "deviceId"];
|
|
17
|
+
_excluded15 = ["callback"];
|
|
24
18
|
import { all, call, put, select, takeLeading } from 'redux-saga/effects';
|
|
25
19
|
import { api, AuthStrategyEnum, ContextHolder, fetch, WebAuthnDeviceType } from '@frontegg/rest-api';
|
|
26
20
|
import { actions } from '../reducer';
|
|
27
|
-
import {
|
|
21
|
+
import { HOSTED_LOGIN_VERIFIER_KEY } from '../../constants';
|
|
28
22
|
import { UserVeirifedOriginTypes } from '../interfaces';
|
|
29
23
|
import { LoginFlow, LoginStep } from './interfaces';
|
|
30
|
-
import { getMfaRequiredState } from './mfaRequiredState.saga';
|
|
24
|
+
import { getMfaRequiredState } from './sagas/mfaRequiredState.saga';
|
|
31
25
|
import { loadAllowSignUps } from '../SignUp/saga';
|
|
32
26
|
import { MFAStep } from '../MfaState/interfaces';
|
|
33
27
|
import { dummyIps, userDemo } from '../dummy';
|
|
34
28
|
import { SamlVendors } from '../SSOState/interfaces';
|
|
35
29
|
import { loadVendorPublicInfo } from '../../vendor/saga';
|
|
36
30
|
import { createRandomString, generateCodeChallenge, getFeatureFlags } from '../../helpers';
|
|
37
|
-
import { base64urlDecode,
|
|
31
|
+
import { base64urlDecode, publicKeyCredentialToJSON } from '../utils';
|
|
38
32
|
import { loadPublicAuthStrategiesPolicy } from '../Security/SecurityPolicyState/saga';
|
|
39
|
-
import {
|
|
40
|
-
import { getPathAndSearchParamsFromUrl, getRedirectUrl, getSearchParam, TENANT_ID_PARAM_KEY, isMfaRequired, isOauthCallbackRoute, isEmailPayload } from './utils';
|
|
33
|
+
import { getSearchParam, TENANT_ID_PARAM_KEY, isMfaRequired, isOauthCallbackRoute, isEmailPayload } from './utils';
|
|
41
34
|
import { errorHandler, GTMEventAction, reportGTMEvent } from '../../utils';
|
|
42
35
|
import { authStrategyLoginStepMap } from './consts';
|
|
43
36
|
import { isEntitlementsDeeplyEqual } from '../Entitlements';
|
|
44
37
|
import { customLoginEnabled, loadCustomLoginRoutes } from '../CustomLoginState/saga';
|
|
45
38
|
import { FronteggNativeModule } from '../../toolkit';
|
|
39
|
+
import { afterAuthenticationStateUpdate, shouldShowPromptPasskeys } from './saga.utils';
|
|
40
|
+
import { afterAuthNavigation, loginWithMfa, preVerifyMFASMSForLogin, verifyMFASMSForLogin, preVerifyMFAWebAuthnForLogin, verifyMFAWebAuthnForLogin, preVerifyMFAEmailCodeForLogin, verifyMFAEmailCodeForLogin } from './sagas';
|
|
41
|
+
|
|
42
|
+
/******************************************************************
|
|
43
|
+
*** ****
|
|
44
|
+
*** PLEASE DO NOT ADD CODE TO THIS FILE ****
|
|
45
|
+
*** NEW SAGAS - ADD AS A NEW FILE IN THE SAGAS FOLDER ****
|
|
46
|
+
*** EXISTING SAGAS - MOVE TO THE SAGAS FOLDER WHEN TOUCHING IT ****
|
|
47
|
+
*** ****
|
|
48
|
+
*******************************************************************/
|
|
46
49
|
|
|
47
50
|
/**
|
|
48
51
|
* Prevent unnecessary entitlements reference update inside the user object by
|
|
@@ -64,65 +67,6 @@ function* handleUnnecessaryEntitlementsUpdate(updatedUser) {
|
|
|
64
67
|
}
|
|
65
68
|
return updatedUser;
|
|
66
69
|
}
|
|
67
|
-
export function* afterAuthenticationStateUpdate({
|
|
68
|
-
user,
|
|
69
|
-
tenants = [],
|
|
70
|
-
activeTenant
|
|
71
|
-
}, additionalUpdate = {}) {
|
|
72
|
-
const {
|
|
73
|
-
tenantsState: currentTenantsState
|
|
74
|
-
} = yield select(state => state.auth);
|
|
75
|
-
yield put(actions.setState(_extends({
|
|
76
|
-
user,
|
|
77
|
-
tenantsState: _extends({}, currentTenantsState, {
|
|
78
|
-
tenants,
|
|
79
|
-
activeTenant,
|
|
80
|
-
loading: false
|
|
81
|
-
})
|
|
82
|
-
}, additionalUpdate)));
|
|
83
|
-
}
|
|
84
|
-
export function* afterAuthNavigation() {
|
|
85
|
-
const onRedirectTo = ContextHolder.onRedirectTo;
|
|
86
|
-
const {
|
|
87
|
-
routes,
|
|
88
|
-
includeQueryParam,
|
|
89
|
-
enforceRedirectToSameSite = false,
|
|
90
|
-
allowedRedirectOrigins = []
|
|
91
|
-
} = yield select(state => state.auth);
|
|
92
|
-
const {
|
|
93
|
-
loginUrl,
|
|
94
|
-
logoutUrl,
|
|
95
|
-
socialLoginCallbackUrl,
|
|
96
|
-
activateUrl
|
|
97
|
-
} = routes;
|
|
98
|
-
let {
|
|
99
|
-
authenticatedUrl,
|
|
100
|
-
customLoginAuthenticatedUrl
|
|
101
|
-
} = routes;
|
|
102
|
-
if (!customLoginAuthenticatedUrl) {
|
|
103
|
-
yield call(loadCustomLoginRoutes);
|
|
104
|
-
customLoginAuthenticatedUrl = yield select(state => {
|
|
105
|
-
var _state$auth$routes;
|
|
106
|
-
return (_state$auth$routes = state.auth.routes) == null ? void 0 : _state$auth$routes.customLoginAuthenticatedUrl;
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
const afterAuthRedirect = window.localStorage.getItem(FRONTEGG_AFTER_AUTH_REDIRECT_URL);
|
|
110
|
-
if (afterAuthRedirect && ![loginUrl, logoutUrl, socialLoginCallbackUrl, activateUrl].includes(afterAuthRedirect)) {
|
|
111
|
-
authenticatedUrl = afterAuthRedirect;
|
|
112
|
-
}
|
|
113
|
-
window.localStorage.removeItem(FRONTEGG_AFTER_AUTH_REDIRECT_URL);
|
|
114
|
-
yield delay(200);
|
|
115
|
-
put(actions.resetLoginState());
|
|
116
|
-
const redirectUrl = getRedirectUrl({
|
|
117
|
-
authenticatedUrl: customLoginAuthenticatedUrl ? getPathAndSearchParamsFromUrl(customLoginAuthenticatedUrl) : authenticatedUrl,
|
|
118
|
-
includeQueryParam,
|
|
119
|
-
enforceRedirectToSameSite,
|
|
120
|
-
allowedRedirectOrigins
|
|
121
|
-
});
|
|
122
|
-
onRedirectTo(redirectUrl, {
|
|
123
|
-
refresh: redirectUrl.startsWith('http')
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
70
|
export function* refreshMetadata() {
|
|
127
71
|
let ssoACS;
|
|
128
72
|
try {
|
|
@@ -783,30 +727,6 @@ function* passwordlessPreLogin(_ref7) {
|
|
|
783
727
|
callback == null ? void 0 : callback();
|
|
784
728
|
}
|
|
785
729
|
}
|
|
786
|
-
export function* shouldShowPromptPasskeys() {
|
|
787
|
-
const {
|
|
788
|
-
publicAuthStrategyPolicy
|
|
789
|
-
} = yield select(state => state.auth.securityPolicyState);
|
|
790
|
-
const {
|
|
791
|
-
policy
|
|
792
|
-
} = publicAuthStrategyPolicy;
|
|
793
|
-
const isPasskeysEnabledByVendor = getPasskeysVendorPolicy(policy);
|
|
794
|
-
const isLoggedInWithPasskeys = localStorage.getItem('preferred-login-method') === 'Passkeys';
|
|
795
|
-
const isMarkedDontShowAgainPrompt = localStorage.getItem('dont-show-again-prompt-passkeys') === 'true';
|
|
796
|
-
const [showPasskeys] = yield call(getFeatureFlags, ['show-passkeys-new']);
|
|
797
|
-
if (!showPasskeys || !isPasskeysEnabledByVendor || isLoggedInWithPasskeys || isMarkedDontShowAgainPrompt) {
|
|
798
|
-
return false;
|
|
799
|
-
} else {
|
|
800
|
-
const {
|
|
801
|
-
devices
|
|
802
|
-
} = yield call(api.auth.getWebAuthnDevices);
|
|
803
|
-
yield put(actions.setPasskeysState({
|
|
804
|
-
devices: devices != null ? devices : []
|
|
805
|
-
}));
|
|
806
|
-
const numOfDevices = !(devices != null && devices.length) ? 0 : devices.length;
|
|
807
|
-
return numOfDevices === 0;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
730
|
function* passwordlessPostLogin(_ref8) {
|
|
811
731
|
let {
|
|
812
732
|
payload: {
|
|
@@ -1340,82 +1260,6 @@ function* login({
|
|
|
1340
1260
|
}));
|
|
1341
1261
|
}
|
|
1342
1262
|
}
|
|
1343
|
-
function* loginWithMfa({
|
|
1344
|
-
payload: {
|
|
1345
|
-
mfaToken,
|
|
1346
|
-
value,
|
|
1347
|
-
rememberDevice,
|
|
1348
|
-
callback
|
|
1349
|
-
}
|
|
1350
|
-
}) {
|
|
1351
|
-
yield put(actions.setLoginState({
|
|
1352
|
-
loading: true
|
|
1353
|
-
}));
|
|
1354
|
-
try {
|
|
1355
|
-
const {
|
|
1356
|
-
user,
|
|
1357
|
-
tenants = [],
|
|
1358
|
-
activeTenant
|
|
1359
|
-
} = yield call(api.auth.loginWithMfaV2, {
|
|
1360
|
-
mfaToken,
|
|
1361
|
-
value,
|
|
1362
|
-
rememberDevice
|
|
1363
|
-
});
|
|
1364
|
-
const {
|
|
1365
|
-
loginState
|
|
1366
|
-
} = yield select(state => state.auth);
|
|
1367
|
-
const step = loginState.flow === LoginFlow.Login ? LoginStep.success : loginState.step;
|
|
1368
|
-
const isAuthenticated = !!user.accessToken;
|
|
1369
|
-
yield call(afterAuthenticationStateUpdate, {
|
|
1370
|
-
user,
|
|
1371
|
-
tenants,
|
|
1372
|
-
activeTenant
|
|
1373
|
-
}, {
|
|
1374
|
-
loginState: {
|
|
1375
|
-
flow: loginState.flow,
|
|
1376
|
-
quickLoginToRegister: loginState.quickLoginToRegister,
|
|
1377
|
-
loading: false,
|
|
1378
|
-
step,
|
|
1379
|
-
error: undefined,
|
|
1380
|
-
tenants
|
|
1381
|
-
},
|
|
1382
|
-
isAuthenticated
|
|
1383
|
-
});
|
|
1384
|
-
if (user.id) {
|
|
1385
|
-
localStorage.setItem('userId', user.id);
|
|
1386
|
-
}
|
|
1387
|
-
yield put(actions.setLoginState({
|
|
1388
|
-
error: undefined,
|
|
1389
|
-
loading: false
|
|
1390
|
-
}));
|
|
1391
|
-
const [securityCenterLoginFlows] = yield call(getFeatureFlags, ['security-center-show-login-flows']);
|
|
1392
|
-
if (loginState.flow === LoginFlow.Login) {
|
|
1393
|
-
if (securityCenterLoginFlows && loginState.isBreachedPassword && !isAuthenticated) {
|
|
1394
|
-
yield put(actions.setLoginState({
|
|
1395
|
-
step: LoginStep.breachedPassword,
|
|
1396
|
-
loading: false
|
|
1397
|
-
}));
|
|
1398
|
-
} else {
|
|
1399
|
-
const shouldShowPrompt = yield call(shouldShowPromptPasskeys);
|
|
1400
|
-
if (shouldShowPrompt) {
|
|
1401
|
-
yield put(actions.setLoginState({
|
|
1402
|
-
step: LoginStep.promptPasskeys,
|
|
1403
|
-
loading: false
|
|
1404
|
-
}));
|
|
1405
|
-
} else {
|
|
1406
|
-
yield afterAuthNavigation();
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
callback == null ? void 0 : callback(true);
|
|
1411
|
-
} catch (e) {
|
|
1412
|
-
yield put(actions.setLoginState({
|
|
1413
|
-
error: errorHandler(e),
|
|
1414
|
-
loading: false
|
|
1415
|
-
}));
|
|
1416
|
-
callback == null ? void 0 : callback(false, e);
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
1263
|
function* recoverMfa({
|
|
1420
1264
|
payload
|
|
1421
1265
|
}) {
|
|
@@ -1501,50 +1345,6 @@ function* handleEnrollMFAResponse({
|
|
|
1501
1345
|
localStorage.setItem('userId', user.id);
|
|
1502
1346
|
}
|
|
1503
1347
|
}
|
|
1504
|
-
function* handleVerifyMFAResponse({
|
|
1505
|
-
user,
|
|
1506
|
-
tenants,
|
|
1507
|
-
activeTenant
|
|
1508
|
-
}) {
|
|
1509
|
-
const {
|
|
1510
|
-
loginState
|
|
1511
|
-
} = yield select(state => state.auth);
|
|
1512
|
-
yield put(actions.setUser(user));
|
|
1513
|
-
yield put(actions.setTenantsState({
|
|
1514
|
-
tenants,
|
|
1515
|
-
activeTenant,
|
|
1516
|
-
loading: false
|
|
1517
|
-
}));
|
|
1518
|
-
if (user.id) {
|
|
1519
|
-
localStorage.setItem('userId', user.id);
|
|
1520
|
-
}
|
|
1521
|
-
const {
|
|
1522
|
-
step: mfaStep
|
|
1523
|
-
} = yield select(state => state.auth.mfaState);
|
|
1524
|
-
const [securityCenterLoginFlows] = yield call(getFeatureFlags, ['security-center-show-login-flows']);
|
|
1525
|
-
const isAuthenticated = !!user.accessToken;
|
|
1526
|
-
if (loginState.flow === LoginFlow.Login) {
|
|
1527
|
-
if (securityCenterLoginFlows && loginState.isBreachedPassword && !isAuthenticated) {
|
|
1528
|
-
yield put(actions.setLoginState({
|
|
1529
|
-
step: LoginStep.breachedPassword,
|
|
1530
|
-
loading: false
|
|
1531
|
-
}));
|
|
1532
|
-
} else {
|
|
1533
|
-
const shouldShowPrompt = yield call(shouldShowPromptPasskeys);
|
|
1534
|
-
if (mfaStep === MFAStep.smsVerifyCode && shouldShowPrompt) {
|
|
1535
|
-
yield put(actions.setLoginState({
|
|
1536
|
-
step: LoginStep.promptPasskeys,
|
|
1537
|
-
loading: false
|
|
1538
|
-
}));
|
|
1539
|
-
} else {
|
|
1540
|
-
yield afterAuthNavigation();
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
yield put(actions.setState({
|
|
1545
|
-
isAuthenticated
|
|
1546
|
-
}));
|
|
1547
|
-
}
|
|
1548
1348
|
function* preEnrollMFASMSForLogin(_ref13) {
|
|
1549
1349
|
let {
|
|
1550
1350
|
payload: {
|
|
@@ -1689,172 +1489,6 @@ function* enrollMFAAuthenticatorAppForLogin(_ref17) {
|
|
|
1689
1489
|
callback == null ? void 0 : callback(null);
|
|
1690
1490
|
}
|
|
1691
1491
|
}
|
|
1692
|
-
function* preVerifyMFASMSForLogin(_ref18) {
|
|
1693
|
-
let {
|
|
1694
|
-
payload: {
|
|
1695
|
-
callback,
|
|
1696
|
-
deviceId
|
|
1697
|
-
}
|
|
1698
|
-
} = _ref18,
|
|
1699
|
-
payload = _objectWithoutPropertiesLoose(_ref18.payload, _excluded16);
|
|
1700
|
-
yield put(actions.setLoginState({
|
|
1701
|
-
loading: true
|
|
1702
|
-
}));
|
|
1703
|
-
try {
|
|
1704
|
-
const data = yield call(api.auth.preVerifyMFASMSForLogin, deviceId, payload);
|
|
1705
|
-
yield put(actions.setMfaState({
|
|
1706
|
-
otcToken: data.otcToken,
|
|
1707
|
-
step: MFAStep.smsVerifyCode,
|
|
1708
|
-
phoneNumber: data.phoneNumber
|
|
1709
|
-
}));
|
|
1710
|
-
yield put(actions.setLoginState({
|
|
1711
|
-
loading: false
|
|
1712
|
-
}));
|
|
1713
|
-
callback == null ? void 0 : callback(true);
|
|
1714
|
-
} catch (e) {
|
|
1715
|
-
yield put(actions.setLoginState({
|
|
1716
|
-
loading: false,
|
|
1717
|
-
error: errorHandler(e)
|
|
1718
|
-
}));
|
|
1719
|
-
callback == null ? void 0 : callback(null);
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
function* preVerifyMFAEmailCode(_ref19) {
|
|
1723
|
-
let {
|
|
1724
|
-
payload: {
|
|
1725
|
-
callback
|
|
1726
|
-
}
|
|
1727
|
-
} = _ref19,
|
|
1728
|
-
payload = _objectWithoutPropertiesLoose(_ref19.payload, _excluded17);
|
|
1729
|
-
try {
|
|
1730
|
-
const data = yield call(api.auth.preVerifyMFAEmailCode, payload);
|
|
1731
|
-
yield put(actions.setMfaState({
|
|
1732
|
-
otcToken: data.otcToken,
|
|
1733
|
-
step: MFAStep.emailVerifyCode
|
|
1734
|
-
}));
|
|
1735
|
-
callback == null ? void 0 : callback(true);
|
|
1736
|
-
} catch (e) {
|
|
1737
|
-
yield put(actions.setLoginState({
|
|
1738
|
-
error: errorHandler(e)
|
|
1739
|
-
}));
|
|
1740
|
-
callback == null ? void 0 : callback(null);
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
function* verifyMFAEmailCode(_ref20) {
|
|
1744
|
-
let {
|
|
1745
|
-
payload: {
|
|
1746
|
-
callback
|
|
1747
|
-
}
|
|
1748
|
-
} = _ref20,
|
|
1749
|
-
payload = _objectWithoutPropertiesLoose(_ref20.payload, _excluded18);
|
|
1750
|
-
yield put(actions.setLoginState({
|
|
1751
|
-
loading: true
|
|
1752
|
-
}));
|
|
1753
|
-
try {
|
|
1754
|
-
const data = yield call(api.auth.verifyMFAEmailCodeV2, payload);
|
|
1755
|
-
yield handleVerifyMFAResponse(data);
|
|
1756
|
-
yield put(actions.setLoginState({
|
|
1757
|
-
loading: false
|
|
1758
|
-
}));
|
|
1759
|
-
callback == null ? void 0 : callback(true);
|
|
1760
|
-
} catch (e) {
|
|
1761
|
-
yield put(actions.setLoginState({
|
|
1762
|
-
loading: false,
|
|
1763
|
-
error: errorHandler(e)
|
|
1764
|
-
}));
|
|
1765
|
-
callback == null ? void 0 : callback(null);
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
function* verifyMFASMSForLogin(_ref21) {
|
|
1769
|
-
let {
|
|
1770
|
-
payload: {
|
|
1771
|
-
callback,
|
|
1772
|
-
deviceId
|
|
1773
|
-
}
|
|
1774
|
-
} = _ref21,
|
|
1775
|
-
payload = _objectWithoutPropertiesLoose(_ref21.payload, _excluded19);
|
|
1776
|
-
yield put(actions.setLoginState({
|
|
1777
|
-
loading: true
|
|
1778
|
-
}));
|
|
1779
|
-
try {
|
|
1780
|
-
const data = yield call(api.auth.verifyMFASMSForLoginV2, deviceId, payload);
|
|
1781
|
-
yield handleVerifyMFAResponse(data);
|
|
1782
|
-
yield put(actions.setLoginState({
|
|
1783
|
-
loading: false
|
|
1784
|
-
}));
|
|
1785
|
-
callback == null ? void 0 : callback(true);
|
|
1786
|
-
} catch (e) {
|
|
1787
|
-
yield put(actions.setLoginState({
|
|
1788
|
-
loading: false,
|
|
1789
|
-
error: errorHandler(e)
|
|
1790
|
-
}));
|
|
1791
|
-
callback == null ? void 0 : callback(null);
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
function* preVerifyMFAWebAuthnForLogin(_ref22) {
|
|
1795
|
-
let {
|
|
1796
|
-
payload: {
|
|
1797
|
-
callback,
|
|
1798
|
-
deviceId
|
|
1799
|
-
}
|
|
1800
|
-
} = _ref22,
|
|
1801
|
-
payload = _objectWithoutPropertiesLoose(_ref22.payload, _excluded20);
|
|
1802
|
-
yield put(actions.setLoginState({
|
|
1803
|
-
loading: true
|
|
1804
|
-
}));
|
|
1805
|
-
try {
|
|
1806
|
-
var _data$options$allowCr;
|
|
1807
|
-
const data = yield call(api.auth.preVerifyMFAWebAuthnForLogin, deviceId, payload);
|
|
1808
|
-
const options = _extends({}, data.options, {
|
|
1809
|
-
challenge: base64urlDecode(data.options.challenge),
|
|
1810
|
-
allowCredentials: (_data$options$allowCr = data.options.allowCredentials) == null ? void 0 : _data$options$allowCr.map(credentials => _extends({}, credentials, {
|
|
1811
|
-
id: base64urlDecode(credentials.id)
|
|
1812
|
-
}))
|
|
1813
|
-
});
|
|
1814
|
-
yield put(actions.setLoginState({
|
|
1815
|
-
loading: false
|
|
1816
|
-
}));
|
|
1817
|
-
callback == null ? void 0 : callback({
|
|
1818
|
-
options,
|
|
1819
|
-
webauthnToken: data.webauthnToken
|
|
1820
|
-
});
|
|
1821
|
-
} catch (e) {
|
|
1822
|
-
yield put(actions.setLoginState({
|
|
1823
|
-
loading: false,
|
|
1824
|
-
error: errorHandler(e)
|
|
1825
|
-
}));
|
|
1826
|
-
callback == null ? void 0 : callback(null);
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1829
|
-
function* verifyMFAWebAuthnForLogin(_ref23) {
|
|
1830
|
-
let {
|
|
1831
|
-
payload: {
|
|
1832
|
-
callback,
|
|
1833
|
-
deviceId
|
|
1834
|
-
}
|
|
1835
|
-
} = _ref23,
|
|
1836
|
-
payload = _objectWithoutPropertiesLoose(_ref23.payload, _excluded21);
|
|
1837
|
-
yield put(actions.setLoginState({
|
|
1838
|
-
loading: true
|
|
1839
|
-
}));
|
|
1840
|
-
try {
|
|
1841
|
-
const publicKey = publicKeyCredentialToJSON(payload.publicKey);
|
|
1842
|
-
const data = yield call(api.auth.verifyMFAWebAuthnForLoginV2, deviceId, _extends({}, payload, {
|
|
1843
|
-
options: publicKey
|
|
1844
|
-
}));
|
|
1845
|
-
yield handleVerifyMFAResponse(data);
|
|
1846
|
-
yield put(actions.setLoginState({
|
|
1847
|
-
loading: false
|
|
1848
|
-
}));
|
|
1849
|
-
callback == null ? void 0 : callback(true);
|
|
1850
|
-
} catch (e) {
|
|
1851
|
-
yield put(actions.setLoginState({
|
|
1852
|
-
loading: false,
|
|
1853
|
-
error: errorHandler(e)
|
|
1854
|
-
}));
|
|
1855
|
-
callback == null ? void 0 : callback(null);
|
|
1856
|
-
}
|
|
1857
|
-
}
|
|
1858
1492
|
function* resetBreachedPassword({
|
|
1859
1493
|
payload
|
|
1860
1494
|
}) {
|
|
@@ -1912,10 +1546,12 @@ export function* loginSagas() {
|
|
|
1912
1546
|
yield takeLeading(actions.verifyMFASMSForLogin, verifyMFASMSForLogin);
|
|
1913
1547
|
yield takeLeading(actions.preVerifyMFAWebAuthnForLogin, preVerifyMFAWebAuthnForLogin);
|
|
1914
1548
|
yield takeLeading(actions.verifyMFAWebAuthnForLogin, verifyMFAWebAuthnForLogin);
|
|
1915
|
-
yield takeLeading(actions.preVerifyMFAEmailCode,
|
|
1916
|
-
yield takeLeading(actions.verifyMFAEmailCode,
|
|
1549
|
+
yield takeLeading(actions.preVerifyMFAEmailCode, preVerifyMFAEmailCodeForLogin);
|
|
1550
|
+
yield takeLeading(actions.verifyMFAEmailCode, verifyMFAEmailCodeForLogin);
|
|
1917
1551
|
yield takeLeading(actions.resetBreachedPassword, resetBreachedPassword);
|
|
1918
1552
|
}
|
|
1553
|
+
export { afterAuthNavigation } from './sagas/afterAuthNavigation.saga';
|
|
1554
|
+
export { mfaWithAuthenticator } from './sagas/mfaWithAuthenticator.saga';
|
|
1919
1555
|
|
|
1920
1556
|
/*********************************
|
|
1921
1557
|
* Preview Sagas
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ILoginResponseV3, IWebAuthnDevices } from '@frontegg/rest-api';
|
|
2
|
+
import { AuthState } from '../interfaces';
|
|
3
|
+
export declare function shouldShowPromptPasskeys(): Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<boolean[]> | import("redux-saga/effects").CallEffect<IWebAuthnDevices> | import("redux-saga/effects").PutEffect<{
|
|
4
|
+
payload: Partial<import("..").PasskeysState>;
|
|
5
|
+
type: string;
|
|
6
|
+
}>, boolean, {
|
|
7
|
+
publicAuthStrategyPolicy: any;
|
|
8
|
+
} & boolean[] & IWebAuthnDevices>;
|
|
9
|
+
export declare function afterAuthenticationStateUpdate({ user, tenants, activeTenant }: ILoginResponseV3, additionalUpdate?: Partial<AuthState>): Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").PutEffect<{
|
|
10
|
+
payload: Partial<AuthState>;
|
|
11
|
+
type: string;
|
|
12
|
+
}>, void, AuthState>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import { call, put, select } from 'redux-saga/effects';
|
|
3
|
+
import { api } from '@frontegg/rest-api';
|
|
4
|
+
import { actions } from '../reducer';
|
|
5
|
+
import { getPasskeysVendorPolicy } from '../PasskeysState/helpers';
|
|
6
|
+
import { getFeatureFlags } from '../../helpers';
|
|
7
|
+
export function* shouldShowPromptPasskeys() {
|
|
8
|
+
const {
|
|
9
|
+
publicAuthStrategyPolicy
|
|
10
|
+
} = yield select(state => state.auth.securityPolicyState);
|
|
11
|
+
const {
|
|
12
|
+
policy
|
|
13
|
+
} = publicAuthStrategyPolicy;
|
|
14
|
+
const isPasskeysEnabledByVendor = getPasskeysVendorPolicy(policy);
|
|
15
|
+
const isLoggedInWithPasskeys = localStorage.getItem('preferred-login-method') === 'Passkeys';
|
|
16
|
+
const isMarkedDontShowAgainPrompt = localStorage.getItem('dont-show-again-prompt-passkeys') === 'true';
|
|
17
|
+
const [showPasskeys] = yield call(getFeatureFlags, ['show-passkeys-new']);
|
|
18
|
+
if (!showPasskeys || !isPasskeysEnabledByVendor || isLoggedInWithPasskeys || isMarkedDontShowAgainPrompt) {
|
|
19
|
+
return false;
|
|
20
|
+
} else {
|
|
21
|
+
const {
|
|
22
|
+
devices
|
|
23
|
+
} = yield call(api.auth.getWebAuthnDevices);
|
|
24
|
+
yield put(actions.setPasskeysState({
|
|
25
|
+
devices: devices != null ? devices : []
|
|
26
|
+
}));
|
|
27
|
+
const numOfDevices = !(devices != null && devices.length) ? 0 : devices.length;
|
|
28
|
+
return numOfDevices === 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function* afterAuthenticationStateUpdate({
|
|
32
|
+
user,
|
|
33
|
+
tenants = [],
|
|
34
|
+
activeTenant
|
|
35
|
+
}, additionalUpdate = {}) {
|
|
36
|
+
const {
|
|
37
|
+
tenantsState: currentTenantsState
|
|
38
|
+
} = yield select(state => state.auth);
|
|
39
|
+
yield put(actions.setState(_extends({
|
|
40
|
+
user,
|
|
41
|
+
tenantsState: _extends({}, currentTenantsState, {
|
|
42
|
+
tenants,
|
|
43
|
+
activeTenant,
|
|
44
|
+
loading: false
|
|
45
|
+
})
|
|
46
|
+
}, additionalUpdate)));
|
|
47
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Action } from '@reduxjs/toolkit';
|
|
2
|
+
/**
|
|
3
|
+
* Utility to share after auth navigation flow between login and step up
|
|
4
|
+
* @param resetStateAction reset state action
|
|
5
|
+
* @param customLoginAuthenticatedUrl custom login authenticated url if exists
|
|
6
|
+
*/
|
|
7
|
+
export declare function afterAuthNavigationUtil(resetStateAction: () => Action, customLoginAuthenticatedUrl?: string): Generator<import("redux-saga/effects").CallEffect<true> | import("redux-saga/effects").CallEffect<string>, void, string>;
|
|
8
|
+
/**
|
|
9
|
+
* After auth navigation for login flow
|
|
10
|
+
*/
|
|
11
|
+
export declare function afterAuthNavigation(): Generator<import("redux-saga/effects").SelectEffect | import("redux-saga/effects").CallEffect<void>, void, {
|
|
12
|
+
routes: {
|
|
13
|
+
customLoginAuthenticatedUrl: any;
|
|
14
|
+
};
|
|
15
|
+
} & string>;
|
|
16
|
+
/**
|
|
17
|
+
* After auth navigation for step up flow
|
|
18
|
+
*/
|
|
19
|
+
export declare function afterStepUpAuthNavigation(): Generator<import("redux-saga/effects").CallEffect<void>, void, unknown>;
|