some improvements from claude

This commit is contained in:
MLH
2025-04-06 16:20:42 +02:00
parent 467d27834c
commit 4dfdb17b1e
7 changed files with 288 additions and 26 deletions

View File

@ -12,14 +12,37 @@ const JWT_SECRET = process.env.JWT_SECRET;
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '1h';
const SALT_ROUNDS = 10; // Cost factor for bcrypt hashing
// Simple rate limiting for login attempts
const loginAttempts = {};
const MAX_ATTEMPTS = 5;
const LOCKOUT_TIME = 15 * 60 * 1000; // 15 minutes
// Password validation function
const isPasswordValid = (password) => {
// At least 8 characters, containing a number and a letter
return password.length >= 8 &&
/\d/.test(password) &&
/[a-zA-Z]/.test(password);
};
// POST /api/auth/register - User Registration
router.post('/register', async (req, res) => {
const { username, password } = req.body;
// Basic validation
// Enhanced validation
if (!username || !password) {
return res.status(400).json({ message: 'Benutzername und Passwort sind erforderlich.' });
}
if (username.length < 3 || username.length > 30) {
return res.status(400).json({ message: 'Benutzername muss zwischen 3 und 30 Zeichen lang sein.' });
}
if (!isPasswordValid(password)) {
return res.status(400).json({
message: 'Passwort muss mindestens 8 Zeichen lang sein und mindestens eine Zahl und einen Buchstaben enthalten.'
});
}
try {
// Check if user already exists
@ -51,6 +74,21 @@ router.post('/register', async (req, res) => {
// POST /api/auth/login - User Login
router.post('/login', async (req, res) => {
const { username, password } = req.body;
const ip = req.ip;
// Check for login attempts rate limiting
if (loginAttempts[ip] && loginAttempts[ip].count >= MAX_ATTEMPTS) {
const timeElapsed = Date.now() - loginAttempts[ip].timestamp;
if (timeElapsed < LOCKOUT_TIME) {
const minutesLeft = Math.ceil((LOCKOUT_TIME - timeElapsed) / 60000);
return res.status(429).json({
message: `Zu viele Anmeldeversuche. Bitte versuchen Sie es in ${minutesLeft} Minuten erneut.`
});
} else {
// Reset attempts after lockout period
delete loginAttempts[ip];
}
}
if (!username || !password) {
return res.status(400).json({ message: 'Benutzername und Passwort sind erforderlich.' });
@ -63,9 +101,19 @@ router.post('/login', async (req, res) => {
// Check if user exists and password is correct
if (!user || !(await bcrypt.compare(password, user.password_hash))) {
// Track failed login attempts
if (!loginAttempts[ip]) {
loginAttempts[ip] = { count: 0, timestamp: Date.now() };
}
loginAttempts[ip].count++;
loginAttempts[ip].timestamp = Date.now();
return res.status(401).json({ message: 'Ungültiger Benutzername oder Passwort.' }); // 401 Unauthorized
}
// Reset login attempts on successful login
delete loginAttempts[ip];
// User authenticated successfully, create JWT payload
const payload = {
id: user.id,