This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.http import HttpRequest
|
||||
from django.utils import timezone
|
||||
@@ -17,7 +18,9 @@ def _identity_for_user(request: HttpRequest) -> str:
|
||||
user = getattr(request, "user", None)
|
||||
if user and getattr(user, "is_authenticated", False):
|
||||
return f"user:{user.pk}"
|
||||
username = (request.POST.get("username", "") if request.method == "POST" else "").strip().lower()
|
||||
username = (
|
||||
(request.POST.get("username", "") if request.method == "POST" else "").strip().lower()
|
||||
)
|
||||
return f"anon:{username or _client_ip(request)}"
|
||||
|
||||
|
||||
@@ -47,7 +50,7 @@ def is_rate_limited(
|
||||
now = timezone.now().timestamp()
|
||||
identity = _identity_for_user(request)
|
||||
block_until = cache.get(_block_key(namespace, identity))
|
||||
if block_until and isinstance(block_until, (int, float)) and block_until > now:
|
||||
if block_until and isinstance(block_until, int | float) and block_until > now:
|
||||
return RateLimitState(True, max(0, int(block_until - now)), 0)
|
||||
|
||||
if cache.get(_attempts_key(namespace, identity), 0) >= max_attempts:
|
||||
@@ -84,7 +87,9 @@ def register_rate_limit_failure(
|
||||
attempts = int(cache.get(_attempts_key(namespace, identity), 0)) + 1
|
||||
if attempts >= max_attempts:
|
||||
now = timezone.now().timestamp()
|
||||
cache.set(_block_key(namespace, identity), now + max(block_seconds, 1), timeout=block_seconds)
|
||||
cache.set(
|
||||
_block_key(namespace, identity), now + max(block_seconds, 1), timeout=block_seconds
|
||||
)
|
||||
cache.delete(_attempts_key(namespace, identity))
|
||||
return RateLimitState(True, max(block_seconds, 1), attempts)
|
||||
|
||||
|
||||
+5
-4
@@ -1,20 +1,20 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.auth.views import LoginView
|
||||
from django.db.models import Count, Q
|
||||
from django.http import JsonResponse
|
||||
from django.utils import timezone
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from apps.core.rate_limit import clear_rate_limit, is_rate_limited, register_rate_limit_failure
|
||||
from apps.jobs.models import Application, JobPosting, ScoreRun
|
||||
from apps.sources.models import Source
|
||||
from apps.core.rate_limit import clear_rate_limit, is_rate_limited, register_rate_limit_failure
|
||||
from apps.sources.services.health import collect_source_health
|
||||
|
||||
from .health import readiness
|
||||
from apps.sources.services.health import collect_source_health
|
||||
|
||||
|
||||
class SecurityAwareLoginView(LoginView):
|
||||
@@ -39,7 +39,8 @@ class SecurityAwareLoginView(LoginView):
|
||||
request,
|
||||
(
|
||||
"Te veel inlogpogingen op dit account. Wacht "
|
||||
f"{self._remaining_minutes(state.remaining_seconds)} en probeer daarna opnieuw."
|
||||
f"{self._remaining_minutes(state.remaining_seconds)} en probeer daarna "
|
||||
"opnieuw."
|
||||
),
|
||||
)
|
||||
return self.form_invalid(self.get_form())
|
||||
|
||||
Reference in New Issue
Block a user