104 lines
3.5 KiB
JavaScript
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; |