certbot-dns-directadmin 0.0.3__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin/__init__.py +1 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin/__pycache__/__init__.cpython-37.pyc +0 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin/__pycache__/directadmin.cpython-37.pyc +0 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin/__pycache__/dns_directadmin.cpython-37.pyc +0 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin/directadmin.py +142 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin/dns_directadmin.py +132 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin-0.0.3-py3.7.egg-info/PKG-INFO +84 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin-0.0.3-py3.7.egg-info/SOURCES.txt +12 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin-0.0.3-py3.7.egg-info/dependency_links.txt +1 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin-0.0.3-py3.7.egg-info/entry_points.txt +3 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin-0.0.3-py3.7.egg-info/requires.txt +3 -0
- Storage/OneDrive/OneDrive - WHS/Projects/certbot-dns-directadmin/.venv/Lib/site-packages/certbot_dns_directadmin-0.0.3-py3.7.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Directadmin dns-01 authenticator plugin"""
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from collections import OrderedDict
|
|
3
|
+
import requests
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
# python 3
|
|
7
|
+
from urllib.request import urlopen, Request
|
|
8
|
+
from urllib.parse import urlencode, parse_qs
|
|
9
|
+
except ImportError:
|
|
10
|
+
# python 2
|
|
11
|
+
from urllib import urlencode
|
|
12
|
+
from urllib2 import urlopen, Request
|
|
13
|
+
from cgi import parse_qs
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DirectAdminClient:
|
|
17
|
+
|
|
18
|
+
def __init__(self, url, username, password):
|
|
19
|
+
|
|
20
|
+
self.version = "0.0.3"
|
|
21
|
+
self.client = requests.session()
|
|
22
|
+
self.headers = {'user-agent': 'pyDirectAdmin/' + str(self.version),
|
|
23
|
+
'Authorization': 'Basic %s' % base64.b64encode(("%s:%s" %
|
|
24
|
+
(username, password))
|
|
25
|
+
.encode()).decode('utf8'),
|
|
26
|
+
}
|
|
27
|
+
self.url = url
|
|
28
|
+
|
|
29
|
+
def make_request(self, endpoint, data=None):
|
|
30
|
+
response = None # Empty response variable
|
|
31
|
+
|
|
32
|
+
if data is not None:
|
|
33
|
+
# Data is present add the fields to call
|
|
34
|
+
response = urlopen(
|
|
35
|
+
Request(
|
|
36
|
+
"%s?%s" % (self.url + '/{}'.format(endpoint), urlencode(data)),
|
|
37
|
+
headers=self.headers,
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
elif data is None:
|
|
41
|
+
# Data is not present so we don't need addition field.
|
|
42
|
+
response = urlopen(
|
|
43
|
+
Request(
|
|
44
|
+
"%s?" % (self.url + '/{}'.format(endpoint)),
|
|
45
|
+
headers=self.headers,
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return response
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def __process_response__(response):
|
|
53
|
+
if int(response['error'][0]) > 0:
|
|
54
|
+
# There was an error
|
|
55
|
+
raise Exception(response['text'][0])
|
|
56
|
+
elif int(response['error'][0]) == 0:
|
|
57
|
+
# Everything succeeded
|
|
58
|
+
return {'error': response['error'][0],
|
|
59
|
+
'message': response['text'][0]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
def get_domain_list(self):
|
|
63
|
+
r = self.make_request('CMD_API_SHOW_DOMAINS')
|
|
64
|
+
|
|
65
|
+
domains = parse_qs(r.read().decode('utf8'),
|
|
66
|
+
keep_blank_values=0,
|
|
67
|
+
strict_parsing=1)
|
|
68
|
+
response = list()
|
|
69
|
+
for domain in domains.values():
|
|
70
|
+
response.append(domain[0])
|
|
71
|
+
return response
|
|
72
|
+
|
|
73
|
+
def get_zone_list(self, domain):
|
|
74
|
+
params = OrderedDict([('domain', domain)])
|
|
75
|
+
r = self.make_request('CMD_API_DNS_CONTROL', params)
|
|
76
|
+
|
|
77
|
+
return r.read()
|
|
78
|
+
|
|
79
|
+
def add_dns_record(self, domain, record_type, record_name, record_value, record_ttl=None):
|
|
80
|
+
|
|
81
|
+
params = OrderedDict([('domain', domain),
|
|
82
|
+
('action', 'add'),
|
|
83
|
+
('type', record_type.upper()),
|
|
84
|
+
('name', record_name),
|
|
85
|
+
('value', record_value)])
|
|
86
|
+
|
|
87
|
+
if record_ttl is not None:
|
|
88
|
+
params.update({'ttl': record_ttl})
|
|
89
|
+
|
|
90
|
+
response = self.make_request('CMD_API_DNS_CONTROL', data=params)
|
|
91
|
+
response = parse_qs(response.read().decode('utf8'),
|
|
92
|
+
keep_blank_values=0,
|
|
93
|
+
strict_parsing=1)
|
|
94
|
+
|
|
95
|
+
return self.__process_response__(response)
|
|
96
|
+
|
|
97
|
+
def update_dns_record(self, domain, record_type, record_name, record_value_old, record_value_new, record_ttl=None):
|
|
98
|
+
|
|
99
|
+
params = OrderedDict([('domain', domain),
|
|
100
|
+
('action', 'edit'),
|
|
101
|
+
('type', record_type.upper()),
|
|
102
|
+
(record_type.lower() + "recs0", 'name={}&value={}'.format(record_name, record_value_old)),
|
|
103
|
+
('name', record_name),
|
|
104
|
+
('value', record_value_new)])
|
|
105
|
+
|
|
106
|
+
if record_ttl is not None:
|
|
107
|
+
params.update({'ttl': record_ttl})
|
|
108
|
+
|
|
109
|
+
response = self.make_request('CMD_API_DNS_CONTROL', data=params)
|
|
110
|
+
response = parse_qs(response.read().decode('utf8'),
|
|
111
|
+
keep_blank_values=0,
|
|
112
|
+
strict_parsing=1)
|
|
113
|
+
|
|
114
|
+
return self.__process_response__(response)
|
|
115
|
+
|
|
116
|
+
def delete_dns_record(self, domain, record_type, record_name, record_value):
|
|
117
|
+
params = OrderedDict([('domain', domain),
|
|
118
|
+
('action', 'select'),
|
|
119
|
+
(record_type.lower() + "recs0", 'name={}&value={}'.format(record_name, record_value))
|
|
120
|
+
])
|
|
121
|
+
|
|
122
|
+
response = self.make_request('CMD_API_DNS_CONTROL', data=params)
|
|
123
|
+
response = parse_qs(response.read().decode('utf8'),
|
|
124
|
+
keep_blank_values=0,
|
|
125
|
+
strict_parsing=1)
|
|
126
|
+
|
|
127
|
+
return self.__process_response__(response)
|
|
128
|
+
|
|
129
|
+
def override_domain_ttl(self, domain, record_name, ttl):
|
|
130
|
+
params = OrderedDict([('domain', domain),
|
|
131
|
+
('action', 'ttl'),
|
|
132
|
+
('ttl_select', 'custom'),
|
|
133
|
+
('name', record_name),
|
|
134
|
+
('ttl', ttl)])
|
|
135
|
+
|
|
136
|
+
response = self.make_request('CMD_API_DNS_CONTROL', data=params)
|
|
137
|
+
response = parse_qs(response.read().decode('utf8'),
|
|
138
|
+
keep_blank_values=0,
|
|
139
|
+
strict_parsing=1)
|
|
140
|
+
|
|
141
|
+
return self.__process_response__(response)
|
|
142
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Directadmin dns-01 authenticator plugin"""
|
|
2
|
+
import logging
|
|
3
|
+
import tldextract
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
# python 3
|
|
7
|
+
from urllib.request import urlopen, Request
|
|
8
|
+
from urllib.parse import urlencode
|
|
9
|
+
except ImportError:
|
|
10
|
+
# python 2
|
|
11
|
+
from urllib import urlencode
|
|
12
|
+
from urllib2 import urlopen, Request
|
|
13
|
+
|
|
14
|
+
import zope.interface
|
|
15
|
+
|
|
16
|
+
from certbot import errors
|
|
17
|
+
from certbot import interfaces
|
|
18
|
+
from certbot.plugins import dns_common
|
|
19
|
+
from certbot_dns_directadmin.directadmin import DirectAdminClient
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@zope.interface.implementer(interfaces.IAuthenticator)
|
|
25
|
+
@zope.interface.provider(interfaces.IPluginFactory)
|
|
26
|
+
class Authenticator(dns_common.DNSAuthenticator):
|
|
27
|
+
"""directadmin dns-01 authenticator plugin"""
|
|
28
|
+
|
|
29
|
+
description = "Obtain a certificate using a DNS TXT record in directadmin"
|
|
30
|
+
problem = "a"
|
|
31
|
+
|
|
32
|
+
def __init__(self, *args, **kwargs):
|
|
33
|
+
super(Authenticator, self).__init__(*args, **kwargs)
|
|
34
|
+
self.credentials = None
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def add_parser_arguments(cls, add): # pylint: disable=arguments-differ
|
|
38
|
+
super(Authenticator, cls).add_parser_arguments(add, default_propagation_seconds=10)
|
|
39
|
+
add("credentials",
|
|
40
|
+
type=str,
|
|
41
|
+
help="The directadmin credentials INI file")
|
|
42
|
+
|
|
43
|
+
def more_info(self): # pylint: disable=missing-docstring
|
|
44
|
+
return self.description
|
|
45
|
+
|
|
46
|
+
def _setup_credentials(self):
|
|
47
|
+
self.credentials = self._configure_credentials(
|
|
48
|
+
'credentials',
|
|
49
|
+
'The directadmin credentials INI file',
|
|
50
|
+
{
|
|
51
|
+
'url': 'directadmin url',
|
|
52
|
+
'username': 'directadmin username',
|
|
53
|
+
'password': 'directadmin password'
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def _perform(self, domain, validation_domain_name, validation):
|
|
58
|
+
self._get_directadmin_client().add_txt_record(validation_domain_name, validation)
|
|
59
|
+
|
|
60
|
+
def _cleanup(self, domain, validation_domain_name, validation):
|
|
61
|
+
self._get_directadmin_client().del_txt_record(validation_domain_name, validation)
|
|
62
|
+
|
|
63
|
+
def _get_directadmin_client(self):
|
|
64
|
+
return _DirectadminClient(
|
|
65
|
+
self.credentials.conf('url'),
|
|
66
|
+
self.credentials.conf('username'),
|
|
67
|
+
self.credentials.conf('password')
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class _DirectadminClient:
|
|
72
|
+
"""Encapsulate communications with the directadmin API"""
|
|
73
|
+
|
|
74
|
+
def __init__(self, url, username, password):
|
|
75
|
+
self.url = url
|
|
76
|
+
self.client = DirectAdminClient(url, username, password)
|
|
77
|
+
|
|
78
|
+
def add_txt_record(self, record_name, record_content, record_ttl=60):
|
|
79
|
+
"""Add a TXT record
|
|
80
|
+
:param str record_name: the domain name to add
|
|
81
|
+
:param str record_content: the content of the TXT record to add
|
|
82
|
+
:param int record_ttl: the TTL of the record to add
|
|
83
|
+
"""
|
|
84
|
+
(directadmin_zone, directadmin_name) = self._get_zone_and_name(record_name)
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
response = self.client.add_dns_record(directadmin_zone,
|
|
88
|
+
'txt',
|
|
89
|
+
directadmin_name,
|
|
90
|
+
record_value=record_content,
|
|
91
|
+
record_ttl=record_ttl)
|
|
92
|
+
|
|
93
|
+
logger.debug(response)
|
|
94
|
+
if int(response['error']) == 0:
|
|
95
|
+
logger.info("Successfully added TXT record for %s", record_name)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
raise errors.PluginError("Error adding TXT record: %s" % e)
|
|
98
|
+
|
|
99
|
+
def del_txt_record(self, record_name, record_content, record_ttl=60):
|
|
100
|
+
"""Remove a TXT record
|
|
101
|
+
:param str record_name: the domain name to remove
|
|
102
|
+
:param str record_content: the content of the TXT record to remove
|
|
103
|
+
:param int record_ttl: the TTL of the record to remove
|
|
104
|
+
"""
|
|
105
|
+
(directadmin_zone, directadmin_name) = self._get_zone_and_name(record_name)
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
response = self.client.delete_dns_record(directadmin_zone, 'txt', directadmin_name, record_content)
|
|
109
|
+
logger.debug(response)
|
|
110
|
+
if int(response['error']) == 0:
|
|
111
|
+
logger.info("Successfully removed TXT record for %s", record_name)
|
|
112
|
+
except Exception as e:
|
|
113
|
+
raise errors.PluginError("Error removing TXT record: %s" % e)
|
|
114
|
+
|
|
115
|
+
def _get_zone_and_name(self, record_domain):
|
|
116
|
+
"""Find a suitable zone for a domain
|
|
117
|
+
:param str record_name: the domain name
|
|
118
|
+
:returns: (the zone, the name in the zone)
|
|
119
|
+
:rtype: tuple
|
|
120
|
+
"""
|
|
121
|
+
directadmin_zone = ''
|
|
122
|
+
directadmin_name = ''
|
|
123
|
+
logger.debug('Record Domain: ' + record_domain)
|
|
124
|
+
(subdomain, domain, suffix) = tldextract.extract(record_domain)
|
|
125
|
+
logger.debug('Subdomain: ' + subdomain)
|
|
126
|
+
logger.debug('Domain: ' + domain)
|
|
127
|
+
logger.debug('Suffix: ' + suffix)
|
|
128
|
+
|
|
129
|
+
directadmin_zone = ".".join((domain, suffix))
|
|
130
|
+
directadmin_name = subdomain
|
|
131
|
+
|
|
132
|
+
return directadmin_zone, directadmin_name
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: certbot-dns-directadmin
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: certbot plugin to allow acme dns-01 authentication of a name managed in DirectAdmin.
|
|
5
|
+
Home-page: https://github.com/cybercinch/certbot-dns-directadmin
|
|
6
|
+
Author: Aaron Guise
|
|
7
|
+
Author-email: aaron@guise.net.nz
|
|
8
|
+
License: Apache Licence 2.0
|
|
9
|
+
Description: # certbot-dns-directadmin
|
|
10
|
+
|
|
11
|
+
Plugin to allow acme dns-01 authentication of a name managed in DirectAdmin. Useful for automating and creating a Let's Encrypt certificate (wildcard or not) for a service with a name managed by DirectAdmin, but installed on a server not managed in DirectAdmin.
|
|
12
|
+
|
|
13
|
+
## How to use
|
|
14
|
+
### 1. Install
|
|
15
|
+
First, install certbot and the plugin using pip:
|
|
16
|
+
```
|
|
17
|
+
pip install certbot certbot-dns-directadmin
|
|
18
|
+
```
|
|
19
|
+
### 2. Configure
|
|
20
|
+
Download the file `credentials.ini.example` and rename it to `directadmin-credentials.ini`. Edit it to set your DirectAdmin url, username and password.
|
|
21
|
+
```
|
|
22
|
+
# The url DirectAdmin url
|
|
23
|
+
# include the scheme and the port number (usually 2222)
|
|
24
|
+
certbot_dns_directadmin:directadmin_url = https://directadmin.example.com:2222
|
|
25
|
+
# The DirectAdmin username
|
|
26
|
+
certbot_dns_directadmin:directadmin_username = user
|
|
27
|
+
|
|
28
|
+
# The DirectAdmin password
|
|
29
|
+
certbot_dns_directadmin:directadmin_password = hunter2
|
|
30
|
+
```
|
|
31
|
+
### 3. Run
|
|
32
|
+
You can now run certbot using the plugin and feeding the credentials file.
|
|
33
|
+
For example, to get a certificate for example.com and www.example.com:
|
|
34
|
+
```
|
|
35
|
+
certbot certonly \
|
|
36
|
+
--authenticator certbot-dns-directadmin:directadmin \
|
|
37
|
+
--certbot-dns-directadmin:panel-credentials /path/to/directadmin-credentials.ini \
|
|
38
|
+
-d example.com \
|
|
39
|
+
-d www.example.com
|
|
40
|
+
```
|
|
41
|
+
To create a wildcard certificate *.example.com and install it on an apache server, the installer plugin must be specified with the `--installer` option.
|
|
42
|
+
You will need to install the apache plugin if it's not already present on your system.
|
|
43
|
+
```
|
|
44
|
+
pip install certbot-apache
|
|
45
|
+
certbot run \
|
|
46
|
+
--apache \
|
|
47
|
+
--authenticator certbot-dns-directadmin:directadmin \
|
|
48
|
+
--installer apache \
|
|
49
|
+
--certbot-dns-directadmin:directadmin-credentials /path/to/directadmin-credentials.ini \
|
|
50
|
+
-d '*.example.com'
|
|
51
|
+
```
|
|
52
|
+
The certbot documentation has some additionnal informations about combining authenticator and installer plugins: https://certbot.eff.org/docs/using.html#getting-certificates-and-choosing-plugins
|
|
53
|
+
|
|
54
|
+
## Docker
|
|
55
|
+
A docker image based on [certbot/certbot](https://hub.docker.com/r/certbot/certbot/) is provided for your convenience:
|
|
56
|
+
```
|
|
57
|
+
docker run \
|
|
58
|
+
-v /path/to/credentials.ini:/tmp/credentials.ini \
|
|
59
|
+
cybercinch/certbot-dns-directadmin \
|
|
60
|
+
certonly \
|
|
61
|
+
--authenticator certbot-dns-directadmin:directadmin \
|
|
62
|
+
--certbot-dns-cpanel:cpanel-credentials /tmp/directadmin-credentials.ini \
|
|
63
|
+
-d example.com \
|
|
64
|
+
-d www.example.com
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Additional documentation
|
|
68
|
+
* https://certbot.eff.org/docs/
|
|
69
|
+
|
|
70
|
+
Keywords: certbot letsencrypt directadmin da dns-01 plugin
|
|
71
|
+
Platform: UNKNOWN
|
|
72
|
+
Classifier: Development Status :: 3 - Alpha
|
|
73
|
+
Classifier: Environment :: Plugins
|
|
74
|
+
Classifier: Intended Audience :: System Administrators
|
|
75
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
76
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
77
|
+
Classifier: Programming Language :: Python
|
|
78
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
79
|
+
Classifier: Topic :: Security
|
|
80
|
+
Classifier: Topic :: System :: Installation/Setup
|
|
81
|
+
Classifier: Topic :: System :: Networking
|
|
82
|
+
Classifier: Topic :: System :: Systems Administration
|
|
83
|
+
Classifier: Topic :: Utilities
|
|
84
|
+
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.cfg
|
|
3
|
+
setup.py
|
|
4
|
+
certbot_dns_directadmin/__init__.py
|
|
5
|
+
certbot_dns_directadmin/directadmin.py
|
|
6
|
+
certbot_dns_directadmin/dns_directadmin.py
|
|
7
|
+
certbot_dns_directadmin.egg-info/PKG-INFO
|
|
8
|
+
certbot_dns_directadmin.egg-info/SOURCES.txt
|
|
9
|
+
certbot_dns_directadmin.egg-info/dependency_links.txt
|
|
10
|
+
certbot_dns_directadmin.egg-info/entry_points.txt
|
|
11
|
+
certbot_dns_directadmin.egg-info/requires.txt
|
|
12
|
+
certbot_dns_directadmin.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
certbot_dns_directadmin
|