mirror of
https://github.com/zulip/zulip.git
synced 2025-11-11 17:36:27 +00:00
Use standard functions for parsing/validating email addresses.
This adds two new functions for parsing out the domain and username
from an email address, and switches our backend to use them and
django.core.validators.valid_email() rather than custom parsing and
raw email.split("@").
(imported from commit 3d6e997d66908811eccb5f82f2f7fe349b40f238)
This commit is contained in:
@@ -9,7 +9,8 @@ from zephyr.models import Realm, Stream, UserProfile, UserActivity, \
|
|||||||
DefaultStream, UserPresence, MAX_SUBJECT_LENGTH, \
|
DefaultStream, UserPresence, MAX_SUBJECT_LENGTH, \
|
||||||
MAX_MESSAGE_LENGTH, get_client, get_stream, get_recipient, get_huddle, \
|
MAX_MESSAGE_LENGTH, get_client, get_stream, get_recipient, get_huddle, \
|
||||||
get_user_profile_by_id, PreregistrationUser, get_display_recipient, \
|
get_user_profile_by_id, PreregistrationUser, get_display_recipient, \
|
||||||
to_dict_cache_key, get_realm, stringify_message_dict, bulk_get_recipients
|
to_dict_cache_key, get_realm, stringify_message_dict, bulk_get_recipients, \
|
||||||
|
email_to_domain, email_to_username
|
||||||
from django.db import transaction, IntegrityError
|
from django.db import transaction, IntegrityError
|
||||||
from django.db.models import F, Q
|
from django.db.models import F, Q
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@@ -190,7 +191,7 @@ def create_mit_user_if_needed(realm, email):
|
|||||||
try:
|
try:
|
||||||
# Forge a user for this person
|
# Forge a user for this person
|
||||||
return create_user(email, initial_password(email), realm,
|
return create_user(email, initial_password(email), realm,
|
||||||
compute_mit_user_fullname(email), email.split("@")[0],
|
compute_mit_user_fullname(email), email_to_username(email),
|
||||||
active=False)
|
active=False)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
# Unless we raced with another thread doing the same
|
# Unless we raced with another thread doing the same
|
||||||
@@ -1358,12 +1359,14 @@ def do_invite_users(user_profile, invitee_emails, streams):
|
|||||||
if email == '':
|
if email == '':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not validators.email_re.match(email):
|
try:
|
||||||
|
validators.validate_email(email)
|
||||||
|
except ValidationError:
|
||||||
errors.append((email, "Invalid address."))
|
errors.append((email, "Invalid address."))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if user_profile.realm.restricted_to_domain and \
|
if user_profile.realm.restricted_to_domain and \
|
||||||
email.split('@', 1)[-1].lower() != user_profile.realm.domain.lower():
|
email_to_domain(email).lower() != user_profile.realm.domain.lower():
|
||||||
errors.append((email, "Outside your domain."))
|
errors.append((email, "Outside your domain."))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
from zephyr.lib.initial_password import initial_password
|
from zephyr.lib.initial_password import initial_password
|
||||||
from zephyr.models import Realm, Stream, UserProfile, Huddle, \
|
from zephyr.models import Realm, Stream, UserProfile, Huddle, \
|
||||||
Subscription, Recipient, Client, get_huddle_hash
|
Subscription, Recipient, Client, get_huddle_hash, email_to_domain
|
||||||
from zephyr.lib.create_user import create_user_profile
|
from zephyr.lib.create_user import create_user_profile
|
||||||
|
|
||||||
def bulk_create_realms(realm_list):
|
def bulk_create_realms(realm_list):
|
||||||
@@ -31,7 +31,7 @@ def bulk_create_users(realms, users_raw):
|
|||||||
# Now create user_profiles
|
# Now create user_profiles
|
||||||
profiles_to_create = []
|
profiles_to_create = []
|
||||||
for (email, full_name, short_name, active) in users:
|
for (email, full_name, short_name, active) in users:
|
||||||
domain = email.split('@')[1]
|
domain = email_to_domain(email)
|
||||||
profile = create_user_profile(realms[domain], email,
|
profile = create_user_profile(realms[domain], email,
|
||||||
initial_password(email), active, False,
|
initial_password(email), active, False,
|
||||||
full_name, short_name, None)
|
full_name, short_name, None)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from django.core.exceptions import ValidationError
|
|||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
|
|
||||||
from zephyr.models import Realm
|
from zephyr.models import Realm, email_to_username
|
||||||
from zephyr.lib.actions import do_create_user
|
from zephyr.lib.actions import do_create_user
|
||||||
from zephyr.views import notify_new_user
|
from zephyr.views import notify_new_user
|
||||||
from zephyr.lib.initial_password import initial_password
|
from zephyr.lib.initial_password import initial_password
|
||||||
@@ -67,7 +67,7 @@ parameters, or specify no parameters for interactive user creation.""")
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
notify_new_user(do_create_user(email, initial_password(email),
|
notify_new_user(do_create_user(email, initial_password(email),
|
||||||
realm, full_name, email.split('@')[0]),
|
realm, full_name, email_to_username(email)),
|
||||||
internal=True)
|
internal=True)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
raise CommandError("User already exists.")
|
raise CommandError("User already exists.")
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ from django.utils.timezone import now
|
|||||||
from django.contrib.sites.models import Site
|
from django.contrib.sites.models import Site
|
||||||
from zephyr.models import Message, UserProfile, Stream, Recipient, Client, \
|
from zephyr.models import Message, UserProfile, Stream, Recipient, Client, \
|
||||||
Subscription, Huddle, get_huddle, Realm, UserMessage, \
|
Subscription, Huddle, get_huddle, Realm, UserMessage, \
|
||||||
get_huddle_hash, clear_database, get_client, get_user_profile_by_id
|
get_huddle_hash, clear_database, get_client, get_user_profile_by_id, \
|
||||||
|
email_to_domain, email_to_username
|
||||||
from zephyr.lib.actions import do_send_message, set_default_streams, \
|
from zephyr.lib.actions import do_send_message, set_default_streams, \
|
||||||
do_activate_user, do_deactivate, do_change_password
|
do_activate_user, do_deactivate, do_change_password
|
||||||
from zephyr.lib.parallel import run_parallel
|
from zephyr.lib.parallel import run_parallel
|
||||||
@@ -32,7 +33,7 @@ settings.TORNADO_SERVER = None
|
|||||||
def create_users(realms, name_list):
|
def create_users(realms, name_list):
|
||||||
user_set = set()
|
user_set = set()
|
||||||
for full_name, email in name_list:
|
for full_name, email in name_list:
|
||||||
(short_name, domain) = email.split("@")
|
short_name = email_to_username(email)
|
||||||
user_set.add((email, full_name, short_name, True))
|
user_set.add((email, full_name, short_name, True))
|
||||||
bulk_create_users(realms, user_set)
|
bulk_create_users(realms, user_set)
|
||||||
|
|
||||||
@@ -336,7 +337,7 @@ def restore_saved_messages():
|
|||||||
|
|
||||||
sender_email = old_message["sender_email"]
|
sender_email = old_message["sender_email"]
|
||||||
|
|
||||||
domain = sender_email.split('@')[1]
|
domain = email_to_domain(sender_email)
|
||||||
realm_set.add(domain)
|
realm_set.add(domain)
|
||||||
|
|
||||||
if old_message["sender_email"] not in email_set:
|
if old_message["sender_email"] not in email_set:
|
||||||
@@ -447,7 +448,7 @@ def restore_saved_messages():
|
|||||||
message = Message()
|
message = Message()
|
||||||
|
|
||||||
sender_email = old_message["sender_email"]
|
sender_email = old_message["sender_email"]
|
||||||
domain = sender_email.split('@')[1]
|
domain = email_to_domain(sender_email)
|
||||||
realm = realms[domain]
|
realm = realms[domain]
|
||||||
|
|
||||||
message.sender = users[sender_email]
|
message.sender = users[sender_email]
|
||||||
|
|||||||
@@ -72,6 +72,18 @@ class Realm(models.Model):
|
|||||||
('administer', "Administer a realm"),
|
('administer', "Administer a realm"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# These functions should only be used on email addresses that have
|
||||||
|
# been validated via django.core.validators.validate_email
|
||||||
|
#
|
||||||
|
# Note that we need to use some care, since can you have multiple @-signs; e.g.
|
||||||
|
# "tabbott@test"@humbughq.com
|
||||||
|
# is valid email address
|
||||||
|
def email_to_username(email):
|
||||||
|
return "@".join(email.split("@")[:-1])
|
||||||
|
|
||||||
|
def email_to_domain(email):
|
||||||
|
return email.split("@")[-1]
|
||||||
|
|
||||||
class UserProfile(AbstractBaseUser, PermissionsMixin):
|
class UserProfile(AbstractBaseUser, PermissionsMixin):
|
||||||
# Fields from models.AbstractUser minus last_name and first_name,
|
# Fields from models.AbstractUser minus last_name and first_name,
|
||||||
# which we don't use; email is modified to make it indexed and unique.
|
# which we don't use; email is modified to make it indexed and unique.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from django.db.models import Q
|
|||||||
from zephyr.models import Message, UserProfile, Stream, Recipient, Subscription, \
|
from zephyr.models import Message, UserProfile, Stream, Recipient, Subscription, \
|
||||||
get_display_recipient, Realm, Client, \
|
get_display_recipient, Realm, Client, \
|
||||||
PreregistrationUser, UserMessage, \
|
PreregistrationUser, UserMessage, \
|
||||||
get_user_profile_by_email
|
get_user_profile_by_email, email_to_domain
|
||||||
from zephyr.tornadoviews import json_get_updates, api_get_messages
|
from zephyr.tornadoviews import json_get_updates, api_get_messages
|
||||||
from zephyr.decorator import RespondAsynchronously, RequestVariableConversionError, profiled
|
from zephyr.decorator import RespondAsynchronously, RequestVariableConversionError, profiled
|
||||||
from zephyr.lib.initial_password import initial_password
|
from zephyr.lib.initial_password import initial_password
|
||||||
@@ -2558,7 +2558,7 @@ class UserPresenceTests(AuthedTestCase):
|
|||||||
self.assertEqual(json['presences'][email][client]['status'], 'idle')
|
self.assertEqual(json['presences'][email][client]['status'], 'idle')
|
||||||
# We only want @humbughq.com emails
|
# We only want @humbughq.com emails
|
||||||
for email in json['presences'].keys():
|
for email in json['presences'].keys():
|
||||||
self.assertEqual(email.split('@')[1], 'humbughq.com')
|
self.assertEqual(email_to_domain(email), 'humbughq.com')
|
||||||
|
|
||||||
class UnreadCountTests(AuthedTestCase):
|
class UnreadCountTests(AuthedTestCase):
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ from zephyr.models import Message, UserProfile, Stream, Subscription, \
|
|||||||
PreregistrationUser, get_client, MitUser, UserActivity, \
|
PreregistrationUser, get_client, MitUser, UserActivity, \
|
||||||
MAX_SUBJECT_LENGTH, get_stream, bulk_get_streams, UserPresence, \
|
MAX_SUBJECT_LENGTH, get_stream, bulk_get_streams, UserPresence, \
|
||||||
get_recipient, valid_stream_name, to_dict_cache_key, to_dict_cache_key_id, \
|
get_recipient, valid_stream_name, to_dict_cache_key, to_dict_cache_key_id, \
|
||||||
extract_message_dict, stringify_message_dict, parse_usermessage_flags
|
extract_message_dict, stringify_message_dict, parse_usermessage_flags, \
|
||||||
|
email_to_domain, email_to_username
|
||||||
from zephyr.lib.actions import do_remove_subscription, bulk_remove_subscriptions, \
|
from zephyr.lib.actions import do_remove_subscription, bulk_remove_subscriptions, \
|
||||||
do_change_password, create_mit_user_if_needed, do_change_full_name, \
|
do_change_password, create_mit_user_if_needed, do_change_full_name, \
|
||||||
do_change_enable_desktop_notifications, do_change_enter_sends, do_change_enable_sounds, \
|
do_change_enable_desktop_notifications, do_change_enter_sends, do_change_enable_sounds, \
|
||||||
@@ -233,6 +234,7 @@ def accounts_register(request):
|
|||||||
email = prereg_user.email
|
email = prereg_user.email
|
||||||
mit_beta_user = isinstance(confirmation.content_object, MitUser)
|
mit_beta_user = isinstance(confirmation.content_object, MitUser)
|
||||||
|
|
||||||
|
validators.validate_email(email)
|
||||||
# If someone invited you, you are joining their realm regardless
|
# If someone invited you, you are joining their realm regardless
|
||||||
# of your e-mail address.
|
# of your e-mail address.
|
||||||
#
|
#
|
||||||
@@ -240,7 +242,7 @@ def accounts_register(request):
|
|||||||
if not mit_beta_user and prereg_user.referred_by:
|
if not mit_beta_user and prereg_user.referred_by:
|
||||||
domain = prereg_user.referred_by.realm.domain
|
domain = prereg_user.referred_by.realm.domain
|
||||||
else:
|
else:
|
||||||
domain = email.split('@')[-1]
|
domain = email_to_domain(email)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if mit_beta_user:
|
if mit_beta_user:
|
||||||
@@ -259,7 +261,7 @@ def accounts_register(request):
|
|||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
password = form.cleaned_data['password']
|
password = form.cleaned_data['password']
|
||||||
full_name = form.cleaned_data['full_name']
|
full_name = form.cleaned_data['full_name']
|
||||||
short_name = email.split('@')[0]
|
short_name = email_to_username(email)
|
||||||
(realm, _) = Realm.objects.get_or_create(domain=domain)
|
(realm, _) = Realm.objects.get_or_create(domain=domain)
|
||||||
first_in_realm = len(UserProfile.objects.filter(realm=realm)) == 0
|
first_in_realm = len(UserProfile.objects.filter(realm=realm)) == 0
|
||||||
|
|
||||||
@@ -328,7 +330,7 @@ def accounts_register(request):
|
|||||||
@login_required(login_url = settings.HOME_NOT_LOGGED_IN)
|
@login_required(login_url = settings.HOME_NOT_LOGGED_IN)
|
||||||
def accounts_accept_terms(request):
|
def accounts_accept_terms(request):
|
||||||
email = request.user.email
|
email = request.user.email
|
||||||
company_name = email.split('@')[-1]
|
domain = email_to_domain(email)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = ToSForm(request.POST)
|
form = ToSForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@@ -347,7 +349,7 @@ def accounts_accept_terms(request):
|
|||||||
else:
|
else:
|
||||||
form = ToSForm()
|
form = ToSForm()
|
||||||
return render_to_response('zephyr/accounts_accept_terms.html',
|
return render_to_response('zephyr/accounts_accept_terms.html',
|
||||||
{ 'form': form, 'company_name': company_name, 'email': email },
|
{ 'form': form, 'company_name': domain, 'email': email },
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
def api_endpoint_docs(request):
|
def api_endpoint_docs(request):
|
||||||
@@ -1012,14 +1014,14 @@ def mit_to_mit(user_profile, email):
|
|||||||
# We have to handle this specially, inferring the domain from the
|
# We have to handle this specially, inferring the domain from the
|
||||||
# e-mail address, because the recipient may not existing in Humbug
|
# e-mail address, because the recipient may not existing in Humbug
|
||||||
# and we may need to make a stub MIT user on the fly.
|
# and we may need to make a stub MIT user on the fly.
|
||||||
if not validators.email_re.match(email):
|
try:
|
||||||
|
validators.validate_email(email)
|
||||||
|
except ValidationError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if user_profile.realm.domain != "mit.edu":
|
domain = email_to_domain(email)
|
||||||
return False
|
|
||||||
|
|
||||||
domain = email.split("@", 1)[1]
|
return user_profile.realm.domain == "mit.edu" and domain == "mit.edu"
|
||||||
return user_profile.realm.domain == domain
|
|
||||||
|
|
||||||
def create_mirrored_message_users(request, user_profile, recipients):
|
def create_mirrored_message_users(request, user_profile, recipients):
|
||||||
if "sender" not in request.POST:
|
if "sender" not in request.POST:
|
||||||
|
|||||||
Reference in New Issue
Block a user