63 lines
2.0 KiB
JavaScript
63 lines
2.0 KiB
JavaScript
import { Router } from 'express';
|
|
import bcrypt from 'bcryptjs';
|
|
import { getAdmin, updateAdminPassword } from '../db.js';
|
|
import { requireAuth, signToken } from '../auth.js';
|
|
|
|
const router = Router();
|
|
const loginAttempts = new Map();
|
|
|
|
function checkRateLimit(ip) {
|
|
const now = Date.now();
|
|
const record = loginAttempts.get(ip) || { count: 0, resetAt: now + 60000 };
|
|
if (now > record.resetAt) {
|
|
loginAttempts.set(ip, { count: 1, resetAt: now + 60000 });
|
|
return true;
|
|
}
|
|
if (record.count >= 5) return false;
|
|
record.count++;
|
|
loginAttempts.set(ip, record);
|
|
return true;
|
|
}
|
|
|
|
router.post('/login', (req, res) => {
|
|
const ip = req.ip;
|
|
if (!checkRateLimit(ip)) {
|
|
return res.status(429).json({ error: 'Too many login attempts', code: 'RATE_LIMITED' });
|
|
}
|
|
|
|
const { username, password } = req.body;
|
|
if (!username || !password) {
|
|
return res.status(400).json({ error: 'Username and password required', code: 'VALIDATION' });
|
|
}
|
|
|
|
const admin = getAdmin();
|
|
if (!admin || username !== admin.username || !bcrypt.compareSync(password, admin.passwordHash)) {
|
|
return res.status(401).json({ error: 'Invalid credentials', code: 'UNAUTHORIZED' });
|
|
}
|
|
|
|
const token = signToken(username);
|
|
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
|
|
res.json({ token, expiresAt });
|
|
});
|
|
|
|
router.get('/me', requireAuth, (req, res) => {
|
|
res.json({ username: req.user.username });
|
|
});
|
|
|
|
router.put('/password', requireAuth, (req, res) => {
|
|
const { currentPassword, newPassword } = req.body;
|
|
if (!currentPassword || !newPassword || newPassword.length < 6) {
|
|
return res.status(400).json({ error: 'Valid current and new password (min 6 chars) required', code: 'VALIDATION' });
|
|
}
|
|
|
|
const admin = getAdmin();
|
|
if (!bcrypt.compareSync(currentPassword, admin.passwordHash)) {
|
|
return res.status(401).json({ error: 'Current password is incorrect', code: 'UNAUTHORIZED' });
|
|
}
|
|
|
|
updateAdminPassword(bcrypt.hashSync(newPassword, 12));
|
|
res.json({ message: 'Password updated' });
|
|
});
|
|
|
|
export default router;
|