new login page

This commit is contained in:
IrosTheBeggar 2020-10-26 02:13:52 -04:00
parent 28fe713547
commit ea56bfaf61
10 changed files with 340 additions and 2 deletions

View File

@ -105,7 +105,7 @@ exports.setup = function (mstream, program) {
});
// Authenticate User
mstream.post('/login', (req, res) => {
function login(req, res) {
if (!req.body.username || !req.body.password) {
return res.redirect('/login-failed');
}
@ -134,7 +134,10 @@ exports.setup = function (mstream, program) {
token: jwt.sign({ username: username }, program.secret) // Make the token
});
});
});
}
mstream.post('/login', (req, res) => { login(req, res); });
mstream.post('/api/v1/auth/login', (req, res) => { login(req, res); });
// Middleware that checks for token
mstream.use((req, res, next) => {

View File

@ -139,6 +139,10 @@ exports.serveIt = config => {
mstream.use('/media/' + key + '/', express.static(program.folders[key].root));
});
// Versioned APIs
mstream.get('/api/', (req, res) => res.json({ "version": "0.1.0", "supportedVersions": ["1"] }));
mstream.get('/api/v1', (req, res) => res.json({ "version": "0.1.0" }));
// Start the server!
server.on('request', mstream);
server.listen(program.port, program.address, () => {

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,74 @@
/* Based On: \
https://codepen.io/phnunes/pen/pwXYxG
https://codepen.io/zellwk/pen/NeRaPw
*/
.login__group {
position: relative
}
.login__group .login__input {
background-color: rgba(0,0,0,0);
margin-top: 50px;
padding: 10px 10px 10px 5px;
color: #FFF;
font-family: "Open Sans", sans-serif;
width: 100%;
font-size: 16px;
display: block;
border: none;
/* border-bottom: 1px solid #d0dce7; */
-webkit-box-sizing: border-box;
box-sizing: border-box
}
.login__group .login__input:focus {
outline: none
}
.login__group .login__input:focus ~ label,
.login__group .login__input:not(:placeholder-shown) ~ label {
top: -20px;
font-size: 12px;
}
.login__group .login__label {
color: #FFF;
font-family: "Open Sans", sans-serif;
font-size: 16px;
font-weight: 400;
position: absolute;
pointer-events: none;
left: 5px;
top: 10px;
-webkit-transition: .2s ease all;
transition: .2s ease all
}
.login__bar {
position: relative;
display: block;
}
.login__bar:before,
.login__bar:after {
content: '';
height: 2px;
width: 0;
bottom: 1px;
position: absolute;
transition: .2s ease all;
-moz-transition: .2s ease all;
-webkit-transition: .2s ease all
}
.login__bar:before {
left: 50%;
}
.login__bar:after {
right: 50%;
}
input:focus ~ .login__bar:before,
input:focus ~ .login__bar:after {
width: 50%;
background: #007ee5;
}
.login__bar:before,
.login__bar:after {
width: 50%;
background: #FFF;
}

View File

@ -26,6 +26,10 @@
<script defer src="/js/spa.js"></script>
<script defer src="/index.js"></script>
<script src="/js/vue3.js"></script>
<script src="/js/lib/axios.js"></script>
<script src="/js/api.js"></script>
<script>API.checkAuthAndKickToLogin();</script>
</head>
<body>
@ -110,6 +114,13 @@
<svg viewBox="-140 140 1024 768" height="24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M384 960C171.969 960 0 902.625 0 832V704c0-11.125 5.562-21.688 13.562-32C56.375 727.125 205.25 768 384 768s327.625-40.875 370.438-96c8 10.312 13.562 20.875 13.562 32v128c0 70.625-172 128-384 128zm0-256C171.969 704 0 646.625 0 576V448c0-6.781 2.562-13.375 6-19.906C7.938 424 10.5 419.969 13.562 416 56.375 471.094 205.25 512 384 512s327.625-40.906 370.438-96c3.062 3.969 5.625 8 7.562 12.094 3.438 6.531 6 13.125 6 19.906v128c0 70.625-172 128-384 128zm0-256C171.969 448 0 390.656 0 320v-64-64C0 121.344 171.969 64 384 64c212 0 384 57.344 384 128v128c0 70.656-172 128-384 128zm0-320c-141.375 0-256 28.594-256 64s114.625 64 256 64 256-28.594 256-64-114.625-64-256-64z"/></svg>
<span>Database</span>
</div>
<div class="side-nav-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#DDD" width="24" height="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.2 5.9l.8-.8C19.6 3.7 17.8 3 16 3s-3.6.7-5 2.1l.8.8C13 4.8 14.5 4.2 16 4.2s3 .6 4.2 1.7zm-.9.8c-.9-.9-2.1-1.4-3.3-1.4s-2.4.5-3.3 1.4l.8.8c.7-.7 1.6-1 2.5-1 .9 0 1.8.3 2.5 1l.8-.8zM19 13h-2V9h-2v4H5c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zM8 18H6v-2h2v2zm3.5 0h-2v-2h2v2zm3.5 0h-2v-2h2v2z"/></svg>
<span>Servers</span>
</div>
<div class="side-nav-item" onclick="API.logout();">
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><rect fill="none" height="24" width="24"/><path d="M9,19l1.41-1.41L5.83,13H22V11H5.83l4.59-4.59L9,5l-7,7L9,19z"/></svg> <span>Log Out</span>
</div>
</div>
<div id="sidenav-cover" class="click-through"></div>
<div id="content">

63
webapp-beta/js/api.js Normal file
View File

@ -0,0 +1,63 @@
const API = (() => {
const module = {};
// initialize with a default server
module.servers = [{
name: "default",
url: window.location.origin,
token: localStorage.getItem('authToken')
}];
module.selectedServer = 0;
module.addServer = (name, url, username, password) => {
module.servers.push({
name: name,
url: url,
token: null
})
}
module.url = () => {
return module.servers[module.selectedServer].url;
}
module.checkAuthAndKickToLogin = async () => {
if (module.servers[0].token === null) {
window.location.replace(`/login?redirect=${encodeURIComponent(window.location.pathname)}`);
}
// Send request to server
try {
await axios({
method: 'GET',
url: `${module.url()}/api/`,
headers: { 'x-access-token': module.servers[0].token }
});
} catch (err) {
window.location.replace(`/login?redirect=${encodeURIComponent(window.location.pathname)}`);
}
}
module.logout = () => {
localStorage.removeItem('authToken');
window.location.replace(`/login`);
}
module.axios = axios.create({
baseURL: module.url(),
headers: { 'x-access-token': module.servers[0].token }
});
// TODO: We also need a way to save servers
module.changeDefaultServer = (serverIndex) => {
// TODO: Throw Error?
if (!module.servers[serverIndex]) { return false; }
module.selectedServer = serverIndex;
// TODO: update module.axios to use the token for that server
}
return module;
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,110 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Login</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="apple-touch-icon" sizes="180x180" href="/fav/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/fav/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/fav/favicon-16x16.png">
<link rel="manifest" href="/fav/site.webmanifest">
<link rel="mask-icon" href="/fav/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="/fav/favicon.ico">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-config" content="/fav/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<script defer src="/js/lib/axios.js"></script>
<script defer src="/js/lib/izi-toast.js"></script>
<script defer src="/js/api.js"></script>
<script defer src="index.js"></script>
<link rel="stylesheet" href="/css/izi-toast.css">
<link rel="stylesheet" href="/css/material-input.css">
<style>
body {
min-height: 100vh;
background-color: #3c414e;
}
.container {
font-family:'Roboto';
width:600px;
margin:30px auto 0;
display:block;
background:#262a33;
padding:10px 50px 50px;
}
button {
background-color: rgb(101, 126, 228);
border-radius: 3px;
border: none;
font-weight: bold;
font-size: 14px;
text-align: center;
color: #FFF;
width: 100%;
height: 40px;
margin: 40px 0px 0px 0px;
padding: 0;
cursor: pointer;
}
</style>
</head>
<body>
<div class="container">
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 612 153" style="enable-background:new 0 0 612 153;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#264679;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#6684B2;}
.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#26477B;}
</style>
<g>
<path class="st0" d="M179.9,45.5c-6.2,0-11.5,1.7-15.9,5c-4.4,3.3-6.5,8.1-6.5,14.4c0,4.9,1.3,9.1,3.8,12.4
c2.5,3.4,5.7,5.8,9.3,7.3c3.7,1.5,7.3,2.8,11,3.8c3.7,1,6.8,2.3,9.3,3.9c2.5,1.5,3.8,3.5,3.8,5.8c0,4.8-4.4,7.2-13.1,7.2h-24.1V118
h24.1c17.1,0,25.6-6.7,25.6-20.2c0-1.9-0.2-3.8-0.6-5.8c-0.4-2-1.2-4-2.6-6c-1.3-2.1-3.3-3.7-5.8-4.9c-2.5-1.2-6.4-2.7-11.5-4.5
l-8.8-3.1c-0.7-0.2-1.7-0.7-2.9-1.3c-1.3-0.7-2.2-1.3-2.8-1.9c-0.6-0.6-1.1-1.4-1.6-2.3c-0.5-0.9-0.7-2-0.7-3.2c0-2,1-3.5,2.9-4.6
c1.9-1.1,4.3-1.6,7-1.6h24.6V45.5H179.9z"/>
<path class="st0" d="M226.4,58.3v31c0,10.2,2.5,17.6,7.6,22c5.1,4.4,13,6.6,23.7,6.6v-12.8c-2.7,0-4.9-0.2-6.8-0.4
c-1.8-0.3-3.7-0.9-5.8-1.9c-2-0.9-3.6-2.6-4.7-4.9c-1.1-2.3-1.6-5.2-1.6-8.7V58.3h18.8V45.5h-18.8V31.6L214,58.3H226.4z"/>
<path class="st0" d="M281.1,118V76.8c0-7.2,0.9-12,2.6-14.5c1-1.3,2.2-2.2,3.6-2.8c1.4-0.6,2.6-1,3.6-1.1c1-0.1,2.5-0.1,4.3-0.1
H310V45.5h-12.2c-3.6,0-6.5,0.1-8.6,0.3c-2.1,0.2-4.5,0.9-7.3,2c-2.8,1.1-5.1,2.8-7.1,5c-4,4.4-6,12.4-6,24V118H281.1z"/>
<path class="st0" d="M326.2,53.8c-6.2,7.4-9.3,17-9.3,28.9c0,10.7,3.2,19.4,9.5,26.2s14.7,10.1,25.3,10.1c8.7,0,16.3-2.7,22.7-8.1
L366,102c-3.7,2.1-8.5,3.2-14.3,3.2c-6.5,0-11.8-2.3-15.8-6.9c-4-4.6-6-10.5-6-17.9c0-7,1.9-12.9,5.6-17.9c3.8-5,8.9-7.5,15.5-7.5
c3.3,0,6.1,0.8,8.2,2.4c2.1,1.6,3.2,4,3.2,7.2c0,5-1.2,8.5-3.6,10.6c-2.4,2.1-6.7,3.2-12.9,3.2h-6.7v11.7h5.7
c20.3,0,30.5-8.5,30.5-25.4c0-13.6-7.9-20.7-23.7-21.5C340.9,43,332.4,46.5,326.2,53.8z"/>
<path class="st0" d="M412.3,73.2c-7.4,0-13.6,1.9-18.5,5.7c-4.9,3.8-7.4,9.4-7.4,16.7c0,7.3,2.3,12.9,7,16.7
c4.6,3.8,10.9,5.7,18.8,5.7h31V73.6c0-9.1-2.4-16-7.2-20.8c-4.8-4.8-11.7-7.2-20.7-7.2h-22.9v12.8h22.3c10.9,0,16.4,6.1,16.4,18.2
v28.7h-18.4c-9.1,0-13.6-3.2-13.6-9.8c0-3.3,1.2-5.9,3.6-7.8c2.4-1.8,5.8-2.7,10.2-2.7c5.1,0,9.4,1.4,12.9,4.3V75.3
C420.9,73.9,416.5,73.2,412.3,73.2z"/>
<path class="st0" d="M458.8,118H471V58.3h24.4V118h12.2V58.3h5.7c6.8,0,11.3,0.7,13.5,2c4.3,2.5,6.5,7.7,6.5,15.5V118h12.2V75.7
c0-6-0.6-11.2-1.9-15.5c-1.2-4.3-3.9-7.8-7.9-10.6c-3.9-2.7-9.1-4.1-15.7-4.1h-61.4V118z"/>
<polygon class="st1" points="75,118.5 75,35.5 96,48.5 96,118.5 "/>
<polygon class="st2" points="99,118.5 99,49.5 110.5,56.5 121,49.5 121,118.5 "/>
<polygon class="st1" points="124,118.5 124,48.5 145,35.5 145,118.5 "/>
</g>
</svg>
<form id="login">
<div class="login__group">
<input id="email" placeholder="&nbsp;" class="login__input" type="text" name="input_email" required>
<label class="login__label" >Username</label>
<div class="login__bar"></div>
</div>
<div class="login__group">
<input id="password" placeholder="&nbsp;" class="login__input" type="password" name="input_password" required>
<label class="login__label">Password </label>
<div class="login__bar"></div>
</div>
<button id="form-submit" type="submit">Login</button>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,59 @@
// Check Token
async function checkToken() {
if (!localStorage.getItem('authToken')) {
return;
}
try {
await axios({
method: 'GET',
url: `${API.url()}/api/`,
headers: { 'x-access-token': localStorage.getItem('authToken') }
});
window.location.replace(`/`);
} catch (err) {
// localStorage.removeItem('authToken');
}
}
checkToken();
document.getElementById("login").addEventListener("submit", async e =>{
e.preventDefault();
// Lock Button
document.getElementById("form-submit").disabled = true;
try {
const res = await axios({
method: 'POST',
url: `${API.url()}/api/v1/auth/login`,
data: {
username: document.getElementById('email').value,
password: document.getElementById('password').value
}
});
localStorage.setItem("authToken", res.data.token);
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const goTo = urlParams.get('redirect') ? urlParams.get('redirect') : '/';
window.location.replace(goTo);
iziToast.success({
title: 'Login Success!',
position: 'topCenter',
timeout: 3500
});
} catch (err) {
iziToast.error({
title: 'Login Failed',
position: 'topCenter',
timeout: 3500
});
}
document.getElementById("form-submit").disabled = false;
});