mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Implement "chunked" TXT/SPF value support for long values
This implements it transparently at Record level. Providers that need things to be chunked (seems to just be Route53 an Dyn) switch to use `chunked_values`, but everything else can stick with `values`. I've run through each provider I have access to verifying that things operate as expected/required. OVH and Azure are untested.
This commit is contained in:
@@ -455,7 +455,7 @@ class DynProvider(BaseProvider):
|
||||
return [{
|
||||
'txtdata': v,
|
||||
'ttl': record.ttl,
|
||||
} for v in record.values]
|
||||
} for v in record.chunked_values]
|
||||
|
||||
def _kwargs_for_SRV(self, record):
|
||||
return [{
|
||||
|
||||
@@ -114,8 +114,7 @@ class _Route53Record(object):
|
||||
for v in record.values]
|
||||
|
||||
def _values_for_quoted(self, record):
|
||||
return ['"{}"'.format(v.replace('"', '\\"'))
|
||||
for v in record.values]
|
||||
return record.chunked_values
|
||||
|
||||
_values_for_SPF = _values_for_quoted
|
||||
_values_for_TXT = _values_for_quoted
|
||||
|
||||
@@ -704,8 +704,8 @@ class SshfpRecord(_ValuesMixin, Record):
|
||||
_unescaped_semicolon_re = re.compile(r'\w;')
|
||||
|
||||
|
||||
class SpfRecord(_ValuesMixin, Record):
|
||||
_type = 'SPF'
|
||||
class _ChunkedValuesMixin(_ValuesMixin):
|
||||
CHUNK_SIZE = 255
|
||||
|
||||
@classmethod
|
||||
def _validate_value(cls, value):
|
||||
@@ -714,9 +714,29 @@ class SpfRecord(_ValuesMixin, Record):
|
||||
return []
|
||||
|
||||
def _process_values(self, values):
|
||||
ret = []
|
||||
for v in values:
|
||||
if v and v[0] == '"':
|
||||
v = v[1:-1]
|
||||
ret.append(v.replace('" "', ''))
|
||||
return ret
|
||||
|
||||
@property
|
||||
def chunked_values(self):
|
||||
values = []
|
||||
for v in self.values:
|
||||
v = v.replace('"', '\\"')
|
||||
vs = [v[i:i + self.CHUNK_SIZE]
|
||||
for i in range(0, len(v), self.CHUNK_SIZE)]
|
||||
vs = '" "'.join(vs)
|
||||
values.append('"{}"'.format(vs))
|
||||
return values
|
||||
|
||||
|
||||
class SpfRecord(_ChunkedValuesMixin, Record):
|
||||
_type = 'SPF'
|
||||
|
||||
|
||||
class SrvValue(object):
|
||||
|
||||
@classmethod
|
||||
@@ -797,14 +817,5 @@ class SrvRecord(_ValuesMixin, Record):
|
||||
return [SrvValue(v) for v in values]
|
||||
|
||||
|
||||
class TxtRecord(_ValuesMixin, Record):
|
||||
class TxtRecord(_ChunkedValuesMixin, Record):
|
||||
_type = 'TXT'
|
||||
|
||||
@classmethod
|
||||
def _validate_value(cls, value):
|
||||
if _unescaped_semicolon_re.search(value):
|
||||
return ['unescaped ;']
|
||||
return []
|
||||
|
||||
def _process_values(self, values):
|
||||
return values
|
||||
|
||||
@@ -1490,3 +1490,59 @@ class TestRecordValidation(TestCase):
|
||||
'value': 'this has some; semi-colons\; in it',
|
||||
})
|
||||
self.assertEquals(['unescaped ;'], ctx.exception.reasons)
|
||||
|
||||
def test_TXT_long_value_chunking(self):
|
||||
expected = '"Lorem ipsum dolor sit amet, consectetur adipiscing ' \
|
||||
'elit, seddo eiusmod tempor incididunt ut labore et dolore ' \
|
||||
'magna aliqua. Ut enim ad minim veniam, quis nostrud ' \
|
||||
'exercitation ullamco laboris nisi ut aliquip ex ea commodo ' \
|
||||
'consequat. Duis aute irure dolor in" " reprehenderit in ' \
|
||||
'voluptate velit esse cillum dolore eu fugiat nulla pariatur. ' \
|
||||
'Excepteur sint occaecat cupidatat non proident, sunt in culpa ' \
|
||||
'qui officia deserunt mollit anim id est laborum."'
|
||||
|
||||
# Single string
|
||||
single = Record.new(self.zone, '', {
|
||||
'type': 'TXT',
|
||||
'ttl': 600,
|
||||
'values': [
|
||||
'hello world',
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed'
|
||||
'do eiusmod tempor incididunt ut labore et dolore magna '
|
||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '
|
||||
'ullamco laboris nisi ut aliquip ex ea commodo consequat. '
|
||||
'Duis aute irure dolor in reprehenderit in voluptate velit '
|
||||
'esse cillum dolore eu fugiat nulla pariatur. Excepteur sint '
|
||||
'occaecat cupidatat non proident, sunt in culpa qui officia '
|
||||
'deserunt mollit anim id est laborum.',
|
||||
'this has some\; semi-colons\; in it',
|
||||
]
|
||||
})
|
||||
self.assertEquals(3, len(single.values))
|
||||
self.assertEquals(3, len(single.chunked_values))
|
||||
# Note we are checking that this normalizes the chunking, not that we
|
||||
# get out what we put in.
|
||||
self.assertEquals(expected, single.chunked_values[0])
|
||||
|
||||
# Chunked
|
||||
chunked = Record.new(self.zone, '', {
|
||||
'type': 'TXT',
|
||||
'ttl': 600,
|
||||
'values': [
|
||||
'"hello world"',
|
||||
'"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed'
|
||||
'do eiusmod tempor incididunt ut labore et dolore magna '
|
||||
'aliqua. Ut enim ad minim veniam, quis nostrud exercitation '
|
||||
'ullamco laboris nisi ut aliquip ex" " ea commodo consequat. '
|
||||
'Duis aute irure dolor in reprehenderit in voluptate velit '
|
||||
'esse cillum dolore eu fugiat nulla pariatur. Excepteur sint '
|
||||
'occaecat cupidatat non proident, sunt in culpa qui officia '
|
||||
'deserunt mollit anim id est laborum."',
|
||||
'"this has some\; semi-colons\; in it"',
|
||||
]
|
||||
})
|
||||
self.assertEquals(expected, chunked.chunked_values[0])
|
||||
# should be single values, no quoting
|
||||
self.assertEquals(single.values, chunked.values)
|
||||
# should be chunked values, with quoting
|
||||
self.assertEquals(single.chunked_values, chunked.chunked_values)
|
||||
|
||||
Reference in New Issue
Block a user