Browse Source

Rate limit team invites to 20/day

pull/248/head
Pēteris Caune 6 years ago
parent
commit
beae8e62b4
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
3 changed files with 27 additions and 2 deletions
  1. +16
    -0
      hc/accounts/tests/test_project.py
  2. +2
    -0
      hc/accounts/views.py
  3. +9
    -2
      hc/api/models.py

+ 16
- 0
hc/accounts/tests/test_project.py View File

@ -1,8 +1,10 @@
from django.core import mail
from django.conf import settings
from django.test.utils import override_settings
from hc.test import BaseTestCase
from hc.accounts.models import Member
from hc.api.models import TokenBucket
class ProjectTestCase(BaseTestCase):
@ -83,6 +85,20 @@ class ProjectTestCase(BaseTestCase):
" Alice's Project on %s" % settings.SITE_NAME)
self.assertEqual(mail.outbox[0].subject, subj)
@override_settings(SECRET_KEY="test-secret")
def test_it_rate_limits_invites(self):
obj = TokenBucket(value="invite-%d" % self.alice.id)
obj.tokens = 0
obj.save()
self.client.login(username="[email protected]", password="password")
form = {"invite_team_member": "1", "email": "[email protected]"}
r = self.client.post(self.url, form)
self.assertContains(r, "Too Many Requests")
self.assertEqual(len(mail.outbox), 0)
def test_it_requires_owner_to_add_team_member(self):
self.client.login(username="[email protected]", password="password")


+ 2
- 0
hc/accounts/views.py View File

@ -285,6 +285,8 @@ def project(request, code):
form = InviteTeamMemberForm(request.POST)
if form.is_valid():
if not TokenBucket.authorize_invite(request.user):
return render(request, "try_later.html")
email = form.cleaned_data["email"]
try:


+ 9
- 2
hc/api/models.py View File

@ -632,7 +632,7 @@ class TokenBucket(models.Model):
salted_encoded = (email + settings.SECRET_KEY).encode()
value = "em-%s" % hashlib.sha1(salted_encoded).hexdigest()
# 20 emails per 3600 seconds (1 hour):
# 20 login attempts for a single email per hour:
return TokenBucket.authorize(value, 20, 3600)
@staticmethod
@ -643,5 +643,12 @@ class TokenBucket(models.Model):
salted_encoded = (ip + settings.SECRET_KEY).encode()
value = "ip-%s" % hashlib.sha1(salted_encoded).hexdigest()
# 20 login attempts from a single IP per 3600 seconds (1 hour):
# 20 login attempts from a single IP per hour:
return TokenBucket.authorize(value, 20, 3600)
@staticmethod
def authorize_invite(user):
value = "invite-%d" % user.id
# 20 invites per day
return TokenBucket.authorize(value, 20, 3600 * 24)

Loading…
Cancel
Save