diff --git a/confirmation/models.py b/confirmation/models.py index 7f6cc9cf55..58fc54eac8 100644 --- a/confirmation/models.py +++ b/confirmation/models.py @@ -132,13 +132,18 @@ _properties = { # Arguably RealmCreationKey should just be another ConfirmationObjT and we should # add another Confirmation.type for this; it's this way for historical reasons. -def check_key_is_valid(creation_key: Text) -> bool: - if not RealmCreationKey.objects.filter(creation_key=creation_key).exists(): - return False - time_elapsed = timezone_now() - RealmCreationKey.objects.get(creation_key=creation_key).date_created +def validate_key(creation_key: Optional[str]) -> Optional['RealmCreationKey']: + """Get the record for this key, raising InvalidCreationKey if non-None but invalid.""" + if creation_key is None: + return None + try: + key_record = RealmCreationKey.objects.get(creation_key=creation_key) + except RealmCreationKey.DoesNotExist: + raise RealmCreationKey.Invalid() + time_elapsed = timezone_now() - key_record.date_created if time_elapsed.total_seconds() > settings.REALM_CREATION_LINK_VALIDITY_DAYS * 24 * 3600: - return False - return True + raise RealmCreationKey.Invalid() + return key_record def generate_realm_creation_url(by_admin: bool=False) -> Text: key = generate_key() @@ -157,3 +162,6 @@ class RealmCreationKey(models.Model): # True just if we should presume the email address the user enters # is theirs, and skip sending mail to it to confirm that. presume_email_valid = models.BooleanField(default=False) # type: bool + + class Invalid(Exception): + pass diff --git a/zerver/views/registration.py b/zerver/views/registration.py index 086e080111..c6b9a55347 100644 --- a/zerver/views/registration.py +++ b/zerver/views/registration.py @@ -37,7 +37,7 @@ from zerver.views.auth import create_preregistration_user, \ from zproject.backends import ldap_auth_enabled, password_auth_enabled, ZulipLDAPAuthBackend from confirmation.models import Confirmation, RealmCreationKey, ConfirmationKeyException, \ - check_key_is_valid, create_confirmation_link, get_object_from_key, \ + validate_key, create_confirmation_link, get_object_from_key, \ render_confirmation_key_error import logging @@ -327,12 +327,14 @@ def redirect_to_email_login_url(email: str) -> HttpResponseRedirect: return HttpResponseRedirect(redirect_url) def create_realm(request: HttpRequest, creation_key: Optional[Text]=None) -> HttpResponse: - if creation_key is not None and not check_key_is_valid(creation_key): + try: + key_record = validate_key(creation_key) + except RealmCreationKey.Invalid: return render(request, "zerver/realm_creation_failed.html", context={'message': _('The organization creation link has expired' ' or is not valid.')}) if not settings.OPEN_REALM_CREATION: - if creation_key is None: + if key_record is None: return render(request, "zerver/realm_creation_failed.html", context={'message': _('New organization creation disabled.')}) @@ -349,8 +351,8 @@ def create_realm(request: HttpRequest, creation_key: Optional[Text]=None) -> Htt logging.error('Error in create_realm: %s' % (str(e),)) return HttpResponseRedirect("/config-error/smtp") - if creation_key is not None: - RealmCreationKey.objects.get(creation_key=creation_key).delete() + if key_record is not None: + key_record.delete() return HttpResponseRedirect(reverse('send_confirm', kwargs={'email': email})) else: form = RealmCreationForm()