mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 21:43:21 +00:00
refactor: Extract zerver/lib/email_validation.py.
This commit is contained in:
@@ -16,6 +16,7 @@ from jinja2 import Markup as mark_safe
|
||||
|
||||
from zerver.lib.actions import do_change_password, email_not_system_bot, \
|
||||
validate_email_not_already_in_realm
|
||||
from zerver.lib.email_validation import email_allowed_for_realm
|
||||
from zerver.lib.name_restrictions import is_reserved_subdomain, is_disposable_domain
|
||||
from zerver.lib.rate_limiter import RateLimited, get_rate_limit_result_from_request, \
|
||||
RateLimitedObject, rate_limit_entity
|
||||
@@ -25,7 +26,7 @@ from zerver.lib.subdomains import get_subdomain, is_root_domain_available
|
||||
from zerver.lib.users import check_full_name
|
||||
from zerver.models import Realm, get_user_by_delivery_email, UserProfile, get_realm, \
|
||||
email_to_domain, \
|
||||
email_allowed_for_realm, DisposableEmailError, DomainNotAllowedForRealmError, \
|
||||
DisposableEmailError, DomainNotAllowedForRealmError, \
|
||||
EmailContainsPlusError
|
||||
from zproject.backends import email_auth_enabled, email_belongs_to_ldap, check_password_strength
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity,
|
||||
ScheduledEmail, MAX_TOPIC_NAME_LENGTH, \
|
||||
MAX_MESSAGE_LENGTH, get_client, get_stream, \
|
||||
get_user_profile_by_id, PreregistrationUser, \
|
||||
get_realm_email_validator, email_to_username, \
|
||||
email_to_username, \
|
||||
get_user_by_delivery_email, get_stream_cache_key, active_non_guest_user_ids, \
|
||||
UserActivityInterval, active_user_ids, get_active_streams, \
|
||||
realm_filters_for_realm, RealmFilter, stream_name_in_use, \
|
||||
@@ -117,6 +117,7 @@ from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity,
|
||||
|
||||
from zerver.lib.alert_words import get_alert_word_automaton
|
||||
from zerver.lib.avatar import avatar_url, avatar_url_from_dict
|
||||
from zerver.lib.email_validation import get_realm_email_validator
|
||||
from zerver.lib.stream_recipient import StreamRecipientMap
|
||||
from zerver.lib.validator import check_widget_content
|
||||
from zerver.lib.widget import do_widget_post_save_actions
|
||||
|
||||
86
zerver/lib/email_validation.py
Normal file
86
zerver/lib/email_validation.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from typing import Callable
|
||||
|
||||
from zerver.lib.name_restrictions import is_disposable_domain
|
||||
|
||||
# TODO: Move DisposableEmailError, etc. into here.
|
||||
from zerver.models import (
|
||||
email_to_username,
|
||||
email_to_domain,
|
||||
DisposableEmailError,
|
||||
DomainNotAllowedForRealmError,
|
||||
EmailContainsPlusError,
|
||||
Realm,
|
||||
RealmDomain,
|
||||
)
|
||||
|
||||
def validate_disposable(email: str) -> None:
|
||||
if is_disposable_domain(email_to_domain(email)):
|
||||
raise DisposableEmailError
|
||||
|
||||
def get_realm_email_validator(realm: Realm) -> Callable[[str], None]:
|
||||
if not realm.emails_restricted_to_domains:
|
||||
# Should we also do '+' check for non-resticted realms?
|
||||
if realm.disallow_disposable_email_addresses:
|
||||
return validate_disposable
|
||||
|
||||
# allow any email through
|
||||
return lambda email: None
|
||||
|
||||
'''
|
||||
RESTRICTIVE REALMS:
|
||||
|
||||
Some realms only allow emails within a set
|
||||
of domains that are configured in RealmDomain.
|
||||
|
||||
We get the set of domains up front so that
|
||||
folks can validate multiple emails without
|
||||
multiple round trips to the database.
|
||||
'''
|
||||
|
||||
query = RealmDomain.objects.filter(realm=realm)
|
||||
rows = list(query.values('allow_subdomains', 'domain'))
|
||||
|
||||
allowed_domains = {
|
||||
r['domain'] for r in rows
|
||||
}
|
||||
|
||||
allowed_subdomains = {
|
||||
r['domain'] for r in rows
|
||||
if r['allow_subdomains']
|
||||
}
|
||||
|
||||
def validate(email: str) -> None:
|
||||
'''
|
||||
We don't have to do a "disposable" check for restricted
|
||||
domains, since the realm is already giving us
|
||||
a small whitelist.
|
||||
'''
|
||||
|
||||
if '+' in email_to_username(email):
|
||||
raise EmailContainsPlusError
|
||||
|
||||
domain = email_to_domain(email)
|
||||
|
||||
if domain in allowed_domains:
|
||||
return
|
||||
|
||||
while len(domain) > 0:
|
||||
subdomain, sep, domain = domain.partition('.')
|
||||
if domain in allowed_subdomains:
|
||||
return
|
||||
|
||||
raise DomainNotAllowedForRealmError
|
||||
|
||||
return validate
|
||||
|
||||
# Is a user with the given email address allowed to be in the given realm?
|
||||
# (This function does not check whether the user has been invited to the realm.
|
||||
# So for invite-only realms, this is the test for whether a user can be invited,
|
||||
# not whether the user can sign up currently.)
|
||||
def email_allowed_for_realm(email: str, realm: Realm) -> None:
|
||||
'''
|
||||
Avoid calling this in a loop!
|
||||
Instead, call get_realm_email_validator()
|
||||
outside of the loop.
|
||||
'''
|
||||
get_realm_email_validator(realm)(email)
|
||||
@@ -5,8 +5,8 @@ from django.core.management.base import CommandError
|
||||
|
||||
from confirmation.models import Confirmation, create_confirmation_link
|
||||
from zerver.lib.management import ZulipBaseCommand
|
||||
from zerver.models import DomainNotAllowedForRealmError, PreregistrationUser, \
|
||||
email_allowed_for_realm
|
||||
from zerver.models import DomainNotAllowedForRealmError, PreregistrationUser
|
||||
from zerver.lib.email_validation import email_allowed_for_realm
|
||||
|
||||
|
||||
class Command(ZulipBaseCommand):
|
||||
|
||||
@@ -30,7 +30,6 @@ from zerver.lib import cache
|
||||
from zerver.lib.validator import check_int, \
|
||||
check_short_string, check_long_string, validate_choice_field, check_date, \
|
||||
check_url, check_list
|
||||
from zerver.lib.name_restrictions import is_disposable_domain
|
||||
from zerver.lib.types import Validator, ExtendedValidator, \
|
||||
ProfileDataElement, ProfileData, RealmUserValidator, \
|
||||
ExtendedFieldElement, UserFieldElement, FieldElement, \
|
||||
@@ -570,78 +569,6 @@ class DisposableEmailError(Exception):
|
||||
class EmailContainsPlusError(Exception):
|
||||
pass
|
||||
|
||||
# Is a user with the given email address allowed to be in the given realm?
|
||||
# (This function does not check whether the user has been invited to the realm.
|
||||
# So for invite-only realms, this is the test for whether a user can be invited,
|
||||
# not whether the user can sign up currently.)
|
||||
def email_allowed_for_realm(email: str, realm: Realm) -> None:
|
||||
'''
|
||||
Avoid calling this in a loop!
|
||||
Instead, call get_realm_email_validator()
|
||||
outside of the loop.
|
||||
'''
|
||||
get_realm_email_validator(realm)(email)
|
||||
|
||||
def validate_disposable(email: str) -> None:
|
||||
if is_disposable_domain(email_to_domain(email)):
|
||||
raise DisposableEmailError
|
||||
|
||||
def get_realm_email_validator(realm: Realm) -> Callable[[str], None]:
|
||||
if not realm.emails_restricted_to_domains:
|
||||
# Should we also do '+' check for non-resticted realms?
|
||||
if realm.disallow_disposable_email_addresses:
|
||||
return validate_disposable
|
||||
|
||||
# allow any email through
|
||||
return lambda email: None
|
||||
|
||||
'''
|
||||
RESTRICTIVE REALMS:
|
||||
|
||||
Some realms only allow emails within a set
|
||||
of domains that are configured in RealmDomain.
|
||||
|
||||
We get the set of domains up front so that
|
||||
folks can validate multiple emails without
|
||||
multiple round trips to the database.
|
||||
'''
|
||||
|
||||
query = RealmDomain.objects.filter(realm=realm)
|
||||
rows = list(query.values('allow_subdomains', 'domain'))
|
||||
|
||||
allowed_domains = {
|
||||
r['domain'] for r in rows
|
||||
}
|
||||
|
||||
allowed_subdomains = {
|
||||
r['domain'] for r in rows
|
||||
if r['allow_subdomains']
|
||||
}
|
||||
|
||||
def validate(email: str) -> None:
|
||||
'''
|
||||
We don't have to do a "disposable" check for restricted
|
||||
domains, since the realm is already giving us
|
||||
a small whitelist.
|
||||
'''
|
||||
|
||||
if '+' in email_to_username(email):
|
||||
raise EmailContainsPlusError
|
||||
|
||||
domain = email_to_domain(email)
|
||||
|
||||
if domain in allowed_domains:
|
||||
return
|
||||
|
||||
while len(domain) > 0:
|
||||
subdomain, sep, domain = domain.partition('.')
|
||||
if domain in allowed_subdomains:
|
||||
return
|
||||
|
||||
raise DomainNotAllowedForRealmError
|
||||
|
||||
return validate
|
||||
|
||||
def get_realm_domains(realm: Realm) -> List[Dict[str, str]]:
|
||||
return list(realm.realmdomain_set.values('domain', 'allow_subdomains'))
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@ from django.db.utils import IntegrityError
|
||||
from zerver.lib.actions import do_change_is_admin, \
|
||||
do_change_realm_domain, do_create_realm, \
|
||||
do_remove_realm_domain
|
||||
from zerver.lib.email_validation import email_allowed_for_realm
|
||||
from zerver.lib.domains import validate_domain
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
from zerver.models import email_allowed_for_realm, get_realm, \
|
||||
from zerver.models import get_realm, \
|
||||
RealmDomain, DomainNotAllowedForRealmError
|
||||
|
||||
import ujson
|
||||
|
||||
@@ -11,10 +11,11 @@ from django.core.exceptions import ValidationError
|
||||
from django.core import validators
|
||||
from zerver.context_processors import get_realm_from_request, login_context
|
||||
from zerver.models import UserProfile, Realm, Stream, MultiuseInvite, \
|
||||
name_changes_disabled, email_to_username, email_allowed_for_realm, \
|
||||
name_changes_disabled, email_to_username, \
|
||||
get_realm, get_user_by_delivery_email, get_default_stream_groups, DisposableEmailError, \
|
||||
DomainNotAllowedForRealmError, get_source_profile, EmailContainsPlusError, \
|
||||
PreregistrationUser
|
||||
from zerver.lib.email_validation import email_allowed_for_realm
|
||||
from zerver.lib.send_email import send_email, FromAddress
|
||||
from zerver.lib.actions import do_change_password, do_change_full_name, \
|
||||
do_activate_user, do_create_user, do_create_realm, \
|
||||
|
||||
@@ -17,6 +17,7 @@ from zerver.lib.actions import do_change_avatar_fields, do_change_bot_owner, \
|
||||
do_update_user_custom_profile_data_if_changed, check_remove_custom_profile_field_value
|
||||
from zerver.lib.avatar import avatar_url, get_gravatar_url
|
||||
from zerver.lib.bot_config import set_bot_config
|
||||
from zerver.lib.email_validation import email_allowed_for_realm
|
||||
from zerver.lib.exceptions import CannotDeactivateLastUserError
|
||||
from zerver.lib.integrations import EMBEDDED_BOTS
|
||||
from zerver.lib.request import has_request_variables, REQ
|
||||
@@ -29,7 +30,7 @@ from zerver.lib.users import check_valid_bot_type, check_bot_creation_policy, \
|
||||
access_bot_by_id, add_service, access_user_by_id, check_bot_name_available, \
|
||||
validate_user_custom_profile_data, get_raw_user_data, get_api_key
|
||||
from zerver.lib.utils import generate_api_key, generate_random_token
|
||||
from zerver.models import UserProfile, Stream, Message, email_allowed_for_realm, \
|
||||
from zerver.models import UserProfile, Stream, Message, \
|
||||
get_user_by_delivery_email, Service, get_user_including_cross_realm, \
|
||||
DomainNotAllowedForRealmError, DisposableEmailError, get_user_profile_by_id_in_realm, \
|
||||
EmailContainsPlusError, get_user_by_id_in_realm_including_cross_realm, Realm, \
|
||||
|
||||
@@ -54,6 +54,7 @@ from zerver.lib.actions import do_create_user, do_reactivate_user, do_deactivate
|
||||
from zerver.lib.avatar import is_avatar_new, avatar_url
|
||||
from zerver.lib.avatar_hash import user_avatar_content_hash
|
||||
from zerver.lib.dev_ldap_directory import init_fakeldap
|
||||
from zerver.lib.email_validation import email_allowed_for_realm
|
||||
from zerver.lib.mobile_auth_otp import is_valid_otp
|
||||
from zerver.lib.rate_limiter import clear_history, rate_limit_request_by_entity, RateLimitedObject
|
||||
from zerver.lib.request import JsonableError
|
||||
@@ -61,7 +62,7 @@ from zerver.lib.users import check_full_name, validate_user_custom_profile_field
|
||||
from zerver.lib.redis_utils import get_redis_client, get_dict_from_redis, put_dict_in_redis
|
||||
from zerver.models import CustomProfileField, DisposableEmailError, DomainNotAllowedForRealmError, \
|
||||
EmailContainsPlusError, PreregistrationUser, UserProfile, Realm, custom_profile_fields_for_realm, \
|
||||
email_allowed_for_realm, get_user_profile_by_id, remote_user_to_email, \
|
||||
get_user_profile_by_id, remote_user_to_email, \
|
||||
email_to_username, get_realm, get_user_by_delivery_email, supported_auth_backends
|
||||
|
||||
redis_client = get_redis_client()
|
||||
|
||||
Reference in New Issue
Block a user