]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
manager: datamodel: types: improved DomainName regex
authorAleš Mrázek <ales.mrazek@nic.cz>
Tue, 12 Apr 2022 12:37:02 +0000 (14:37 +0200)
committerAleš Mrázek <ales.mrazek@nic.cz>
Tue, 12 Apr 2022 12:37:02 +0000 (14:37 +0200)
- tests: testing domain for length

manager/knot_resolver_manager/datamodel/types/types.py
manager/tests/unit/datamodel/types/test_custom_types.py

index 73603f2c956d49e8738ca0f2ad99fe29c441ef21..185924e3a39f0711fffb5fbfbdf5ef0261ba282a 100644 (file)
@@ -61,12 +61,12 @@ class DomainName(StrBase):
     """
 
     _re = re.compile(
-        r"(?=^.{,253}$)"  # max 253 chars
-        r"^([a-zA-Z0-9]"  # do not start with hyphen
-        r"([a-zA-Z0-9-]){1,61}"  # max 63 chars in label
-        r"[a-zA-Z0-9]\.)"  # do not end with hyphen
-        r"{0,126}"  # max 126 levels+TLD
-        r"([a-zA-Z]){2,6}($|.$)"  # TLD; end with or without '.'
+        r"(?=^.{,253}\.?$)"  # max 253 chars
+        r"^(?!\.)"  # do not start name with dot
+        r"((?!-)"  # do not start label with hyphen
+        r"\.?[a-zA-Z0-9-]{,62}"  # max 63 chars in label
+        r"[a-zA-Z0-9])+"  # do not end label with hyphen
+        r"\.?$"  # end with or without '.'
     )
 
     def __init__(self, source_value: Any, object_path: str = "/") -> None:
@@ -99,8 +99,8 @@ class DomainName(StrBase):
             return hash(self._value)
         return hash(f"{self._value}.")
 
-    def punycode(self) -> bytes:
-        return self._value.encode("idna")
+    def punycode(self) -> str:
+        return self._value.encode("idna").decode("utf-8")
 
     @classmethod
     def json_schema(cls: Type["DomainName"]) -> Dict[Any, Any]:
index 2130d8acfcd8bf5b31f451fe935363c844b84b6f..4980a5f57a4afc13f432c36625866ff5a0387e2b 100644 (file)
@@ -1,4 +1,6 @@
 import ipaddress
+import random
+import string
 from typing import Any
 
 import pytest
@@ -24,6 +26,12 @@ from knot_resolver_manager.exceptions import KresManagerException
 from knot_resolver_manager.utils import SchemaNode
 
 
+def _rand_domain(label_chars: int, levels: int = 1) -> str:
+    return "".join(
+        ["".join(random.choices(string.ascii_letters + string.digits, k=label_chars)) + "." for i in range(levels)]
+    )
+
+
 @pytest.mark.parametrize("val", [1, 65_535, 5353, 5000])
 def test_port_number_valid(val: int):
     assert int(PortNumber(val)) == val
@@ -83,15 +91,37 @@ def test_checked_path():
     assert str(TestSchema({"p": "/tmp"}).p) == "/tmp"
 
 
-@pytest.mark.parametrize("val", ["example.com.", "test.example.com", "test-example.com", "bücher.com.", "příklad.cz"])
+@pytest.mark.parametrize(
+    "val",
+    [
+        "example.com",
+        "this.is.example.com.",
+        "test.example.com",
+        "test-example.com",
+        "bücher.com.",
+        "příklad.cz",
+        _rand_domain(63),
+        _rand_domain(1, 127),
+    ],
+)
 def test_domain_name_valid(val: str):
     o = DomainName(val)
     assert str(o) == val
     assert o == DomainName(val)
-    assert o.punycode() == val.encode("idna")
+    assert o.punycode() == val.encode("idna").decode("utf-8")
 
 
-@pytest.mark.parametrize("val", ["test.example.com..", "-example.com", "test-.example.net"])
+@pytest.mark.parametrize(
+    "val",
+    [
+        "test.example..com.",
+        "-example.com",
+        "test-.example.net",
+        ".example.net",
+        _rand_domain(64),
+        _rand_domain(1, 128),
+    ],
+)
 def test_domain_name_invalid(val: str):
     with raises(KresManagerException):
         DomainName(val)