diff --git a/routes/auth.js b/routes/auth.js new file mode 100644 index 0000000..646d909 --- /dev/null +++ b/routes/auth.js @@ -0,0 +1,50 @@ +import { Router } from 'express'; +import bcrypt from 'bcryptjs'; +import db from '../db/index.js'; +import { signToken, requireAuth } from './auth-middleware.js'; + +const router = Router(); + +router.post('/login', (req, res) => { + const { username, password } = req.body || {}; + if (!username || !password) { + return res.status(400).json({ error: 'username and password required' }); + } + const user = db.prepare('SELECT * FROM users WHERE username = ?').get(username); + if (!user || !bcrypt.compareSync(password, user.password_hash)) { + return res.status(401).json({ error: 'invalid credentials' }); + } + const token = signToken(user); + res.cookie('nn_token', token, { + httpOnly: true, + sameSite: 'lax', + secure: true, // nginx terminates HTTPS in front + maxAge: 8 * 60 * 60 * 1000, + }); + res.json({ token, user: { id: user.id, username: user.username, role: user.role } }); +}); + +router.post('/logout', (req, res) => { + res.clearCookie('nn_token'); + res.json({ ok: true }); +}); + +router.get('/me', requireAuth, (req, res) => { + res.json({ user: req.user }); +}); + +router.post('/change-password', requireAuth, (req, res) => { + const { currentPassword, newPassword } = req.body || {}; + if (!currentPassword || !newPassword || newPassword.length < 8) { + return res.status(400).json({ error: 'newPassword must be at least 8 characters' }); + } + const user = db.prepare('SELECT * FROM users WHERE id = ?').get(req.user.id); + if (!user || !bcrypt.compareSync(currentPassword, user.password_hash)) { + return res.status(401).json({ error: 'current password incorrect' }); + } + const hash = bcrypt.hashSync(newPassword, 10); + db.prepare('UPDATE users SET password_hash = ? WHERE id = ?').run(hash, user.id); + res.json({ ok: true }); +}); + +export default router;