From 64364582b12a01cb3b57b5cb96219663a8f643f3 Mon Sep 17 00:00:00 2001 From: ZeroPath Date: Thu, 14 Aug 2025 04:57:23 +0000 Subject: [PATCH] fix: implement failed login attempt tracking and lockout mechanism --- .../loginBenderChallenge_2_correct.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/data/static/codefixes/loginBenderChallenge_2_correct.ts b/data/static/codefixes/loginBenderChallenge_2_correct.ts index cdc351bea65..1898aadded9 100644 --- a/data/static/codefixes/loginBenderChallenge_2_correct.ts +++ b/data/static/codefixes/loginBenderChallenge_2_correct.ts @@ -1,4 +1,7 @@ import {BasketModel} from "../../../models/basket"; +const failedLoginAttempts = new Map(); +const MAX_FAILED_LOGIN_ATTEMPTS = 5; +const LOCKOUT_TIME_MS = 15 * 60 * 1000; module.exports = function login () { function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) { @@ -31,9 +34,22 @@ module.exports = function login () { } else if (user.data?.id) { afterLogin(user, res, next) } else { - res.status(401).send(res.__('Invalid email or password.')) + // Record failed login attempt + const now = Date.now(); + const email = req.body.email; + let attempt = failedLoginAttempts.get(email) || { count: 0, lastAttempt: now }; + if (now - attempt.lastAttempt > LOCKOUT_TIME_MS) { + attempt = { count: 0, lastAttempt: now }; + } + attempt.count++; + attempt.lastAttempt = now; + failedLoginAttempts.set(email, attempt); + if (attempt.count > MAX_FAILED_LOGIN_ATTEMPTS) { + return res.status(429).send(res.__('Too many failed login attempts. Please try again later.')); + } + res.status(401).send(res.__('Invalid email or password.')); } }).catch((error: Error) => { next(error) }) - } \ No newline at end of file + }