Ver código fonte

refactor(api): use specialized subcalls inside Domain.is_registrable()

Peter Thomassen 5 anos atrás
pai
commit
579a6154d1
1 arquivos alterados com 46 adições e 33 exclusões
  1. 46 33
      api/desecapi/models.py

+ 46 - 33
api/desecapi/models.py

@@ -8,6 +8,7 @@ import string
 import time
 import time
 import uuid
 import uuid
 from datetime import timedelta
 from datetime import timedelta
+from functools import cached_property
 from hashlib import sha256
 from hashlib import sha256
 
 
 import psl_dns
 import psl_dns
@@ -219,21 +220,8 @@ class Domain(ExportModelOperationsMixin('Domain'), models.Model):
     minimum_ttl = models.PositiveIntegerField(default=get_minimum_ttl_default)
     minimum_ttl = models.PositiveIntegerField(default=get_minimum_ttl_default)
     _keys = None
     _keys = None
 
 
-    def is_registrable(self):
-        """
-        Returns False in any of the following cases:
-        (a) the domain name is under .internal,
-        (b) the domain_name appears on the public suffix list,
-        (c) the domain is descendant to a zone that belongs to any user different from the given one,
-            unless it's parent is a public suffix, either through the Internet PSL or local settings.
-        Otherwise, True is returned.
-        """
-        if self.name != self.name.lower():
-            raise ValueError
-
-        if f'.{self.name}'.endswith('.internal'):
-            return False
-
+    @cached_property
+    def public_suffix(self):
         try:
         try:
             public_suffix = psl.get_public_suffix(self.name)
             public_suffix = psl.get_public_suffix(self.name)
             is_public_suffix = psl.is_public_suffix(self.name)
             is_public_suffix = psl.is_public_suffix(self.name)
@@ -248,34 +236,59 @@ class Domain(ExportModelOperationsMixin('Domain'), models.Model):
             # and makes sure admins are notified.
             # and makes sure admins are notified.
             raise e
             raise e
 
 
-        if not is_public_suffix:
-            # Take into account that any of the parent domains could be a local public suffix. To that
-            # end, identify the longest local public suffix that is actually a suffix of domain_name.
-            # Then, override the global PSL result.
-            for local_public_suffix in settings.LOCAL_PUBLIC_SUFFIXES:
-                has_local_public_suffix_parent = ('.' + self.name).endswith('.' + local_public_suffix)
-                if has_local_public_suffix_parent and len(local_public_suffix) > len(public_suffix):
-                    public_suffix = local_public_suffix
-                    is_public_suffix = (public_suffix == self.name)
-
-        if is_public_suffix and self.name not in settings.LOCAL_PUBLIC_SUFFIXES:
-            return False
+        if is_public_suffix:
+            return public_suffix
 
 
+        # Take into account that any of the parent domains could be a local public suffix. To that
+        # end, identify the longest local public suffix that is actually a suffix of domain_name.
+        for local_public_suffix in settings.LOCAL_PUBLIC_SUFFIXES:
+            has_local_public_suffix_parent = ('.' + self.name).endswith('.' + local_public_suffix)
+            if has_local_public_suffix_parent and len(local_public_suffix) > len(public_suffix):
+                public_suffix = local_public_suffix
+
+        return public_suffix
+
+    def is_covered_by_foreign_zone(self):
         # Generate a list of all domains connecting this one and its public suffix.
         # Generate a list of all domains connecting this one and its public suffix.
         # If another user owns a zone with one of these names, then the requested
         # If another user owns a zone with one of these names, then the requested
         # domain is unavailable because it is part of the other user's zone.
         # domain is unavailable because it is part of the other user's zone.
-        private_components = self.name.rsplit(public_suffix, 1)[0].rstrip('.')
+        private_components = self.name.rsplit(self.public_suffix, 1)[0].rstrip('.')
         private_components = private_components.split('.') if private_components else []
         private_components = private_components.split('.') if private_components else []
-        private_components += [public_suffix]
-        private_domains = ['.'.join(private_components[i:]) for i in range(0, len(private_components) - 1)]
-        assert is_public_suffix or self.name == private_domains[0]
+        private_domains = ['.'.join(private_components[i:]) for i in range(0, len(private_components))]
+        private_domains = [f'{private_domain}.{self.public_suffix}' for private_domain in private_domains]
+        assert self.name == next(iter(private_domains), self.public_suffix)
 
 
-        # Deny registration for non-local public suffixes and for domains covered by other users' zones
+        # Determine whether domain is covered by other users' zones
         try:
         try:
             owner = self.owner
             owner = self.owner
         except Domain.owner.RelatedObjectDoesNotExist:
         except Domain.owner.RelatedObjectDoesNotExist:
             owner = None
             owner = None
-        return not Domain.objects.filter(Q(name__in=private_domains) & ~Q(owner=owner)).exists()
+        return Domain.objects.filter(Q(name__in=private_domains) & ~Q(owner=owner)).exists()
+
+    def is_registrable(self):
+        """
+        Returns False in any of the following cases:
+        (a) the domain name is under .internal,
+        (b) the domain_name appears on the public suffix list,
+        (c) the domain is descendant to a zone that belongs to any user different from the given one,
+            unless it's parent is a public suffix, either through the Internet PSL or local settings.
+        Otherwise, True is returned.
+        """
+        self.clean()  # ensure .name is a domain name
+
+        # .internal is reserved
+        if f'.{self.name}'.endswith('.internal'):
+            return False
+
+        # Public suffixes can only be registered if they are local
+        if self.name == self.public_suffix and self.name not in settings.LOCAL_PUBLIC_SUFFIXES:
+            return False
+
+        # Domains covered by another user's zone can't be registered
+        if self.is_covered_by_foreign_zone():
+            return False
+
+        return True
 
 
     @property
     @property
     def keys(self):
     def keys(self):