login and register logic

This commit is contained in:
biglyderv 2025-02-25 19:47:28 -05:00
parent a2f8452eec
commit 8d0c02e27e
Signed by: biglyderv
GPG key ID: 0E2EB0B4CD7397B5
15 changed files with 496 additions and 106 deletions

98
routes/init.js Normal file
View file

@ -0,0 +1,98 @@
import { importRouters } from "../lib.js";
import multer from "multer";
import cookieParser from "cookie-parser";
import { initDb } from "../db.js";
let db = await initDb();
const upload = multer({ dest: 'uploads/' });
const aliases = {
'/': '/walls/get/home'
};
const routers = {
'/you': './routes/you.js',
'/api/form/you': './routes/youApi.js'
}
function doAliases(app) {
for (let alias in aliases) {
app.all(alias, (req, res, next) => {
res.redirect(aliases[alias])
})
}
}
async function auther(req, res, next) {
let body = { ...req.cookies, ...req.body };
let { token } = body;
let match = await db.all('SELECT * FROM token WHERE token = ?', [
token || 'blah'
]);
let username = match[0] ? match[0].username : '!nobody';
let valid = await db.all('SELECT * FROM auth WHERE username = ?', [
username
]);
res.auth = {
username,
valid: valid[0],
rootUrl: process.env.URL,
};
next();
}
function initr(req, res, next) {
let headerCtx = [
{ link: '/walls/get/home', icon: '/icon.svg', name: 'DervNet' },
{ link: '/walls/list', icon: '/walls.svg', name: 'Explore' },
{ link: '/you/logout', icon: '/logout.svg', name: 'Leave' } // fix icon
];
if (!res.auth || !res.auth.valid) {
headerCtx = [
{ link: '/walls/get/home', icon: '/icon.svg', name: 'DervNet' },
{ link: '/you/login', icon: '/walls.svg', name: 'Log in' },
{ link: '/you/new', icon: '/walls.svg', name: 'Join' }
];
}
res.ctx = {
mainPage: '404.ejs',
mainCtx: {},
headerCtx
};
next();
}
async function doInit(app) {
app.use(cookieParser());
app.use(auther)
app.use(initr)
app.use('/api/form', upload.none());
app.use('/api/file', upload.single('file'));
doAliases(app);
await importRouters(app, routers);
app.use('/api', (req, res, next) => {
res.send(res.api);
})
app.use((req, res, next) => {
res.render('root.ejs', res.ctx)
})
}
export { doInit };

58
routes/you.js Normal file
View file

@ -0,0 +1,58 @@
import { Router } from "express";
const router = Router();
router.get('/login', (req, res, next) => {
res.ctx.mainPage = 'form'
res.ctx.mainCtx = {
title: "Log in",
message: 'Log into an existing account.',
action: "/api/form/you/login",
inputs: [
{
"key": "Username",
"type": "text",
"name": "user",
"default": ""
},
{
"key": "Password",
"type": "password",
"name": "pass",
"default": ""
}
]
}
next();
})
router.get('/new', (req, res, next) => {
res.ctx.mainPage = 'form'
res.ctx.mainCtx = {
title: "Register",
message: 'Create an account and join the community!',
action: "/api/form/you/new",
inputs: [
{
"key": "Username",
"type": "text",
"name": "user",
"default": ""
},
{
"key": "Password",
"type": "password",
"name": "pass",
"default": ""
},
{
"key": "Password (again)",
"type": "password",
"name": "pass2",
"default": ""
}
]
}
next();
})
export default router;

101
routes/youApi.js Normal file
View file

@ -0,0 +1,101 @@
import { Router } from "express";
import { apiStat } from "../lib.js";
import { hash, compare } from "bcrypt";
import { initDb } from "../db.js";
import { randomBytes } from 'node:crypto';
let db = await initDb();
const router = Router();
const minChar = 1;
const maxChar = 32;
function legalName(user) {
return user.search(/[^A-Za-z0-9\-\_]/g) == -1;
}
async function login(req, res, next) {
let { user, pass } = req.body;
if (!pass || !user) {
apiStat(res, next, 'Fields are missing.')
return;
}
let isExist = await db.all('SELECT * FROM auth WHERE UPPER(username) LIKE UPPER(?)', [
user
]); // TODO: dont use all
if (isExist.length < 1) {
apiStat(res, next, `Username wasn't taken.`)
return;
}
let passHash = await compare(pass, isExist[0].password);
if (!passHash) {
apiStat(res, next, `Password is wrong.`);
return;
}
let token = randomBytes(32).toString('hex');
await db.run('INSERT INTO token (username, token) VALUES (?, ?)', [
user,
token
])
res.cookie('token', token);
let stat = `Login succeeded.`;
apiStat(res, next, stat, '/');
return stat;
}
router.post('/login', login)
router.post('/new', async (req, res, next) => {
let { user, pass, pass2 } = req.body;
if (pass != pass2) {
apiStat(res, next, "Passwords don't match.")
return;
}
if (!pass || !user || !pass2) {
apiStat(res, next, 'Fields are missing.')
return;
}
if (!legalName(user)) {
apiStat(res, next, 'Username is invalid.')
return;
}
if (user.length < minChar || user.length > maxChar) {
apiStat(res, next, `Username length isn't ${minChar} to ${maxChar} characters.`)
return;
} // TODO: fix this horrible logic chain thing
let isExist = await db.all('SELECT * FROM auth WHERE UPPER(username) LIKE UPPER(?)', [
user
]); // TODO: dont use all
if (isExist.length > 0) {
apiStat(res, next, `Username was taken.`)
return;
}
var passHash = await hash(pass, 10);
await db.run('INSERT INTO auth (username, password) VALUES (?, ?)', [
user,
passHash
]);
let testLogin = await login(req, res, () => { });
apiStat(res, next, `Account created. Login status: ${testLogin}`, '/')
})
export default router;