Browse Source

chore(api): bump dnspython to 2.1.0

Peter Thomassen 4 years ago
parent
commit
075c286664

+ 12 - 18
api/desecapi/dns.py

@@ -2,9 +2,9 @@ import struct
 
 import dns
 import dns.rdtypes.txtbase
-import dns.rdtypes.ANY.OPENPGPKEY
 
 
+@dns.immutable.immutable
 class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
     """
     A TXT record like RFC 1035, but
@@ -12,20 +12,22 @@ class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
     - all tokens must be quoted.
     """
 
+    def __init__(self, rdclass, rdtype, strings):
+        # Same as in parent class, but with max_length=None. Note that we are calling __init__ from the grandparent.
+        super(dns.rdtypes.txtbase.TXTBase, self).__init__(rdclass, rdtype)
+        self.strings = self._as_tuple(strings,
+                                      lambda x: self._as_bytes(x, True, max_length=None))
+
     @classmethod
     def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
         strings = []
-        while 1:
-            token = tok.get().unescape()
-            if token.is_eol_or_eof():
-                break
+        for token in tok.get_remaining():
+            token = token.unescape_to_bytes()
+            # The 'if' below is always true in the current code, but we
+            # are leaving this check in in case things change some day.
             if not token.is_quoted_string():
                 raise dns.exception.SyntaxError("Content must be quoted.")
-            value = token.value
-            if isinstance(value, bytes):
-                strings.append(value)
-            else:
-                strings.append(value.encode())
+            strings.append(token.value)
         if len(strings) == 0:
             raise dns.exception.UnexpectedEnd
         return cls(rdclass, rdtype, strings)
@@ -37,11 +39,3 @@ class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
                 assert l < 256
                 file.write(struct.pack('!B', l))
                 file.write(s)
-
-
-class OPENPGPKEY(dns.rdtypes.ANY.OPENPGPKEY.OPENPGPKEY):
-    # TODO remove when https://github.com/rthalley/dnspython/commit/d6a95982fcd454a10467260bfb874c3c9d31d06f was
-    #  released
-
-    def to_text(self, origin=None, relativize=True, **kw):
-        return super().to_text(origin, relativize, **kw).replace(' ', '')

+ 13 - 10
api/desecapi/models.py

@@ -30,7 +30,7 @@ from django.db.models.expressions import RawSQL
 from django.template.loader import get_template
 from django.utils import timezone
 from django_prometheus.models import ExportModelOperationsMixin
-from dns import rdata, rdataclass, rdatatype
+from dns import rdataclass, rdatatype
 from dns.exception import Timeout
 from dns.rdtypes import ANY, IN
 from dns.resolver import NoNameservers
@@ -39,7 +39,7 @@ from rest_framework.exceptions import APIException
 
 from desecapi import metrics
 from desecapi import pdns
-from desecapi.dns import LongQuotedTXT, OPENPGPKEY
+from desecapi.dns import LongQuotedTXT
 
 logger = logging.getLogger(__name__)
 psl = psl_dns.PSL(resolver=settings.PSL_RESOLVER, timeout=.5)
@@ -672,12 +672,11 @@ class RR(ExportModelOperationsMixin('RR'), models.Model):
         if type_ in (dns.rdatatype.TXT, dns.rdatatype.SPF):
             # for TXT record, we slightly deviate from RFC 1035 and allow tokens that are longer than 255 byte.
             cls = LongQuotedTXT
-        elif type_ == dns.rdatatype.OPENPGPKEY:
-            cls = OPENPGPKEY
         else:
             # For all other record types, let dnspython decide
-            cls = rdata
+            cls = dns.rdata
 
+        # Convert to wire format, ensuring input validation.
         wire = cls.from_text(
             rdclass=rdataclass.IN,
             rdtype=type_,
@@ -697,11 +696,15 @@ class RR(ExportModelOperationsMixin('RR'), models.Model):
 
         parser = dns.wire.Parser(wire, current=0)
         with parser.restrict_to(len(wire)):
-            return cls.from_wire_parser(
-                rdclass=rdataclass.IN,
-                rdtype=type_,
-                parser=parser,
-            ).to_text()
+            rdata = cls.from_wire_parser(rdclass=rdataclass.IN, rdtype=type_, parser=parser)
+
+        # Convert to canonical presentation format, disable chunking of records.
+        # Exempt types which have chunksize hardcoded (prevents "got multiple values for keyword argument 'chunksize'").
+        chunksize_exception_types = (dns.rdatatype.OPENPGPKEY, dns.rdatatype.EUI48, dns.rdatatype.EUI64)
+        if type_ in chunksize_exception_types:
+            return rdata.to_text()
+        else:
+            return rdata.to_text(chunksize=0)
 
     def __str__(self):
         return '<RR %s %s rr_set=%s>' % (self.pk, self.content, self.rrset.pk)

+ 8 - 2
api/desecapi/tests/test_rrsets.py

@@ -354,10 +354,14 @@ class AuthenticatedRRSetTestCase(AuthenticatedRRSetBaseTestCase):
             ('SPF', ('"foo" "bar"', '"foo" "bar"')),
             ('SPF', ('"foobar"', '"foobar"')),
             ('SRV', ('0 000 0 .', '0 0 0 .')),
-            # ('SRV', ('100 1 5061 EXAMPLE.com.', '100 1 5061 example.com.')),  # TODO fixed in dnspython 5c58601
+            ('SRV', ('100 1 5061 EXAMPLE.com.', '100 1 5061 example.com.')),
             ('SRV', ('100 1 5061 example.com.', '100 1 5061 example.com.')),
             ('SSHFP', ('2 2 aabbccEEddff', '2 2 aabbcceeddff')),
             ('TLSA', ('3 0001 1 000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', '3 1 1 000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')),
+            ('TLSA', ('003 00 002 696B8F6B92A913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd',
+                      '3 0 2 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd')),
+            ('TLSA', ('3 0 2 696B8F6B92A913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd696B8F6B92A913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd',
+                      '3 0 2 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd')),
             ('TXT', ('"foo" "bar"', '"foo" "bar"')),
             ('TXT', ('"foobar"', '"foobar"')),
             ('TXT', ('"foo" "" "bar"', '"foo" "" "bar"')),
@@ -417,7 +421,9 @@ class AuthenticatedRRSetTestCase(AuthenticatedRRSetBaseTestCase):
                     '"spf2.0/pra,mfrom ip6:2001:558:fe14:76:68:87:28:0/120 -all"'],
             'SRV': ['0 0 0 .', '100 1 5061 example.com.'],
             'SSHFP': ['2 2 aabbcceeddff'],
-            'TLSA': ['3 1 1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'],
+            'TLSA': ['3 1 1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
+                     '3 0 2 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd',
+                     '3 0 2 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd'],
             'TXT': ['"foobar"', '"foo" "bar"', '"“红色联合”对“四·二八兵团”总部大楼的攻击已持续了两天"', '"new\\010line"'
                     '"🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿  🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 👓 🕶 🥽 🥼 🌂 🧵"'],
             'URI': ['10 1 "ftp://ftp1.example.com/public"'],

+ 1 - 1
api/requirements.txt

@@ -8,7 +8,7 @@ djangorestframework~=3.12.2
 django-celery-email~=3.0.0
 django-netfields~=1.2.2
 django-prometheus~=2.1.0
-dnspython~=2.0.0
+dnspython~=2.1.0
 httpretty~=1.0.2
 psycopg2~=2.8.5
 prometheus-client~=0.9.0  # added to control django-prometheus' dependency version

+ 1 - 1
test/e2e2/requirements.txt

@@ -1,4 +1,4 @@
 pytest
 pytest-xdist
 requests
-dnspython
+dnspython~=2.1.0

+ 3 - 3
test/e2e2/spec/test_api_rr_validation.py

@@ -45,7 +45,7 @@ VALID_RECORDS_CANONICAL = {
     ],
     'NS': ['ns1.example.com.'],
     'OPENPGPKEY': [
-        'mG8EXtVIsRMFK4EEACIDAwQSZPNqE4tS xLFJYhX+uabSgMrhOqUizJhkLx82',  # key incomplete due to 500 byte limit
+        'mG8EXtVIsRMFK4EEACIDAwQSZPNqE4tSxLFJYhX+uabSgMrhOqUizJhkLx82',  # key incomplete due to 500 byte limit
     ],
     'PTR': ['example.com.', '*.example.com.'],
     'RP': ['hostmaster.example.com. .'],
@@ -58,7 +58,7 @@ VALID_RECORDS_CANONICAL = {
     ],
     'SRV': ['0 0 0 .', '100 1 5061 example.com.'],
     'SSHFP': ['2 2 aabbcceeddff'],
-    'TLSA': ['3 1 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',],
+    'TLSA': ['3 0 2 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd',],
     'TXT': [
         '"foobar"',
         '"foo" "bar"',
@@ -111,7 +111,7 @@ VALID_RECORDS_NON_CANONICAL = {
     'SPF': [],
     'SRV': ['100 01 5061 example.com.'],
     'SSHFP': ['02 2 aabbcceeddff'],
-    'TLSA': ['3 0001 1 000AAAAAAABBAAAAAAAAAAAAAAAAAAAAAAAA',],
+    'TLSA': ['003 00 002 696B8F6B92A913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd',],
     'TXT': [
         f'"{"a" * 498}"',
         '"🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿  🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 "',