浏览代码

chore(api): bump dnspython to 2.1.0

Peter Thomassen 4 年之前
父节点
当前提交
075c286664

+ 12 - 18
api/desecapi/dns.py

@@ -2,9 +2,9 @@ import struct
 
 
 import dns
 import dns
 import dns.rdtypes.txtbase
 import dns.rdtypes.txtbase
-import dns.rdtypes.ANY.OPENPGPKEY
 
 
 
 
+@dns.immutable.immutable
 class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
 class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
     """
     """
     A TXT record like RFC 1035, but
     A TXT record like RFC 1035, but
@@ -12,20 +12,22 @@ class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
     - all tokens must be quoted.
     - 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
     @classmethod
     def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
     def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True):
         strings = []
         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():
             if not token.is_quoted_string():
                 raise dns.exception.SyntaxError("Content must be quoted.")
                 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:
         if len(strings) == 0:
             raise dns.exception.UnexpectedEnd
             raise dns.exception.UnexpectedEnd
         return cls(rdclass, rdtype, strings)
         return cls(rdclass, rdtype, strings)
@@ -37,11 +39,3 @@ class LongQuotedTXT(dns.rdtypes.txtbase.TXTBase):
                 assert l < 256
                 assert l < 256
                 file.write(struct.pack('!B', l))
                 file.write(struct.pack('!B', l))
                 file.write(s)
                 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.template.loader import get_template
 from django.utils import timezone
 from django.utils import timezone
 from django_prometheus.models import ExportModelOperationsMixin
 from django_prometheus.models import ExportModelOperationsMixin
-from dns import rdata, rdataclass, rdatatype
+from dns import rdataclass, rdatatype
 from dns.exception import Timeout
 from dns.exception import Timeout
 from dns.rdtypes import ANY, IN
 from dns.rdtypes import ANY, IN
 from dns.resolver import NoNameservers
 from dns.resolver import NoNameservers
@@ -39,7 +39,7 @@ from rest_framework.exceptions import APIException
 
 
 from desecapi import metrics
 from desecapi import metrics
 from desecapi import pdns
 from desecapi import pdns
-from desecapi.dns import LongQuotedTXT, OPENPGPKEY
+from desecapi.dns import LongQuotedTXT
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 psl = psl_dns.PSL(resolver=settings.PSL_RESOLVER, timeout=.5)
 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):
         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.
             # for TXT record, we slightly deviate from RFC 1035 and allow tokens that are longer than 255 byte.
             cls = LongQuotedTXT
             cls = LongQuotedTXT
-        elif type_ == dns.rdatatype.OPENPGPKEY:
-            cls = OPENPGPKEY
         else:
         else:
             # For all other record types, let dnspython decide
             # For all other record types, let dnspython decide
-            cls = rdata
+            cls = dns.rdata
 
 
+        # Convert to wire format, ensuring input validation.
         wire = cls.from_text(
         wire = cls.from_text(
             rdclass=rdataclass.IN,
             rdclass=rdataclass.IN,
             rdtype=type_,
             rdtype=type_,
@@ -697,11 +696,15 @@ class RR(ExportModelOperationsMixin('RR'), models.Model):
 
 
         parser = dns.wire.Parser(wire, current=0)
         parser = dns.wire.Parser(wire, current=0)
         with parser.restrict_to(len(wire)):
         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):
     def __str__(self):
         return '<RR %s %s rr_set=%s>' % (self.pk, self.content, self.rrset.pk)
         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', ('"foo" "bar"', '"foo" "bar"')),
             ('SPF', ('"foobar"', '"foobar"')),
             ('SPF', ('"foobar"', '"foobar"')),
             ('SRV', ('0 000 0 .', '0 0 0 .')),
             ('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.')),
             ('SRV', ('100 1 5061 example.com.', '100 1 5061 example.com.')),
             ('SSHFP', ('2 2 aabbccEEddff', '2 2 aabbcceeddff')),
             ('SSHFP', ('2 2 aabbccEEddff', '2 2 aabbcceeddff')),
             ('TLSA', ('3 0001 1 000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', '3 1 1 000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')),
             ('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', ('"foo" "bar"', '"foo" "bar"')),
             ('TXT', ('"foobar"', '"foobar"')),
             ('TXT', ('"foobar"', '"foobar"')),
             ('TXT', ('"foo" "" "bar"', '"foo" "" "bar"')),
             ('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"'],
                     '"spf2.0/pra,mfrom ip6:2001:558:fe14:76:68:87:28:0/120 -all"'],
             'SRV': ['0 0 0 .', '100 1 5061 example.com.'],
             'SRV': ['0 0 0 .', '100 1 5061 example.com.'],
             'SSHFP': ['2 2 aabbcceeddff'],
             '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"'
             'TXT': ['"foobar"', '"foo" "bar"', '"“红色联合”对“四·二八兵团”总部大楼的攻击已持续了两天"', '"new\\010line"'
                     '"🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿  🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 👓 🕶 🥽 🥼 🌂 🧵"'],
                     '"🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿  🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 👓 🕶 🥽 🥼 🌂 🧵"'],
             'URI': ['10 1 "ftp://ftp1.example.com/public"'],
             '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-celery-email~=3.0.0
 django-netfields~=1.2.2
 django-netfields~=1.2.2
 django-prometheus~=2.1.0
 django-prometheus~=2.1.0
-dnspython~=2.0.0
+dnspython~=2.1.0
 httpretty~=1.0.2
 httpretty~=1.0.2
 psycopg2~=2.8.5
 psycopg2~=2.8.5
 prometheus-client~=0.9.0  # added to control django-prometheus' dependency version
 prometheus-client~=0.9.0  # added to control django-prometheus' dependency version

+ 1 - 1
test/e2e2/requirements.txt

@@ -1,4 +1,4 @@
 pytest
 pytest
 pytest-xdist
 pytest-xdist
 requests
 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.'],
     'NS': ['ns1.example.com.'],
     'OPENPGPKEY': [
     '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.'],
     'PTR': ['example.com.', '*.example.com.'],
     'RP': ['hostmaster.example.com. .'],
     'RP': ['hostmaster.example.com. .'],
@@ -58,7 +58,7 @@ VALID_RECORDS_CANONICAL = {
     ],
     ],
     'SRV': ['0 0 0 .', '100 1 5061 example.com.'],
     'SRV': ['0 0 0 .', '100 1 5061 example.com.'],
     'SSHFP': ['2 2 aabbcceeddff'],
     'SSHFP': ['2 2 aabbcceeddff'],
-    'TLSA': ['3 1 1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',],
+    'TLSA': ['3 0 2 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd 696b8f6b92a913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd',],
     'TXT': [
     'TXT': [
         '"foobar"',
         '"foobar"',
         '"foo" "bar"',
         '"foo" "bar"',
@@ -111,7 +111,7 @@ VALID_RECORDS_NON_CANONICAL = {
     'SPF': [],
     'SPF': [],
     'SRV': ['100 01 5061 example.com.'],
     'SRV': ['100 01 5061 example.com.'],
     'SSHFP': ['02 2 aabbcceeddff'],
     'SSHFP': ['02 2 aabbcceeddff'],
-    'TLSA': ['3 0001 1 000AAAAAAABBAAAAAAAAAAAAAAAAAAAAAAAA',],
+    'TLSA': ['003 00 002 696B8F6B92A913560b23ef5720c378881faffe74432d04eb35db957c0a93987b47adf26abb5dac10ba482597ae16edb069b511bec3e26010d1927bf6392760dd',],
     'TXT': [
     'TXT': [
         f'"{"a" * 498}"',
         f'"{"a" * 498}"',
         '"🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿  🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 "',
         '"🧥 👚 👕 👖 👔 👗 👙 👘 👠 👡 👢 👞 👟 🥾 🥿  🧦 🧤 🧣 🎩 🧢 👒 🎓 ⛑ 👑 👝 👛 👜 💼 🎒 "',