-
+
or scan this QR code in your authenticator app
-
+
interface State {
loginRes: RequestState
;
form: {
- username_or_email?: string;
- password?: string;
- totp_2fa_token?: string;
+ username_or_email: string;
+ password: string;
};
- showTotp: boolean;
siteRes: GetSiteResponse;
}
+async function handleLoginSuccess(i: Login, loginRes: LoginResponse) {
+ UserService.Instance.login({
+ res: loginRes,
+ });
+ const site = await HttpService.client.getSite();
+
+ if (site.state === "success") {
+ UserService.Instance.myUserInfo = site.data.my_user;
+ }
+
+ const { prev } = getLoginQueryParams();
+
+ prev
+ ? i.props.history.replace(prev)
+ : i.props.history.action === "PUSH"
+ ? i.props.history.back()
+ : i.props.history.replace("/");
+}
+
async function handleLoginSubmit(i: Login, event: any) {
event.preventDefault();
- const { password, totp_2fa_token, username_or_email } = i.state.form;
+ const { password, username_or_email } = i.state.form;
if (username_or_email && password) {
i.setState({ loginRes: { state: "loading" } });
@@ -43,39 +61,23 @@ async function handleLoginSubmit(i: Login, event: any) {
const loginRes = await HttpService.client.login({
username_or_email,
password,
- totp_2fa_token,
});
switch (loginRes.state) {
case "failed": {
if (loginRes.msg === "missing_totp_token") {
- i.setState({ showTotp: true });
- toast(I18NextService.i18n.t("enter_two_factor_code"), "info");
+ const Modal = (await import("bootstrap/js/dist/modal")).default;
+ const modal = new Modal(document.getElementById("totpModal")!);
+ modal.show();
} else {
toast(I18NextService.i18n.t(loginRes.msg), "danger");
}
- i.setState({ loginRes: { state: "failed", msg: loginRes.msg } });
+ i.setState({ loginRes });
break;
}
case "success": {
- UserService.Instance.login({
- res: loginRes.data,
- });
- const site = await HttpService.client.getSite();
-
- if (site.state === "success") {
- UserService.Instance.myUserInfo = site.data.my_user;
- }
-
- const { prev } = getLoginQueryParams();
-
- prev
- ? i.props.history.replace(prev)
- : i.props.history.action === "PUSH"
- ? i.props.history.back()
- : i.props.history.replace("/");
-
+ handleLoginSuccess(i, loginRes.data);
break;
}
}
@@ -88,10 +90,6 @@ function handleLoginUsernameChange(i: Login, event: any) {
);
}
-function handleLoginTotpChange(i: Login, event: any) {
- i.setState(prevState => (prevState.form.totp_2fa_token = event.target.value));
-}
-
function handleLoginPasswordChange(i: Login, event: any) {
i.setState(prevState => (prevState.form.password = event.target.value));
}
@@ -104,13 +102,17 @@ export class Login extends Component<
state: State = {
loginRes: { state: "empty" },
- form: {},
- showTotp: false,
+ form: {
+ username_or_email: "",
+ password: "",
+ },
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
+
+ this.handleSubmitTotp = this.handleSubmitTotp.bind(this);
}
componentDidMount() {
@@ -137,6 +139,7 @@ export class Login extends Component<
title={this.documentTitle}
path={this.context.router.route.match.url}
/>
+
@@ -144,6 +147,23 @@ export class Login extends Component<
);
}
+ async handleSubmitTotp(totp: string) {
+ const loginRes = await HttpService.client.login({
+ password: this.state.form.password,
+ username_or_email: this.state.form.username_or_email,
+ totp_2fa_token: totp,
+ });
+
+ const succeeded = loginRes.state === "success";
+ if (succeeded) {
+ handleLoginSuccess(this, loginRes.data);
+ } else {
+ toast("Invalid 2FA Token", "danger");
+ }
+
+ return succeeded;
+ }
+
loginForm() {
return (
@@ -178,28 +198,6 @@ export class Login extends Component<
showForgotLink
/>
- {this.state.showTotp && (
-
-
-
-
-
-
- )}