| import express from "express"; | |
| import bcrypt from "bcrypt"; | |
| import jwt from "jsonwebtoken"; | |
| import crypto from "crypto"; | |
| import { User } from "../models/User.js"; | |
| import { loginLimiter } from "../middleware/rateLimit.js"; | |
| import { JWT_CONFIG, PASSWORD_POLICY } from "../config/security.js"; | |
| const r = express.Router(); | |
| r.post("/register", async (req, res) => { | |
| if (!req.body.password || req.body.password.length < PASSWORD_POLICY.minLength) | |
| return res.status(400).json({ error: "Weak password" }); | |
| const hash = await bcrypt.hash(req.body.password, 10); | |
| await User.create({ email: req.body.email, passwordHash: hash }); | |
| res.json({ ok: true }); | |
| }); | |
| r.post("/login", loginLimiter, async (req, res) => { | |
| const user = await User.findOne({ email: req.body.email }); | |
| if (!user) return res.sendStatus(401); | |
| const ok = await bcrypt.compare(req.body.password, user.passwordHash); | |
| await new Promise((r) => setTimeout(r, 500)); | |
| if (!ok) return res.sendStatus(401); | |
| const accessToken = jwt.sign( | |
| { id: user.id, role: user.role }, | |
| process.env.JWT_SECRET, | |
| { expiresIn: "15m", ...JWT_CONFIG } | |
| ); | |
| const refresh = crypto.randomBytes(64).toString("hex"); | |
| user.refreshTokens.push({ | |
| hash: await bcrypt.hash(refresh, 10), | |
| ip: req.ip, | |
| userAgent: req.headers["user-agent"], | |
| }); | |
| await user.save(); | |
| res.json({ accessToken, refreshToken: refresh }); | |
| }); | |
| export default r; | |