diff --git a/hc/accounts/decorators.py b/hc/accounts/decorators.py index 5c253136..49dd49d3 100644 --- a/hc/accounts/decorators.py +++ b/hc/accounts/decorators.py @@ -3,6 +3,7 @@ import secrets from django.core.signing import TimestampSigner, SignatureExpired from django.shortcuts import redirect, render +from hc.api.models import TokenBucket from hc.lib import emails @@ -25,6 +26,9 @@ def require_sudo_mode(f): if _session_unsign(request, "sudo", 1800) == "active": return f(request, *args, **kwds) + if not TokenBucket.authorize_sudo_code(request.user): + return render(request, "try_later.html") + # has the user submitted a code to enter sudo mode? if "sudo_code" in request.POST: ours = _session_unsign(request, "sudo_code", 900) diff --git a/hc/api/models.py b/hc/api/models.py index 1612a80d..b756f164 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -884,3 +884,10 @@ class TokenBucket(models.Model): # 10 messages for a single chat per minute: return TokenBucket.authorize(value, 10, 60) + + @staticmethod + def authorize_sudo_code(user): + value = "sudo-%d" % user.id + + # 10 sudo attempts per day + return TokenBucket.authorize(value, 10, 3600 * 24) diff --git a/templates/accounts/sudo.html b/templates/accounts/sudo.html index 1fcccefa..6a9a853b 100644 --- a/templates/accounts/sudo.html +++ b/templates/accounts/sudo.html @@ -16,11 +16,16 @@