Skip to content

Commit

Permalink
rate limit account creations
Browse files Browse the repository at this point in the history
  • Loading branch information
Changaco committed Sep 17, 2017
1 parent 1adb441 commit 3e6621a
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 1 deletion.
3 changes: 3 additions & 0 deletions liberapay/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ def check_bits(bits):
'log-in.email.not-verified': (2, 60*60*24), # 2 per day
'log-in.email.verified': (10, 60*60*24), # 10 per day
'log-in.password': (3, 60*60), # 3 per hour
'sign-up.ip-addr': (2, 60*60), # 2 per hour per IP address
'sign-up.ip-net': (15, 15*60), # 15 per 15 minutes per IP network
'sign-up.ip-version': (15, 15*60), # 15 per 15 minutes per IP version
}

SEPA = set("""
Expand Down
12 changes: 12 additions & 0 deletions liberapay/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ def msg(self, _):
)


class TooManySignUps(LazyResponseXXX):
code = 429
def msg(self, _):
return _(
"Too many accounts have been created recently. This either means that "
"a lot of people are trying to join Liberapay today, or that an attacker "
"is trying to overload our system. As a result we have to ask you to come "
"back later (e.g. in a few hours), or send an email to [email protected]. "
"We apologize for the inconvenience."
)


class BadPasswordSize(LazyResponse400):
def msg(self, _):
return _("The password must be at least {0} and at most {1} characters long.",
Expand Down
9 changes: 8 additions & 1 deletion liberapay/security/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
from pando import Response

from liberapay.constants import SESSION, SESSION_TIMEOUT
from liberapay.exceptions import LoginRequired, TooManyLoginEmails, TooManyPasswordLogins
from liberapay.exceptions import (
LoginRequired, TooManyLoginEmails, TooManyPasswordLogins, TooManySignUps
)
from liberapay.models.participant import Participant
from liberapay.utils import get_ip_net


class _ANON(object):
Expand Down Expand Up @@ -88,6 +91,10 @@ def sign_in_with_form_data(body, state):
email = body.pop('sign-in.email')
if not email:
raise response.error(400, 'email is required')
src_addr = state['request'].source
website.db.hit_rate_limit('sign-up.ip-addr', str(src_addr), TooManySignUps)
website.db.hit_rate_limit('sign-up.ip-net', get_ip_net(src_addr), TooManySignUps)
website.db.hit_rate_limit('sign-up.ip-version', src_addr.version, TooManySignUps)
with website.db.get_cursor() as c:
p = Participant.make_active(
kind, body.pop('sign-in.username', None),
Expand Down
7 changes: 7 additions & 0 deletions liberapay/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,3 +411,10 @@ def mkdir_p(path):
if e.errno == errno.EEXIST and os.path.isdir(path):
return
raise


def get_ip_net(addr):
if addr.max_prefixlen == 32:
return '.'.join(str(addr).split('.', 3)[:2])
else:
return hexlify(addr.packed[:4])

0 comments on commit 3e6621a

Please sign in to comment.