From 2af34eb35fdf43e7e178ca7ce021f2e9b0f904f3 Mon Sep 17 00:00:00 2001 From: BurnyLlama Date: Sat, 22 Jan 2022 21:32:14 +0100 Subject: [PATCH] Basic registration and login done. --- libs/database.js | 12 ++++++ package.json | 1 + routes/auth.js | 79 ++++++++++++++++++++++++---------------- routes/routes.js | 2 + static/css/theme.css | 57 +++++++++++++++++++++++++++++ views/pages/login.njk | 18 +++++++++ views/pages/register.njk | 25 +++++++++++++ 7 files changed, 163 insertions(+), 31 deletions(-) create mode 100644 views/pages/login.njk create mode 100644 views/pages/register.njk diff --git a/libs/database.js b/libs/database.js index 8f23bfb..dfb04ec 100644 --- a/libs/database.js +++ b/libs/database.js @@ -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() { diff --git a/package.json b/package.json index e1d04fb..4072dd6 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/routes/auth.js b/routes/auth.js index 04813b4..d44535b 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -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: './' }) }) diff --git a/routes/routes.js b/routes/routes.js index 30364e7..d51b175 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -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 \ No newline at end of file diff --git a/static/css/theme.css b/static/css/theme.css index c97e303..e6ce47e 100644 --- a/static/css/theme.css +++ b/static/css/theme.css @@ -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; } \ No newline at end of file diff --git a/views/pages/login.njk b/views/pages/login.njk new file mode 100644 index 0000000..bb60387 --- /dev/null +++ b/views/pages/login.njk @@ -0,0 +1,18 @@ +{% extends "templates/base.njk" %} + +{% block head %} + qwik account manager +{% endblock %} + +{% block body %} +

Login to an account

+
+ + + + + + + +
+{% endblock %} \ No newline at end of file diff --git a/views/pages/register.njk b/views/pages/register.njk new file mode 100644 index 0000000..cd20e89 --- /dev/null +++ b/views/pages/register.njk @@ -0,0 +1,25 @@ +{% extends "templates/base.njk" %} + +{% block head %} + qwik account manager +{% endblock %} + +{% block body %} +

Register account

+
+ + +

The username must be alphanumeric and between 2-20 characters.

+ + + +

There are no formal password requirements, but we recommend making a secure passphrase.

+ + + + +

Enter the text you see in the image.

+ + +
+{% endblock %} \ No newline at end of file