feat: replace fixed login rate limit with progressive lockout
Made-with: Cursor
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import { AuthService } from '../services/auth/auth.service.js';
|
||||
import { checkBlocked, clearOnSuccess, recordFailedAttempt } from '../utils/loginLockout.js';
|
||||
|
||||
const registerSchema = {
|
||||
body: {
|
||||
@@ -89,20 +90,43 @@ export async function authRoutes(app: FastifyInstance) {
|
||||
|
||||
app.post(
|
||||
'/login',
|
||||
{ schema: loginSchema, config: { rateLimit: rateLimitOptions.login } },
|
||||
{
|
||||
schema: loginSchema,
|
||||
preValidation: async (req, reply) => {
|
||||
const ip = req.ip ?? 'unknown';
|
||||
const { blocked, retryAfter } = await checkBlocked(app.redis, ip);
|
||||
if (blocked) {
|
||||
if (retryAfter !== undefined) {
|
||||
reply.header('Retry-After', String(retryAfter));
|
||||
}
|
||||
return reply.status(429).send({
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many failed login attempts. Please try again later.',
|
||||
retryAfter,
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
async (req, reply) => {
|
||||
const body = req.body as { email: string; password: string };
|
||||
const userAgent = req.headers['user-agent'];
|
||||
const ipAddress = req.ip;
|
||||
const ip = req.ip ?? 'unknown';
|
||||
|
||||
const result = await authService.login({
|
||||
email: body.email,
|
||||
password: body.password,
|
||||
userAgent,
|
||||
ipAddress,
|
||||
});
|
||||
|
||||
return reply.send(result);
|
||||
try {
|
||||
const result = await authService.login({
|
||||
email: body.email,
|
||||
password: body.password,
|
||||
userAgent,
|
||||
ipAddress: ip,
|
||||
});
|
||||
await clearOnSuccess(app.redis, ip);
|
||||
return reply.send(result);
|
||||
} catch (err) {
|
||||
await recordFailedAttempt(app.redis, ip);
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user