Files
nuitdelinfo2023/api/routes/users.js
2023-12-08 02:28:05 +01:00

104 lines
3.5 KiB
JavaScript

/* eslint-disable no-undef */
import express from 'express';
import { pool } from '../modules/database.js';
import { generateToken } from '../modules/token.js';
import { requestLimiter, respondWithStatus, respondWithStatusJSON } from '../modules/requestHandler.js';
const router = express.Router();
router.post('/register', requestLimiter, async (req, res) => {
const { username, password } = req.body;
if ([ username, password ].every(Boolean)) {
try {
const [existingUsername] = await pool.execute('SELECT * FROM users WHERE username = ? LIMIT 1', [username]);
if (existingUsername.length) return await respondWithStatus(res, 400, 'Username is already taken');
const hashedPassword = await Bun.password.hash(password);
const [result] = await pool.execute('INSERT INTO users (username, password) VALUES (?, ?)', [ username, hashedPassword ]);
if (result.affectedRows === 0) return await respondWithStatus(res, 500, 'Error storing user');
const user = await pool.execute('SELECT * FROM users WHERE username = ? LIMIT 1', [ username ]);
const token = await generateToken(user[0].id, password);
return await respondWithStatusJSON(res, 200, { message: 'Successfully registered', token: token, username: username });
}
catch (error) {
console.error(error);
return await respondWithStatus(res, 500, 'An error has occured');
}
}
else {
return await respondWithStatus(res, 400, 'Missing fields');
}
});
router.post('/login', requestLimiter, async (req, res) => {
const { username, password } = req.body;
if ([username, password].every(Boolean)) {
try {
const [rows] = await pool.execute(
'SELECT * FROM users WHERE username = ? LIMIT 1', [username],
);
if (!rows.length) return await respondWithStatus(res, 404, 'Incorrect username or email');
const user = rows[0];
const passwordMatch = await Bun.password.verify(password, user.password);
if (!passwordMatch) return await respondWithStatus(res, 401, 'Incorrect password');
const token = await generateToken(user.id, password);
return await respondWithStatusJSON(res, 200, {
message: 'Login successful',
token: token,
user: {
id: user.id,
username: user.username,
},
});
}
catch (error) {
console.error(error);
return await respondWithStatus(res, 500, 'An error has occured');
}
}
else {
return await respondWithStatus(res, 400, 'Missing fields');
}
});
router.post('verify', requestLimiter, async (req, res) => {
try {
const token = req.headers.authorization;
if (!token) return await respondWithStatus(res, 401, 'No token provided');
}
catch (error) {
console.error(error);
return await respondWithStatus(res, 500, 'An error has occured');
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userId = decoded.userId;
const [rows] = await pool.execute(
'SELECT * FROM users WHERE id = ? LIMIT 1', [req.userId],
);
if (!rows.length) return await respondWithStatus(res, 404, 'User not found!');
const passwordMatch = await Bun.password.verify(decoded.password, rows[0].password);
if (!passwordMatch) return await respondWithStatus(res, 401, 'Token is invalid');
const now = Date.now().valueOf() / 1000;
if (decoded.exp - now <= 0) {
return await respondWithStatus(res, 401, 'Token is invalid');
}
return await respondWithStatusJSON(res, 200, {
message: 'Token is valid',
user: {
id: rows[0].id,
username: rows[0].username,
},
});
}
catch (error) {
return await respondWithStatus(res, 401, 'Invalid user');
}
});
export default router;