Can login using access reset token

This commit is contained in:
Pierre HUBERT 2021-05-12 17:05:46 +02:00
parent b1929fc21f
commit 05117e71a3
3 changed files with 168 additions and 26 deletions

View File

@ -25,12 +25,13 @@ export async function serverRequest(uri: string, args?: any): Promise<any> {
// TODO : add access token, once supported
const result = await (
await fetch((await ConfigHelper.apiURL()) + uri, {
method: "POST",
body: fd,
})
).json();
const result = await fetch((await ConfigHelper.apiURL()) + uri, {
method: "POST",
body: fd,
});
return result;
if (result.status !== 200)
throw new Error("Request failed with status " + result.status);
return await result.json();
}

View File

@ -10,6 +10,8 @@ export interface AuthOptions {
reset_token: string;
}
const SESSION_STORAGE_TOKEN = "auth_token";
export class AccountHelper {
/**
* Check whether access token are available
@ -30,4 +32,19 @@ export class AccountHelper {
mail: mail,
});
}
/**
* Attempt to authenticate user using a reset token
*
* @param mail Email address of the admin
* @param token The reset token
*/
static async authWithResetToken(mail: string, token: string) {
const res = await serverRequest("accounts/auth_with_reset_token", {
mail: mail,
token: token,
});
sessionStorage.setItem(SESSION_STORAGE_TOKEN, res.token);
}
}

View File

@ -5,24 +5,41 @@
*/
import {
Typography,
Link,
makeStyles,
Avatar,
Box,
Button,
Container,
CssBaseline,
Avatar,
List,
ListItem,
ListItemAvatar,
ListItemText,
Paper,
TextField,
FormControlLabel,
Checkbox,
Button,
Grid,
Box,
Typography,
} from "@material-ui/core";
import { ErrorOutline, Lock, VpnKey } from "@material-ui/icons";
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
import React from "react";
import { AccountHelper } from "../../helpers/AccountHelper";
import { matAlert } from "../widgets/DialogsProvider";
import { AccountHelper, AuthOptions } from "../../helpers/AccountHelper";
import { input, matAlert } from "../widgets/DialogsProvider";
function ErrorGettingOptions() {
return (
<Paper
style={{
width: "100%",
padding: "10px",
marginTop: "10px",
display: "flex",
alignItems: "center",
}}
>
<ErrorOutline></ErrorOutline>
&nbsp; Could not get your auth options!
</Paper>
);
}
function Copyright() {
return (
@ -37,6 +54,8 @@ function Copyright() {
interface LoginRouteState {
currEmail: string;
errorGettingAuthOptions: boolean;
authOptions?: AuthOptions;
}
export class LoginRoute extends React.Component<{}, LoginRouteState> {
@ -45,6 +64,8 @@ export class LoginRoute extends React.Component<{}, LoginRouteState> {
this.state = {
currEmail: "",
errorGettingAuthOptions: false,
authOptions: undefined,
};
this.handleChangedEmail = this.handleChangedEmail.bind(this);
@ -56,17 +77,31 @@ export class LoginRoute extends React.Component<{}, LoginRouteState> {
}
handleChangedEmail(e: React.ChangeEvent<HTMLInputElement>) {
this.setState({ currEmail: e.target.value });
this.setState({
currEmail: e.target.value,
errorGettingAuthOptions: false,
authOptions: undefined,
});
}
handleSubmitEmail(e: React.ChangeEvent<any>) {
e.preventDefault();
async handleSubmitEmail(e: React.ChangeEvent<any>) {
try {
e.preventDefault();
if (!this.canSubmit) return;
if (!this.canSubmit) return;
AccountHelper.getAuthOptions(this.state.currEmail).then((r) =>
matAlert("reset token => " + r.reset_token)
);
const options = await AccountHelper.getAuthOptions(
this.state.currEmail
);
this.setState({
errorGettingAuthOptions: false,
authOptions: options,
});
} catch (e) {
console.error("Failed to get auth options!", e);
this.setState({ errorGettingAuthOptions: true });
}
}
render() {
@ -138,6 +173,23 @@ export class LoginRoute extends React.Component<{}, LoginRouteState> {
Sign In
</Button>
</form>
{/* Login error (if any) */}
{this.state.errorGettingAuthOptions ? (
ErrorGettingOptions()
) : (
<div></div>
)}
{/* Auth options */}
{this.state.authOptions ? (
<AuthOptionsWidget
email={this.state.currEmail}
options={this.state.authOptions}
></AuthOptionsWidget>
) : (
<div></div>
)}
</div>
<Box mt={8}>
<Copyright />
@ -147,3 +199,75 @@ export class LoginRoute extends React.Component<{}, LoginRouteState> {
);
}
}
interface AuthOptionsWidgetProps {
email: string;
options: AuthOptions;
}
interface AuthOptionsWidgetState {}
class AuthOptionsWidget extends React.Component<
AuthOptionsWidgetProps,
AuthOptionsWidgetState
> {
constructor(props: Readonly<AuthOptionsWidgetProps>) {
super(props);
this.state = {};
this.loginWithResetToken = this.loginWithResetToken.bind(this);
}
async loginWithResetToken() {
try {
const token = await input({
label: "Reset token",
message: "Please specify here your token:",
minLength: 2,
title: "Login using access token",
});
await AccountHelper.authWithResetToken(this.props.email, token);
document.location.href = document.location.href + "";
} catch (e) {
console.error(e);
matAlert("Authentication failed!");
}
}
render() {
return (
<Paper style={{ width: "100%", marginTop: "10px" }}>
<List style={{ width: "100%" }}>
{/* Password reset token */}
{this.props.options.reset_token ? (
<ListItem button onClick={this.loginWithResetToken}>
<ListItemAvatar>
<Avatar>
<Lock />
</Avatar>
</ListItemAvatar>
<ListItemText
primary="Reset token"
secondary="Sign in using a reset token"
/>
</ListItem>
) : (
<span></span>
)}
<ListItem>
<ListItemAvatar>
<Avatar>
<VpnKey />
</Avatar>
</ListItemAvatar>
<ListItemText primary="Work" secondary="Jan 7, 2014" />
</ListItem>
</List>
</Paper>
);
}
}