Skip to content

Commit bf57f20

Browse files
committed
TLSA tests pass
1 parent 2f9e910 commit bf57f20

File tree

2 files changed

+55
-19
lines changed

2 files changed

+55
-19
lines changed

api/desecapi/models.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,10 @@ def filter_qname(self, qname: str, **kwargs) -> models.query.QuerySet:
220220
).filter(dotted_qname__endswith=F('dotted_name'), **kwargs)
221221

222222
def most_specific_zone(self, fqdn: str) -> Tuple[Domain, str]:
223-
domain = self.filter_qname(fqdn).order_by('-name_length').first()
223+
try:
224+
domain = self.filter_qname(fqdn).order_by('-name_length')[0]
225+
except IndexError:
226+
raise Domain.DoesNotExist
224227
subname = fqdn[:-len(domain.name)].rstrip('.')
225228
return domain, subname
226229

@@ -999,7 +1002,7 @@ class Identity(models.Model):
9991002
created = models.DateTimeField(auto_now_add=True)
10001003
owner = models.ForeignKey(User, on_delete=models.PROTECT, related_name='identities')
10011004
default_ttl = models.PositiveIntegerField(default=300)
1002-
rrs = models.ManyToManyField(to=RR)
1005+
rrs = models.ManyToManyField(to=RR, related_name='identities')
10031006
scheduled_removal = models.DateTimeField(null=True)
10041007

10051008
class Meta:
@@ -1010,14 +1013,14 @@ def get_rrs(self) -> List[RR]:
10101013

10111014
def save(self, *args, **kwargs):
10121015
for rr in self.get_rrs():
1013-
self.rrs.add(rr)
10141016
rr.rrset.save()
10151017
rr.save()
1018+
self.rrs.add(rr)
10161019
return super().save(*args, **kwargs)
10171020

10181021
def delete(self, using=None, keep_parents=False):
10191022
for rr in self.rrs.all(): # TODO use one query
1020-
if len(rr.identities) == 1:
1023+
if len(rr.identities.all()) == 1:
10211024
rr.delete()
10221025
return super().delete(using, keep_parents)
10231026

@@ -1076,7 +1079,7 @@ def __init__(self, *args, **kwargs):
10761079
if 'not_valid_after' not in kwargs:
10771080
self.scheduled_removal = self.not_valid_after
10781081

1079-
def get_record_contents(self) -> List[str]:
1082+
def get_record_content(self) -> str:
10801083
# choose hash function
10811084
if self.tlsa_matching_type == self.MatchingType.SHA256:
10821085
hash_function = hazmat.primitives.hashes.SHA256()
@@ -1100,7 +1103,7 @@ def get_record_contents(self) -> List[str]:
11001103
hash = h.finalize().hex()
11011104

11021105
# create TLSA record content
1103-
return [f"{self.tlsa_certificate_usage} {self.tlsa_selector} {self.tlsa_matching_type} {hash}"]
1106+
return f"{self.tlsa_certificate_usage} {self.tlsa_selector} {self.tlsa_matching_type} {hash}"
11041107

11051108
@property
11061109
def _cert(self) -> x509.Certificate:
@@ -1145,14 +1148,17 @@ def subject_names_clean(self) -> Set[str]:
11451148
return clean
11461149

11471150
def get_rrs(self) -> List[RR]:
1148-
return [
1149-
self.get_or_create_rr(
1150-
fqdn=f"_{self.port:n}._{self.protocol}.{qname}",
1151-
content=content,
1152-
)
1153-
for qname in self.subject_names_clean
1154-
for content in self.get_record_contents()
1155-
]
1151+
rrs = []
1152+
content = self.get_record_content()
1153+
for qname in self.subject_names_clean:
1154+
try:
1155+
rrs.append(self.get_or_create_rr(
1156+
fqdn=f"_{self.port:n}._{self.protocol}.{qname}",
1157+
content=content,
1158+
))
1159+
except Domain.DoesNotExist:
1160+
pass
1161+
return rrs
11561162

11571163
@property
11581164
def not_valid_before(self):

api/desecapi/tests/test_identities.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,7 @@ def test_generated_rrs_many_rrsets(self):
4747

4848
id = models.TLSIdentity(certificate=CERTIFICATE, owner=self.user, protocol=models.TLSIdentity.Protocol.SCTP)
4949

50-
self.assertEqual(
51-
id.domains_subnames(),
52-
{(domain, '_443._sctp'), (domain, '_443._sctp.desec'), (domain, '_443._sctp.dedyn')},
53-
)
50+
self.assertEqual(id.subject_names, SUBJECT_NAMES)
5451

5552
rrs = id.get_rrs()
5653
self.assertEqual(len(rrs), 3)
@@ -69,7 +66,6 @@ def test_generated_rrs_one_rrset(self):
6966
domain.save()
7067

7168
id = models.TLSIdentity(certificate=CERTIFICATE, owner=self.user, port=123)
72-
self.assertEqual(id.domains_subnames(), {(domain, '_123._tcp')})
7369

7470
rrs = id.get_rrs()
7571
self.assertEqual(len(rrs), 1)
@@ -115,3 +111,37 @@ def test_create_delete_rrs(self):
115111
id.delete()
116112
rrset = models.RRset.objects.get(domain__name='desec.example.dedyn.io', type='TLSA', subname='_123._tcp')
117113
self.assertEqual(len(rrset.records.all()), 1)
114+
115+
def test_duplicate_record(self):
116+
def count_tlsa_records():
117+
return models.RRset.objects.get(
118+
domain__name='desec.example.dedyn.io',
119+
type='TLSA', subname='_443._tcp'
120+
).records.count()
121+
122+
domain = models.Domain(name='desec.example.dedyn.io', owner=self.user)
123+
domain.save()
124+
125+
# insert first cert, insert second, delete first, delete second
126+
id1 = models.TLSIdentity(certificate=CERTIFICATE, owner=self.user)
127+
id2 = models.TLSIdentity(certificate=CERTIFICATE, owner=self.user)
128+
id1.save()
129+
self.assertEqual(count_tlsa_records(), 1)
130+
id2.save()
131+
self.assertEqual(count_tlsa_records(), 1)
132+
id1.delete()
133+
self.assertEqual(count_tlsa_records(), 1)
134+
id2.delete()
135+
self.assertEqual(count_tlsa_records(), 0)
136+
137+
# insert first cert, insert second, delete second, delete first
138+
id1 = models.TLSIdentity(certificate=CERTIFICATE, owner=self.user)
139+
id2 = models.TLSIdentity(certificate=CERTIFICATE, owner=self.user)
140+
id1.save()
141+
self.assertEqual(count_tlsa_records(), 1)
142+
id2.save()
143+
self.assertEqual(count_tlsa_records(), 1)
144+
id2.delete()
145+
self.assertEqual(count_tlsa_records(), 1)
146+
id1.delete()
147+
self.assertEqual(count_tlsa_records(), 0)

0 commit comments

Comments
 (0)