import express from 'express'; import jwt from 'jsonwebtoken'; import argon2 from 'argon2'; import Mailer from "./mail.js" import * as crypto from "node:crypto"; export const auth = express.Router(); const mailer = new Mailer().init() let mfaCodes = [] auth.get('/user', async (req, res) => { const UserDB = req.app.locals.db; const token = req.cookies.token; if (!token) { return res.status(401).json({error: 'No token'}); } let decoded; try { decoded = jwt.verify(token, process.env.JWT_SECRET); } catch { res.clearCookie('token', { httpOnly: true, secure: false, sameSite: 'lax', path: '/' }); return res.status(401).json({error: 'Invalid token'}); } const row = await UserDB.find('users', {_id: decoded.id}); if (!row) { res.clearCookie('token', { httpOnly: true, secure: false, sameSite: 'lax', path: '/' }); return res.status(401).json({error: 'Invalid token'}); } const {password, ...safeRow} = row; res.json(safeRow); }); auth.get('/login/:data', async (req, res) => { const UserDB = req.app.locals.db; if (!req.params.data) { return res.status(401).send('Invalid token'); } try { const data = JSON.parse(atob(req.params.data)); const row = await UserDB.find('users', {_id: data.id}); if (!row) { return res.status(401).send('Invalid token'); } console.log(mfaCodes) const mfaRow = mfaCodes.find(obj => String(obj.id) === String(data.id)); if (!mfaRow) { return res.status(401).send('Invalid token'); } if (mfaRow.token !== data.token) { return res.status(401).send('Invalid token'); } const token = jwt.sign( {id: row._id, username: row.username}, process.env.JWT_SECRET, {expiresIn: '1h'} ); res.cookie('token', token, { httpOnly: true, secure: false, sameSite: 'lax', maxAge: 60 * 60 * 1000, path: '/' }); const index = mfaCodes.findIndex(obj => String(obj.id) === String(data.id)); if (index !== -1) { mfaCodes.splice(index, 1); } res.redirect('http://localhost:5173/'); } catch (e) { console.log(e); res.status(401).send('Invalid token'); } }); auth.post('/login', async (req, res) => { let UserDB = req.app.locals.db; const {username, password} = req.body; if (!username || !password) { return res.status(400).json({error: 'Missing credentials'}); } const row = await UserDB.find('users', {username}); if (!row) return res.status(401).json({error: 'User doesnt exist'}); if (!await argon2.verify(row.password, password)) return res.status(401).json({error: 'Invalid password'}); let mfgen = crypto.randomBytes(64).toString('hex'); const mfaToken = {id: row._id, token: mfgen} mfaCodes.push(mfaToken) console.log(mfaCodes) await mailer.send(row.email, "2FA Login Link", `Hey, ${row.username}!\n\nYour login link is: http://localhost:3000/api/auth/login/${btoa(JSON.stringify(mfaToken))}`) res.json({success: true, user: {username}}); }); auth.post('/register', async (req, res) => { let UserDB = req.app.locals.db; const {email, password} = req.body; const username = email.split("@")[0] //await mailer.send(email, "signup request", "this worked?") if (await UserDB.find('users', {username: username})) return res.status(400).json({error: 'User already exists'}); const hash = await hashPass(password) UserDB.add('users', {username: username, email: email, password: hash}) res.json({success: true, user: {username}}); }) async function hashPass(input) { return await argon2.hash(input, { type: argon2.argon2id, salt: Buffer.from(process.env.SALT, 'utf8'), timeCost: 2, memoryCost: 19456, parallelism: 1 }) }