diff --git a/data/static/codefixes/loginBenderChallenge_2_correct.ts b/data/static/codefixes/loginBenderChallenge_2_correct.ts index cdc351bea65..ff07b43beef 100644 --- a/data/static/codefixes/loginBenderChallenge_2_correct.ts +++ b/data/static/codefixes/loginBenderChallenge_2_correct.ts @@ -1,6 +1,10 @@ import {BasketModel} from "../../../models/basket"; module.exports = function login () { + const MAX_FAILED_ATTEMPTS = 5 + const LOCKOUT_TIME_MS = 15 * 60 * 1000 + const failedLoginAttempts: Record = {} + function afterLogin (user: { data: User, bid: number }, res: Response, next: NextFunction) { BasketModel.findOrCreate({ where: { UserId: user.data.id } }) .then(([basket]: [BasketModel, boolean]) => { @@ -14,6 +18,13 @@ module.exports = function login () { } return (req: Request, res: Response, next: NextFunction) => { + const email = req.body.email; + const attemptInfo = failedLoginAttempts[email]; + if (attemptInfo && attemptInfo.count >= MAX_FAILED_ATTEMPTS && (Date.now() - attemptInfo.lastAttempt) < LOCKOUT_TIME_MS) { + return res.status(429).send(res.__('Too many login attempts. Please try again later.')); + } else if (attemptInfo && (Date.now() - attemptInfo.lastAttempt) >= LOCKOUT_TIME_MS) { + delete failedLoginAttempts[email]; + } models.sequelize.query(`SELECT * FROM Users WHERE email = $mail AND password = $pass AND deletedAt IS NULL`, { bind: { mail: req.body.email, pass: security.hash(req.body.password) }, model: models.User, plain: true }) .then((authenticatedUser) => { @@ -29,11 +40,19 @@ module.exports = function login () { } }) } else if (user.data?.id) { + delete failedLoginAttempts[email]; afterLogin(user, res, next) } else { - res.status(401).send(res.__('Invalid email or password.')) + const email = req.body.email; + if (!failedLoginAttempts[email]) { + failedLoginAttempts[email] = { count: 1, lastAttempt: Date.now() }; + } else { + failedLoginAttempts[email].count++; + failedLoginAttempts[email].lastAttempt = Date.now(); + } + res.status(401).send(res.__('Invalid email or password.')); } }).catch((error: Error) => { next(error) }) - } \ No newline at end of file + }