|
1 | 1 | import logging |
| 2 | +import os |
2 | 3 | import time |
3 | 4 | from typing import Any, Callable, Optional, cast |
4 | 5 |
|
| 6 | +from django.conf import settings |
5 | 7 | from django.core.cache import cache |
6 | 8 | from django.http import HttpRequest, HttpResponse |
7 | 9 | from redis.exceptions import RedisError |
8 | 10 |
|
9 | 11 | logger = logging.getLogger(__name__) |
10 | 12 |
|
11 | 13 |
|
| 14 | +def get_whitelisted_ips() -> set[str]: |
| 15 | + """Get the set of whitelisted IPs from settings or environment variable. |
| 16 | +
|
| 17 | + Can be configured via: |
| 18 | + - RATE_LIMIT_WHITELIST_IPS in Django settings (list) |
| 19 | + - RATE_LIMIT_WHITELIST_IPS environment variable (comma-separated string) |
| 20 | + """ |
| 21 | + # First check Django settings |
| 22 | + whitelist = getattr(settings, "RATE_LIMIT_WHITELIST_IPS", None) |
| 23 | + if whitelist: |
| 24 | + return set(whitelist) |
| 25 | + |
| 26 | + # Fall back to environment variable |
| 27 | + env_whitelist = os.environ.get("RATE_LIMIT_WHITELIST_IPS", "") |
| 28 | + if env_whitelist: |
| 29 | + return {ip.strip() for ip in env_whitelist.split(",") if ip.strip()} |
| 30 | + |
| 31 | + return set() |
| 32 | + |
| 33 | + |
12 | 34 | class HttpResponseTooManyRequests(HttpResponse): |
13 | 35 | status_code = 429 |
14 | 36 |
|
15 | 37 |
|
16 | 38 | def rate_limit_middleware( |
17 | | - get_response: Callable[[HttpRequest], HttpResponse] |
| 39 | + get_response: Callable[[HttpRequest], HttpResponse], |
18 | 40 | ) -> Callable[[HttpRequest], HttpResponse]: |
19 | 41 | """Rate limiting middleware that uses a simple cache-based counter.""" |
20 | 42 |
|
@@ -78,10 +100,18 @@ def check_rate_limit(request: HttpRequest) -> bool: |
78 | 100 | return True # Allow request on unexpected error |
79 | 101 |
|
80 | 102 | def middleware(request: HttpRequest) -> HttpResponse: |
| 103 | + client_ip = get_client_ip(request) |
| 104 | + whitelisted_ips = get_whitelisted_ips() |
| 105 | + |
| 106 | + # Skip rate limiting for whitelisted IPs |
| 107 | + if client_ip in whitelisted_ips: |
| 108 | + logger.debug(f"Skipping rate limit for whitelisted IP: {client_ip}") |
| 109 | + return get_response(request) |
| 110 | + |
81 | 111 | if not check_rate_limit(request): |
82 | 112 | logger.warning( |
83 | 113 | f"Rate limited - Method: {request.method}, " |
84 | | - f"Path: {request.path}, IP: {get_client_ip(request)}" |
| 114 | + f"Path: {request.path}, IP: {client_ip}" |
85 | 115 | ) |
86 | 116 | return HttpResponseTooManyRequests() |
87 | 117 |
|
|
0 commit comments