import { describe, it, expect, beforeEach, vi } from 'vitest' import { createMockEvent } from '../helpers/createMockEvent.js' describe('rate-limit middleware', () => { // Fresh import per describe block to get fresh limiter instances let rateLimitMiddleware beforeEach(async () => { vi.resetModules() const mod = await import('../../../server/middleware/03.rate-limit.js') rateLimitMiddleware = mod.default }) describe('non-API paths', () => { it('skips rate limiting for non-/api/ paths', async () => { const event = createMockEvent({ path: '/about', remoteAddress: '10.0.0.1' }) await expect(rateLimitMiddleware(event)).resolves.toBeUndefined() }) }) describe('auth endpoint limiting (5 per 5 min)', () => { it('allows 5 requests then blocks the 6th', async () => { const ip = '10.0.1.1' // First 5 should succeed for (let i = 0; i < 5; i++) { const event = createMockEvent({ method: 'POST', path: '/api/auth/login', remoteAddress: ip }) await expect(rateLimitMiddleware(event)).resolves.toBeUndefined() } // 6th should be rate limited const event = createMockEvent({ method: 'POST', path: '/api/auth/login', remoteAddress: ip }) await expect(rateLimitMiddleware(event)).rejects.toMatchObject({ statusCode: 429 }) // Check Retry-After header was set expect(event._testSetHeaders['retry-after']).toBeDefined() }) }) describe('payment endpoint limiting (10 per min)', () => { it('allows 10 requests then blocks the 11th', async () => { const ip = '10.0.2.1' for (let i = 0; i < 10; i++) { const event = createMockEvent({ method: 'POST', path: '/api/helcim/initialize-payment', remoteAddress: ip }) await expect(rateLimitMiddleware(event)).resolves.toBeUndefined() } const event = createMockEvent({ method: 'POST', path: '/api/helcim/initialize-payment', remoteAddress: ip }) await expect(rateLimitMiddleware(event)).rejects.toMatchObject({ statusCode: 429 }) }) }) describe('IP isolation', () => { it('different IPs have separate rate limit counters', async () => { // Exhaust limit for IP A for (let i = 0; i < 5; i++) { const event = createMockEvent({ method: 'POST', path: '/api/auth/login', remoteAddress: '10.0.3.1' }) await rateLimitMiddleware(event) } // IP B should still be able to make requests const event = createMockEvent({ method: 'POST', path: '/api/auth/login', remoteAddress: '10.0.3.2' }) await expect(rateLimitMiddleware(event)).resolves.toBeUndefined() }) }) })