This commit is contained in:
Iliyan Angelov
2025-09-14 23:24:25 +03:00
commit c67067a2a4
71311 changed files with 6800714 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
from contextlib import contextmanager
from contextvars import ContextVar
_request_var = ContextVar("request", default=None)
def __getattr__(name):
if name == "request":
return _request_var.get()
raise AttributeError(name)
@contextmanager
def request_context(request):
token = _request_var.set(request)
try:
yield
finally:
_request_var.reset(token)

View File

@@ -0,0 +1,8 @@
class ImmediateHttpResponse(Exception):
"""
This exception is used to interrupt the flow of processing to immediately
return a custom HttpResponse.
"""
def __init__(self, response):
self.response = response

View File

@@ -0,0 +1,77 @@
import hashlib
import time
from collections import namedtuple
from django.core.cache import cache
from django.shortcuts import render
Rate = namedtuple("Rate", "amount duration")
def parse(rate):
ret = None
if rate:
amount, duration = rate.split("/")
amount = int(amount)
duration_map = {"s": 1, "m": 60, "h": 3600, "d": 86400}
if duration not in duration_map:
raise ValueError("Invalid duration: %s" % duration)
duration = duration_map[duration]
ret = Rate(amount, duration)
return ret
def _cache_key(request, *, action, key=None, user=None):
from allauth.account.adapter import get_adapter
if key:
source = ()
elif user or request.user.is_authenticated:
source = ("user", str((user or request.user).pk))
else:
source = ("ip", get_adapter().get_client_ip(request))
keys = ["allauth", "rl", action, *source]
if key is not None:
key_hash = hashlib.sha256(key.encode("utf8")).hexdigest()
keys.append(key_hash)
return ":".join(keys)
def clear(request, *, action, key=None, user=None):
cache_key = _cache_key(request, action=action, key=key, user=user)
cache.delete(cache_key)
def consume(request, *, action, key=None, amount=None, duration=None, user=None):
allowed = True
from allauth.account import app_settings
rate = app_settings.RATE_LIMITS.get(action)
if rate:
rate = parse(rate)
if not amount:
amount = rate.amount
if not duration:
duration = rate.duration
if not request or request.method == "GET" or not amount or not duration:
pass
else:
cache_key = _cache_key(request, action=action, key=key, user=user)
history = cache.get(cache_key, [])
now = time.time()
while history and history[-1] <= now - duration:
history.pop()
allowed = len(history) < amount
if allowed:
history.insert(0, now)
cache.set(cache_key, history, duration)
return allowed
def consume_or_429(request, *args, **kwargs):
from allauth.account import app_settings
if not consume(request, *args, **kwargs):
return render(request, "429." + app_settings.TEMPLATE_EXTENSION, status=429)