Basic registration and login done.
This commit is contained in:
parent
618ffa7029
commit
2af34eb35f
|
@ -1,5 +1,17 @@
|
||||||
import SQLDatabase from 'better-sqlite3'
|
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 let glauth = undefined
|
||||||
|
|
||||||
export function dbInit() {
|
export function dbInit() {
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bcrypt": "^5.0.1",
|
||||||
"better-sqlite3": "^7.4.6",
|
"better-sqlite3": "^7.4.6",
|
||||||
"dotenv": "^12.0.3",
|
"dotenv": "^12.0.3",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.2",
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
import bcrypt from 'bcrypt'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import { Router } from 'express'
|
import { Router } from 'express'
|
||||||
|
import { glauth } from '../libs/database.js'
|
||||||
import execawait from '../libs/execawait.js'
|
import execawait from '../libs/execawait.js'
|
||||||
|
|
||||||
const AUTH = Router()
|
const AUTH = Router()
|
||||||
|
@ -7,47 +9,64 @@ let valid = {}
|
||||||
|
|
||||||
|
|
||||||
AUTH.post('/register', (req, res) => {
|
AUTH.post('/register', (req, res) => {
|
||||||
|
const { captcha, password, username } = req.body
|
||||||
|
|
||||||
// Was input sent?
|
// Was input sent?
|
||||||
if(!req.body.username)
|
if (!username || !password || !captcha)
|
||||||
return(res.send("No username entered!"))
|
return(res.send(`Not entered:${username ? '' : ' username,'}${password ? '' : ' password,'}${captcha ? '' : ' captcha'}`))
|
||||||
|
|
||||||
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"))
|
|
||||||
|
|
||||||
// is captcha valid
|
// is captcha valid
|
||||||
if(!valid[req.body.captcha])
|
if (!valid[captcha])
|
||||||
return(res.send("Invalid 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!"))
|
return(res.send("Invalid captcha!"))
|
||||||
|
|
||||||
// expire the captcha
|
// expire the captcha
|
||||||
delete valid[req.body.captcha]
|
delete valid[captcha]
|
||||||
|
|
||||||
// Does user already exist?
|
// does the username match the requirements
|
||||||
if(glauth.prepare(`SELECT * FROM users WHERE name = ?`).get(req.body.username))
|
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"))
|
return(res.send("User already exists"))
|
||||||
|
|
||||||
// Create the user!
|
bcrypt.hash(password, 10).then(
|
||||||
glauth.prepare(`
|
hash => {
|
||||||
INSERT INTO users(
|
glauth.prepare(`
|
||||||
name, primarygroup, passsha256
|
INSERT INTO users(
|
||||||
) VALUES(?, 0, ?)
|
name, primarygroup, passbcrypt
|
||||||
`).run(req.body.username, crypto.createHash('sha256').update(req.body.password).digest('hex'))
|
) 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) => {
|
AUTH.get('/captcha', async (req, res) => {
|
||||||
|
@ -58,10 +77,8 @@ AUTH.get('/captcha', async (req, res) => {
|
||||||
valid[captcha] = new Date()
|
valid[captcha] = new Date()
|
||||||
|
|
||||||
// Send the captcha image
|
// Send the captcha image
|
||||||
res.contentType('image/png');
|
res.contentType('image/png')
|
||||||
res.sendFile('captcha.png', {
|
.sendFile('captcha.png', { root: './' })
|
||||||
root: './'
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import AUTH from './auth.js'
|
||||||
const ROUTES = Router()
|
const ROUTES = Router()
|
||||||
|
|
||||||
ROUTES.get('/', (_, res) => res.render("pages/landing.njk"))
|
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)
|
ROUTES.use('/auth', AUTH)
|
||||||
|
|
||||||
export default ROUTES
|
export default ROUTES
|
|
@ -196,4 +196,61 @@ img.logo {
|
||||||
.buttons > a:hover, .buttons > a:focus {
|
.buttons > a:hover, .buttons > a:focus {
|
||||||
color: var(--surface);
|
color: var(--surface);
|
||||||
background-color: var(--primary);
|
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
18
views/pages/login.njk
Normal 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
25
views/pages/register.njk
Normal 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 %}
|
Loading…
Reference in New Issue
Block a user