invitations: Limit realms to 100 invites per day.

To guard against using zulip invites as a vector for spam. Stopgap measure
until we figure out something better.
This commit is contained in:
Rishi Gupta 2017-11-29 16:53:09 -08:00 committed by Tim Abbott
parent 8dc0adbed8
commit 7d1c88f0fb
4 changed files with 54 additions and 0 deletions

View File

@ -3931,6 +3931,19 @@ def do_invite_users(user_profile: UserProfile,
streams: Iterable[Stream], streams: Iterable[Stream],
invite_as_admin: Optional[bool]=False, invite_as_admin: Optional[bool]=False,
body: Optional[str]=None) -> None: body: Optional[str]=None) -> None:
if settings.OPEN_REALM_CREATION:
# Discourage using invitation emails as a vector for carrying spam
sent_invites = Confirmation.objects.filter(
realm=user_profile.realm,
date_sent__gte=timezone_now() - datetime.timedelta(days=1),
type=Confirmation.INVITATION).count()
if len(invitee_emails) + sent_invites > user_profile.realm.max_invites:
raise InvitationError(
_("You do not have enough remaining invites; "
"try again with fewer emails, or contact %s. "
"No invitations were sent." % (settings.ZULIP_ADMINISTRATOR)),
[], sent_invitations=False)
validated_emails = [] # type: List[Text] validated_emails = [] # type: List[Text]
errors = [] # type: List[Tuple[Text, str]] errors = [] # type: List[Tuple[Text, str]]
skipped = [] # type: List[Tuple[Text, str]] skipped = [] # type: List[Tuple[Text, str]]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-11-30 04:58
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('zerver', '0124_stream_enable_notifications'),
]
operations = [
migrations.AddField(
model_name='realm',
name='max_invites',
field=models.IntegerField(default=100),
),
]

View File

@ -170,6 +170,8 @@ class Realm(models.Model):
authentication_methods = BitField(flags=AUTHENTICATION_FLAGS, authentication_methods = BitField(flags=AUTHENTICATION_FLAGS,
default=2**31 - 1) # type: BitHandler default=2**31 - 1) # type: BitHandler
waiting_period_threshold = models.PositiveIntegerField(default=0) # type: int waiting_period_threshold = models.PositiveIntegerField(default=0) # type: int
DEFAULT_MAX_INVITES = 100
max_invites = models.IntegerField(default=DEFAULT_MAX_INVITES) # type: int
# Define the types of the various automatically managed properties # Define the types of the various automatically managed properties
property_types = dict( property_types = dict(

View File

@ -665,6 +665,25 @@ earl-test@zulip.com""", ["Denmark"]))
self.check_sent_emails(["bob-test@zulip.com", "carol-test@zulip.com", self.check_sent_emails(["bob-test@zulip.com", "carol-test@zulip.com",
"dave-test@zulip.com", "earl-test@zulip.com"]) "dave-test@zulip.com", "earl-test@zulip.com"])
def test_invite_too_many_users(self) -> None:
# Only a light test of this pathway; e.g. doesn't test that
# the limit gets reset after 24 hours
self.login(self.example_email("iago"))
self.client_post("/json/invites",
{"invitee_emails": "1@zulip.com, 2@zulip.com",
"stream": ["Denmark"],
"custom_body": ''}),
self.assert_json_error(
self.client_post("/json/invites",
{"invitee_emails": ", ".join(
[str(i) for i in range(get_realm("zulip").max_invites - 1)]),
"stream": ["Denmark"],
"custom_body": ''}),
"You do not have enough remaining invites; "
"try again with fewer emails, or contact zulip-admin@example.com. "
"No invitations were sent.")
def test_missing_or_invalid_params(self) -> None: def test_missing_or_invalid_params(self) -> None:
""" """
Tests inviting with various missing or invalid parameters. Tests inviting with various missing or invalid parameters.