@stokr/components-library 3.0.47 → 3.0.49
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/components/2FA/enable-2fa-flow.js +12 -3
- package/dist/components/2FA/login-with-otp-flow.js +16 -0
- package/dist/components/2FA/main-flow.js +28 -3
- package/dist/components/headerHo/HeaderHo.js +10 -0
- package/dist/index.js +3 -0
- package/dist/utils/show-account-locked-modal.js +23 -0
- package/package.json +1 -1
|
@@ -9,10 +9,11 @@ import stdin_default$5 from "./EnterCode.js";
|
|
|
9
9
|
import { AuthContext } from "../../context/AuthContext.js";
|
|
10
10
|
import stdin_default$1 from "./Sucess2FA.js";
|
|
11
11
|
import fetchData from "../../api/fetchData.js";
|
|
12
|
+
import { getFirebaseAuth } from "../../firebase-config.js";
|
|
12
13
|
import { ModalInner, ModalBack } from "../Modal/Modal.styles.js";
|
|
13
14
|
const stepsNames = ["app", "connect", "enter-code"];
|
|
14
15
|
const Enable2FAFlow = ({ showFlow, setShowFlow, onSuccess, totpData, onRequiresRecentLoginError }) => {
|
|
15
|
-
const { user, enrollUserToTotp, refreshIdToken } = useContext(AuthContext);
|
|
16
|
+
const { user, firebaseUser, enrollUserToTotp, refreshIdToken } = useContext(AuthContext);
|
|
16
17
|
const [showSuccess, setshowSuccess] = useState(false);
|
|
17
18
|
const [popupError, setpopupError] = useState({
|
|
18
19
|
popup: void 0,
|
|
@@ -31,9 +32,17 @@ const Enable2FAFlow = ({ showFlow, setShowFlow, onSuccess, totpData, onRequiresR
|
|
|
31
32
|
}
|
|
32
33
|
}, [user]);
|
|
33
34
|
const onSubmit = async (data) => {
|
|
34
|
-
if (!
|
|
35
|
+
if (!data) return console.log("not enough data");
|
|
36
|
+
const mfaUser = firebaseUser || getFirebaseAuth()?.currentUser || user;
|
|
37
|
+
if (!mfaUser) {
|
|
38
|
+
setpopupError({
|
|
39
|
+
popup: "enter2fa",
|
|
40
|
+
message: "Unable to complete 2FA setup. Please log in again and retry."
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
35
44
|
try {
|
|
36
|
-
await enrollUserToTotp(
|
|
45
|
+
await enrollUserToTotp(mfaUser, totpData.totpSecret, data.otpInput, user?.displayName || mfaUser?.displayName);
|
|
37
46
|
setshowSuccess(true);
|
|
38
47
|
try {
|
|
39
48
|
await fetchData("auth/enable-2fa-email");
|
|
@@ -10,6 +10,7 @@ import stdin_default$3 from "./ResetCode.js";
|
|
|
10
10
|
import { authenticationApi } from "../../api/authenticationApi.js";
|
|
11
11
|
import { useNavigate } from "react-router-dom";
|
|
12
12
|
import { getConfig, getPlatformURL } from "../../runtime-config.js";
|
|
13
|
+
import { isAccountLockedError, showAccountLockedModal } from "../../utils/show-account-locked-modal.js";
|
|
13
14
|
import { navigateToHref } from "../../routing/navigate-app.js";
|
|
14
15
|
const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
|
|
15
16
|
const navigate = useNavigate();
|
|
@@ -95,6 +96,21 @@ const LoginWithOTP = ({ withBackground, useRelativePathForMenu = false }) => {
|
|
|
95
96
|
clearPopupError();
|
|
96
97
|
return;
|
|
97
98
|
}
|
|
99
|
+
if (isAccountLockedError(error)) {
|
|
100
|
+
clearPopupError();
|
|
101
|
+
setIsModalOpen((prev) => ({
|
|
102
|
+
...prev,
|
|
103
|
+
login: false
|
|
104
|
+
}));
|
|
105
|
+
await showAccountLockedModal({
|
|
106
|
+
background: withBackground ? backgroundProp : void 0
|
|
107
|
+
});
|
|
108
|
+
setIsModalOpen((prev) => ({
|
|
109
|
+
...prev,
|
|
110
|
+
login: true
|
|
111
|
+
}));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
98
114
|
if (errorMessage) {
|
|
99
115
|
handleSetPopupError("login", errorMessage);
|
|
100
116
|
} else {
|
|
@@ -13,11 +13,14 @@ import { InfoIcon } from "../InfoIcon/InfoIcon.js";
|
|
|
13
13
|
import { Modal } from "../Modal/Modal.js";
|
|
14
14
|
import stdin_default$4 from "./Sucess2FA.js";
|
|
15
15
|
import { ModalInner } from "../Modal/Modal.styles.js";
|
|
16
|
+
import { showProgress } from "../Modal/SuccessModal/SuccessModal.js";
|
|
17
|
+
const SUPPORT_URL = "https://support.stokr.io/";
|
|
16
18
|
const Main2FAFlow = ({
|
|
17
19
|
onRequiresRecentLoginError,
|
|
18
20
|
open2faflow,
|
|
19
21
|
onLoginAgainClick,
|
|
20
22
|
openDisable2faflow,
|
|
23
|
+
allowDisable2FA = false,
|
|
21
24
|
title = "SET UP YOUR LOG IN TWO FACTOR AUTHENTICATION",
|
|
22
25
|
subtitle = "Protect your account with an additional layer of security to log in",
|
|
23
26
|
showSwitch = true,
|
|
@@ -27,7 +30,7 @@ const Main2FAFlow = ({
|
|
|
27
30
|
const { user, checkMfaEnrollment, userMfaEnrollment, generateTotpSecret } = useContext(AuthContext);
|
|
28
31
|
const [isFlowopen, setIsFlowOpen] = useState({
|
|
29
32
|
enable2fa: open2faflow || false,
|
|
30
|
-
disable2fa: openDisable2faflow || false,
|
|
33
|
+
disable2fa: allowDisable2FA && (openDisable2faflow || false),
|
|
31
34
|
requiresRecentLogin: false
|
|
32
35
|
});
|
|
33
36
|
const [is2FAEnabled, setis2FAEnabled] = useState(false);
|
|
@@ -81,6 +84,16 @@ const Main2FAFlow = ({
|
|
|
81
84
|
[nextFlowId]: true
|
|
82
85
|
}));
|
|
83
86
|
};
|
|
87
|
+
const showDisable2faBlockedModal = () => showProgress({
|
|
88
|
+
title: "TWO-FACTOR AUTHENTICATION REQUIRED",
|
|
89
|
+
subtitle: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
90
|
+
"Under our security policy, two-factor authentication is required on all accounts and cannot be turned off. To reset your method, contact our",
|
|
91
|
+
" ",
|
|
92
|
+
/* @__PURE__ */ jsx("a", { href: SUPPORT_URL, target: "_blank", rel: "noreferrer", style: { textDecoration: "underline" }, children: /* @__PURE__ */ jsx("u", { children: "support team" }) }),
|
|
93
|
+
"."
|
|
94
|
+
] }),
|
|
95
|
+
maxWidth: "820px"
|
|
96
|
+
});
|
|
84
97
|
const handleFlowClose = (flowId, completed = false) => {
|
|
85
98
|
setIsFlowOpen((prev) => ({ ...prev, [flowId]: false }));
|
|
86
99
|
if (onFlowClose) onFlowClose({ flow: flowId, completed });
|
|
@@ -99,7 +112,14 @@ const Main2FAFlow = ({
|
|
|
99
112
|
};
|
|
100
113
|
const flowActions = {
|
|
101
114
|
openEnable2FA: () => switchOpenFlow("disable2fa", "enable2fa"),
|
|
102
|
-
openDisable2FA: () =>
|
|
115
|
+
openDisable2FA: () => {
|
|
116
|
+
if (!is2FAEnabled) return;
|
|
117
|
+
if (!allowDisable2FA) {
|
|
118
|
+
void showDisable2faBlockedModal();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
switchOpenFlow("enable2fa", "disable2fa");
|
|
122
|
+
},
|
|
103
123
|
closeFlows: () => {
|
|
104
124
|
const wasOpen = Object.keys(isFlowopen).find((key) => isFlowopen[key]);
|
|
105
125
|
setIsFlowOpen({
|
|
@@ -148,6 +168,10 @@ const Main2FAFlow = ({
|
|
|
148
168
|
} else if (value === "enabled") {
|
|
149
169
|
switchOpenFlow("disable2fa", "enable2fa");
|
|
150
170
|
} else if (value === "disabled") {
|
|
171
|
+
if (!allowDisable2FA) {
|
|
172
|
+
void showDisable2faBlockedModal();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
151
175
|
switchOpenFlow("enable2fa", "disable2fa");
|
|
152
176
|
}
|
|
153
177
|
}
|
|
@@ -177,7 +201,7 @@ const Main2FAFlow = ({
|
|
|
177
201
|
onSuccess: onEnable2FASuccess
|
|
178
202
|
}
|
|
179
203
|
),
|
|
180
|
-
isFlowopen.disable2fa && /* @__PURE__ */ jsx(
|
|
204
|
+
allowDisable2FA && isFlowopen.disable2fa && /* @__PURE__ */ jsx(
|
|
181
205
|
stdin_default$3,
|
|
182
206
|
{
|
|
183
207
|
showFlow: isFlowopen.disable2fa,
|
|
@@ -210,6 +234,7 @@ const Main2FAFlow = ({
|
|
|
210
234
|
};
|
|
211
235
|
Main2FAFlow.propTypes = {
|
|
212
236
|
onRequiresRecentLoginError: PropTypes.func,
|
|
237
|
+
allowDisable2FA: PropTypes.bool,
|
|
213
238
|
/** Called when any flow/modal is closed. Receives the flowId: 'enable2fa' | 'disable2fa' | 'requiresRecentLogin' */
|
|
214
239
|
onFlowClose: PropTypes.func
|
|
215
240
|
};
|
|
@@ -23,6 +23,7 @@ import { auth } from "../../firebase-config.js";
|
|
|
23
23
|
import { getConfig } from "../../runtime-config.js";
|
|
24
24
|
import { getBackofficeAppUrl } from "../../utils/app-urls-analytics-backoffice.js";
|
|
25
25
|
import { track } from "../../analytics/index.js";
|
|
26
|
+
import { isAccountLockedError, showAccountLockedModal } from "../../utils/show-account-locked-modal.js";
|
|
26
27
|
import { navigateToHref } from "../../routing/navigate-app.js";
|
|
27
28
|
const Outer = styled.div.withConfig({
|
|
28
29
|
shouldForwardProp: (props) => !["fixed"].includes(props)
|
|
@@ -320,6 +321,15 @@ const _HeaderHoClass = class _HeaderHoClass extends Component {
|
|
|
320
321
|
this.setIsActionLoading(void 0);
|
|
321
322
|
return;
|
|
322
323
|
}
|
|
324
|
+
if (isAccountLockedError(error)) {
|
|
325
|
+
this.setOpenModalStatus("login", false);
|
|
326
|
+
setIsLoginModalOpen?.(false);
|
|
327
|
+
this.clearPopupError();
|
|
328
|
+
this.setIsActionLoading(void 0);
|
|
329
|
+
await showAccountLockedModal();
|
|
330
|
+
this.setOpenModalStatus("login", true);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
323
333
|
if (errorMessage) {
|
|
324
334
|
this.setPopupError("login", errorMessage);
|
|
325
335
|
} else {
|
package/dist/index.js
CHANGED
|
@@ -135,6 +135,7 @@ import { isUSInvestor, usCountries } from "./utils/isUSInvestor.js";
|
|
|
135
135
|
import { km_ify } from "./utils/km_ify.js";
|
|
136
136
|
import { momentUtils } from "./utils/moment.js";
|
|
137
137
|
import { openFile, saveAs } from "./utils/saveAs.js";
|
|
138
|
+
import { isAccountLockedError, showAccountLockedModal } from "./utils/show-account-locked-modal.js";
|
|
138
139
|
import { ScrollToTop, scrollToElement, useScrollActions } from "./utils/scrollUtils.js";
|
|
139
140
|
import { useTimer } from "./hooks/useTimer.js";
|
|
140
141
|
import { useTransactionPolling } from "./hooks/useTransactionPolling.js";
|
|
@@ -625,6 +626,7 @@ export {
|
|
|
625
626
|
iconsMap,
|
|
626
627
|
identify,
|
|
627
628
|
initAnalytics,
|
|
629
|
+
isAccountLockedError,
|
|
628
630
|
isAlreadyOnOnboardingFlow,
|
|
629
631
|
isExternalUrl,
|
|
630
632
|
isUSInvestor,
|
|
@@ -647,6 +649,7 @@ export {
|
|
|
647
649
|
scrollToElement,
|
|
648
650
|
default6 as semanticUiStyle,
|
|
649
651
|
setUserProperties,
|
|
652
|
+
showAccountLockedModal,
|
|
650
653
|
showProgress,
|
|
651
654
|
showSuccess,
|
|
652
655
|
sizes,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
2
|
+
import "react";
|
|
3
|
+
import { showProgress } from "../components/Modal/SuccessModal/SuccessModal.js";
|
|
4
|
+
const SUPPORT_URL = "https://support.stokr.io/";
|
|
5
|
+
const ACCOUNT_LOCKED_CODE = "auth/user-disabled";
|
|
6
|
+
const isAccountLockedError = (error) => error?.code === ACCOUNT_LOCKED_CODE;
|
|
7
|
+
const showAccountLockedModal = ({ background } = {}) => showProgress({
|
|
8
|
+
title: "TOO MANY ATTEMPTS",
|
|
9
|
+
subtitle: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10
|
+
"For your security, your account has been temporarily locked after multiple failed sign-in attempts. To restore access, contact our",
|
|
11
|
+
" ",
|
|
12
|
+
/* @__PURE__ */ jsx("a", { href: SUPPORT_URL, target: "_blank", rel: "noreferrer", style: { textDecoration: "underline" }, children: /* @__PURE__ */ jsx("u", { children: "support team" }) }),
|
|
13
|
+
"."
|
|
14
|
+
] }),
|
|
15
|
+
maxWidth: "820px",
|
|
16
|
+
modalProps: {
|
|
17
|
+
background
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
export {
|
|
21
|
+
isAccountLockedError,
|
|
22
|
+
showAccountLockedModal
|
|
23
|
+
};
|