@@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from django.core.cache import cache
|
||||
from django.test import RequestFactory
|
||||
|
||||
from apps.core.rate_limit import clear_rate_limit, is_rate_limited, register_rate_limit_failure
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _clear_rate_limit_cache():
|
||||
cache.clear()
|
||||
yield
|
||||
cache.clear()
|
||||
|
||||
|
||||
def _post_request(payload: dict[str, str], *, username: str | None = None):
|
||||
factory = RequestFactory()
|
||||
request = factory.post("/login/", data=payload)
|
||||
request.META["REMOTE_ADDR"] = "203.0.113.10"
|
||||
if username is None:
|
||||
request.user = SimpleNamespace(is_authenticated=False, is_anonymous=True)
|
||||
else:
|
||||
request.user = SimpleNamespace(is_authenticated=True, pk=42)
|
||||
payload["username"] = username
|
||||
request.user.username = username
|
||||
return request
|
||||
|
||||
|
||||
def test_rate_limit_blocks_after_max_attempts_and_reports_block_state():
|
||||
request = _post_request({"username": "alice"}, username="alice")
|
||||
|
||||
state = is_rate_limited(
|
||||
request,
|
||||
namespace="manual_import",
|
||||
max_attempts=2,
|
||||
window_seconds=300,
|
||||
block_seconds=120,
|
||||
)
|
||||
assert not state.is_blocked
|
||||
assert state.attempts == 0
|
||||
|
||||
state = register_rate_limit_failure(
|
||||
request,
|
||||
namespace="manual_import",
|
||||
max_attempts=2,
|
||||
window_seconds=300,
|
||||
block_seconds=120,
|
||||
)
|
||||
assert not state.is_blocked
|
||||
assert state.attempts == 1
|
||||
|
||||
state = register_rate_limit_failure(
|
||||
request,
|
||||
namespace="manual_import",
|
||||
max_attempts=2,
|
||||
window_seconds=300,
|
||||
block_seconds=120,
|
||||
)
|
||||
assert state.is_blocked
|
||||
assert state.remaining_seconds > 0
|
||||
|
||||
assert is_rate_limited(
|
||||
request,
|
||||
namespace="manual_import",
|
||||
max_attempts=2,
|
||||
window_seconds=300,
|
||||
block_seconds=120,
|
||||
).is_blocked
|
||||
|
||||
|
||||
def test_rate_limit_clear_resets_state_for_authenticated_identity():
|
||||
request = _post_request({"username": "alice"}, username="alice")
|
||||
|
||||
state = register_rate_limit_failure(
|
||||
request,
|
||||
namespace="login",
|
||||
max_attempts=1,
|
||||
window_seconds=300,
|
||||
block_seconds=10,
|
||||
)
|
||||
assert state.is_blocked
|
||||
|
||||
clear_rate_limit(request, namespace="login")
|
||||
state = is_rate_limited(
|
||||
request,
|
||||
namespace="login",
|
||||
max_attempts=1,
|
||||
window_seconds=300,
|
||||
block_seconds=10,
|
||||
)
|
||||
assert not state.is_blocked
|
||||
assert state.attempts == 0
|
||||
Reference in New Issue
Block a user