From 9071f0744334fd755f2be7b79e058bfd5be2cdac Mon Sep 17 00:00:00 2001
From: Aaron
Date: Fri, 22 Feb 2019 10:14:07 -0600
Subject: [PATCH] admin MFAuth refactoring & cosmetics
---
admin/src/components/MFAuth/index.less | 16 +++--
admin/src/components/MFAuth/index.tsx | 96 +++++++++++++++-----------
2 files changed, 66 insertions(+), 46 deletions(-)
diff --git a/admin/src/components/MFAuth/index.less b/admin/src/components/MFAuth/index.less
index b3c4e298..92282cd2 100644
--- a/admin/src/components/MFAuth/index.less
+++ b/admin/src/components/MFAuth/index.less
@@ -14,8 +14,7 @@
margin-bottom: 0.8rem;
}
- &-codes,
- &-qrcode {
+ &-codes {
margin: 1.5rem 0;
font-size: 1rem;
font-family: 'Courier New', Courier, monospace;
@@ -48,13 +47,21 @@
& > div {
white-space: nowrap;
line-height: 2rem;
- margin-right: 0.6rem;
+ margin-right: 0.5rem;
+ font-weight: bold;
}
}
&-controls {
+ display: flex;
margin-top: 1rem;
- text-align: right;
+ justify-content: flex-end;
+
+ &-label {
+ white-space: nowrap;
+ line-height: 2rem;
+ font-weight: bold;
+ }
& > * + * {
margin-left: 0.5rem;
@@ -63,6 +70,7 @@
ol {
margin-left: 1rem;
+ margin-bottom: 2rem;
& > li {
margin: 1rem 0;
diff --git a/admin/src/components/MFAuth/index.tsx b/admin/src/components/MFAuth/index.tsx
index 7c5fc1ec..65adb013 100644
--- a/admin/src/components/MFAuth/index.tsx
+++ b/admin/src/components/MFAuth/index.tsx
@@ -1,5 +1,5 @@
import React, { ReactNode } from 'react';
-import { Link, Redirect } from 'react-router-dom';
+import { Link, Redirect, withRouter, RouteComponentProps } from 'react-router-dom';
import { view } from 'react-easy-state';
import CopyToClipboard from 'react-copy-to-clipboard';
import QRCode from 'qrcode.react';
@@ -15,10 +15,12 @@ import store, {
import { downloadString } from 'src/util/file';
import './index.less';
-interface Props {
+interface OwnProps {
isReset?: boolean;
}
+type Props = OwnProps & RouteComponentProps;
+
const STATE = {
// remote
isLoginFresh: false,
@@ -31,10 +33,10 @@ const STATE = {
isEmailVerified: false,
// local
loaded: false,
- hasReadSetup: false,
+ stepOutlineComplete: false,
initializing: false,
- hasSavedCodes: false,
- hasVerified: false,
+ stepRecoveryCodesComplete: false,
+ stepTotpComplete: false,
password: '',
verifyCode: '',
isVerifying: false,
@@ -50,10 +52,10 @@ class MFAuth extends React.Component {
render() {
const {
loaded,
- hasReadSetup,
+ stepOutlineComplete,
password,
- hasSavedCodes,
- hasVerified,
+ stepRecoveryCodesComplete,
+ stepTotpComplete,
verifyCode,
isLoginFresh,
has2fa,
@@ -86,7 +88,7 @@ class MFAuth extends React.Component {
has2fa &&
backupCodeCount < 5 && (
You only have {backupCodeCount} recovery codes remaining! Generate
@@ -103,7 +105,6 @@ class MFAuth extends React.Component {
{isReset ? 'Reset two-factor authentication' : 'Two-factor authentication'}
- {lowBackupCodesWarning}
{children}
>
)}
@@ -126,12 +127,14 @@ class MFAuth extends React.Component {
Too much time has elapsed since you last affirmed your credentials, please
enter your password below.
- this.setState({ password: e.target.value })}
- value={password}
- />
+
+
this.setState({ password: e.target.value })}
+ value={password}
+ autoFocus={true}
+ />
{
}
// STEP 1 (outline)
- if ((!has2fa || isReset) && !hasReadSetup) {
+ if ((!has2fa || isReset) && !stepOutlineComplete) {
return wrap(
- {!has2fa &&
}
+ {!has2fa && (
+
Administration requires two-factor authentication setup.>}
+ />
+ )}
{isReset && (
{
- {isReset && (
-
-
Cancel
-
- )}
+ {isReset &&
Cancel }
I'm ready
@@ -184,7 +188,7 @@ class MFAuth extends React.Component
{
}
// STEP 2 (recovery codes)
- if ((!has2fa || isReset) && !hasSavedCodes) {
+ if ((!has2fa || isReset) && !stepRecoveryCodesComplete) {
return wrap(
((initializing || !backupCodes.length) && (
@@ -228,7 +232,7 @@ class MFAuth extends React.Component {
Cancel
this.setState({ hasSavedCodes: true })}
+ onClick={() => this.setState({ stepRecoveryCodesComplete: true })}
>
Next
@@ -239,7 +243,7 @@ class MFAuth extends React.Component {
}
// STEP 4 (totp setup/verify)
- if ((!has2fa || isReset) && !hasVerified) {
+ if ((!has2fa || isReset) && !stepTotpComplete) {
return wrap(
3. Set up Authenticator
@@ -273,11 +277,13 @@ class MFAuth extends React.Component
{
-
Enter code from application:
+
Enter code from application
this.setState({ verifyCode: e.target.value })}
+ onPressEnter={this.handleEnable}
+ autoFocus={true}
/>
@@ -288,7 +294,7 @@ class MFAuth extends React.Component
{
disabled={verifyCode.length === 0}
loading={isVerifying}
>
- {isReset ? 'Reset' : 'Enable'}
+ {isReset ? 'Save' : 'Enable'}
,
@@ -299,21 +305,22 @@ class MFAuth extends React.Component {
if (has2fa && !is2faAuthed) {
return wrap(
<>
- 2FAuthentication required
+ {lowBackupCodesWarning}
+ Two-Factor authentication required
- Enter the current code from your authenticator application. Enter a backup
+ Enter the current code from your authenticator application. Enter a recovery
code if you do not have access to your authenticator application.
-
-
Enter code from application:
+
+
+
Enter code from application
this.setState({ verifyCode: e.target.value })}
onPressEnter={this.handleVerify}
+ autoFocus={true}
/>
-
-
{
};
private handleCancel = async () => {
- this.setState({ ...STATE });
- this.update2faStateFromServer();
+ const { isReset } = this.props;
+ if (isReset) {
+ message.info('Canceled two-factor reset');
+ this.props.history.replace('/settings');
+ } else {
+ this.setState({ ...STATE });
+ this.update2faStateFromServer();
+ }
};
private handleReadSetup = async () => {
- if (this.state.isLoginFresh) {
- this.setState({ hasReadSetup: true });
- this.loadSetup();
- }
+ this.setState({ stepOutlineComplete: true });
+ this.loadSetup();
};
private handleSubmitPassword = async () => {
@@ -382,13 +393,13 @@ class MFAuth extends React.Component {
private handleEnable = async () => {
const { backupCodes, totpSecret, verifyCode } = this.state;
+ if (verifyCode.length === 0) return; // for pressEnter
this.setState({ isVerifying: true });
try {
await post2faEnable({ backupCodes, totpSecret, verifyCode });
message.success('Two-factor setup complete!');
store.checkLogin(); // should return authenticated status
- this.setState({ hasVerified: true });
- // await this.update2faStateFromServer();
+ this.setState({ stepTotpComplete: true });
} catch (e) {
handleApiError(e);
}
@@ -397,6 +408,7 @@ class MFAuth extends React.Component {
private handleVerify = async () => {
const { verifyCode } = this.state;
+ if (verifyCode.length === 0) return; // for pressEnter
this.setState({ isVerifying: true });
try {
await post2faVerify({ verifyCode });
@@ -409,4 +421,4 @@ class MFAuth extends React.Component {
};
}
-export default view(MFAuth);
+export default withRouter(view(MFAuth));