You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

138 lines
3.7 KiB

#
#
#
import re
from ..equality import EqualityTupleMixin
from ..idna import idna_encode
from .base import Record, ValuesMixin, unquote
from .rr import RrParseError
class UriValue(EqualityTupleMixin, dict):
@classmethod
def parse_rdata_text(self, value):
try:
priority, weight, target = value.split(' ')
except ValueError:
raise RrParseError()
try:
priority = int(priority)
except ValueError:
pass
try:
weight = int(weight)
except ValueError:
pass
target = unquote(target)
return {'priority': priority, 'weight': weight, 'target': target}
@classmethod
def validate(cls, data, _type):
reasons = []
for value in data:
# TODO: validate algorithm and fingerprint_type values
try:
int(value['priority'])
except KeyError:
reasons.append('missing priority')
except ValueError:
reasons.append(f'invalid priority "{value["priority"]}"')
try:
int(value['weight'])
except KeyError:
reasons.append('missing weight')
except ValueError:
reasons.append(f'invalid weight "{value["weight"]}"')
try:
target = value['target']
if not target:
reasons.append('missing target')
continue
# actual validation of the target is non-trivial and specific
# to the details of the schema etc. rfc3986 has support for
# validation, but we don't currently require the module and
# this seems too esoteric a use case to add it
except KeyError:
reasons.append('missing target')
return reasons
@classmethod
def process(cls, values):
return [cls(v) for v in values]
def __init__(self, value):
super().__init__(
{
'priority': int(value['priority']),
'weight': int(value['weight']),
'target': idna_encode(value['target']),
}
)
@property
def priority(self):
return self['priority']
@priority.setter
def priority(self, value):
self['priority'] = value
@property
def weight(self):
return self['weight']
@weight.setter
def weight(self, value):
self['weight'] = value
@property
def target(self):
return self['target']
@target.setter
def target(self, value):
self['target'] = value
@property
def data(self):
return self
@property
def rdata_text(self):
return f'{self.priority} {self.weight} "{self.target}"'
def template(self, params):
if '{' not in self.target:
return self
new = self.__class__(self)
new.target = new.target.format(**params)
return new
def __hash__(self):
return hash(self.__repr__())
def _equality_tuple(self):
return (self.priority, self.weight, self.target)
def __repr__(self):
return f"'{self.priority} {self.weight} \"{self.target}\"'"
# https://datatracker.ietf.org/doc/html/rfc7553
class UriRecord(ValuesMixin, Record):
_type = 'URI'
_value_type = UriValue
_name_re = re.compile(r'^(\*|_[^\.]+)\.[^\.]+')
@classmethod
def validate(cls, name, fqdn, data):
reasons = []
if not cls._name_re.match(name):
reasons.append('invalid name for URI record')
reasons.extend(super().validate(name, fqdn, data))
return reasons
Record.register_type(UriRecord)