fix search feature
Build & Push / Pipeline Tests (push) Failing after 1m14s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 53s
Test / API Unit Tests (push) Failing after 50s
Test / Homepage Unit Tests (push) Successful in 45s
Test / Carplace Unit Tests (push) Successful in 44s
Test / Admin Unit Tests (push) Successful in 42s
Test / Dashboard Unit Tests (push) Successful in 43s
Test / API Integration Tests (push) Successful in 1m4s
Build & Push / Pipeline Tests (push) Failing after 1m14s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Successful in 53s
Test / API Unit Tests (push) Failing after 50s
Test / Homepage Unit Tests (push) Successful in 45s
Test / Carplace Unit Tests (push) Successful in 44s
Test / Admin Unit Tests (push) Successful in 42s
Test / Dashboard Unit Tests (push) Successful in 43s
Test / API Integration Tests (push) Successful in 1m4s
This commit is contained in:
@@ -31,6 +31,8 @@ describe('rateLimiter middleware configuration', () => {
|
||||
|
||||
expect(authLimiter.max).toBe(20)
|
||||
expect(authLimiter.windowMs).toBe(15 * 60 * 1000)
|
||||
expect(authLimiter.skip({ method: 'OPTIONS' } as any)).toBe(true)
|
||||
expect(authLimiter.skip({ method: 'POST' } as any)).toBe(false)
|
||||
expect(authLimiter.skipSuccessfulRequests).toBe(true)
|
||||
expect(authLimiter.message).toMatchObject({ error: 'too_many_requests', statusCode: 429 })
|
||||
expect(rateLimit).toHaveBeenCalled()
|
||||
@@ -63,7 +65,18 @@ describe('rateLimiter middleware configuration', () => {
|
||||
|
||||
expect(publicLimiter.max).toBe(60)
|
||||
expect(publicLimiter.message.message).toBe('Rate limit exceeded')
|
||||
expect(publicLimiter.skip({ method: 'OPTIONS' } as any)).toBe(true)
|
||||
expect(adminLimiter.max).toBe(100)
|
||||
expect(adminLimiter.message.message).toBe('Too many admin requests')
|
||||
expect(adminLimiter.skip({ method: 'OPTIONS' } as any)).toBe(true)
|
||||
})
|
||||
|
||||
it('uses a higher API cap and skips preflight requests before authenticated actor limits', async () => {
|
||||
const { apiLimiter, actorLimiter } = await import('./rateLimiter')
|
||||
|
||||
expect(apiLimiter.max).toBe(300)
|
||||
expect(apiLimiter.skip({ method: 'OPTIONS' } as any)).toBe(true)
|
||||
expect(apiLimiter.skip({ method: 'GET' } as any)).toBe(false)
|
||||
expect(actorLimiter.skip({ method: 'OPTIONS' } as any)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -52,6 +52,7 @@ function getAuthenticatedActorKey(req: Request): string | null {
|
||||
|
||||
// req.ip is already the real client IP when app.set('trust proxy', 1) is configured
|
||||
const getClientIpKey = (req: Request) => ipKeyGenerator(req.ip ?? '')
|
||||
const skipPreflightRequest = (req: Request) => req.method === 'OPTIONS'
|
||||
|
||||
// Strict limiter for auth endpoints — prevents brute-force and credential stuffing.
|
||||
// Successful requests (e.g. GET /me profile reads) are skipped so only failed
|
||||
@@ -61,6 +62,7 @@ export const authLimiter = rateLimit({
|
||||
max: 20,
|
||||
standardHeaders: 'draft-7',
|
||||
legacyHeaders: false,
|
||||
skip: skipPreflightRequest,
|
||||
skipSuccessfulRequests: true,
|
||||
keyGenerator: (req) => getClientIpKey(req),
|
||||
message: { error: 'too_many_requests', message: 'Too many attempts, please try again later', statusCode: 429 },
|
||||
@@ -69,9 +71,10 @@ export const authLimiter = rateLimit({
|
||||
// Standard limiter for general authenticated API endpoints
|
||||
export const apiLimiter = rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 120,
|
||||
max: 300,
|
||||
standardHeaders: 'draft-7',
|
||||
legacyHeaders: false,
|
||||
skip: skipPreflightRequest,
|
||||
keyGenerator: (req) => {
|
||||
const ip = getClientIpKey(req)
|
||||
const actorKey = getAuthenticatedActorKey(req)
|
||||
@@ -88,6 +91,7 @@ export const publicLimiter = rateLimit({
|
||||
max: 60,
|
||||
standardHeaders: 'draft-7',
|
||||
legacyHeaders: false,
|
||||
skip: skipPreflightRequest,
|
||||
keyGenerator: (req) => getClientIpKey(req),
|
||||
message: { error: 'too_many_requests', message: 'Rate limit exceeded', statusCode: 429 },
|
||||
})
|
||||
@@ -99,6 +103,7 @@ export const webhookLimiter = rateLimit({
|
||||
max: 30,
|
||||
standardHeaders: 'draft-7',
|
||||
legacyHeaders: false,
|
||||
skip: skipPreflightRequest,
|
||||
keyGenerator: (req) => getClientIpKey(req),
|
||||
message: { error: 'too_many_requests', message: 'Webhook rate limit exceeded', statusCode: 429 },
|
||||
})
|
||||
@@ -109,6 +114,7 @@ export const adminLimiter = rateLimit({
|
||||
max: 100,
|
||||
standardHeaders: 'draft-7',
|
||||
legacyHeaders: false,
|
||||
skip: skipPreflightRequest,
|
||||
keyGenerator: (req) => {
|
||||
const ip = getClientIpKey(req)
|
||||
return `${ip}:${getAuthenticatedActorKey(req) || 'anonymous'}`
|
||||
@@ -124,6 +130,7 @@ export const actorLimiter = rateLimit({
|
||||
max: 240,
|
||||
standardHeaders: 'draft-7',
|
||||
legacyHeaders: false,
|
||||
skip: skipPreflightRequest,
|
||||
keyGenerator: (req) => {
|
||||
const ip = getClientIpKey(req)
|
||||
const actorKey = getAuthenticatedActorKey(req)
|
||||
|
||||
Reference in New Issue
Block a user