Basic registration and login done.

This commit is contained in:
BurnyLlama 2022-01-22 21:32:14 +01:00
parent 618ffa7029
commit 2af34eb35f
7 changed files with 163 additions and 31 deletions

View File

@ -1,5 +1,17 @@
import SQLDatabase from 'better-sqlite3'
/**
* @typedef {object} User
* @param {string} name
* @param {string} passbcrypt
* @param {number} uidnumber
* @param {number} id
* @param {number} disabled
*/
/**
* @type {SQLDatabase.Database}
*/
export let glauth = undefined
export function dbInit() {

View File

@ -10,6 +10,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"better-sqlite3": "^7.4.6",
"dotenv": "^12.0.3",
"express": "^4.17.2",

View File

@ -1,5 +1,7 @@
import bcrypt from 'bcrypt'
import crypto from 'crypto'
import { Router } from 'express'
import { glauth } from '../libs/database.js'
import execawait from '../libs/execawait.js'
const AUTH = Router()
@ -7,47 +9,64 @@ let valid = {}
AUTH.post('/register', (req, res) => {
const { captcha, password, username } = req.body
// Was input sent?
if(!req.body.username)
return(res.send("No username entered!"))
if(!req.body.password)
return(res.send("No password entered!"))
if(!req.body.password)
return(res.send("No captcha entered!"))
// does the username match the requirements
if(!(/^(?=[a-zA-Z0-9]{2,20}$).*$/.test(req.body.username)))
return(res.send("Username does not match the requirements"))
if (!username || !password || !captcha)
return(res.send(`Not entered:${username ? '' : ' username,'}${password ? '' : ' password,'}${captcha ? '' : ' captcha'}`))
// is captcha valid
if(!valid[req.body.captcha])
if (!valid[captcha])
return(res.send("Invalid captcha!"))
const captchaAge = Math.abs((valid[req.body.captcha].getTime() - new Date().getTime())/1000)
const captchaAge = Math.abs((valid[captcha].getTime() - new Date().getTime())/1000)
if(captchaAge > 600)
if (captchaAge > 600)
return(res.send("Invalid captcha!"))
// expire the captcha
delete valid[req.body.captcha]
delete valid[captcha]
// Does user already exist?
if(glauth.prepare(`SELECT * FROM users WHERE name = ?`).get(req.body.username))
// does the username match the requirements
if (!(/^(?=[a-zA-Z0-9]{2,20}$).*$/.test(username)))
return(res.send("Username does not match the requirements"))
if (glauth.prepare(`SELECT * FROM users WHERE name = ?`).get(username))
return(res.send("User already exists"))
// Create the user!
glauth.prepare(`
INSERT INTO users(
name, primarygroup, passsha256
) VALUES(?, 0, ?)
`).run(req.body.username, crypto.createHash('sha256').update(req.body.password).digest('hex'))
bcrypt.hash(password, 10).then(
hash => {
glauth.prepare(`
INSERT INTO users(
name, primarygroup, passbcrypt
) VALUES(?, 0, ?)
`).run(username, hash)
console.log(`>>> User: ${req.body.username} was succesfully created!`)
res.send("Account registered!")
res.send("Account registered!")
}
)
})
res.end()
AUTH.post('/login', (req, res) => {
const { password, username } = req.body
// Was input sent?
if (!username || !password )
return(res.send(`Not entered:${username ? '' : ' username,'}${password ? '' : ' password'}`))
const user = glauth.prepare(`SELECT * FROM users WHERE name = ?`).get(username)
if (!user)
return(res.send("User doesn't exist!"))
bcrypt.compare(password, user.passbcrypt).then(
match => {
if (!match)
return res.send("Password's is incorrect!")
return res.send("Welcome " + user.name + "!")
}
)
})
AUTH.get('/captcha', async (req, res) => {
@ -58,10 +77,8 @@ AUTH.get('/captcha', async (req, res) => {
valid[captcha] = new Date()
// Send the captcha image
res.contentType('image/png');
res.sendFile('captcha.png', {
root: './'
});
res.contentType('image/png')
.sendFile('captcha.png', { root: './' })
})

View File

@ -4,6 +4,8 @@ import AUTH from './auth.js'
const ROUTES = Router()
ROUTES.get('/', (_, res) => res.render("pages/landing.njk"))
ROUTES.get('/login', (_, res) => res.render("pages/login.njk"))
ROUTES.get('/register', (_, res) => res.render("pages/register.njk"))
ROUTES.use('/auth', AUTH)
export default ROUTES

View File

@ -196,4 +196,61 @@ img.logo {
.buttons > a:hover, .buttons > a:focus {
color: var(--surface);
background-color: var(--primary);
}
form {
display: flex;
flex-direction: column;
width: fit-content;
width: min(100%, 45ch);
}
label {
margin: 1rem 0 .5rem 0;
color: var(--primary);
}
input {
width: 100%;
background-color: var(--grey3);
border: .1rem solid var(--grey3);
border-radius: .5rem;
padding: .25rem .75rem;
transition: border-color .3s, background-color .3s, color .3s;
}
input:hover {
border-color: var(--grey4);
background-color: var(--grey4);
}
input:focus, input:active {
border-color: var(--primary);
outline: 0 none transparent;
}
input[type="submit"] {
color: var(--primary);
background-color: transparent;
border: .1rem solid var(--primary);
border-radius: .5rem;
width: max-content;
margin: 1rem 0;
padding: .5rem 1.5rem;
cursor: pointer;
}
input[type="submit"]:hover {
color: var(--surface);
background-color: var(--primary);
}
.captcha {
display: block;
margin: 0 0 .75rem 0;
}
p.hint {
font-size: .65rem;
}

18
views/pages/login.njk Normal file
View File

@ -0,0 +1,18 @@
{% extends "templates/base.njk" %}
{% block head %}
<title>qwik account manager</title>
{% endblock %}
{% block body %}
<h1>Login to an account</h1>
<form action="/auth/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" placeholder="FancyFox89">
<label for="password">Password:</label>
<input type="password" id="password" name="password" placeholder="VerySecurePassword;PleaseDon'tHackMe!LOL">
<input type="submit" value="Log in!">
</form>
{% endblock %}

25
views/pages/register.njk Normal file
View File

@ -0,0 +1,25 @@
{% extends "templates/base.njk" %}
{% block head %}
<title>qwik account manager</title>
{% endblock %}
{% block body %}
<h1>Register account</h1>
<form action="/auth/register" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" placeholder="FancyFox89" autocomplete="off">
<p class="hint">The username must be alphanumeric and between 2-20 characters.</p>
<label for="password">Password:</label>
<input type="password" id="password" name="password" placeholder="VerySecurePassword;PleaseDon'tHackMe!LOL">
<p class="hint">There are no formal password requirements, but we recommend making a secure passphrase.</p>
<label for="captcha">Captcha:</label>
<img src="/auth/captcha" class="captcha">
<input type="text" id="captcha" name="captcha" placeholder="xxxxxx">
<p class="hint">Enter the text you see in the image.</p>
<input type="submit" value="Register!">
</form>
{% endblock %}