#!/bin/bash # End-to-End Rate Limiting Verification Script # This script tests the Supabase-based rate limiting implementation set -e echo "================================================" echo "E2E Rate Limiting Verification" echo "================================================" echo "" # Configuration API_URL="http://localhost:3000/api/contact" MAX_REQUESTS=5 EXPECTED_WINDOW_MS=3600000 # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Test counters TESTS_PASSED=0 TESTS_FAILED=0 # Helper function to print test result print_result() { local test_name=$1 local result=$2 if [ "$result" = "PASS" ]; then echo -e "${GREEN}✅ PASS${NC}: $test_name" ((TESTS_PASSED++)) else echo -e "${RED}❌ FAIL${NC}: $test_name" ((TESTS_FAILED++)) fi } # Helper function to make API request make_request() { local name=$1 local email=$2 local message=$3 curl -s -w "\n%{http_code}\n%{header_json}" -X POST "$API_URL" \ -H "Content-Type: application/json" \ -d "{\"name\":\"$name\",\"email\":\"$email\",\"message\":\"$message\"}" } echo "Step 1: Check if dev server is running..." if ! curl -s -f -o /dev/null "$API_URL" -X POST -H "Content-Type: application/json" -d '{}'; then if [ $? -eq 7 ]; then echo -e "${RED}❌ Dev server is not running!${NC}" echo "Please start it with: npm run dev" exit 1 fi fi echo -e "${GREEN}✅ Dev server is running${NC}" echo "" echo "Step 2: Testing basic rate limiting flow..." echo "Sending $MAX_REQUESTS requests (should all succeed)..." # Track response headers declare -a status_codes declare -a remaining_counts for i in $(seq 1 $MAX_REQUESTS); do echo -n "Request #$i... " response=$(make_request "Test User $i" "test$i@example.com" "Test message $i") # Extract HTTP status code status_code=$(echo "$response" | tail -n 2 | head -n 1) status_codes[$i]=$status_code # Extract X-RateLimit-Remaining header remaining=$(echo "$response" | grep -i "x-ratelimit-remaining" | grep -oP '\d+' | head -n 1 || echo "N/A") remaining_counts[$i]=$remaining if [ "$status_code" = "200" ]; then echo -e "${GREEN}200 OK${NC} (Remaining: $remaining)" else echo -e "${RED}$status_code${NC} (Unexpected!)" fi sleep 0.5 done echo "" # Verify all requests succeeded echo "Verifying first $MAX_REQUESTS requests..." all_success=true for i in $(seq 1 $MAX_REQUESTS); do if [ "${status_codes[$i]}" != "200" ]; then all_success=false print_result "Request #$i should return 200" "FAIL" fi done if [ "$all_success" = true ]; then print_result "First $MAX_REQUESTS requests succeeded" "PASS" fi echo "" # Verify remaining counts decrement echo "Verifying rate limit counters..." for i in $(seq 1 $((MAX_REQUESTS - 1))); do current=${remaining_counts[$i]} next=${remaining_counts[$((i + 1))]} if [ "$current" != "N/A" ] && [ "$next" != "N/A" ]; then expected=$((current - 1)) if [ "$next" -eq "$expected" ]; then print_result "Counter decremented from $current to $next" "PASS" else print_result "Counter should decrement (expected $expected, got $next)" "FAIL" fi fi done echo "" echo "Step 3: Testing rate limit enforcement..." echo "Sending 6th request (should be rate limited)..." response=$(make_request "Test User 6" "test6@example.com" "Test message 6") status_code=$(echo "$response" | tail -n 2 | head -n 1) body=$(echo "$response" | head -n -2) echo "Status Code: $status_code" echo "Response: $body" echo "" if [ "$status_code" = "429" ]; then print_result "6th request returns 429 Too Many Requests" "PASS" # Check for Retry-After header retry_after=$(echo "$response" | grep -i "retry-after" | grep -oP '\d+' || echo "") if [ -n "$retry_after" ]; then print_result "Retry-After header present ($retry_after seconds)" "PASS" else print_result "Retry-After header should be present" "FAIL" fi # Check for X-RateLimit-Remaining: 0 remaining=$(echo "$response" | grep -i "x-ratelimit-remaining" | grep -oP '\d+' || echo "") if [ "$remaining" = "0" ]; then print_result "X-RateLimit-Remaining is 0" "PASS" else print_result "X-RateLimit-Remaining should be 0" "FAIL" fi # Check for error message in body if echo "$body" | grep -q "too many\|rate limit"; then print_result "Response body contains rate limit error message" "PASS" else print_result "Response body should contain rate limit error" "FAIL" fi else print_result "6th request should return 429" "FAIL" fi echo "" echo "Step 4: Testing rate limit persistence..." echo "Sending another request (should still be rate limited)..." response=$(make_request "Test User 7" "test7@example.com" "Test message 7") status_code=$(echo "$response" | tail -n 2 | head -n 1) if [ "$status_code" = "429" ]; then print_result "Subsequent request still rate limited" "PASS" else print_result "Rate limiting should persist" "FAIL" fi echo "" echo "Step 5: Testing validation (should not count against rate limit)..." echo "Sending request with invalid data..." response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \ -H "Content-Type: application/json" \ -d '{"name":"","email":"invalid","message":""}') status_code=$(echo "$response" | tail -n 1) if [ "$status_code" = "400" ] || [ "$status_code" = "429" ]; then print_result "Invalid data returns 400 or still rate limited (429)" "PASS" else print_result "Invalid data handling (got $status_code)" "FAIL" fi echo "" echo "================================================" echo "Test Summary" echo "================================================" echo -e "${GREEN}Passed: $TESTS_PASSED${NC}" echo -e "${RED}Failed: $TESTS_FAILED${NC}" echo "" if [ $TESTS_FAILED -eq 0 ]; then echo -e "${GREEN}✅ All tests passed!${NC}" echo "" echo "Next steps:" echo "1. Verify database records in Supabase dashboard" echo "2. Test browser UI at http://localhost:3000/en/contact" echo "3. Test persistence across page refreshes" echo "4. Complete manual verification scenarios in E2E_VERIFICATION.md" exit 0 else echo -e "${RED}❌ Some tests failed${NC}" echo "Please review the failures above and check:" echo "- Is the migration applied in Supabase?" echo "- Are environment variables set correctly?" echo "- Check server logs for errors" exit 1 fi