mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
127 lines
3.8 KiB
TypeScript
127 lines
3.8 KiB
TypeScript
import React, { Component } from "react";
|
|
|
|
import Button from "@material/react-button";
|
|
|
|
import styles from '../../assets/scss/views/OneTimePasswordRegistrationView/OneTimePasswordRegistrationView.module.scss';
|
|
import { RouteProps, RouterProps } from "react-router";
|
|
import QueryString from 'query-string';
|
|
|
|
import QRCode from 'qrcode.react';
|
|
import Notification from "../../components/Notification/Notification";
|
|
|
|
import googleStoreImage from '../../assets/images/googleplay-badge.svg';
|
|
import appleStoreImage from '../../assets/images/applestore-badge.svg';
|
|
import { Secret } from "./Secret";
|
|
import CircleLoader, { Status } from "../../components/CircleLoader/CircleLoader";
|
|
|
|
export interface Props extends RouteProps, RouterProps {
|
|
secret: Secret | null;
|
|
error: string | null;
|
|
onInit: (token: string) => void;
|
|
onRetryClicked: () => void;
|
|
onCancelClicked: () => void;
|
|
onLoginClicked: () => void;
|
|
}
|
|
|
|
class OneTimePasswordRegistrationView extends Component<Props> {
|
|
private token: string | null;
|
|
constructor(props: Props) {
|
|
super(props);
|
|
this.token = null;
|
|
}
|
|
|
|
componentWillMount() {
|
|
// If secret is already populated, we skip onInit (for testing purposes).
|
|
if (this.props.secret) return;
|
|
|
|
if (!this.props.location) {
|
|
console.error('There is no location to retrieve query params from...');
|
|
return;
|
|
}
|
|
const params = QueryString.parse(this.props.location.search);
|
|
if (!('token' in params)) {
|
|
console.error('Token parameter is expected and not provided');
|
|
return;
|
|
}
|
|
this.token = params['token'] as string;
|
|
this.props.onInit(this.token);
|
|
}
|
|
|
|
private renderWithSecret(secret: Secret) {
|
|
return (
|
|
<div>
|
|
<div className={styles.text}>
|
|
Register your device by scanning the barcode or adding the key.
|
|
</div>
|
|
<div className={styles.secretContainer}>
|
|
<div className={styles.qrcodeContainer}>
|
|
<QRCode value={secret.otpauth_url} size={180} level="Q"></QRCode>
|
|
</div>
|
|
<div className={styles.base32Container}>{secret.base32_secret}</div>
|
|
</div>
|
|
<div className={styles.loginButtonContainer}>
|
|
<Button
|
|
color="primary"
|
|
raised={true}
|
|
onClick={this.props.onLoginClicked}>
|
|
Login
|
|
</Button>
|
|
</div>
|
|
<div className={styles.needGoogleAuthenticator}>
|
|
<div className={styles.needGoogleAuthenticatorText}>Need Google Authenticator?</div>
|
|
<img src={appleStoreImage} className={styles.store} alt='Google Authenticator on Apple Store'/>
|
|
<img src={googleStoreImage} className={styles.store} alt='Google Authenticator on Google Store'/>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
private renderError() {
|
|
return (
|
|
<div>
|
|
<Notification show={true}>
|
|
<div>{this.props.error}</div>
|
|
</Notification>
|
|
<div className={styles.buttonContainer}>
|
|
<Button
|
|
color="primary"
|
|
raised={true}
|
|
className={styles.button}
|
|
onClick={this.props.onRetryClicked}>
|
|
Retry
|
|
</Button>
|
|
<Button
|
|
color="primary"
|
|
raised={true}
|
|
className={styles.button}
|
|
onClick={this.props.onCancelClicked}>
|
|
Cancel
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
private renderSecret() {
|
|
return this.props.secret
|
|
? this.renderWithSecret(this.props.secret)
|
|
: this.renderError();
|
|
}
|
|
|
|
private renderLoading() {
|
|
return (
|
|
<div>
|
|
<div>One-Time password secret is being generated...</div>
|
|
<div className={styles.progressContainer}><CircleLoader status={Status.LOADING} /></div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
render() {
|
|
return !this.props.secret && !this.props.error
|
|
? this.renderLoading()
|
|
: this.renderSecret();
|
|
}
|
|
}
|
|
|
|
export default OneTimePasswordRegistrationView; |