Improve password reset rate limit.

Used django-ratelimit instead of django-ratelimit-backend
to configure two different rate limit configurations for same
endpoint.

PROD-1708
This commit is contained in:
Waheed Ahmed
2020-07-01 18:07:23 +05:00
parent a6a69224d1
commit 4f80fd6540
8 changed files with 81 additions and 121 deletions

View File

@@ -3,9 +3,6 @@ A utility class which wraps the RateLimitMixin 3rd party class to do bad request
which can be used for rate limiting
"""
from datetime import datetime, timedelta
from django.conf import settings
from ratelimitbackend.backends import RateLimitMixin
@@ -32,72 +29,3 @@ class BadRequestRateLimiter(RequestRateLimiter):
Default rate limit is 30 requests for every 5 minutes.
"""
pass
class PasswordResetEmailRateLimiter(RequestRateLimiter):
"""
Rate limiting requests to send password reset emails.
"""
email_rate_limit = getattr(settings, 'PASSWORD_RESET_EMAIL_RATE_LIMIT', {})
requests = email_rate_limit.get('no_of_emails', 1)
cache_timeout_seconds = email_rate_limit.get('per_seconds', 60)
reset_email_cache_prefix = 'resetemail'
def key(self, request, dt):
"""
Returns IP based cache key.
"""
return '%s-%s-%s' % (
self.reset_email_cache_prefix,
self.get_ip(request),
dt.strftime('%Y%m%d%H%M'),
)
def email_key(self, request, dt):
"""
Returns email based cache key.
"""
return '%s-%s-%s' % (
self.reset_email_cache_prefix,
self.get_email(request),
dt.strftime('%Y%m%d%H%M'),
)
def expire_after(self):
"""
Returns timeout for cache keys.
"""
return self.cache_timeout_seconds
def get_email(self, request):
"""
Returns email id for cache key.
"""
user = request.user
# Prefer logged-in user's email
email = user.email if user.is_authenticated else request.POST.get('email')
return email
def keys_to_check(self, request):
"""
Return list of IP and email based keys.
"""
keys = super(PasswordResetEmailRateLimiter, self).keys_to_check(request)
now = datetime.now()
email_keys = [
self.email_key(
request,
now - timedelta(minutes=minute),
) for minute in range(self.minutes + 1)
]
keys.extend(email_keys)
return keys
def tick_request_counter(self, request):
"""
Ticks any counters used to compute when rate limit has been reached.
"""
for key in self.keys_to_check(request):
self.cache_incr(key)