mirror of https://github.com/zulip/zulip.git
reset_password: Show user-facing page on rate-limit.
This commit is contained in:
parent
d3ecbf96a8
commit
c8badbd858
|
@ -326,13 +326,13 @@ class ZulipPasswordResetForm(PasswordResetForm):
|
|||
rate_limit_password_reset_form_by_email(email)
|
||||
rate_limit_request_by_ip(request, domain="sends_email_by_ip")
|
||||
except RateLimited:
|
||||
# TODO: Show an informative, user-facing error message.
|
||||
logging.info(
|
||||
"Too many password reset attempts for email %s from %s",
|
||||
email,
|
||||
request.META["REMOTE_ADDR"],
|
||||
)
|
||||
return
|
||||
# The view will handle the RateLimit exception and render an appropriate page
|
||||
raise
|
||||
|
||||
user: Optional[UserProfile] = None
|
||||
try:
|
||||
|
|
|
@ -227,6 +227,18 @@ class RateLimitTests(ZulipTestCase):
|
|||
is_json=False,
|
||||
)
|
||||
|
||||
@rate_limit_rule(1, 5, domain="sends_email_by_ip")
|
||||
def test_password_reset_rate_limiting(self) -> None:
|
||||
with self.assertLogs(level="INFO") as m:
|
||||
self.do_test_hit_ratelimits(
|
||||
lambda: self.client_post("/accounts/password/reset/", {"email": "new@zulip.com"}),
|
||||
is_json=False,
|
||||
)
|
||||
self.assertEqual(
|
||||
m.output,
|
||||
["INFO:root:Too many password reset attempts for email new@zulip.com from 127.0.0.1"],
|
||||
)
|
||||
|
||||
# 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.
|
||||
|
|
|
@ -51,6 +51,7 @@ from zerver.lib.exceptions import (
|
|||
JsonableError,
|
||||
PasswordAuthDisabledError,
|
||||
PasswordResetRequiredError,
|
||||
RateLimited,
|
||||
RealmDeactivatedError,
|
||||
UserDeactivatedError,
|
||||
)
|
||||
|
@ -992,11 +993,20 @@ def password_reset(request: HttpRequest) -> HttpResponse:
|
|||
)
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
response = DjangoPasswordResetView.as_view(
|
||||
template_name="zerver/reset.html",
|
||||
form_class=ZulipPasswordResetForm,
|
||||
success_url="/accounts/password/reset/done/",
|
||||
)(request)
|
||||
try:
|
||||
response = DjangoPasswordResetView.as_view(
|
||||
template_name="zerver/reset.html",
|
||||
form_class=ZulipPasswordResetForm,
|
||||
success_url="/accounts/password/reset/done/",
|
||||
)(request)
|
||||
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,
|
||||
)
|
||||
assert isinstance(response, HttpResponse)
|
||||
return response
|
||||
|
||||
|
|
Loading…
Reference in New Issue