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:
|
finally:
|
||||||
remove_ratelimit_rule(1, 5, domain="create_realm_by_ip")
|
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")
|
@skipUnless(settings.ZILENCER_ENABLED, "requires zilencer")
|
||||||
def test_hit_ratelimits_as_remote_server(self) -> None:
|
def test_hit_ratelimits_as_remote_server(self) -> None:
|
||||||
add_ratelimit_rule(1, 5, domain="api_by_remote_server")
|
add_ratelimit_rule(1, 5, domain="api_by_remote_server")
|
||||||
|
|
|
@ -711,6 +711,17 @@ def find_account(request: HttpRequest) -> HttpResponse:
|
||||||
form = FindMyTeamForm(request.POST)
|
form = FindMyTeamForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
emails = form.cleaned_data["emails"]
|
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
|
# 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.
|
# to use Qs to get around that without needing to do multiple queries.
|
||||||
|
|
|
@ -387,6 +387,9 @@ RATE_LIMITING_RULES = {
|
||||||
"create_realm_by_ip": [
|
"create_realm_by_ip": [
|
||||||
(1800, 5),
|
(1800, 5),
|
||||||
],
|
],
|
||||||
|
"find_account_by_ip": [
|
||||||
|
(3600, 10),
|
||||||
|
],
|
||||||
"password_reset_form_by_email": [
|
"password_reset_form_by_email": [
|
||||||
(3600, 2), # 2 reset emails per hour
|
(3600, 2), # 2 reset emails per hour
|
||||||
(86400, 5), # 5 per day
|
(86400, 5), # 5 per day
|
||||||
|
|
|
@ -265,6 +265,7 @@ RATE_LIMITING_RULES: Dict[str, List[Tuple[int, int]]] = {
|
||||||
"api_by_remote_server": [],
|
"api_by_remote_server": [],
|
||||||
"authenticate_by_username": [],
|
"authenticate_by_username": [],
|
||||||
"create_realm_by_ip": [],
|
"create_realm_by_ip": [],
|
||||||
|
"find_account_by_ip": [],
|
||||||
"password_reset_form_by_email": [],
|
"password_reset_form_by_email": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue