2022-01-22 21:32:14 +01:00
|
|
|
import bcrypt from 'bcrypt'
|
2022-01-15 19:27:18 +01:00
|
|
|
import crypto from 'crypto'
|
2022-01-31 20:47:34 +01:00
|
|
|
import jwt from 'jsonwebtoken'
|
2022-01-15 19:27:18 +01:00
|
|
|
import { Router } from 'express'
|
2022-01-22 21:32:14 +01:00
|
|
|
import { glauth } from '../libs/database.js'
|
2022-01-15 19:27:18 +01:00
|
|
|
import execawait from '../libs/execawait.js'
|
|
|
|
|
2022-01-31 20:47:34 +01:00
|
|
|
export const SECRET = process.env.TK_SECRET ?? crypto.generateKeySync("aes", { length: 128 }).export().toString()
|
2022-01-15 19:27:18 +01:00
|
|
|
const AUTH = Router()
|
|
|
|
let valid = {}
|
|
|
|
|
2022-01-23 17:49:27 +01:00
|
|
|
/**
|
2022-01-31 20:47:34 +01:00
|
|
|
* This is needed because GLAuth (GLAuth's bcrypt) and Node (Node's bcrypt) read hashes differently.
|
2022-01-23 17:49:27 +01:00
|
|
|
* @param {string} hash The hash to be converted to hex.
|
|
|
|
* @returns {string} hex of hash
|
|
|
|
*/
|
|
|
|
function hash2hex(hash) {
|
|
|
|
return hash
|
|
|
|
.split('')
|
|
|
|
.map(e => e
|
|
|
|
.charCodeAt(0)
|
|
|
|
.toString(16)
|
|
|
|
)
|
|
|
|
.join('')
|
|
|
|
}
|
2022-01-15 19:27:18 +01:00
|
|
|
|
2022-01-23 15:52:12 +01:00
|
|
|
AUTH.post('/register', async (req, res) => {
|
2022-01-22 21:32:14 +01:00
|
|
|
const { captcha, password, username } = req.body
|
2022-01-15 19:27:18 +01:00
|
|
|
|
2022-01-22 21:32:14 +01:00
|
|
|
if (!username || !password || !captcha)
|
|
|
|
return(res.send(`Not entered:${username ? '' : ' username,'}${password ? '' : ' password,'}${captcha ? '' : ' captcha'}`))
|
2022-01-15 19:27:18 +01:00
|
|
|
|
2022-01-22 21:32:14 +01:00
|
|
|
if (!valid[captcha])
|
2022-01-15 19:27:18 +01:00
|
|
|
return(res.send("Invalid captcha!"))
|
|
|
|
|
2022-01-22 21:32:14 +01:00
|
|
|
const captchaAge = Math.abs((valid[captcha].getTime() - new Date().getTime())/1000)
|
2022-01-15 19:27:18 +01:00
|
|
|
|
2022-01-22 21:32:14 +01:00
|
|
|
if (captchaAge > 600)
|
2022-01-15 19:27:18 +01:00
|
|
|
return(res.send("Invalid captcha!"))
|
|
|
|
|
2022-01-31 20:47:34 +01:00
|
|
|
// Expire the captcha.
|
2022-01-22 21:32:14 +01:00
|
|
|
delete valid[captcha]
|
2022-01-15 19:27:18 +01:00
|
|
|
|
2022-01-31 20:47:34 +01:00
|
|
|
// Does the username match the requirements?
|
2022-01-22 21:32:14 +01:00
|
|
|
if (!(/^(?=[a-zA-Z0-9]{2,20}$).*$/.test(username)))
|
|
|
|
return(res.send("Username does not match the requirements"))
|
|
|
|
|
2022-01-23 15:52:12 +01:00
|
|
|
if ((await glauth.query("SELECT * FROM users WHERE name = $1::text", [ username ])).rowCount)
|
2022-01-15 19:27:18 +01:00
|
|
|
return(res.send("User already exists"))
|
|
|
|
|
2022-01-22 21:32:14 +01:00
|
|
|
bcrypt.hash(password, 10).then(
|
|
|
|
hash => {
|
2022-01-23 17:49:27 +01:00
|
|
|
const hexHash = hash2hex(hash)
|
2022-01-23 15:52:12 +01:00
|
|
|
glauth.query(
|
2022-01-23 17:49:27 +01:00
|
|
|
"INSERT INTO users(name, primarygroup, passbcrypt, qam_pass) VALUES($1::text, 0, $2::text, $3::text)",
|
|
|
|
[ username, hexHash, hash ]
|
2022-01-23 15:52:12 +01:00
|
|
|
).then(
|
|
|
|
() => res.send("Account registered!")
|
|
|
|
).catch(
|
|
|
|
err => res.json({ _: "Sorry an error occured!", err })
|
|
|
|
)
|
2022-01-22 21:32:14 +01:00
|
|
|
}
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2022-01-23 15:52:12 +01:00
|
|
|
AUTH.post('/login', async (req, res) => {
|
2022-01-22 21:32:14 +01:00
|
|
|
const { password, username } = req.body
|
|
|
|
|
|
|
|
// Was input sent?
|
|
|
|
if (!username || !password )
|
|
|
|
return(res.send(`Not entered:${username ? '' : ' username,'}${password ? '' : ' password'}`))
|
|
|
|
|
2022-01-23 15:52:12 +01:00
|
|
|
const user = (await glauth.query("SELECT * FROM users WHERE name = $1::text", [ username ])).rows[0]
|
2022-01-22 21:32:14 +01:00
|
|
|
|
|
|
|
if (!user)
|
|
|
|
return(res.send("User doesn't exist!"))
|
2022-01-15 19:27:18 +01:00
|
|
|
|
2022-01-23 17:49:27 +01:00
|
|
|
bcrypt.compare(password, user.qam_pass).then(
|
2022-01-31 20:47:34 +01:00
|
|
|
async match => {
|
2022-01-22 21:32:14 +01:00
|
|
|
if (!match)
|
|
|
|
return res.send("Password's is incorrect!")
|
2022-01-15 19:27:18 +01:00
|
|
|
|
2022-01-31 20:47:34 +01:00
|
|
|
const bearer = {
|
|
|
|
name: user.name,
|
|
|
|
id: user.uidnumber,
|
|
|
|
group: (await glauth.query("SELECT name FROM groups WHERE gidnumber = $1::int", [ user.primarygroup ])).rows[0].name
|
|
|
|
}
|
|
|
|
|
|
|
|
const token = jwt.sign(
|
|
|
|
bearer,
|
|
|
|
SECRET,
|
|
|
|
{ expiresIn: '1h' }
|
|
|
|
)
|
|
|
|
|
|
|
|
const fourHoursInMillis = 60 * 60 * 1000
|
|
|
|
res.cookie(
|
|
|
|
'api-token',
|
|
|
|
token,
|
|
|
|
{
|
|
|
|
expires: new Date(Date.now() + fourHoursInMillis),
|
|
|
|
httpOnly: true,
|
|
|
|
signed: true
|
|
|
|
}
|
|
|
|
).redirect('/manager')
|
2022-01-22 21:32:14 +01:00
|
|
|
}
|
|
|
|
)
|
2022-01-15 19:27:18 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
AUTH.get('/captcha', async (req, res) => {
|
|
|
|
const captcha = crypto.randomBytes(3).toString('hex')
|
2022-01-23 15:52:12 +01:00
|
|
|
await execawait(`./captcha.sh ${captcha} > captcha.png`)
|
|
|
|
|
|
|
|
// Make it valid for 10 minutes
|
|
|
|
valid[captcha] = new Date()
|
|
|
|
|
|
|
|
// Send the captcha image
|
|
|
|
res.contentType('image/png')
|
|
|
|
.sendFile('captcha.png', { root: './' })
|
2022-01-15 19:27:18 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
export default AUTH
|