|
|
@@ -1,8 +1,8 @@
|
|
|
-import express from 'express';
|
|
|
-import argon2 from 'argon2';
|
|
|
-import * as crypto from "node:crypto";
|
|
|
+import express from "express"
|
|
|
+import argon2 from "argon2"
|
|
|
+import * as crypto from "node:crypto"
|
|
|
|
|
|
-import Jwt from "../adapters/jwt.js";
|
|
|
+import Jwt from "../adapters/jwt.js"
|
|
|
import Mailer from "../adapters/mail.js"
|
|
|
|
|
|
const mailer = new Mailer().init()
|
|
|
@@ -12,148 +12,160 @@ const jwt = new Jwt(process.env.JWT_SECRET)
|
|
|
let mfaCodes = []
|
|
|
|
|
|
export default function authRoutes(UserDB) {
|
|
|
+ const auth = express.Router()
|
|
|
+
|
|
|
+ auth.get("/user", async (req, res) => {
|
|
|
+ //@cookies { in:token }
|
|
|
+ //@output { username, email, _id }
|
|
|
+ const token = req.query.token
|
|
|
+
|
|
|
+ if (!token) {
|
|
|
+ return res.status(401).json({ error: "No token" })
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log(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" })
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log(decoded)
|
|
|
+
|
|
|
+ const row = await UserDB.find("users", { _id: decoded.id })
|
|
|
+
|
|
|
+ console.log(row)
|
|
|
+
|
|
|
+ if (!row) {
|
|
|
+ res.clearCookie("token", {
|
|
|
+ httpOnly: true,
|
|
|
+ secure: false,
|
|
|
+ sameSite: "lax",
|
|
|
+ path: "/",
|
|
|
+ })
|
|
|
+ return res.status(401).json({ error: "Invalid token" })
|
|
|
+ }
|
|
|
|
|
|
- const auth = express.Router();
|
|
|
-
|
|
|
- auth.get('/user', async (req, res) => {
|
|
|
- //@cookies { in:token }
|
|
|
- //@output { username, email, _id }
|
|
|
- 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});
|
|
|
+ const { password, ...safeRow } = row
|
|
|
+ res.json(safeRow)
|
|
|
+ })
|
|
|
|
|
|
- if (!row) {
|
|
|
- res.clearCookie('token', {
|
|
|
- httpOnly: true,
|
|
|
- secure: false,
|
|
|
- sameSite: 'lax',
|
|
|
- path: '/'
|
|
|
- });
|
|
|
- return res.status(401).json({error: 'Invalid token'});
|
|
|
- }
|
|
|
+ auth.get("/login/:data", async (req, res) => {
|
|
|
+ //@input { /:data }
|
|
|
+ //@output { redirect:http://localhost:5173/ }
|
|
|
+ if (!req.params.data) {
|
|
|
+ return res.status(401).send("Invalid token")
|
|
|
+ }
|
|
|
|
|
|
- const {password, ...safeRow} = row;
|
|
|
- res.json(safeRow);
|
|
|
- });
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(atob(req.params.data))
|
|
|
|
|
|
- auth.get('/login/:data', async (req, res) => {
|
|
|
- //@input { /:data }
|
|
|
- //@output { redirect:http://localhost:5173/ }
|
|
|
- if (!req.params.data) {
|
|
|
- return res.status(401).send('Invalid token');
|
|
|
- }
|
|
|
+ const row = await UserDB.find("users", { _id: data.id })
|
|
|
+ if (!row) {
|
|
|
+ return res.status(401).send("Invalid token")
|
|
|
+ }
|
|
|
|
|
|
- try {
|
|
|
- const data = JSON.parse(atob(req.params.data));
|
|
|
+ const mfaRow = mfaCodes.find((obj) => String(obj.id) === String(data.id))
|
|
|
+ if (!mfaRow) {
|
|
|
+ return res.status(401).send("Invalid token")
|
|
|
+ }
|
|
|
|
|
|
- const row = await UserDB.find('users', {_id: data.id});
|
|
|
- if (!row) {
|
|
|
- return res.status(401).send('Invalid token');
|
|
|
- }
|
|
|
+ if (mfaRow.token !== data.token) {
|
|
|
+ return res.status(401).send("Invalid token")
|
|
|
+ }
|
|
|
|
|
|
- const mfaRow = mfaCodes.find(obj => String(obj.id) === String(data.id));
|
|
|
- if (!mfaRow) {
|
|
|
- return res.status(401).send('Invalid token');
|
|
|
- }
|
|
|
+ const token = jwt.create({ id: row._id, username: row.username }, "1h")
|
|
|
|
|
|
- if (mfaRow.token !== data.token) {
|
|
|
- return res.status(401).send('Invalid token');
|
|
|
- }
|
|
|
+ res.cookie("token", token, {
|
|
|
+ httpOnly: true,
|
|
|
+ secure: false,
|
|
|
+ sameSite: "lax",
|
|
|
+ maxAge: 60 * 60 * 1000,
|
|
|
+ path: "/",
|
|
|
+ })
|
|
|
|
|
|
- const token = jwt.create({id: row._id, username: row.username}, '1h');
|
|
|
+ const index = mfaCodes.findIndex(
|
|
|
+ (obj) => String(obj.id) === String(data.id)
|
|
|
+ )
|
|
|
+ if (index !== -1) {
|
|
|
+ mfaCodes.splice(index, 1)
|
|
|
+ }
|
|
|
|
|
|
- res.cookie('token', token, {
|
|
|
- httpOnly: true,
|
|
|
- secure: false,
|
|
|
- sameSite: 'lax',
|
|
|
- maxAge: 60 * 60 * 1000,
|
|
|
- path: '/'
|
|
|
- });
|
|
|
+ res.redirect("http://localhost:5173/")
|
|
|
+ } catch (e) {
|
|
|
+ console.log(e)
|
|
|
+ res.status(401).send("Invalid token")
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
- const index = mfaCodes.findIndex(obj => String(obj.id) === String(data.id));
|
|
|
- if (index !== -1) {
|
|
|
- mfaCodes.splice(index, 1);
|
|
|
- }
|
|
|
+ auth.post("/login", async (req, res) => {
|
|
|
+ //@input { username, password, redirect }
|
|
|
+ //@output { redirect:https://url.com/token }
|
|
|
+ //@cookies { out:token }
|
|
|
+ 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" })
|
|
|
|
|
|
- res.redirect('http://localhost:5173/');
|
|
|
- } catch (e) {
|
|
|
- console.log(e);
|
|
|
- res.status(401).send('Invalid token');
|
|
|
- }
|
|
|
- });
|
|
|
+ if (!(await argon2.verify(row.password, password)))
|
|
|
+ return res.status(401).json({ error: "Invalid password" })
|
|
|
|
|
|
- auth.post('/login', async (req, res) => {
|
|
|
- //@input { username, password }
|
|
|
- //@output { success, user }
|
|
|
- //@cookies { out:token }
|
|
|
- const {username, password} = req.body;
|
|
|
- if (!username || !password) {
|
|
|
- return res.status(400).json({error: 'Missing credentials'});
|
|
|
- }
|
|
|
+ //let mfgen = crypto.randomBytes(64).toString('hex');
|
|
|
|
|
|
- const row = await UserDB.find('users', {username});
|
|
|
- if (!row) return res.status(401).json({error: 'User doesnt exist'});
|
|
|
+ //const mfaToken = {id: row._id, token: mfgen}
|
|
|
|
|
|
- if (!await argon2.verify(row.password, password)) return res.status(401).json({error: 'Invalid password'});
|
|
|
+ //mfaCodes.push(mfaToken)
|
|
|
+
|
|
|
+ //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))}`)
|
|
|
|
|
|
- let mfgen = crypto.randomBytes(64).toString('hex');
|
|
|
+ const token = jwt.create(
|
|
|
+ { id: row._id, username: row.username, email: row.email },
|
|
|
+ "1h"
|
|
|
+ )
|
|
|
|
|
|
- const mfaToken = {id: row._id, token: mfgen}
|
|
|
+ res.json({ token })
|
|
|
+ })
|
|
|
|
|
|
- mfaCodes.push(mfaToken)
|
|
|
+ auth.post("/register", async (req, res) => {
|
|
|
+ //@input { email, password }
|
|
|
+ //@output { success, username }
|
|
|
|
|
|
- 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))}`)
|
|
|
+ const { email, password } = req.body
|
|
|
|
|
|
- res.json({success: true, user: {username}});
|
|
|
- });
|
|
|
+ const username = email.split("@")[0]
|
|
|
|
|
|
- auth.post('/register', async (req, res) => {
|
|
|
- //@input { email, password }
|
|
|
- //@output { success, username }
|
|
|
+ //await mailer.send(email, "signup request", "this worked?")
|
|
|
|
|
|
- const {email, password} = req.body;
|
|
|
+ if (await UserDB.find("users", { username: username }))
|
|
|
+ return res.status(400).json({ error: "User already exists" })
|
|
|
|
|
|
- const username = email.split("@")[0]
|
|
|
+ const hash = await hashPass(password)
|
|
|
|
|
|
- //await mailer.send(email, "signup request", "this worked?")
|
|
|
+ UserDB.add("users", { username: username, email: email, password: hash })
|
|
|
|
|
|
- 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}});
|
|
|
-
|
|
|
- })
|
|
|
-
|
|
|
- return auth
|
|
|
+ res.json({ success: true, user: { username } })
|
|
|
+ })
|
|
|
|
|
|
+ return auth
|
|
|
}
|
|
|
|
|
|
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
|
|
|
- })
|
|
|
-}
|
|
|
+ return await argon2.hash(input, {
|
|
|
+ type: argon2.argon2id,
|
|
|
+ salt: Buffer.from(process.env.SALT, "utf8"),
|
|
|
+ timeCost: 2,
|
|
|
+ memoryCost: 19456,
|
|
|
+ parallelism: 1,
|
|
|
+ })
|
|
|
+}
|