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 // TODO : add access token, once supported
const result = await ( const result = await fetch((await ConfigHelper.apiURL()) + uri, {
await fetch((await ConfigHelper.apiURL()) + uri, {
method: "POST", method: "POST",
body: fd, body: fd,
}) });
).json();
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; reset_token: string;
} }
const SESSION_STORAGE_TOKEN = "auth_token";
export class AccountHelper { export class AccountHelper {
/** /**
* Check whether access token are available * Check whether access token are available
@ -30,4 +32,19 @@ export class AccountHelper {
mail: mail, 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 { import {
Typography, Avatar,
Link, Box,
makeStyles, Button,
Container, Container,
CssBaseline, CssBaseline,
Avatar, List,
ListItem,
ListItemAvatar,
ListItemText,
Paper,
TextField, TextField,
FormControlLabel, Typography,
Checkbox,
Button,
Grid,
Box,
} from "@material-ui/core"; } from "@material-ui/core";
import { ErrorOutline, Lock, VpnKey } from "@material-ui/icons";
import LockOutlinedIcon from "@material-ui/icons/LockOutlined"; import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
import React from "react"; import React from "react";
import { AccountHelper } from "../../helpers/AccountHelper"; import { AccountHelper, AuthOptions } from "../../helpers/AccountHelper";
import { matAlert } from "../widgets/DialogsProvider"; 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() { function Copyright() {
return ( return (
@ -37,6 +54,8 @@ function Copyright() {
interface LoginRouteState { interface LoginRouteState {
currEmail: string; currEmail: string;
errorGettingAuthOptions: boolean;
authOptions?: AuthOptions;
} }
export class LoginRoute extends React.Component<{}, LoginRouteState> { export class LoginRoute extends React.Component<{}, LoginRouteState> {
@ -45,6 +64,8 @@ export class LoginRoute extends React.Component<{}, LoginRouteState> {
this.state = { this.state = {
currEmail: "", currEmail: "",
errorGettingAuthOptions: false,
authOptions: undefined,
}; };
this.handleChangedEmail = this.handleChangedEmail.bind(this); this.handleChangedEmail = this.handleChangedEmail.bind(this);
@ -56,17 +77,31 @@ export class LoginRoute extends React.Component<{}, LoginRouteState> {
} }
handleChangedEmail(e: React.ChangeEvent<HTMLInputElement>) { 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>) { async handleSubmitEmail(e: React.ChangeEvent<any>) {
try {
e.preventDefault(); e.preventDefault();
if (!this.canSubmit) return; if (!this.canSubmit) return;
AccountHelper.getAuthOptions(this.state.currEmail).then((r) => const options = await AccountHelper.getAuthOptions(
matAlert("reset token => " + r.reset_token) this.state.currEmail
); );
this.setState({
errorGettingAuthOptions: false,
authOptions: options,
});
} catch (e) {
console.error("Failed to get auth options!", e);
this.setState({ errorGettingAuthOptions: true });
}
} }
render() { render() {
@ -138,6 +173,23 @@ export class LoginRoute extends React.Component<{}, LoginRouteState> {
Sign In Sign In
</Button> </Button>
</form> </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> </div>
<Box mt={8}> <Box mt={8}>
<Copyright /> <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>
);
}
}