From 6915ce518b667c6fd68763192ee382ca2bae7230 Mon Sep 17 00:00:00 2001 From: Zaki <18zaki18@gmail.com> Date: Sat, 9 May 2026 22:17:03 +0100 Subject: [PATCH] Rate-limit /reauth endpoint: 5 attempts per 15min --- api.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api.php b/api.php index 8b02b32..bde09b3 100644 --- a/api.php +++ b/api.php @@ -511,18 +511,20 @@ try { case ($path === '/reauth' && $method === 'POST'): $auth = authenticate($db); requireCSRF($db, $auth['userId']); + if (checkRateLimit($db) >= 5) { http_response_code(429); echo json_encode(['error'=>'Too many attempts. Try again later.']); break; } $p = $input['masterPassword'] ?? ''; $st = $db->prepare('SELECT * FROM users WHERE id=:uid'); $st->bindValue(':uid', $auth['userId'], SQLITE3_INTEGER); $user = $st->execute()->fetchArray(SQLITE3_ASSOC); - if (!$user) { http_response_code(401); echo json_encode(['error'=>'User not found']); break; } + if (!$user) { recordAttempt($db); http_response_code(401); echo json_encode(['error'=>'User not found']); break; } $algo = $user['hash_algo'] ?? 'pbkdf2'; if ($algo === 'bcrypt') { $valid = password_verify($p, $user['password_hash']); } else { $valid = hash_equals($user['password_hash'], hash_pbkdf2('sha256', $p, $user['salt'], 100000)); } - if (!$valid) { logAudit($db, $auth['userId'], 'failed_reauth'); http_response_code(401); echo json_encode(['error'=>'Invalid password']); break; } + if (!$valid) { recordAttempt($db); logAudit($db, $auth['userId'], 'failed_reauth'); http_response_code(401); echo json_encode(['error'=>'Invalid password']); break; } + clearAttempts($db); logAudit($db, $auth['userId'], 'reauth'); echo json_encode(['message'=>'OK']); break;