From 4e64e2997c2a0da0f68e57e2f38477a09c7ef188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20=C4=B0pek?= Date: Thu, 20 Nov 2025 15:57:45 +0300 Subject: [PATCH] feat: use `CF-Connecting-IP` and `X-Forwarded-For` headers for rate limiting and add a test script. --- scripts/test-rate-limit-headers.ts | 54 ++++++++++++++++++++++++++++++ src/middleware.ts | 10 ++++-- 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 scripts/test-rate-limit-headers.ts diff --git a/scripts/test-rate-limit-headers.ts b/scripts/test-rate-limit-headers.ts new file mode 100644 index 0000000..207929e --- /dev/null +++ b/scripts/test-rate-limit-headers.ts @@ -0,0 +1,54 @@ + +import { apiClient } from '../src/lib/api/client' + +// Mock fetch for testing if running outside of browser/node with fetch +if (!global.fetch) { + console.error("Fetch is not available") + process.exit(1) +} + +async function testRateLimitWithHeaders() { + console.log('šŸš€ Starting Rate Limit Test with Headers...') + + const url = 'http://localhost:3002/api/packages?limit=1' + const headers = { + 'CF-Connecting-IP': '1.2.3.4' + } + + let successCount = 0 + let failCount = 0 + + const startTime = Date.now() + + // Limit is 50, so we send 60 requests + for (let i = 0; i < 60; i++) { + try { + const res = await fetch(url, { headers }) + if (res.status === 200) { + successCount++ + process.stdout.write('.') + } else if (res.status === 429) { + failCount++ + process.stdout.write('x') + } else { + console.log(`\nUnexpected status: ${res.status}`) + } + } catch (e) { + console.error(`\nRequest failed: ${e}`) + } + } + + const duration = (Date.now() - startTime) / 1000 + console.log(`\n\nšŸ“Š Results for IP 1.2.3.4:`) + console.log(`Time: ${duration.toFixed(2)}s`) + console.log(`Success: ${successCount}`) + console.log(`Rate Limited: ${failCount}`) + + if (failCount > 0) { + console.log('āœ… Rate limiting with CF-Connecting-IP is working!') + } else { + console.log('āŒ Rate limiting did NOT trigger.') + } +} + +testRateLimitWithHeaders() diff --git a/src/middleware.ts b/src/middleware.ts index af80d55..9c177bf 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -10,8 +10,14 @@ export async function middleware(request: NextRequest) { // Only rate limit API routes if (request.nextUrl.pathname.startsWith('/api')) { try { - // 100 requests per minute per IP - await limiter.check(null, 50, request.ip ?? 'CACHE_TOKEN') + // Get real IP from Cloudflare or Proxy headers + const ip = request.headers.get('cf-connecting-ip') || + request.headers.get('x-forwarded-for')?.split(',')[0] || + request.ip || + 'CACHE_TOKEN' + + // 50 requests per minute per IP + await limiter.check(null, 50, ip) } catch { return NextResponse.json( { error: 'Too Many Requests' },