mirror of https://github.com/zulip/zulip.git
rate_limit: Rate limit the /accounts/find/ endpoint.
Closes #19287 This endpoint allows submitting multiple addresses so we need to "weigh" the rate limit more heavily the more emails are submitted. Clearly e.g. a request triggering emails to 2 addresses should weigh twice as much as a request doing that for just 1 address.
This commit is contained in:
parent
29b3e81dd4
commit
ddcfd9e2ee
|
@ -200,6 +200,36 @@ class RateLimitTests(ZulipTestCase):
|
|||
finally:
|
||||
remove_ratelimit_rule(1, 5, domain="create_realm_by_ip")
|
||||
|
||||
def test_find_account_rate_limiting(self) -> None:
|
||||
def assert_func(result: HttpResponse) -> None:
|
||||
self.assertEqual(result.status_code, 429)
|
||||
self.assert_in_response("Rate limit exceeded.", result)
|
||||
|
||||
add_ratelimit_rule(1, 5, domain="find_account_by_ip")
|
||||
try:
|
||||
RateLimitedIPAddr("127.0.0.1", domain="find_account_by_ip").clear_history()
|
||||
self.do_test_hit_ratelimits(
|
||||
lambda: self.client_post("/accounts/find/", {"emails": "new@zulip.com"}),
|
||||
assert_func=assert_func,
|
||||
)
|
||||
finally:
|
||||
remove_ratelimit_rule(1, 5, domain="find_account_by_ip")
|
||||
|
||||
# Now test whether submitting multiple emails is handled correctly.
|
||||
# The limit is set to 10 per second, so 5 requests with 2 emails
|
||||
# submitted in each should be allowed.
|
||||
add_ratelimit_rule(1, 10, domain="find_account_by_ip")
|
||||
try:
|
||||
RateLimitedIPAddr("127.0.0.1", domain="find_account_by_ip").clear_history()
|
||||
self.do_test_hit_ratelimits(
|
||||
lambda: self.client_post(
|
||||
"/accounts/find/", {"emails": "new@zulip.com,new2@zulip.com"}
|
||||
),
|
||||
assert_func=assert_func,
|
||||
)
|
||||
finally:
|
||||
remove_ratelimit_rule(1, 10, domain="find_account_by_ip")
|
||||
|
||||
@skipUnless(settings.ZILENCER_ENABLED, "requires zilencer")
|
||||
def test_hit_ratelimits_as_remote_server(self) -> None:
|
||||
add_ratelimit_rule(1, 5, domain="api_by_remote_server")
|
||||
|
|
|
@ -711,6 +711,17 @@ def find_account(request: HttpRequest) -> HttpResponse:
|
|||
form = FindMyTeamForm(request.POST)
|
||||
if form.is_valid():
|
||||
emails = form.cleaned_data["emails"]
|
||||
for i in range(len(emails)):
|
||||
try:
|
||||
rate_limit_request_by_ip(request, domain="find_account_by_ip")
|
||||
except RateLimited as e:
|
||||
assert e.secs_to_freedom is not None
|
||||
return render(
|
||||
request,
|
||||
"zerver/rate_limit_exceeded.html",
|
||||
context={"retry_after": int(e.secs_to_freedom)},
|
||||
status=429,
|
||||
)
|
||||
|
||||
# Django doesn't support __iexact__in lookup with EmailField, so we have
|
||||
# to use Qs to get around that without needing to do multiple queries.
|
||||
|
|
|
@ -387,6 +387,9 @@ RATE_LIMITING_RULES = {
|
|||
"create_realm_by_ip": [
|
||||
(1800, 5),
|
||||
],
|
||||
"find_account_by_ip": [
|
||||
(3600, 10),
|
||||
],
|
||||
"password_reset_form_by_email": [
|
||||
(3600, 2), # 2 reset emails per hour
|
||||
(86400, 5), # 5 per day
|
||||
|
|
|
@ -265,6 +265,7 @@ RATE_LIMITING_RULES: Dict[str, List[Tuple[int, int]]] = {
|
|||
"api_by_remote_server": [],
|
||||
"authenticate_by_username": [],
|
||||
"create_realm_by_ip": [],
|
||||
"find_account_by_ip": [],
|
||||
"password_reset_form_by_email": [],
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue