浏览代码

feat(api): allow _ in domains, but check against _acme-challenge hijack

Peter Thomassen 5 年之前
父节点
当前提交
c7e49e21b2
共有 2 个文件被更改,包括 23 次插入12 次删除
  1. 3 4
      api/desecapi/models.py
  2. 20 8
      api/desecapi/tests/test_domains.py

+ 3 - 4
api/desecapi/models.py

@@ -196,10 +196,9 @@ class Token(ExportModelOperationsMixin('Token'), rest_framework.authtoken.models
 validate_domain_name = [
     validate_lower,
     RegexValidator(
-        # TODO See how far this validation can be relaxed (allow for non-hostname domains?)
-        regex=r'^(([a-z0-9][a-z0-9-]{0,61}[a-z0-9]|[a-z0-9])\.)*[a-z]{1,63}$',
-        message='Domain names must be labels separated by dots. Labels may consist of up to 63 hyphens, digits, and '
-                'letters, and must not start or end with a hyphen. The last label may only contain letters.',
+        regex=r'^(([a-z0-9_-]{1,63})\.)*[a-z]{1,63}$',
+        message='Domain names must be labels separated by dots. Labels may consist of up to 63 letters, digits, '
+                'hyphens, and underscores. The last label may only contain letters.',
         code='invalid_domain_name',
         flags=re.IGNORECASE
     )

+ 20 - 8
api/desecapi/tests/test_domains.py

@@ -101,21 +101,32 @@ class IsRegistrableTestCase(DesecTestCase, PublicSuffixMockMixin):
             self.assertRegistrable('b.a.public.suffix', user_a)
 
     def test_cant_register_ancestors_of_registered_domains(self):
+        user_a = self.create_user()
+        user_b = self.create_user()
+
         with self.mock(
             global_public_suffixes={'public.suffix'},
             local_public_suffixes={'public.suffix'},
         ):
             # let A own c.b.a.public.suffix
-            user_a = self.create_user()
             self.assertRegistrable('c.b.a.public.suffix', user_a)
             self.create_domain(owner=user_a, name='c.b.a.public.suffix')
+
             # user B shall not register b.a.public.suffix or a.public.suffix, but A may
-            user_b = self.create_user()
             self.assertNotRegistrable('b.a.public.suffix', user_b)
             self.assertNotRegistrable('a.public.suffix', user_b)
             self.assertRegistrable('b.a.public.suffix', user_a)
             self.assertRegistrable('a.public.suffix', user_a)
 
+            # let A own _acme-challenge.foobar.public.suffix
+            self.assertRegistrable('_acme-challenge.foobar.public.suffix', user_a)
+            self.create_domain(owner=user_a, name='_acme-challenge.foobar.public.suffix')
+
+            # user B shall not register foobar.public.suffix, but A may
+            user_b = self.create_user()
+            self.assertNotRegistrable('foobar.public.suffix', user_b)
+            self.assertRegistrable('foobar.public.suffix', user_a)
+
     def test_can_register_public_suffixes_under_private_domains(self):
         with self.mock(
             global_public_suffixes={'public.suffix'},
@@ -164,20 +175,21 @@ class DomainOwnerTestCase1(DomainOwnerTestCase):
             'ORG',
             '--BLAH.example.com',
             '_ASDF.jp',
-            '_example.com', '_.example.com',
-            '-dedyn.io', '--dedyn.io', '-.dedyn123.io',
-            'exam_ple.com',
             'too.long.x012345678901234567890123456789012345678901234567890123456789012.com',
-            '-foobar.example.com',
-            '_foobar.example.com',
-            'hyphen-.example.com',
         ]:
             with self.assertRaises(ValidationError):
                 Domain(owner=self.owner, name=name).save()
+
         for name in [
             'org',
             'foobar.io',
             'hyphens--------------------hyphens-hyphens.com',
+            '_example.com', '_.example.com',
+            'exam_ple.com',
+            '-dedyn.io', '--dedyn.io', '-.dedyn123.io',
+            '_foobar.example.com',
+            '-foobar.example.com',
+            'hyphen-.example.com',
             'max.length.x01234567890123456789012345678901234567890123456789012345678901.com',
         ]:
             with self.assertPdnsRequests(