Skip to content

Commit df1af8e

Browse files
Merge branch 'dev'
2 parents 3620408 + b92039a commit df1af8e

File tree

5 files changed

+31
-82
lines changed

5 files changed

+31
-82
lines changed

Readme.md

-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,6 @@ All modules used by this project are listed below:
333333
| [zope.interface](https://github.com/zopefoundation/zope.interface) | [ZPL-2.1](https://raw.githubusercontent.com/zopefoundation/zope.interface/master/LICENSE.txt) |
334334
| [setuptools](https://github.com/pypa/setuptools) | [MIT](https://raw.githubusercontent.com/pypa/setuptools/main/LICENSE) |
335335
| [pkb_client](https://github.com/infinityofspace/pkb_client) | [MIT](https://github.com/infinityofspace/pkb_client/blob/main/License) |
336-
| [tldextract](https://github.com/john-kurkowski/tldextract) | [BSD 3-Clause](https://raw.githubusercontent.com/john-kurkowski/tldextract/master/LICENSE) |
337336
| [dnspython](https://github.com/rthalley/dnspython) | [ISC](https://raw.githubusercontent.com/rthalley/dnspython/master/LICENSE) |
338337

339338
Furthermore, this readme file contains embeddings of [Shields.io](https://github.com/badges/shields).

certbot_dns_porkbun/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "v0.3"
1+
__version__ = "v0.4"

certbot_dns_porkbun/cert/client.py

+29-44
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22

3-
import tldextract
3+
import dns.name
44
import zope.interface
55
from certbot import errors, interfaces
66
from certbot.plugins import dns_common
@@ -75,6 +75,7 @@ def _setup_credentials(self) -> None:
7575
def _perform(self, domain: str, validation_name: str, validation: str) -> None:
7676
"""
7777
Add the validation DNS TXT record to the provided Porkbun domain.
78+
Moreover, it resolves the canonical name (CNAME) for the provided domain with the acme txt prefix.
7879
7980
:param domain: the Porkbun domain for which a TXT record will be created
8081
:param validation_name: the value to validate the dns challenge
@@ -83,56 +84,44 @@ def _perform(self, domain: str, validation_name: str, validation: str) -> None:
8384
:raise PluginError: if the TXT record can not be set or something goes wrong
8485
"""
8586

86-
self._domain = Authenticator._resolve_canonical_name(domain)
87+
# replace wildcard in domain
88+
domain = domain.replace("*", "")
89+
domain = f"{ACME_TXT_PREFIX}.{domain}"
8790

88-
tld = tldextract.TLDExtract(suffix_list_urls=None)
89-
extracted_domain = tld(self._domain)
91+
propagation_seconds = self.conf("propagation_seconds")
9092

91-
subdomains = extracted_domain.subdomain
92-
# remove wildcard from subdomains
93-
subdomains = subdomains.replace("*.", "")
94-
subdomains = subdomains.replace("*", "")
93+
try:
94+
# follow all CNAME and DNAME records
95+
canonical_name = resolver.canonical_name(domain)
96+
97+
if domain != canonical_name.to_text().rstrip('.') and propagation_seconds < 600:
98+
logging.warning("Make sure your CNAME record is propagated to all DNS servers, "
99+
"because the default CNAME TTL propagation time is 600 seconds "
100+
f"and your certbot propagation time is only {propagation_seconds}.")
101+
102+
self._root_domain = canonical_name.split(3)[1].to_text().rstrip('.')
103+
104+
acme_challenge_prefix = dns.name.Name(labels=[ACME_TXT_PREFIX])
105+
if acme_challenge_prefix.fullcompare(dns.name.Name(labels=[canonical_name.labels[0]]))[0] \
106+
== dns.name.NAMERELN_EQUAL:
107+
name = canonical_name.split(3)[0].to_text()
108+
else:
109+
name = acme_challenge_prefix.concatenate(canonical_name.split(3)[0]).to_text()
110+
except (resolver.NoAnswer, resolver.NXDOMAIN):
111+
canonical_name = domain
95112

96-
if subdomains:
97-
name = f"{ACME_TXT_PREFIX}.{subdomains}"
98-
else:
99-
name = ACME_TXT_PREFIX
113+
self._root_domain = ".".join(canonical_name.split('.')[-2:])
100114

101-
root_domain = f"{extracted_domain.domain}.{extracted_domain.suffix}"
115+
name = ".".join(canonical_name.split('.')[:-2])
102116

103117
try:
104-
self.record_ids[validation] = self._get_porkbun_client().dns_create(root_domain,
118+
self.record_ids[validation] = self._get_porkbun_client().dns_create(self._root_domain,
105119
"TXT",
106120
validation,
107121
name=name)
108122
except Exception as e:
109123
raise errors.PluginError(e)
110124

111-
@staticmethod
112-
def _resolve_canonical_name(domain: str) -> str:
113-
"""
114-
Resolve canonical name (CNAME) for the provided domain with the acme txt prefix.
115-
116-
:param domain: the domain to resolve
117-
:raise PluginError: if something goes wrong when following CNAME
118-
:return: the final resolved domain
119-
"""
120-
121-
# ipv4
122-
try:
123-
return resolver.resolve(f"{ACME_TXT_PREFIX}.{domain}", 'A').canonical_name.to_text().rstrip('.')
124-
except resolver.NXDOMAIN as e:
125-
raise errors.PluginError(e)
126-
except resolver.NoAnswer as e:
127-
# only logging and give a second try with ipv6
128-
logging.warning(e)
129-
130-
# ipv6
131-
try:
132-
return resolver.resolve(f"{ACME_TXT_PREFIX}.{domain}", "AAAA").canonical_name.to_text().rstrip('.')
133-
except (resolver.NoAnswer, resolver.NXDOMAIN) as e:
134-
raise errors.PluginError(e)
135-
136125
def _cleanup(self, domain: str, validation_name: str, validation: str) -> None:
137126
"""
138127
Delete the TXT record of the provided Porkbun domain.
@@ -144,15 +133,11 @@ def _cleanup(self, domain: str, validation_name: str, validation: str) -> None:
144133
:raise PluginError: if the TXT record can not be deleted or something goes wrong
145134
"""
146135

147-
tld = tldextract.TLDExtract(suffix_list_urls=None)
148-
extracted_domain = tld(self._domain)
149-
root_domain = f"{extracted_domain.domain}.{extracted_domain.suffix}"
150-
151136
# get the record id with the TXT record
152137
record_id = self.record_ids[validation]
153138

154139
try:
155-
if not self._get_porkbun_client().dns_delete(root_domain, record_id):
140+
if not self._get_porkbun_client().dns_delete(self._root_domain, record_id):
156141
raise errors.PluginError("TXT for domain {} was not deleted".format(domain))
157142
except Exception as e:
158143
raise errors.PluginError(e)

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
setuptools>=39.0.1
2+
zope.interface>=5.0.0
23
certbot>=1.7.0
34
pkb_client>=1.1
4-
tldextract>=3.1.0
55
dnspython~=2.2

third-party-notices

-35
Original file line numberDiff line numberDiff line change
@@ -326,41 +326,6 @@ SOFTWARE.
326326

327327
###########################################################################################
328328

329-
###########################################################################################
330-
## tldextract: ##
331-
332-
BSD 3-Clause License
333-
334-
Copyright (c) 2020, John Kurkowski
335-
All rights reserved.
336-
337-
Redistribution and use in source and binary forms, with or without
338-
modification, are permitted provided that the following conditions are met:
339-
340-
1. Redistributions of source code must retain the above copyright notice, this
341-
list of conditions and the following disclaimer.
342-
343-
2. Redistributions in binary form must reproduce the above copyright notice,
344-
this list of conditions and the following disclaimer in the documentation
345-
and/or other materials provided with the distribution.
346-
347-
3. Neither the name of the copyright holder nor the names of its
348-
contributors may be used to endorse or promote products derived from
349-
this software without specific prior written permission.
350-
351-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
352-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
353-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
354-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
355-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
356-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
357-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
358-
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
359-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
360-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
361-
362-
###########################################################################################
363-
364329

365330
###########################################################################################
366331
## dnspython: ##

0 commit comments

Comments
 (0)