mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	imports: Add better checking for subdomains.
Add a `--allow-reserved-subdomain` flag which allows creation of
reserved keyword domains.  This also always enforces that the domain
is not in use, which was removed in 0258d7d.
Fixes #16924.
			
			
This commit is contained in:
		@@ -65,7 +65,7 @@ def email_is_not_mit_mailing_list(email: str) -> None:
 | 
				
			|||||||
            else:
 | 
					            else:
 | 
				
			||||||
                raise AssertionError("Unexpected DNS error")
 | 
					                raise AssertionError("Unexpected DNS error")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check_subdomain_available(subdomain: str, from_management_command: bool=False) -> None:
 | 
					def check_subdomain_available(subdomain: str, allow_reserved_subdomain: bool=False) -> None:
 | 
				
			||||||
    error_strings = {
 | 
					    error_strings = {
 | 
				
			||||||
        'too short': _("Subdomain needs to have length 3 or greater."),
 | 
					        'too short': _("Subdomain needs to have length 3 or greater."),
 | 
				
			||||||
        'extremal dash': _("Subdomain cannot start or end with a '-'."),
 | 
					        'extremal dash': _("Subdomain cannot start or end with a '-'."),
 | 
				
			||||||
@@ -80,12 +80,11 @@ def check_subdomain_available(subdomain: str, from_management_command: bool=Fals
 | 
				
			|||||||
        raise ValidationError(error_strings['extremal dash'])
 | 
					        raise ValidationError(error_strings['extremal dash'])
 | 
				
			||||||
    if not re.match('^[a-z0-9-]*$', subdomain):
 | 
					    if not re.match('^[a-z0-9-]*$', subdomain):
 | 
				
			||||||
        raise ValidationError(error_strings['bad character'])
 | 
					        raise ValidationError(error_strings['bad character'])
 | 
				
			||||||
    if from_management_command:
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
    if len(subdomain) < 3:
 | 
					    if len(subdomain) < 3:
 | 
				
			||||||
        raise ValidationError(error_strings['too short'])
 | 
					        raise ValidationError(error_strings['too short'])
 | 
				
			||||||
    if is_reserved_subdomain(subdomain) or \
 | 
					    if Realm.objects.filter(string_id=subdomain).exists():
 | 
				
			||||||
       Realm.objects.filter(string_id=subdomain).exists():
 | 
					        raise ValidationError(error_strings['unavailable'])
 | 
				
			||||||
 | 
					    if is_reserved_subdomain(subdomain) and not allow_reserved_subdomain:
 | 
				
			||||||
        raise ValidationError(error_strings['unavailable'])
 | 
					        raise ValidationError(error_strings['unavailable'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RegistrationForm(forms.Form):
 | 
					class RegistrationForm(forms.Form):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ import subprocess
 | 
				
			|||||||
from typing import Any
 | 
					from typing import Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
from django.core.management import call_command
 | 
					from django.core.management import call_command
 | 
				
			||||||
from django.core.management.base import BaseCommand, CommandError, CommandParser
 | 
					from django.core.management.base import BaseCommand, CommandError, CommandParser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,6 +27,10 @@ import a database dump from one or more JSON files."""
 | 
				
			|||||||
                            action="store_true",
 | 
					                            action="store_true",
 | 
				
			||||||
                            help='Import into an existing nonempty database.')
 | 
					                            help='Import into an existing nonempty database.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        parser.add_argument('--allow-reserved-subdomain',
 | 
				
			||||||
 | 
					                            action="store_true",
 | 
				
			||||||
 | 
					                            help='Allow use of reserved subdomains')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        parser.add_argument('subdomain', metavar='<subdomain>',
 | 
					        parser.add_argument('subdomain', metavar='<subdomain>',
 | 
				
			||||||
                            help="Subdomain")
 | 
					                            help="Subdomain")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,7 +60,15 @@ import a database dump from one or more JSON files."""
 | 
				
			|||||||
        elif options["import_into_nonempty"]:
 | 
					        elif options["import_into_nonempty"]:
 | 
				
			||||||
            print("NOTE: The argument 'import_into_nonempty' is now the default behavior.")
 | 
					            print("NOTE: The argument 'import_into_nonempty' is now the default behavior.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        check_subdomain_available(subdomain, from_management_command=True)
 | 
					        allow_reserved_subdomain = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if options["allow_reserved_subdomain"]:
 | 
				
			||||||
 | 
					            allow_reserved_subdomain = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            check_subdomain_available(subdomain, allow_reserved_subdomain)
 | 
				
			||||||
 | 
					        except ValidationError:
 | 
				
			||||||
 | 
					            raise CommandError("Subdomain reserved: pass --allow-reserved-subdomain to use.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        paths = []
 | 
					        paths = []
 | 
				
			||||||
        for path in options['export_paths']:
 | 
					        for path in options['export_paths']:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2634,13 +2634,29 @@ class RealmCreationTest(ZulipTestCase):
 | 
				
			|||||||
        self.assert_not_in_success_response(["unavailable"], result)
 | 
					        self.assert_not_in_success_response(["unavailable"], result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_subdomain_check_management_command(self) -> None:
 | 
					    def test_subdomain_check_management_command(self) -> None:
 | 
				
			||||||
        # Short names should work
 | 
					        # Short names should not work, even with the flag
 | 
				
			||||||
        check_subdomain_available('aa', from_management_command=True)
 | 
					 | 
				
			||||||
        # So should reserved ones
 | 
					 | 
				
			||||||
        check_subdomain_available('zulip', from_management_command=True)
 | 
					 | 
				
			||||||
        # malformed names should still not
 | 
					 | 
				
			||||||
        with self.assertRaises(ValidationError):
 | 
					        with self.assertRaises(ValidationError):
 | 
				
			||||||
            check_subdomain_available('-ba_d-', from_management_command=True)
 | 
					            check_subdomain_available('aa')
 | 
				
			||||||
 | 
					        with self.assertRaises(ValidationError):
 | 
				
			||||||
 | 
					            check_subdomain_available('aa', allow_reserved_subdomain=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Malformed names should never work
 | 
				
			||||||
 | 
					        with self.assertRaises(ValidationError):
 | 
				
			||||||
 | 
					            check_subdomain_available('-ba_d-')
 | 
				
			||||||
 | 
					        with self.assertRaises(ValidationError):
 | 
				
			||||||
 | 
					            check_subdomain_available('-ba_d-', allow_reserved_subdomain=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with patch('zerver.lib.name_restrictions.is_reserved_subdomain', return_value = False):
 | 
				
			||||||
 | 
					            # Existing realms should never work even if they are not reserved keywords
 | 
				
			||||||
 | 
					            with self.assertRaises(ValidationError):
 | 
				
			||||||
 | 
					                check_subdomain_available('zulip')
 | 
				
			||||||
 | 
					            with self.assertRaises(ValidationError):
 | 
				
			||||||
 | 
					                check_subdomain_available('zulip', allow_reserved_subdomain=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Reserved ones should only work with the flag
 | 
				
			||||||
 | 
					        with self.assertRaises(ValidationError):
 | 
				
			||||||
 | 
					            check_subdomain_available('stream')
 | 
				
			||||||
 | 
					        check_subdomain_available('stream', allow_reserved_subdomain=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserSignUpTest(InviteUserBase):
 | 
					class UserSignUpTest(InviteUserBase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user