refacto: Keeping entrypoints clean and making files by purpose
This commit is contained in:
83
server/routes/auth.js
Normal file
83
server/routes/auth.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import express from "express";
|
||||
import bcrypt from "bcryptjs";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { JWT_SECRET, authMiddleware } from "../middleware/auth.js";
|
||||
import { createUser, getUserByUsername, getUserById } from "../db/usersDb.js";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
function issueToken(user) {
|
||||
return jwt.sign(
|
||||
{ userId: user.id, username: user.username, team: user.team, role: user.role },
|
||||
JWT_SECRET,
|
||||
{ expiresIn: "7d" }
|
||||
);
|
||||
}
|
||||
|
||||
// POST /api/auth/register
|
||||
router.post("/register", async (req, res) => {
|
||||
const { username, email, password, team } = req.body ?? {};
|
||||
if (!username || !email || !password || !team) {
|
||||
return res.status(400).json({ error: "missing_fields" });
|
||||
}
|
||||
if (team !== "blue" && team !== "red") {
|
||||
return res.status(400).json({ error: "invalid_team" });
|
||||
}
|
||||
if (typeof username !== "string" || username.length < 2 || username.length > 32) {
|
||||
return res.status(400).json({ error: "invalid_username" });
|
||||
}
|
||||
if (typeof password !== "string" || password.length < 6) {
|
||||
return res.status(400).json({ error: "password_too_short" });
|
||||
}
|
||||
try {
|
||||
const passwordHash = await bcrypt.hash(password, 12);
|
||||
const user = await createUser(username.trim(), email.trim().toLowerCase(), passwordHash, team);
|
||||
const token = issueToken(user);
|
||||
return res.status(201).json({
|
||||
token,
|
||||
user: { id: user.id, username: user.username, team: user.team, role: user.role },
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.code === "23505") {
|
||||
if (e.constraint?.includes("email")) return res.status(409).json({ error: "email_taken" });
|
||||
return res.status(409).json({ error: "username_taken" });
|
||||
}
|
||||
console.error(e);
|
||||
return res.status(500).json({ error: "database_error" });
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/auth/login
|
||||
router.post("/login", async (req, res) => {
|
||||
const { username, password } = req.body ?? {};
|
||||
if (!username || !password) return res.status(400).json({ error: "missing_fields" });
|
||||
try {
|
||||
const user = await getUserByUsername(username.trim());
|
||||
if (!user) return res.status(401).json({ error: "invalid_credentials" });
|
||||
const valid = await bcrypt.compare(password, user.password_hash);
|
||||
if (!valid) return res.status(401).json({ error: "invalid_credentials" });
|
||||
const token = issueToken(user);
|
||||
return res.json({
|
||||
token,
|
||||
user: { id: user.id, username: user.username, team: user.team, role: user.role },
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return res.status(500).json({ error: "database_error" });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/auth/me
|
||||
router.get("/me", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const user = await getUserById(req.user.userId);
|
||||
if (!user) return res.status(404).json({ error: "user_not_found" });
|
||||
const token = issueToken(user);
|
||||
return res.json({ token, user });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return res.status(500).json({ error: "database_error" });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user