Merge tag 'upstream/1.3.0'
Upstream version 1.3.0
Harlan Lieberman-Berg
3 years ago
0 | 0 | include LICENSE.txt |
1 | 1 | include README.rst |
2 | 2 | recursive-include docs * |
3 | recursive-include tests * | |
4 | global-exclude __pycache__ | |
5 | global-exclude *.py[cod] |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: certbot-dns-dnsimple |
2 | Version: 0.31.0 | |
2 | Version: 1.3.0 | |
3 | 3 | Summary: DNSimple DNS Authenticator plugin for Certbot |
4 | 4 | Home-page: https://github.com/certbot/certbot |
5 | 5 | Author: Certbot Project |
7 | 7 | License: Apache License 2.0 |
8 | 8 | Description: UNKNOWN |
9 | 9 | Platform: UNKNOWN |
10 | Classifier: Development Status :: 3 - Alpha | |
10 | Classifier: Development Status :: 5 - Production/Stable | |
11 | 11 | Classifier: Environment :: Plugins |
12 | 12 | Classifier: Intended Audience :: System Administrators |
13 | 13 | Classifier: License :: OSI Approved :: Apache Software License |
16 | 16 | Classifier: Programming Language :: Python :: 2 |
17 | 17 | Classifier: Programming Language :: Python :: 2.7 |
18 | 18 | Classifier: Programming Language :: Python :: 3 |
19 | Classifier: Programming Language :: Python :: 3.4 | |
20 | 19 | Classifier: Programming Language :: Python :: 3.5 |
21 | 20 | Classifier: Programming Language :: Python :: 3.6 |
22 | 21 | Classifier: Programming Language :: Python :: 3.7 |
22 | Classifier: Programming Language :: Python :: 3.8 | |
23 | 23 | Classifier: Topic :: Internet :: WWW/HTTP |
24 | 24 | Classifier: Topic :: Security |
25 | 25 | Classifier: Topic :: System :: Installation/Setup |
26 | 26 | Classifier: Topic :: System :: Networking |
27 | 27 | Classifier: Topic :: System :: Systems Administration |
28 | 28 | Classifier: Topic :: Utilities |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* | |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* | |
30 | 30 | Provides-Extra: docs |
0 | """Internal implementation of `~certbot_dns_dnsimple.dns_dnsimple` plugin.""" |
0 | """DNS Authenticator for DNSimple DNS.""" | |
1 | import logging | |
2 | ||
3 | from lexicon.providers import dnsimple | |
4 | import zope.interface | |
5 | ||
6 | from certbot import errors | |
7 | from certbot import interfaces | |
8 | from certbot.plugins import dns_common | |
9 | from certbot.plugins import dns_common_lexicon | |
10 | ||
11 | logger = logging.getLogger(__name__) | |
12 | ||
13 | ACCOUNT_URL = 'https://dnsimple.com/user' | |
14 | ||
15 | ||
16 | @zope.interface.implementer(interfaces.IAuthenticator) | |
17 | @zope.interface.provider(interfaces.IPluginFactory) | |
18 | class Authenticator(dns_common.DNSAuthenticator): | |
19 | """DNS Authenticator for DNSimple | |
20 | ||
21 | This Authenticator uses the DNSimple v2 API to fulfill a dns-01 challenge. | |
22 | """ | |
23 | ||
24 | description = 'Obtain certificates using a DNS TXT record (if you are using DNSimple for DNS).' | |
25 | ttl = 60 | |
26 | ||
27 | def __init__(self, *args, **kwargs): | |
28 | super(Authenticator, self).__init__(*args, **kwargs) | |
29 | self.credentials = None | |
30 | ||
31 | @classmethod | |
32 | def add_parser_arguments(cls, add): # pylint: disable=arguments-differ | |
33 | super(Authenticator, cls).add_parser_arguments(add, default_propagation_seconds=30) | |
34 | add('credentials', help='DNSimple credentials INI file.') | |
35 | ||
36 | def more_info(self): # pylint: disable=missing-function-docstring | |
37 | return 'This plugin configures a DNS TXT record to respond to a dns-01 challenge using ' + \ | |
38 | 'the DNSimple API.' | |
39 | ||
40 | def _setup_credentials(self): | |
41 | self.credentials = self._configure_credentials( | |
42 | 'credentials', | |
43 | 'DNSimple credentials INI file', | |
44 | { | |
45 | 'token': 'User access token for DNSimple v2 API. (See {0}.)'.format(ACCOUNT_URL) | |
46 | } | |
47 | ) | |
48 | ||
49 | def _perform(self, domain, validation_name, validation): | |
50 | self._get_dnsimple_client().add_txt_record(domain, validation_name, validation) | |
51 | ||
52 | def _cleanup(self, domain, validation_name, validation): | |
53 | self._get_dnsimple_client().del_txt_record(domain, validation_name, validation) | |
54 | ||
55 | def _get_dnsimple_client(self): | |
56 | return _DNSimpleLexiconClient(self.credentials.conf('token'), self.ttl) | |
57 | ||
58 | ||
59 | class _DNSimpleLexiconClient(dns_common_lexicon.LexiconClient): | |
60 | """ | |
61 | Encapsulates all communication with the DNSimple via Lexicon. | |
62 | """ | |
63 | ||
64 | def __init__(self, token, ttl): | |
65 | super(_DNSimpleLexiconClient, self).__init__() | |
66 | ||
67 | config = dns_common_lexicon.build_lexicon_config('dnssimple', { | |
68 | 'ttl': ttl, | |
69 | }, { | |
70 | 'auth_token': token, | |
71 | }) | |
72 | ||
73 | self.provider = dnsimple.Provider(config) | |
74 | ||
75 | def _handle_http_error(self, e, domain_name): | |
76 | hint = None | |
77 | if str(e).startswith('401 Client Error: Unauthorized for url:'): | |
78 | hint = 'Is your API token value correct?' | |
79 | ||
80 | return errors.PluginError('Error determining zone identifier for {0}: {1}.{2}' | |
81 | .format(domain_name, e, ' ({0})'.format(hint) if hint else '')) |
0 | """DNS Authenticator for DNSimple DNS.""" | |
1 | import logging | |
2 | ||
3 | import zope.interface | |
4 | from lexicon.providers import dnsimple | |
5 | ||
6 | from certbot import errors | |
7 | from certbot import interfaces | |
8 | from certbot.plugins import dns_common | |
9 | from certbot.plugins import dns_common_lexicon | |
10 | ||
11 | logger = logging.getLogger(__name__) | |
12 | ||
13 | ACCOUNT_URL = 'https://dnsimple.com/user' | |
14 | ||
15 | ||
16 | @zope.interface.implementer(interfaces.IAuthenticator) | |
17 | @zope.interface.provider(interfaces.IPluginFactory) | |
18 | class Authenticator(dns_common.DNSAuthenticator): | |
19 | """DNS Authenticator for DNSimple | |
20 | ||
21 | This Authenticator uses the DNSimple v2 API to fulfill a dns-01 challenge. | |
22 | """ | |
23 | ||
24 | description = 'Obtain certificates using a DNS TXT record (if you are using DNSimple for DNS).' | |
25 | ttl = 60 | |
26 | ||
27 | def __init__(self, *args, **kwargs): | |
28 | super(Authenticator, self).__init__(*args, **kwargs) | |
29 | self.credentials = None | |
30 | ||
31 | @classmethod | |
32 | def add_parser_arguments(cls, add): # pylint: disable=arguments-differ | |
33 | super(Authenticator, cls).add_parser_arguments(add, default_propagation_seconds=30) | |
34 | add('credentials', help='DNSimple credentials INI file.') | |
35 | ||
36 | def more_info(self): # pylint: disable=missing-docstring,no-self-use | |
37 | return 'This plugin configures a DNS TXT record to respond to a dns-01 challenge using ' + \ | |
38 | 'the DNSimple API.' | |
39 | ||
40 | def _setup_credentials(self): | |
41 | self.credentials = self._configure_credentials( | |
42 | 'credentials', | |
43 | 'DNSimple credentials INI file', | |
44 | { | |
45 | 'token': 'User access token for DNSimple v2 API. (See {0}.)'.format(ACCOUNT_URL) | |
46 | } | |
47 | ) | |
48 | ||
49 | def _perform(self, domain, validation_name, validation): | |
50 | self._get_dnsimple_client().add_txt_record(domain, validation_name, validation) | |
51 | ||
52 | def _cleanup(self, domain, validation_name, validation): | |
53 | self._get_dnsimple_client().del_txt_record(domain, validation_name, validation) | |
54 | ||
55 | def _get_dnsimple_client(self): | |
56 | return _DNSimpleLexiconClient(self.credentials.conf('token'), self.ttl) | |
57 | ||
58 | ||
59 | class _DNSimpleLexiconClient(dns_common_lexicon.LexiconClient): | |
60 | """ | |
61 | Encapsulates all communication with the DNSimple via Lexicon. | |
62 | """ | |
63 | ||
64 | def __init__(self, token, ttl): | |
65 | super(_DNSimpleLexiconClient, self).__init__() | |
66 | ||
67 | config = dns_common_lexicon.build_lexicon_config('dnssimple', { | |
68 | 'ttl': ttl, | |
69 | }, { | |
70 | 'auth_token': token, | |
71 | }) | |
72 | ||
73 | self.provider = dnsimple.Provider(config) | |
74 | ||
75 | def _handle_http_error(self, e, domain_name): | |
76 | hint = None | |
77 | if str(e).startswith('401 Client Error: Unauthorized for url:'): | |
78 | hint = 'Is your API token value correct?' | |
79 | ||
80 | return errors.PluginError('Error determining zone identifier for {0}: {1}.{2}' | |
81 | .format(domain_name, e, ' ({0})'.format(hint) if hint else '')) |
0 | """Tests for certbot_dns_dnsimple.dns_dnsimple.""" | |
1 | ||
2 | import os | |
3 | import unittest | |
4 | ||
5 | import mock | |
6 | from requests.exceptions import HTTPError | |
7 | ||
8 | from certbot.plugins import dns_test_common | |
9 | from certbot.plugins import dns_test_common_lexicon | |
10 | from certbot.tests import util as test_util | |
11 | ||
12 | TOKEN = 'foo' | |
13 | ||
14 | ||
15 | class AuthenticatorTest(test_util.TempDirTestCase, | |
16 | dns_test_common_lexicon.BaseLexiconAuthenticatorTest): | |
17 | ||
18 | def setUp(self): | |
19 | super(AuthenticatorTest, self).setUp() | |
20 | ||
21 | from certbot_dns_dnsimple.dns_dnsimple import Authenticator | |
22 | ||
23 | path = os.path.join(self.tempdir, 'file.ini') | |
24 | dns_test_common.write({"dnsimple_token": TOKEN}, path) | |
25 | ||
26 | self.config = mock.MagicMock(dnsimple_credentials=path, | |
27 | dnsimple_propagation_seconds=0) # don't wait during tests | |
28 | ||
29 | self.auth = Authenticator(self.config, "dnsimple") | |
30 | ||
31 | self.mock_client = mock.MagicMock() | |
32 | # _get_dnsimple_client | pylint: disable=protected-access | |
33 | self.auth._get_dnsimple_client = mock.MagicMock(return_value=self.mock_client) | |
34 | ||
35 | ||
36 | class DNSimpleLexiconClientTest(unittest.TestCase, dns_test_common_lexicon.BaseLexiconClientTest): | |
37 | ||
38 | LOGIN_ERROR = HTTPError('401 Client Error: Unauthorized for url: ...') | |
39 | ||
40 | def setUp(self): | |
41 | from certbot_dns_dnsimple.dns_dnsimple import _DNSimpleLexiconClient | |
42 | ||
43 | self.client = _DNSimpleLexiconClient(TOKEN, 0) | |
44 | ||
45 | self.provider_mock = mock.MagicMock() | |
46 | self.client.provider = self.provider_mock | |
47 | ||
48 | ||
49 | if __name__ == "__main__": | |
50 | unittest.main() # pragma: no cover |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: certbot-dns-dnsimple |
2 | Version: 0.31.0 | |
2 | Version: 1.3.0 | |
3 | 3 | Summary: DNSimple DNS Authenticator plugin for Certbot |
4 | 4 | Home-page: https://github.com/certbot/certbot |
5 | 5 | Author: Certbot Project |
7 | 7 | License: Apache License 2.0 |
8 | 8 | Description: UNKNOWN |
9 | 9 | Platform: UNKNOWN |
10 | Classifier: Development Status :: 3 - Alpha | |
10 | Classifier: Development Status :: 5 - Production/Stable | |
11 | 11 | Classifier: Environment :: Plugins |
12 | 12 | Classifier: Intended Audience :: System Administrators |
13 | 13 | Classifier: License :: OSI Approved :: Apache Software License |
16 | 16 | Classifier: Programming Language :: Python :: 2 |
17 | 17 | Classifier: Programming Language :: Python :: 2.7 |
18 | 18 | Classifier: Programming Language :: Python :: 3 |
19 | Classifier: Programming Language :: Python :: 3.4 | |
20 | 19 | Classifier: Programming Language :: Python :: 3.5 |
21 | 20 | Classifier: Programming Language :: Python :: 3.6 |
22 | 21 | Classifier: Programming Language :: Python :: 3.7 |
22 | Classifier: Programming Language :: Python :: 3.8 | |
23 | 23 | Classifier: Topic :: Internet :: WWW/HTTP |
24 | 24 | Classifier: Topic :: Security |
25 | 25 | Classifier: Topic :: System :: Installation/Setup |
26 | 26 | Classifier: Topic :: System :: Networking |
27 | 27 | Classifier: Topic :: System :: Systems Administration |
28 | 28 | Classifier: Topic :: Utilities |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* | |
29 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* | |
30 | 30 | Provides-Extra: docs |
3 | 3 | setup.cfg |
4 | 4 | setup.py |
5 | 5 | certbot_dns_dnsimple/__init__.py |
6 | certbot_dns_dnsimple/dns_dnsimple.py | |
7 | certbot_dns_dnsimple/dns_dnsimple_test.py | |
8 | 6 | certbot_dns_dnsimple.egg-info/PKG-INFO |
9 | 7 | certbot_dns_dnsimple.egg-info/SOURCES.txt |
10 | 8 | certbot_dns_dnsimple.egg-info/dependency_links.txt |
11 | 9 | certbot_dns_dnsimple.egg-info/entry_points.txt |
12 | 10 | certbot_dns_dnsimple.egg-info/requires.txt |
13 | 11 | certbot_dns_dnsimple.egg-info/top_level.txt |
12 | certbot_dns_dnsimple/_internal/__init__.py | |
13 | certbot_dns_dnsimple/_internal/dns_dnsimple.py | |
14 | 14 | docs/.gitignore |
15 | 15 | docs/Makefile |
16 | 16 | docs/api.rst |
17 | 17 | docs/conf.py |
18 | 18 | docs/index.rst |
19 | 19 | docs/make.bat |
20 | docs/api/dns_dnsimple.rst⏎ | |
20 | tests/dns_dnsimple_test.py⏎ |
0 | 0 | [certbot.plugins] |
1 | dns-dnsimple = certbot_dns_dnsimple.dns_dnsimple:Authenticator | |
1 | dns-dnsimple = certbot_dns_dnsimple._internal.dns_dnsimple:Authenticator | |
2 | 2 |
0 | 0 | acme>=0.31.0 |
1 | certbot>=0.31.0 | |
2 | dns-lexicon>=2.2.1 | |
1 | certbot>=1.1.0 | |
3 | 2 | mock |
4 | 3 | setuptools |
5 | 4 | zope.interface |
5 | dns-lexicon>=3.2.1 | |
6 | 6 | |
7 | 7 | [docs] |
8 | 8 | Sphinx>=1.0 |
0 | :mod:`certbot_dns_dnsimple.dns_dnsimple` | |
1 | ---------------------------------------- | |
2 | ||
3 | .. automodule:: certbot_dns_dnsimple.dns_dnsimple | |
4 | :members: |
1 | 1 | API Documentation |
2 | 2 | ================= |
3 | 3 | |
4 | .. toctree:: | |
5 | :glob: | |
6 | ||
7 | api/** | |
4 | Certbot plugins implement the Certbot plugins API, and do not otherwise have an external API. |
16 | 16 | # documentation root, use os.path.abspath to make it absolute, like shown here. |
17 | 17 | # |
18 | 18 | import os |
19 | ||
19 | 20 | # import sys |
20 | 21 | # sys.path.insert(0, os.path.abspath('.')) |
21 | 22 | |
36 | 37 | 'sphinx.ext.viewcode'] |
37 | 38 | |
38 | 39 | autodoc_member_order = 'bysource' |
39 | autodoc_default_flags = ['show-inheritance', 'private-members'] | |
40 | autodoc_default_flags = ['show-inheritance'] | |
40 | 41 | |
41 | 42 | # Add any paths that contain templates here, relative to this directory. |
42 | 43 | templates_path = ['_templates'] |
82 | 83 | pygments_style = 'sphinx' |
83 | 84 | |
84 | 85 | # If true, `todo` and `todoList` produce output, else they produce nothing. |
85 | todo_include_todos = True | |
86 | todo_include_todos = False | |
86 | 87 | |
87 | 88 | |
88 | 89 | # -- Options for HTML output ---------------------------------------------- |
0 | import os | |
1 | import sys | |
2 | ||
3 | from setuptools import find_packages | |
0 | 4 | from setuptools import setup |
1 | from setuptools import find_packages | |
5 | from setuptools.command.test import test as TestCommand | |
2 | 6 | |
3 | ||
4 | version = '0.31.0' | |
7 | version = '1.3.0' | |
5 | 8 | |
6 | 9 | # Remember to update local-oldest-requirements.txt when changing the minimum |
7 | 10 | # acme/certbot version. |
8 | 11 | install_requires = [ |
9 | 12 | 'acme>=0.31.0', |
10 | 'certbot>=0.31.0', | |
11 | 'dns-lexicon>=2.2.1', # Support for >1 TXT record per name | |
13 | 'certbot>=1.1.0', | |
12 | 14 | 'mock', |
13 | 15 | 'setuptools', |
14 | 16 | 'zope.interface', |
15 | 17 | ] |
16 | 18 | |
19 | # This package normally depends on dns-lexicon>=3.2.1 to address the | |
20 | # problem described in https://github.com/AnalogJ/lexicon/issues/387, | |
21 | # however, the fix there has been backported to older versions of | |
22 | # lexicon found in various Linux distros. This conditional helps us test | |
23 | # that we've maintained compatibility with these versions of lexicon | |
24 | # which allows us to potentially upgrade our packages in these distros | |
25 | # as necessary. | |
26 | if os.environ.get('CERTBOT_OLDEST') == '1': | |
27 | install_requires.append('dns-lexicon>=2.2.1') | |
28 | else: | |
29 | install_requires.append('dns-lexicon>=3.2.1') | |
30 | ||
17 | 31 | docs_extras = [ |
18 | 32 | 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags |
19 | 33 | 'sphinx_rtd_theme', |
20 | 34 | ] |
35 | ||
36 | class PyTest(TestCommand): | |
37 | user_options = [] | |
38 | ||
39 | def initialize_options(self): | |
40 | TestCommand.initialize_options(self) | |
41 | self.pytest_args = '' | |
42 | ||
43 | def run_tests(self): | |
44 | import shlex | |
45 | # import here, cause outside the eggs aren't loaded | |
46 | import pytest | |
47 | errno = pytest.main(shlex.split(self.pytest_args)) | |
48 | sys.exit(errno) | |
21 | 49 | |
22 | 50 | setup( |
23 | 51 | name='certbot-dns-dnsimple', |
27 | 55 | author="Certbot Project", |
28 | 56 | author_email='client-dev@letsencrypt.org', |
29 | 57 | license='Apache License 2.0', |
30 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', | |
58 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', | |
31 | 59 | classifiers=[ |
32 | 'Development Status :: 3 - Alpha', | |
60 | 'Development Status :: 5 - Production/Stable', | |
33 | 61 | 'Environment :: Plugins', |
34 | 62 | 'Intended Audience :: System Administrators', |
35 | 63 | 'License :: OSI Approved :: Apache Software License', |
38 | 66 | 'Programming Language :: Python :: 2', |
39 | 67 | 'Programming Language :: Python :: 2.7', |
40 | 68 | 'Programming Language :: Python :: 3', |
41 | 'Programming Language :: Python :: 3.4', | |
42 | 69 | 'Programming Language :: Python :: 3.5', |
43 | 70 | 'Programming Language :: Python :: 3.6', |
44 | 71 | 'Programming Language :: Python :: 3.7', |
72 | 'Programming Language :: Python :: 3.8', | |
45 | 73 | 'Topic :: Internet :: WWW/HTTP', |
46 | 74 | 'Topic :: Security', |
47 | 75 | 'Topic :: System :: Installation/Setup', |
58 | 86 | }, |
59 | 87 | entry_points={ |
60 | 88 | 'certbot.plugins': [ |
61 | 'dns-dnsimple = certbot_dns_dnsimple.dns_dnsimple:Authenticator', | |
89 | 'dns-dnsimple = certbot_dns_dnsimple._internal.dns_dnsimple:Authenticator', | |
62 | 90 | ], |
63 | 91 | }, |
92 | tests_require=["pytest"], | |
64 | 93 | test_suite='certbot_dns_dnsimple', |
94 | cmdclass={"test": PyTest}, | |
65 | 95 | ) |
0 | """Tests for certbot_dns_dnsimple._internal.dns_dnsimple.""" | |
1 | ||
2 | import unittest | |
3 | ||
4 | import mock | |
5 | from requests.exceptions import HTTPError | |
6 | ||
7 | from certbot.compat import os | |
8 | from certbot.plugins import dns_test_common | |
9 | from certbot.plugins import dns_test_common_lexicon | |
10 | from certbot.tests import util as test_util | |
11 | ||
12 | TOKEN = 'foo' | |
13 | ||
14 | ||
15 | class AuthenticatorTest(test_util.TempDirTestCase, | |
16 | dns_test_common_lexicon.BaseLexiconAuthenticatorTest): | |
17 | ||
18 | def setUp(self): | |
19 | super(AuthenticatorTest, self).setUp() | |
20 | ||
21 | from certbot_dns_dnsimple._internal.dns_dnsimple import Authenticator | |
22 | ||
23 | path = os.path.join(self.tempdir, 'file.ini') | |
24 | dns_test_common.write({"dnsimple_token": TOKEN}, path) | |
25 | ||
26 | self.config = mock.MagicMock(dnsimple_credentials=path, | |
27 | dnsimple_propagation_seconds=0) # don't wait during tests | |
28 | ||
29 | self.auth = Authenticator(self.config, "dnsimple") | |
30 | ||
31 | self.mock_client = mock.MagicMock() | |
32 | # _get_dnsimple_client | pylint: disable=protected-access | |
33 | self.auth._get_dnsimple_client = mock.MagicMock(return_value=self.mock_client) | |
34 | ||
35 | ||
36 | class DNSimpleLexiconClientTest(unittest.TestCase, dns_test_common_lexicon.BaseLexiconClientTest): | |
37 | ||
38 | LOGIN_ERROR = HTTPError('401 Client Error: Unauthorized for url: ...') | |
39 | ||
40 | def setUp(self): | |
41 | from certbot_dns_dnsimple._internal.dns_dnsimple import _DNSimpleLexiconClient | |
42 | ||
43 | self.client = _DNSimpleLexiconClient(TOKEN, 0) | |
44 | ||
45 | self.provider_mock = mock.MagicMock() | |
46 | self.client.provider = self.provider_mock | |
47 | ||
48 | ||
49 | if __name__ == "__main__": | |
50 | unittest.main() # pragma: no cover |