@oneblink/apps-react 10.3.1 → 11.0.0-beta.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/apps/auth-service.d.ts +3 -2
- package/dist/apps/auth-service.js +2 -2
- package/dist/apps/auth-service.js.map +1 -1
- package/dist/apps/services/AWSCognitoClient.d.ts +39 -4
- package/dist/apps/services/AWSCognitoClient.js +238 -23
- package/dist/apps/services/AWSCognitoClient.js.map +1 -1
- package/dist/apps/services/cognito.d.ts +50 -41
- package/dist/apps/services/cognito.js +85 -48
- package/dist/apps/services/cognito.js.map +1 -1
- package/dist/components/mfa/MfaAuthenticatorAppDialog.d.ts +12 -0
- package/dist/components/mfa/MfaAuthenticatorAppDialog.js +64 -0
- package/dist/components/mfa/MfaAuthenticatorAppDialog.js.map +1 -0
- package/dist/components/mfa/MfaDisableDialog.d.ts +10 -0
- package/dist/components/mfa/MfaDisableDialog.js +31 -0
- package/dist/components/mfa/MfaDisableDialog.js.map +1 -0
- package/dist/components/mfa/MfaErrorSnackbar.d.ts +10 -0
- package/dist/components/mfa/MfaErrorSnackbar.js +17 -0
- package/dist/components/mfa/MfaErrorSnackbar.js.map +1 -0
- package/dist/components/mfa/MfaMethodRow.d.ts +19 -0
- package/dist/components/mfa/MfaMethodRow.js +10 -0
- package/dist/components/mfa/MfaMethodRow.js.map +1 -0
- package/dist/components/mfa/MfaPhoneNumberDialog.d.ts +11 -0
- package/dist/components/mfa/MfaPhoneNumberDialog.js +120 -0
- package/dist/components/mfa/MfaPhoneNumberDialog.js.map +1 -0
- package/dist/components/mfa/MfaRemovePhoneNumberDialog.d.ts +10 -0
- package/dist/components/mfa/MfaRemovePhoneNumberDialog.js +24 -0
- package/dist/components/mfa/MfaRemovePhoneNumberDialog.js.map +1 -0
- package/dist/components/mfa/MfaStatusChip.d.ts +10 -0
- package/dist/components/mfa/MfaStatusChip.js +29 -0
- package/dist/components/mfa/MfaStatusChip.js.map +1 -0
- package/dist/components/mfa/MfaSuccessSnackbar.d.ts +10 -0
- package/dist/components/mfa/MfaSuccessSnackbar.js +17 -0
- package/dist/components/mfa/MfaSuccessSnackbar.js.map +1 -0
- package/dist/components/mfa/MultiFactorAuthentication.d.ts +1 -2
- package/dist/components/mfa/MultiFactorAuthentication.js +30 -30
- package/dist/components/mfa/MultiFactorAuthentication.js.map +1 -1
- package/dist/hooks/useLogin.d.ts +14 -8
- package/dist/hooks/useLogin.js +16 -6
- package/dist/hooks/useLogin.js.map +1 -1
- package/dist/hooks/useMfa.d.ts +46 -14
- package/dist/hooks/useMfa.js +388 -43
- package/dist/hooks/useMfa.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/components/mfa/MfaDialog.d.ts +0 -9
- package/dist/components/mfa/MfaDialog.js +0 -47
- package/dist/components/mfa/MfaDialog.js.map +0 -1
package/dist/hooks/useMfa.d.ts
CHANGED
|
@@ -4,19 +4,39 @@ type MfaState = {
|
|
|
4
4
|
isExternalIdentityProviderUser: boolean;
|
|
5
5
|
isLoading: boolean;
|
|
6
6
|
isMfaEnabled: boolean;
|
|
7
|
+
mfaSettings: authService.MfaSettings;
|
|
8
|
+
isSetupSuccessOpen: boolean;
|
|
7
9
|
loadingError?: Error;
|
|
8
10
|
isSettingUpMfa: boolean;
|
|
9
|
-
|
|
11
|
+
settingUpMfaMethod?: authService.MfaMethod;
|
|
12
|
+
isSetupMethodDialogOpen: boolean;
|
|
13
|
+
disablingMfaMethod?: authService.MfaMethod;
|
|
14
|
+
isSettingPreferredMfaMethod: boolean;
|
|
10
15
|
setupError?: Error;
|
|
11
|
-
|
|
16
|
+
mfaAuthenticatorAppSetup?: Awaited<ReturnType<typeof authService.setupMfaAuthenticatorApp>>;
|
|
17
|
+
isPhoneNumberDialogOpen: boolean;
|
|
18
|
+
phoneVerificationCodeSentAt?: number;
|
|
19
|
+
isRemovePhoneNumberDialogOpen: boolean;
|
|
12
20
|
};
|
|
13
21
|
export declare const MfaContext: React.Context<MfaState & {
|
|
14
|
-
beginMfaSetup: () => void
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
beginMfaSetup: (mfaMethod: authService.MfaMethod) => Promise<void>;
|
|
23
|
+
openMfaSetupMethodDialog: () => void;
|
|
24
|
+
closeMfaSetupMethodDialog: () => void;
|
|
25
|
+
beginDisablingMfaMethod: (mfaMethod: authService.MfaMethod) => void;
|
|
26
|
+
setPreferredMfaMethod: (mfaMethod: authService.MfaMethod) => Promise<void>;
|
|
27
|
+
openPhoneNumberDialog: () => void;
|
|
28
|
+
closePhoneNumberDialog: () => void;
|
|
29
|
+
savePhoneNumber: (phoneNumber: string) => Promise<void>;
|
|
30
|
+
verifyPhoneNumber: (code: string) => Promise<void>;
|
|
31
|
+
resendPhoneNumberVerificationCode: () => Promise<void>;
|
|
32
|
+
beginRemovingPhoneNumber: () => void;
|
|
33
|
+
cancelRemovingPhoneNumber: () => void;
|
|
34
|
+
completeRemovingPhoneNumber: () => Promise<void>;
|
|
35
|
+
hideSetupSuccess: () => void;
|
|
36
|
+
cancelMfaAuthenticatorAppSetup: () => void;
|
|
37
|
+
completeMfaAuthenticatorAppSetup: () => Promise<void>;
|
|
18
38
|
cancelDisablingMfa: () => void;
|
|
19
|
-
completeDisablingMfa: () => void
|
|
39
|
+
completeDisablingMfa: () => Promise<void>;
|
|
20
40
|
clearMfaSetupError: () => void;
|
|
21
41
|
loadMfa: () => void;
|
|
22
42
|
}>;
|
|
@@ -65,19 +85,31 @@ export declare function MfaProvider({ children, isExternalIdentityProviderUser,
|
|
|
65
85
|
isExternalIdentityProviderUser: boolean;
|
|
66
86
|
}): import("react/jsx-runtime").JSX.Element;
|
|
67
87
|
export default function useMfa(): MfaState & {
|
|
68
|
-
beginMfaSetup: () => void
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
beginMfaSetup: (mfaMethod: authService.MfaMethod) => Promise<void>;
|
|
89
|
+
openMfaSetupMethodDialog: () => void;
|
|
90
|
+
closeMfaSetupMethodDialog: () => void;
|
|
91
|
+
beginDisablingMfaMethod: (mfaMethod: authService.MfaMethod) => void;
|
|
92
|
+
setPreferredMfaMethod: (mfaMethod: authService.MfaMethod) => Promise<void>;
|
|
93
|
+
openPhoneNumberDialog: () => void;
|
|
94
|
+
closePhoneNumberDialog: () => void;
|
|
95
|
+
savePhoneNumber: (phoneNumber: string) => Promise<void>;
|
|
96
|
+
verifyPhoneNumber: (code: string) => Promise<void>;
|
|
97
|
+
resendPhoneNumberVerificationCode: () => Promise<void>;
|
|
98
|
+
beginRemovingPhoneNumber: () => void;
|
|
99
|
+
cancelRemovingPhoneNumber: () => void;
|
|
100
|
+
completeRemovingPhoneNumber: () => Promise<void>;
|
|
101
|
+
hideSetupSuccess: () => void;
|
|
102
|
+
cancelMfaAuthenticatorAppSetup: () => void;
|
|
103
|
+
completeMfaAuthenticatorAppSetup: () => Promise<void>;
|
|
72
104
|
cancelDisablingMfa: () => void;
|
|
73
|
-
completeDisablingMfa: () => void
|
|
105
|
+
completeDisablingMfa: () => Promise<void>;
|
|
74
106
|
clearMfaSetupError: () => void;
|
|
75
107
|
loadMfa: () => void;
|
|
76
108
|
};
|
|
77
109
|
/**
|
|
78
110
|
* React hook to check if the logged in user meets the MFA requirement of your
|
|
79
|
-
* application. Will throw an Error if used outside of the
|
|
80
|
-
* component.
|
|
111
|
+
* application. Will throw an Error if used outside of the
|
|
112
|
+
* `<MfaProvider />` component.
|
|
81
113
|
*
|
|
82
114
|
* Example
|
|
83
115
|
*
|
package/dist/hooks/useMfa.js
CHANGED
|
@@ -1,21 +1,83 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { authService } from '../apps';
|
|
4
|
+
import useLoadDataEffect from './useLoadDataEffect';
|
|
4
5
|
export const MfaContext = React.createContext({
|
|
5
6
|
isExternalIdentityProviderUser: false,
|
|
6
7
|
isLoading: true,
|
|
7
8
|
isMfaEnabled: false,
|
|
9
|
+
mfaSettings: authService.DEFAULT_MFA_SETTINGS,
|
|
10
|
+
isSetupSuccessOpen: false,
|
|
8
11
|
isSettingUpMfa: false,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
isSetupMethodDialogOpen: false,
|
|
13
|
+
isSettingPreferredMfaMethod: false,
|
|
14
|
+
isPhoneNumberDialogOpen: false,
|
|
15
|
+
isRemovePhoneNumberDialogOpen: false,
|
|
16
|
+
beginMfaSetup: async () => { },
|
|
17
|
+
openMfaSetupMethodDialog: () => { },
|
|
18
|
+
closeMfaSetupMethodDialog: () => { },
|
|
19
|
+
beginDisablingMfaMethod: () => { },
|
|
20
|
+
setPreferredMfaMethod: async () => { },
|
|
21
|
+
openPhoneNumberDialog: () => { },
|
|
22
|
+
closePhoneNumberDialog: () => { },
|
|
23
|
+
savePhoneNumber: async () => { },
|
|
24
|
+
verifyPhoneNumber: async () => { },
|
|
25
|
+
resendPhoneNumberVerificationCode: async () => { },
|
|
26
|
+
beginRemovingPhoneNumber: () => { },
|
|
27
|
+
cancelRemovingPhoneNumber: () => { },
|
|
28
|
+
completeRemovingPhoneNumber: async () => { },
|
|
29
|
+
hideSetupSuccess: () => { },
|
|
30
|
+
cancelMfaAuthenticatorAppSetup: () => { },
|
|
31
|
+
completeMfaAuthenticatorAppSetup: async () => { },
|
|
14
32
|
cancelDisablingMfa: () => { },
|
|
15
|
-
completeDisablingMfa: () => { },
|
|
33
|
+
completeDisablingMfa: async () => { },
|
|
16
34
|
clearMfaSetupError: () => { },
|
|
17
35
|
loadMfa: () => { },
|
|
18
36
|
});
|
|
37
|
+
function getIsMfaEnabled(mfaSettings) {
|
|
38
|
+
return mfaSettings.authenticator.enabled || mfaSettings.sms.enabled;
|
|
39
|
+
}
|
|
40
|
+
function hasPreferredMfaMethod(mfaSettings) {
|
|
41
|
+
return ((mfaSettings.authenticator.enabled &&
|
|
42
|
+
mfaSettings.authenticator.preferred) ||
|
|
43
|
+
(mfaSettings.sms.enabled && mfaSettings.sms.preferred));
|
|
44
|
+
}
|
|
45
|
+
function enableSmsMfaInSettings(mfaSettings, smsPreferred) {
|
|
46
|
+
return {
|
|
47
|
+
...mfaSettings,
|
|
48
|
+
sms: {
|
|
49
|
+
...mfaSettings.sms,
|
|
50
|
+
enabled: true,
|
|
51
|
+
preferred: smsPreferred,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function enableAuthenticatorMfaInSettings(mfaSettings, authenticatorPreferred) {
|
|
56
|
+
return {
|
|
57
|
+
...mfaSettings,
|
|
58
|
+
authenticator: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
preferred: authenticatorPreferred,
|
|
61
|
+
},
|
|
62
|
+
sms: {
|
|
63
|
+
...mfaSettings.sms,
|
|
64
|
+
preferred: authenticatorPreferred ? false : mfaSettings.sms.preferred,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function setPreferredMfaMethodInSettings(mfaSettings, mfaMethod) {
|
|
69
|
+
return {
|
|
70
|
+
...mfaSettings,
|
|
71
|
+
authenticator: {
|
|
72
|
+
...mfaSettings.authenticator,
|
|
73
|
+
preferred: mfaMethod === 'authenticator',
|
|
74
|
+
},
|
|
75
|
+
sms: {
|
|
76
|
+
...mfaSettings.sms,
|
|
77
|
+
preferred: mfaMethod === 'sms',
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
19
81
|
/**
|
|
20
82
|
* React Component that provides the context for the
|
|
21
83
|
* `useUserMeetsMfaRequirement()` hook and `<MultiFactorAuthentication />`
|
|
@@ -61,112 +123,383 @@ export function MfaProvider({ children, isExternalIdentityProviderUser, }) {
|
|
|
61
123
|
isExternalIdentityProviderUser,
|
|
62
124
|
isLoading: !isExternalIdentityProviderUser,
|
|
63
125
|
isMfaEnabled: false,
|
|
126
|
+
mfaSettings: authService.DEFAULT_MFA_SETTINGS,
|
|
127
|
+
isSetupSuccessOpen: false,
|
|
64
128
|
isSettingUpMfa: false,
|
|
65
|
-
|
|
129
|
+
isSetupMethodDialogOpen: false,
|
|
130
|
+
isSettingPreferredMfaMethod: false,
|
|
131
|
+
isPhoneNumberDialogOpen: false,
|
|
132
|
+
isRemovePhoneNumberDialogOpen: false,
|
|
66
133
|
});
|
|
67
|
-
const
|
|
134
|
+
const handleLoadMfa = React.useCallback(async (abortSignal) => {
|
|
135
|
+
if (isExternalIdentityProviderUser) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
68
138
|
setState((currentState) => ({
|
|
69
139
|
...currentState,
|
|
70
140
|
isLoading: true,
|
|
71
141
|
isMfaEnabled: false,
|
|
142
|
+
mfaSettings: authService.DEFAULT_MFA_SETTINGS,
|
|
72
143
|
loadingError: undefined,
|
|
73
144
|
}));
|
|
74
145
|
try {
|
|
75
|
-
const
|
|
76
|
-
if (!
|
|
146
|
+
const mfaSettings = await authService.getMfaSettings(abortSignal);
|
|
147
|
+
if (!abortSignal.aborted) {
|
|
77
148
|
setState((currentState) => ({
|
|
78
149
|
...currentState,
|
|
79
150
|
isLoading: false,
|
|
80
|
-
|
|
151
|
+
mfaSettings,
|
|
152
|
+
isMfaEnabled: getIsMfaEnabled(mfaSettings),
|
|
81
153
|
}));
|
|
82
154
|
}
|
|
83
155
|
}
|
|
84
156
|
catch (error) {
|
|
157
|
+
if (abortSignal.aborted) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
85
160
|
setState((currentState) => ({
|
|
86
161
|
...currentState,
|
|
87
162
|
isLoading: false,
|
|
88
163
|
loadingError: error,
|
|
89
164
|
}));
|
|
90
165
|
}
|
|
91
|
-
}, []);
|
|
166
|
+
}, [isExternalIdentityProviderUser]);
|
|
167
|
+
const loadMfa = useLoadDataEffect(handleLoadMfa);
|
|
92
168
|
const clearMfaSetupError = React.useCallback(() => {
|
|
93
169
|
setState((currentState) => ({
|
|
94
170
|
...currentState,
|
|
95
171
|
setupError: undefined,
|
|
96
172
|
}));
|
|
97
173
|
}, []);
|
|
98
|
-
const
|
|
174
|
+
const openMfaSetupMethodDialog = React.useCallback(() => {
|
|
175
|
+
setState((currentState) => ({
|
|
176
|
+
...currentState,
|
|
177
|
+
isSetupMethodDialogOpen: true,
|
|
178
|
+
}));
|
|
179
|
+
}, []);
|
|
180
|
+
const closeMfaSetupMethodDialog = React.useCallback(() => {
|
|
99
181
|
setState((currentState) => ({
|
|
100
182
|
...currentState,
|
|
101
|
-
|
|
183
|
+
isSetupMethodDialogOpen: false,
|
|
102
184
|
}));
|
|
103
185
|
}, []);
|
|
104
|
-
const
|
|
186
|
+
const hideSetupSuccess = React.useCallback(() => {
|
|
105
187
|
setState((currentState) => ({
|
|
106
188
|
...currentState,
|
|
107
|
-
|
|
108
|
-
mfaSetup: undefined,
|
|
189
|
+
isSetupSuccessOpen: false,
|
|
109
190
|
}));
|
|
110
191
|
}, []);
|
|
111
|
-
const
|
|
192
|
+
const cancelMfaAuthenticatorAppSetup = React.useCallback(() => {
|
|
193
|
+
setState((currentState) => ({
|
|
194
|
+
...currentState,
|
|
195
|
+
mfaAuthenticatorAppSetup: undefined,
|
|
196
|
+
settingUpMfaMethod: undefined,
|
|
197
|
+
}));
|
|
198
|
+
}, []);
|
|
199
|
+
const completeMfaAuthenticatorAppSetup = React.useCallback(async () => {
|
|
200
|
+
setState((currentState) => {
|
|
201
|
+
const authenticatorPreferred = !hasPreferredMfaMethod(currentState.mfaSettings);
|
|
202
|
+
const mfaSettings = enableAuthenticatorMfaInSettings(currentState.mfaSettings, authenticatorPreferred);
|
|
203
|
+
return {
|
|
204
|
+
...currentState,
|
|
205
|
+
isSetupSuccessOpen: true,
|
|
206
|
+
isMfaEnabled: getIsMfaEnabled(mfaSettings),
|
|
207
|
+
mfaSettings,
|
|
208
|
+
mfaAuthenticatorAppSetup: undefined,
|
|
209
|
+
settingUpMfaMethod: undefined,
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
}, []);
|
|
213
|
+
const openPhoneNumberDialog = React.useCallback(() => {
|
|
214
|
+
setState((currentState) => ({
|
|
215
|
+
...currentState,
|
|
216
|
+
isPhoneNumberDialogOpen: true,
|
|
217
|
+
phoneVerificationCodeSentAt: undefined,
|
|
218
|
+
setupError: undefined,
|
|
219
|
+
}));
|
|
220
|
+
}, []);
|
|
221
|
+
const closePhoneNumberDialog = React.useCallback(() => {
|
|
222
|
+
setState((currentState) => ({
|
|
223
|
+
...currentState,
|
|
224
|
+
isPhoneNumberDialogOpen: false,
|
|
225
|
+
phoneVerificationCodeSentAt: undefined,
|
|
226
|
+
}));
|
|
227
|
+
}, []);
|
|
228
|
+
const setupSmsMfaMethod = React.useCallback(async () => {
|
|
229
|
+
let smsPreferred = false;
|
|
230
|
+
setState((currentState) => {
|
|
231
|
+
smsPreferred = !hasPreferredMfaMethod(currentState.mfaSettings);
|
|
232
|
+
return currentState;
|
|
233
|
+
});
|
|
234
|
+
await authService.setupSmsMfa({
|
|
235
|
+
preferred: smsPreferred,
|
|
236
|
+
});
|
|
237
|
+
setState((currentState) => {
|
|
238
|
+
const mfaSettings = enableSmsMfaInSettings(currentState.mfaSettings, smsPreferred);
|
|
239
|
+
return {
|
|
240
|
+
...currentState,
|
|
241
|
+
isSetupSuccessOpen: true,
|
|
242
|
+
isSettingUpMfa: false,
|
|
243
|
+
settingUpMfaMethod: undefined,
|
|
244
|
+
isMfaEnabled: getIsMfaEnabled(mfaSettings),
|
|
245
|
+
mfaSettings,
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
}, []);
|
|
249
|
+
const savePhoneNumber = React.useCallback(async (phoneNumber) => {
|
|
250
|
+
setState((currentState) => ({
|
|
251
|
+
...currentState,
|
|
252
|
+
setupError: undefined,
|
|
253
|
+
}));
|
|
254
|
+
try {
|
|
255
|
+
const { isPhoneNumberVerified } = await authService.updateUserPhoneNumber(phoneNumber);
|
|
256
|
+
if (!isPhoneNumberVerified) {
|
|
257
|
+
setState((currentState) => ({
|
|
258
|
+
...currentState,
|
|
259
|
+
phoneVerificationCodeSentAt: Date.now(),
|
|
260
|
+
mfaSettings: {
|
|
261
|
+
...currentState.mfaSettings,
|
|
262
|
+
sms: {
|
|
263
|
+
...currentState.mfaSettings.sms,
|
|
264
|
+
phoneNumber,
|
|
265
|
+
isPhoneNumberVerified: false,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
}));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
setState((currentState) => ({
|
|
272
|
+
...currentState,
|
|
273
|
+
mfaSettings: {
|
|
274
|
+
...currentState.mfaSettings,
|
|
275
|
+
sms: {
|
|
276
|
+
...currentState.mfaSettings.sms,
|
|
277
|
+
phoneNumber,
|
|
278
|
+
isPhoneNumberVerified,
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
isPhoneNumberDialogOpen: false,
|
|
282
|
+
phoneVerificationCodeSentAt: undefined,
|
|
283
|
+
}));
|
|
284
|
+
await setupSmsMfaMethod();
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
setState((currentState) => ({
|
|
288
|
+
...currentState,
|
|
289
|
+
setupError: error,
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
}, [setupSmsMfaMethod]);
|
|
293
|
+
const verifyPhoneNumber = React.useCallback(async (code) => {
|
|
294
|
+
setState((currentState) => ({
|
|
295
|
+
...currentState,
|
|
296
|
+
setupError: undefined,
|
|
297
|
+
}));
|
|
298
|
+
try {
|
|
299
|
+
await authService.verifyUserPhoneNumber(code);
|
|
300
|
+
setState((currentState) => ({
|
|
301
|
+
...currentState,
|
|
302
|
+
mfaSettings: {
|
|
303
|
+
...currentState.mfaSettings,
|
|
304
|
+
sms: {
|
|
305
|
+
...currentState.mfaSettings.sms,
|
|
306
|
+
isPhoneNumberVerified: true,
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
isPhoneNumberDialogOpen: false,
|
|
310
|
+
phoneVerificationCodeSentAt: undefined,
|
|
311
|
+
}));
|
|
312
|
+
await setupSmsMfaMethod();
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
setState((currentState) => ({
|
|
316
|
+
...currentState,
|
|
317
|
+
setupError: error,
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
}, [setupSmsMfaMethod]);
|
|
321
|
+
const resendPhoneNumberVerificationCode = React.useCallback(async () => {
|
|
322
|
+
setState((currentState) => ({
|
|
323
|
+
...currentState,
|
|
324
|
+
setupError: undefined,
|
|
325
|
+
phoneVerificationCodeSentAt: Date.now(),
|
|
326
|
+
}));
|
|
327
|
+
try {
|
|
328
|
+
await authService.sendPhoneNumberVerificationCode();
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
setState((currentState) => ({
|
|
332
|
+
...currentState,
|
|
333
|
+
setupError: error,
|
|
334
|
+
}));
|
|
335
|
+
}
|
|
336
|
+
}, []);
|
|
337
|
+
const beginRemovingPhoneNumber = React.useCallback(() => {
|
|
338
|
+
setState((currentState) => ({
|
|
339
|
+
...currentState,
|
|
340
|
+
isRemovePhoneNumberDialogOpen: true,
|
|
341
|
+
setupError: undefined,
|
|
342
|
+
}));
|
|
343
|
+
}, []);
|
|
344
|
+
const cancelRemovingPhoneNumber = React.useCallback(() => {
|
|
345
|
+
setState((currentState) => ({
|
|
346
|
+
...currentState,
|
|
347
|
+
isRemovePhoneNumberDialogOpen: false,
|
|
348
|
+
}));
|
|
349
|
+
}, []);
|
|
350
|
+
const completeRemovingPhoneNumber = React.useCallback(async () => {
|
|
351
|
+
setState((currentState) => ({
|
|
352
|
+
...currentState,
|
|
353
|
+
setupError: undefined,
|
|
354
|
+
}));
|
|
355
|
+
try {
|
|
356
|
+
await authService.removeUserPhoneNumber();
|
|
357
|
+
setState((currentState) => ({
|
|
358
|
+
...currentState,
|
|
359
|
+
isRemovePhoneNumberDialogOpen: false,
|
|
360
|
+
mfaSettings: {
|
|
361
|
+
...currentState.mfaSettings,
|
|
362
|
+
sms: {
|
|
363
|
+
...currentState.mfaSettings.sms,
|
|
364
|
+
phoneNumber: undefined,
|
|
365
|
+
isPhoneNumberVerified: false,
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
}));
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
setState((currentState) => ({
|
|
372
|
+
...currentState,
|
|
373
|
+
setupError: error,
|
|
374
|
+
}));
|
|
375
|
+
}
|
|
376
|
+
}, []);
|
|
377
|
+
const beginMfaSetup = React.useCallback(async (mfaMethod) => {
|
|
112
378
|
setState((currentState) => ({
|
|
113
379
|
...currentState,
|
|
114
380
|
isSettingUpMfa: true,
|
|
115
|
-
|
|
381
|
+
settingUpMfaMethod: mfaMethod,
|
|
382
|
+
mfaAuthenticatorAppSetup: undefined,
|
|
116
383
|
setupError: undefined,
|
|
117
384
|
}));
|
|
118
385
|
try {
|
|
119
|
-
|
|
386
|
+
let mfaSettings = authService.DEFAULT_MFA_SETTINGS;
|
|
387
|
+
setState((currentState) => {
|
|
388
|
+
mfaSettings = currentState.mfaSettings;
|
|
389
|
+
return currentState;
|
|
390
|
+
});
|
|
391
|
+
if (mfaMethod === 'sms') {
|
|
392
|
+
if (!mfaSettings.sms.phoneNumber ||
|
|
393
|
+
!mfaSettings.sms.isPhoneNumberVerified) {
|
|
394
|
+
setState((currentState) => ({
|
|
395
|
+
...currentState,
|
|
396
|
+
isSettingUpMfa: false,
|
|
397
|
+
settingUpMfaMethod: undefined,
|
|
398
|
+
isSetupMethodDialogOpen: false,
|
|
399
|
+
isPhoneNumberDialogOpen: true,
|
|
400
|
+
}));
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
await setupSmsMfaMethod();
|
|
404
|
+
setState((currentState) => ({
|
|
405
|
+
...currentState,
|
|
406
|
+
isSetupMethodDialogOpen: false,
|
|
407
|
+
}));
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const hasPreferredMethod = hasPreferredMfaMethod(mfaSettings);
|
|
411
|
+
const newMfaAuthenticatorAppSetup = await authService.setupMfaAuthenticatorApp({
|
|
412
|
+
preferred: !hasPreferredMethod,
|
|
413
|
+
});
|
|
120
414
|
setState((currentState) => ({
|
|
121
415
|
...currentState,
|
|
122
416
|
isSettingUpMfa: false,
|
|
123
|
-
|
|
417
|
+
isSetupMethodDialogOpen: false,
|
|
418
|
+
mfaAuthenticatorAppSetup: newMfaAuthenticatorAppSetup,
|
|
124
419
|
}));
|
|
125
420
|
}
|
|
126
421
|
catch (error) {
|
|
127
422
|
setState((currentState) => ({
|
|
128
423
|
...currentState,
|
|
129
424
|
isSettingUpMfa: false,
|
|
425
|
+
settingUpMfaMethod: undefined,
|
|
130
426
|
setupError: error,
|
|
131
427
|
}));
|
|
132
428
|
}
|
|
133
|
-
}, []);
|
|
134
|
-
const
|
|
429
|
+
}, [setupSmsMfaMethod]);
|
|
430
|
+
const disablingMfaMethodRef = React.useRef(undefined);
|
|
431
|
+
const beginDisablingMfaMethod = React.useCallback((mfaMethod) => {
|
|
432
|
+
disablingMfaMethodRef.current = mfaMethod;
|
|
135
433
|
setState((currentState) => ({
|
|
136
434
|
...currentState,
|
|
137
|
-
|
|
435
|
+
disablingMfaMethod: mfaMethod,
|
|
138
436
|
}));
|
|
139
437
|
}, []);
|
|
140
438
|
const cancelDisablingMfa = React.useCallback(() => {
|
|
439
|
+
disablingMfaMethodRef.current = undefined;
|
|
141
440
|
setState((currentState) => ({
|
|
142
441
|
...currentState,
|
|
143
|
-
|
|
442
|
+
disablingMfaMethod: undefined,
|
|
144
443
|
}));
|
|
145
444
|
}, []);
|
|
146
445
|
const completeDisablingMfa = React.useCallback(async () => {
|
|
147
|
-
|
|
446
|
+
const disablingMfaMethod = disablingMfaMethodRef.current;
|
|
447
|
+
if (!disablingMfaMethod) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
await authService.disableMfaMethod(disablingMfaMethod);
|
|
451
|
+
const mfaSettings = await authService.getMfaSettings();
|
|
452
|
+
disablingMfaMethodRef.current = undefined;
|
|
148
453
|
setState((currentState) => ({
|
|
149
454
|
...currentState,
|
|
150
|
-
|
|
151
|
-
|
|
455
|
+
disablingMfaMethod: undefined,
|
|
456
|
+
mfaSettings,
|
|
457
|
+
isMfaEnabled: getIsMfaEnabled(mfaSettings),
|
|
152
458
|
}));
|
|
153
459
|
}, []);
|
|
154
|
-
React.
|
|
155
|
-
|
|
156
|
-
|
|
460
|
+
const setPreferredMfaMethod = React.useCallback(async (mfaMethod) => {
|
|
461
|
+
setState((currentState) => ({
|
|
462
|
+
...currentState,
|
|
463
|
+
isSettingPreferredMfaMethod: true,
|
|
464
|
+
setupError: undefined,
|
|
465
|
+
}));
|
|
466
|
+
try {
|
|
467
|
+
await authService.setPreferredMfaMethod(mfaMethod);
|
|
468
|
+
setState((currentState) => ({
|
|
469
|
+
...currentState,
|
|
470
|
+
isSettingPreferredMfaMethod: false,
|
|
471
|
+
mfaSettings: setPreferredMfaMethodInSettings(currentState.mfaSettings, mfaMethod),
|
|
472
|
+
}));
|
|
473
|
+
}
|
|
474
|
+
catch (error) {
|
|
475
|
+
setState((currentState) => ({
|
|
476
|
+
...currentState,
|
|
477
|
+
isSettingPreferredMfaMethod: false,
|
|
478
|
+
setupError: error,
|
|
479
|
+
}));
|
|
157
480
|
}
|
|
158
|
-
|
|
159
|
-
return () => { };
|
|
160
|
-
}, [isExternalIdentityProviderUser, loadMfa]);
|
|
481
|
+
}, []);
|
|
161
482
|
const value = React.useMemo(() => {
|
|
162
483
|
return {
|
|
163
484
|
...state,
|
|
164
485
|
clearMfaSetupError,
|
|
165
486
|
loadMfa,
|
|
166
487
|
beginMfaSetup,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
488
|
+
openMfaSetupMethodDialog,
|
|
489
|
+
closeMfaSetupMethodDialog,
|
|
490
|
+
beginDisablingMfaMethod,
|
|
491
|
+
setPreferredMfaMethod,
|
|
492
|
+
openPhoneNumberDialog,
|
|
493
|
+
closePhoneNumberDialog,
|
|
494
|
+
savePhoneNumber,
|
|
495
|
+
verifyPhoneNumber,
|
|
496
|
+
resendPhoneNumberVerificationCode,
|
|
497
|
+
beginRemovingPhoneNumber,
|
|
498
|
+
cancelRemovingPhoneNumber,
|
|
499
|
+
completeRemovingPhoneNumber,
|
|
500
|
+
hideSetupSuccess,
|
|
501
|
+
cancelMfaAuthenticatorAppSetup,
|
|
502
|
+
completeMfaAuthenticatorAppSetup,
|
|
170
503
|
cancelDisablingMfa,
|
|
171
504
|
completeDisablingMfa,
|
|
172
505
|
};
|
|
@@ -175,21 +508,33 @@ export function MfaProvider({ children, isExternalIdentityProviderUser, }) {
|
|
|
175
508
|
clearMfaSetupError,
|
|
176
509
|
loadMfa,
|
|
177
510
|
beginMfaSetup,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
511
|
+
openMfaSetupMethodDialog,
|
|
512
|
+
closeMfaSetupMethodDialog,
|
|
513
|
+
beginDisablingMfaMethod,
|
|
514
|
+
setPreferredMfaMethod,
|
|
515
|
+
openPhoneNumberDialog,
|
|
516
|
+
closePhoneNumberDialog,
|
|
517
|
+
savePhoneNumber,
|
|
518
|
+
verifyPhoneNumber,
|
|
519
|
+
resendPhoneNumberVerificationCode,
|
|
520
|
+
beginRemovingPhoneNumber,
|
|
521
|
+
cancelRemovingPhoneNumber,
|
|
522
|
+
completeRemovingPhoneNumber,
|
|
523
|
+
hideSetupSuccess,
|
|
524
|
+
cancelMfaAuthenticatorAppSetup,
|
|
525
|
+
completeMfaAuthenticatorAppSetup,
|
|
181
526
|
cancelDisablingMfa,
|
|
182
527
|
completeDisablingMfa,
|
|
183
528
|
]);
|
|
184
|
-
return _jsx(MfaContext.Provider, { value: value, children: children });
|
|
529
|
+
return (_jsx(MfaContext.Provider, { value: value, children: children }));
|
|
185
530
|
}
|
|
186
531
|
export default function useMfa() {
|
|
187
532
|
return React.useContext(MfaContext);
|
|
188
533
|
}
|
|
189
534
|
/**
|
|
190
535
|
* React hook to check if the logged in user meets the MFA requirement of your
|
|
191
|
-
* application. Will throw an Error if used outside of the
|
|
192
|
-
* component.
|
|
536
|
+
* application. Will throw an Error if used outside of the
|
|
537
|
+
* `<MfaProvider />` component.
|
|
193
538
|
*
|
|
194
539
|
* Example
|
|
195
540
|
*
|