mirror of
https://github.com/openziti/zrok.git
synced 2024-11-07 08:44:14 +01:00
revamped registration infrastructure (#143)
This commit is contained in:
parent
63f2049c2c
commit
0033021139
@ -21,7 +21,7 @@
|
||||
-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/bootstrap.min.css">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Russo+One&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap" rel="stylesheet">
|
||||
<title>zrok</title>
|
||||
|
@ -50,7 +50,7 @@ const Login = (props) => {
|
||||
</Row>
|
||||
<Row>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<Form.Group controlId={"email"} >
|
||||
<Form.Group controlId={"email"}>
|
||||
<Form.Control
|
||||
type={"email"}
|
||||
placeholder={"Email Address"}
|
||||
@ -71,9 +71,11 @@ const Login = (props) => {
|
||||
<Button variant={"light"} type={"submit"}>Log In</Button>
|
||||
</Form>
|
||||
</Row>
|
||||
<Row>
|
||||
{message}
|
||||
</Row>
|
||||
</Container>
|
||||
</Row>
|
||||
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
|
@ -68,6 +68,7 @@ code, pre {
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
@ -77,7 +78,7 @@ code, pre {
|
||||
}
|
||||
|
||||
.fullscreen h1 {
|
||||
font-size: 96pt;
|
||||
font-size: 64pt;
|
||||
}
|
||||
|
||||
.fullscreen-body {
|
||||
@ -93,6 +94,14 @@ code, pre {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.fullscreen a {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.fullscreen pre {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
color: deeppink;
|
||||
}
|
||||
|
16
ui/src/register/InvalidRequest.js
Normal file
16
ui/src/register/InvalidRequest.js
Normal file
@ -0,0 +1,16 @@
|
||||
import {Button, Container, Row} from "react-bootstrap";
|
||||
|
||||
const InvalidRequest = () => {
|
||||
return (
|
||||
<Container fluid>
|
||||
<Row>
|
||||
<img alt="ziggy" src={"/ziggy.svg"} width={200}/>
|
||||
</Row>
|
||||
<Row>
|
||||
<h1>Invitation not found!</h1>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default InvalidRequest;
|
@ -1,105 +1,8 @@
|
||||
import Icon from "@mdi/react";
|
||||
import { useParams } from 'react-router-dom';
|
||||
import {useEffect, useState} from "react";
|
||||
import {mdiContentCopy} from "@mdi/js";
|
||||
import * as account from "../api/account";
|
||||
|
||||
const RegistrationForm = (props) => {
|
||||
const [password, setPassword] = useState('');
|
||||
const [confirm, setConfirm] = useState('');
|
||||
const [message, setMessage] = useState();
|
||||
const [authToken, setAuthToken] = useState('');
|
||||
const [complete, setComplete] = useState(false);
|
||||
|
||||
const passwordMismatchMessage = <h2 className={"errorMessage"}>Entered passwords do not match!</h2>
|
||||
const registerFailed = <h2 className={"errorMessage"}>Account creation failed!</h2>
|
||||
|
||||
const handleSubmit = async e => {
|
||||
e.preventDefault();
|
||||
console.log("handleSubmit");
|
||||
if(confirm !== password) {
|
||||
setMessage(passwordMismatchMessage);
|
||||
} else {
|
||||
account.register({body: {"token": props.token, "password": password}})
|
||||
.then(resp => {
|
||||
if(!resp.error) {
|
||||
console.log("resp", resp)
|
||||
setMessage(undefined);
|
||||
setAuthToken(resp.data.token);
|
||||
setComplete(true);
|
||||
} else {
|
||||
setMessage(registerFailed);
|
||||
}
|
||||
})
|
||||
.catch(resp => {
|
||||
console.log("resp", resp);
|
||||
setMessage(registerFailed);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if(!complete) {
|
||||
return (
|
||||
<div className={"fullscreen"}>
|
||||
<img src={"/ziggy.svg"} width={200}/>
|
||||
<h1>A new zrok user!</h1>
|
||||
<h2>{props.email}</h2>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<fieldset>
|
||||
<legend>Set A Password</legend>
|
||||
<p><label htmlFor={"password"}>password: </label><input type={"password"} value={password} placeholder={"Password"} onChange={({target}) => setPassword(target.value)}/></p>
|
||||
<p>
|
||||
<label htmlFor={"confirm"}>confirm: </label><input type={"password"} value={confirm} placeholder={"Confirm Password"} onChange={({target}) => setConfirm(target.value)}/>
|
||||
<button type={"submit"}>Register</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
{message}
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return <Success email={props.email} token={authToken}/>
|
||||
}
|
||||
}
|
||||
|
||||
const NoAccountRequest = () => {
|
||||
return (
|
||||
<div className={"fullscreen"}>
|
||||
<img src={"/ziggy.svg"} width={200}/>
|
||||
<h1>No such account request!</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Success = (props) => {
|
||||
const handleCopy = async () => {
|
||||
let copiedText = document.getElementById("zrok-enable-command").innerHTML;
|
||||
try {
|
||||
await navigator.clipboard.writeText(copiedText);
|
||||
console.log("copied enable command");
|
||||
} catch(err) {
|
||||
console.error("failed to copy", err);
|
||||
}
|
||||
}
|
||||
|
||||
// clear local storage on new account registration success.
|
||||
localStorage.clear();
|
||||
|
||||
return (
|
||||
<div className={"fullscreen"}>
|
||||
<img src={"/ziggy.svg"} width={200}/>
|
||||
<h1>Welcome to zrok!</h1>
|
||||
|
||||
<p>You can proceed to the <a href={"/"}>zrok web portal</a> and log in with your email and password.</p>
|
||||
|
||||
<p>To enable your shell for zrok, use this command:</p>
|
||||
|
||||
<pre>
|
||||
$ <span id={"zrok-enable-command"}>zrok enable {props.token}</span> <Icon path={mdiContentCopy} size={0.7} onClick={handleCopy}/>
|
||||
</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import InvalidRequest from "./InvalidRequest";
|
||||
import SetPasswordForm from "./SetPasswordForm";
|
||||
|
||||
let step;
|
||||
|
||||
@ -130,16 +33,13 @@ const Register = () => {
|
||||
}, []);
|
||||
|
||||
if(activeRequest) {
|
||||
step = <RegistrationForm
|
||||
email={email}
|
||||
token={token}
|
||||
/>
|
||||
step = <SetPasswordForm email={email} token={token}/>
|
||||
} else {
|
||||
step = <NoAccountRequest />
|
||||
step = <InvalidRequest />
|
||||
}
|
||||
|
||||
return (
|
||||
<div>{step}</div>
|
||||
<div className={"fullscreen"}>{step}</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
92
ui/src/register/SetPasswordForm.js
Normal file
92
ui/src/register/SetPasswordForm.js
Normal file
@ -0,0 +1,92 @@
|
||||
import React, {useState} from "react";
|
||||
import * as account from "../api/account";
|
||||
import Success from "./Success";
|
||||
import {Button, Container, Form, Row} from "react-bootstrap";
|
||||
|
||||
const SetPasswordForm = (props) => {
|
||||
const [password, setPassword] = useState('');
|
||||
const [confirm, setConfirm] = useState('');
|
||||
const [message, setMessage] = useState();
|
||||
const [authToken, setAuthToken] = useState('');
|
||||
const [complete, setComplete] = useState(false);
|
||||
|
||||
const passwordMismatchMessage = <h2 className={"errorMessage"}>Entered passwords do not match!</h2>
|
||||
const passwordTooShortMessage = <h2 className={"errorMessage"}>Entered password too short! (4 characters, minimum)</h2>
|
||||
const registerFailed = <h2 className={"errorMessage"}>Account creation failed!</h2>
|
||||
|
||||
const handleSubmit = async e => {
|
||||
e.preventDefault();
|
||||
if(confirm.length < 4) {
|
||||
setMessage(passwordTooShortMessage);
|
||||
return;
|
||||
}
|
||||
if(confirm !== password) {
|
||||
setMessage(passwordMismatchMessage);
|
||||
return;
|
||||
}
|
||||
account.register({body: {"token": props.token, "password": password}})
|
||||
.then(resp => {
|
||||
if(!resp.error) {
|
||||
console.log("resp", resp)
|
||||
setMessage(undefined);
|
||||
setAuthToken(resp.data.token);
|
||||
setComplete(true);
|
||||
} else {
|
||||
setMessage(registerFailed);
|
||||
}
|
||||
})
|
||||
.catch(resp => {
|
||||
console.log("resp", resp);
|
||||
setMessage(registerFailed);
|
||||
});
|
||||
};
|
||||
|
||||
if(!complete) {
|
||||
return (
|
||||
<Container fluid>
|
||||
<Row>
|
||||
<img alt="ziggy" src={"/ziggy.svg"} width={200}/>
|
||||
</Row>
|
||||
<Row>
|
||||
<h1>Welcome new zrok user!</h1>
|
||||
</Row>
|
||||
<Row>
|
||||
<h2>{props.email}</h2>
|
||||
</Row>
|
||||
<Row className={"fullscreen-body"}>
|
||||
<Container className={"fullscreen-form"}>
|
||||
<Row>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<Form.Group controlId={"password"}>
|
||||
<Form.Control
|
||||
type={"password"}
|
||||
placeholder={"Set Password"}
|
||||
onChange={t => { setMessage(null); setPassword(t.target.value); }}
|
||||
value={password}
|
||||
/>
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group controlId={"confirm"}>
|
||||
<Form.Control
|
||||
type={"password"}
|
||||
placeholder={"Confirm Password"}
|
||||
onChange={t => { setMessage(null); setConfirm(t.target.value); }}
|
||||
value={confirm}
|
||||
/>
|
||||
</Form.Group>
|
||||
|
||||
<Button variant={"light"} type={"submit"}>Register Account</Button>
|
||||
</Form>
|
||||
</Row>
|
||||
<Row>
|
||||
{message}
|
||||
</Row>
|
||||
</Container>
|
||||
</Row>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
return <Success email={props.email} token={authToken}/>;
|
||||
};
|
||||
|
||||
export default SetPasswordForm;
|
47
ui/src/register/Success.js
Normal file
47
ui/src/register/Success.js
Normal file
@ -0,0 +1,47 @@
|
||||
import Icon from "@mdi/react";
|
||||
import {mdiContentCopy} from "@mdi/js";
|
||||
import {Container, Row} from "react-bootstrap";
|
||||
import React from "react";
|
||||
|
||||
const Success = (props) => {
|
||||
const handleCopy = async () => {
|
||||
let copiedText = document.getElementById("zrok-enable-command").innerHTML;
|
||||
try {
|
||||
await navigator.clipboard.writeText(copiedText);
|
||||
console.log("copied enable command");
|
||||
} catch(err) {
|
||||
console.error("failed to copy", err);
|
||||
}
|
||||
}
|
||||
|
||||
// clear local storage on new account registration success.
|
||||
localStorage.clear();
|
||||
|
||||
return (
|
||||
<Container fluid>
|
||||
<Row>
|
||||
<img alt="ziggy" src={"/ziggy.svg"} width={200}/>
|
||||
</Row>
|
||||
<Row>
|
||||
<h1>Welcome to zrok!</h1>
|
||||
</Row>
|
||||
<Row className={"fullscreen-body"}>
|
||||
<Container className={"fullscreen-form"}>
|
||||
<Row>
|
||||
<p>You can proceed to the <a href={"/"}>zrok web portal</a> and log in with your email and password.</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<p>To enable your shell for zrok, use this command:</p>
|
||||
</Row>
|
||||
<Row>
|
||||
<pre>
|
||||
$ <span id={"zrok-enable-command"}>zrok enable {props.token}</span> <Icon path={mdiContentCopy} size={0.7} onClick={handleCopy}/>
|
||||
</pre>
|
||||
</Row>
|
||||
</Container>
|
||||
</Row>
|
||||
</Container>
|
||||
)
|
||||
};
|
||||
|
||||
export default Success;
|
Loading…
Reference in New Issue
Block a user