auth.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import express from 'express';
  2. import jwt from 'jsonwebtoken';
  3. import argon2 from 'argon2';
  4. import Mailer from "./mail.js"
  5. import * as crypto from "node:crypto";
  6. export const auth = express.Router();
  7. const mailer = new Mailer().init()
  8. let mfaCodes = []
  9. auth.get('/user', async (req, res) => {
  10. const UserDB = req.app.locals.db;
  11. const token = req.cookies.token;
  12. if (!token) {
  13. return res.status(401).json({error: 'No token'});
  14. }
  15. let decoded;
  16. try {
  17. decoded = jwt.verify(token, process.env.JWT_SECRET);
  18. } catch {
  19. res.clearCookie('token', {
  20. httpOnly: true,
  21. secure: false,
  22. sameSite: 'lax',
  23. path: '/'
  24. });
  25. return res.status(401).json({error: 'Invalid token'});
  26. }
  27. const row = await UserDB.find('users', {_id: decoded.id});
  28. if (!row) {
  29. res.clearCookie('token', {
  30. httpOnly: true,
  31. secure: false,
  32. sameSite: 'lax',
  33. path: '/'
  34. });
  35. return res.status(401).json({error: 'Invalid token'});
  36. }
  37. const {password, ...safeRow} = row;
  38. res.json(safeRow);
  39. });
  40. auth.get('/login/:data', async (req, res) => {
  41. const UserDB = req.app.locals.db;
  42. if (!req.params.data) {
  43. return res.status(401).send('Invalid token');
  44. }
  45. try {
  46. const data = JSON.parse(atob(req.params.data));
  47. const row = await UserDB.find('users', {_id: data.id});
  48. if (!row) {
  49. return res.status(401).send('Invalid token');
  50. }
  51. console.log(mfaCodes)
  52. const mfaRow = mfaCodes.find(obj => String(obj.id) === String(data.id));
  53. if (!mfaRow) {
  54. return res.status(401).send('Invalid token');
  55. }
  56. if (mfaRow.token !== data.token) {
  57. return res.status(401).send('Invalid token');
  58. }
  59. const token = jwt.sign(
  60. {id: row._id, username: row.username},
  61. process.env.JWT_SECRET,
  62. {expiresIn: '1h'}
  63. );
  64. res.cookie('token', token, {
  65. httpOnly: true,
  66. secure: false,
  67. sameSite: 'lax',
  68. maxAge: 60 * 60 * 1000,
  69. path: '/'
  70. });
  71. const index = mfaCodes.findIndex(obj => String(obj.id) === String(data.id));
  72. if (index !== -1) {
  73. mfaCodes.splice(index, 1);
  74. }
  75. res.redirect('http://localhost:5173/');
  76. } catch (e) {
  77. console.log(e);
  78. res.status(401).send('Invalid token');
  79. }
  80. });
  81. auth.post('/login', async (req, res) => {
  82. let UserDB = req.app.locals.db;
  83. const {username, password} = req.body;
  84. if (!username || !password) {
  85. return res.status(400).json({error: 'Missing credentials'});
  86. }
  87. const row = await UserDB.find('users', {username});
  88. if (!row) return res.status(401).json({error: 'User doesnt exist'});
  89. if (!await argon2.verify(row.password, password)) return res.status(401).json({error: 'Invalid password'});
  90. let mfgen = crypto.randomBytes(64).toString('hex');
  91. const mfaToken = {id: row._id, token: mfgen}
  92. mfaCodes.push(mfaToken)
  93. console.log(mfaCodes)
  94. 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))}`)
  95. res.json({success: true, user: {username}});
  96. });
  97. auth.post('/register', async (req, res) => {
  98. let UserDB = req.app.locals.db;
  99. const {email, password} = req.body;
  100. const username = email.split("@")[0]
  101. //await mailer.send(email, "signup request", "this worked?")
  102. if (await UserDB.find('users', {username: username})) return res.status(400).json({error: 'User already exists'});
  103. const hash = await hashPass(password)
  104. UserDB.add('users', {username: username, email: email, password: hash})
  105. res.json({success: true, user: {username}});
  106. })
  107. async function hashPass(input) {
  108. return await argon2.hash(input, {
  109. type: argon2.argon2id,
  110. salt: Buffer.from(process.env.SALT, 'utf8'),
  111. timeCost: 2,
  112. memoryCost: 19456,
  113. parallelism: 1
  114. })
  115. }