diff --git a/.gitignore b/.gitignore index 2283895..7ed1617 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +#Snap +certbot-dns-ionos_20240108_amd64.snap +#snap-constraints.txt # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig # Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,python diff --git a/README.md b/README.md new file mode 100644 index 0000000..2f4f814 --- /dev/null +++ b/README.md @@ -0,0 +1,156 @@ +# certbot-dns-ionos + +[IONOS](https://www.ionos.de/) DNS Authenticator plugin for [Certbot](https://certbot.eff.org/) + +![Ionos](https://www.ionos.co.uk/newsroom/wp-content/uploads/sites/7/2021/12/LOGO_IONOS_Blue_RGB-1.png) + +This plugin automates the process of completing a ``dns-01`` challenge by +creating, and subsequently removing, TXT records using the [IONOS Remote API](https://developer.hosting.ionos.com/docs/dns). + +## Configuration of IONOS + +In the `System -> Remote Users` you have to have a user, with the following rights + +- Client Functions +- DNS zone functions +- DNS txt functions + +## Installation + +### Snap + +[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/certbot-dns-ionos) +Snap version will be compatible with certbot 3.0. Thanks to [DorianCoding](https://github.com/DorianCoding) to make this plugin avalabe in the Snap Store. + +### Pip + +`pip install certbot-dns-ionos` + +## Named Arguments + +To start using DNS authentication for ionos, pass the following arguments on certbot's command line: + +| Command args | Command definition | +| --- | --- | +|``--authenticator dns-ionos`` | select the authenticator plugin (Required) | +|``--dns-ionos-credentials`` |ionos Remote User credentials INI file. (Required) | +|``--dns-ionos-propagation-seconds``|waiting time for DNS to propagate before asking the ACME server to verify the DNS record. (Default: 10, Recommended: 60) | + +## Credentials + +An example ``credentials.ini`` file: + +```ini +dns_ionos_prefix = myapikeyprefix +dns_ionos_secret = verysecureapikeysecret +dns_ionos_endpoint = https://api.hosting.ionos.com +``` + +The key can be managed under the following link: + +The path to this file can be provided interactively or using the +`--dns-ionos-credentials` command-line argument. Certbot +records the path to this file for use during renewal, but does not store the file's contents. + +> [!CAUTION] +> You should protect these API credentials as you would the +password to your ionos account. Users who can read this file can use these credentials to issue arbitrary API calls +on your behalf. Users who can cause Certbot to run using these credentials can complete a ``dns-01`` challenge +to acquire new certificates or revoke existing certificates for associated domains, even if those domains aren't +being managed by this server. + +> [!WARNING] +> Certbot will emit a warning if it detects that the credentials file can be accessed by other users on your system. +The warning reads "Unsafe permissions on credentials configuration file", followed by the path to the +credentials file. This warning will be emitted each time Certbot uses the credentials file, including for renewal, +and cannot be silenced except by addressing the issue (e.g., by using a command like ``chmod 600`` to +restrict access to the file and ``chmod 700`` to restrict access to the folder). + +## Examples + +To acquire a single certificate for both ``example.com`` and +``*.example.com``, waiting 900 seconds for DNS propagation: + +```bash +certbot certonly \ +--authenticator dns-ionos \ +--dns-ionos-credentials /etc/letsencrypt/.secrets/domain.tld.ini \ +--dns-ionos-propagation-seconds 900 \ +--server https://acme-v02.api.letsencrypt.org/directory \ +--agree-tos \ +--rsa-key-size 4096 \ +-d 'example.com' \ +-d '*.example.com' +``` + +## Docker + +In order to create a docker container with a certbot-dns-ionos installation, +create an empty directory with the following ``Dockerfile``: + +```docker +FROM certbot/certbot +RUN pip install certbot-dns-ionos +``` + +Proceed to build the image + +```docker +docker build -t certbot/dns-ionos . +``` + +Once that's finished, the application can be run as follows:: + +```docker +docker run --rm \ +-v /var/lib/letsencrypt:/var/lib/letsencrypt \ +-v /etc/letsencrypt:/etc/letsencrypt \ +--cap-drop=all \ +certbot/dns-ionos certonly \ +--authenticator dns-ionos \ +--dns-ionos-propagation-seconds 900 \ +--dns-ionos-credentials \ +/etc/letsencrypt/.secrets/domain.tld.ini \ +--no-self-upgrade \ +--keep-until-expiring --non-interactive --expand \ +--server https://acme-v02.api.letsencrypt.org/directory \ +-d example.com -d '*.example.com' +``` + +It is suggested to secure the folder as follows + +```bash +chown root:root /etc/letsencrypt/.secrets +chmod 700 /etc/letsencrypt/.secrets +``` + +The file 'domain.tld.ini' must be replaced with the version of the example 'credentials.ini' adapted to your provider. + +## Changelog + +- 2024.10.19 + - Update for Certbot 2.11.0 + - Update README.md, changed from README.rst + - Addition of a snap + - Correction in case of API error +- 2024.01.08 + - Update README.rst + - Add Link to IONOS control panel and reference between credentials.ini and domain.tld.ini +- 2023.11.13 + - Fix managed zone lookup to ensure correct domain is selected where there are two domains with the same ending e.g. example.com and thisisanexample.com (PR #22) +- 2022.11.24 + - Remove zope to fix compatibility with Certbot 2.x (Fixes #19) + - As a reminder, Certbot will default to issuing ECDSA certificates from release 2.0.0. + - If you update from a prior certbot release, run the plugin once manually. You will be prompted to update RSA key type to ECDSA. +- 2022.05.15 + - Added capability to handle multiple domain validations #16 +- 2021.09.20.post1 + - Fix version number +- 2021.09.20 + - Fix #9 Domain not known when using subdomain + +## Related Plugins + +It's important to note that this plugin targets [IONOS Developer DNS API](https://developer.hosting.ionos.com/docs/dns>). +If you are using IONOS [Cloud DNS service](https://cloud.ionos.com/network/cloud-dns>), +there is a different plugin provided by IONOS: \ No newline at end of file diff --git a/README.rst b/README.rst deleted file mode 100644 index 0bb04b4..0000000 --- a/README.rst +++ /dev/null @@ -1,177 +0,0 @@ -certbot-dns-ionos -===================== - -IONOS_ DNS Authenticator plugin for Certbot_ - -This plugin automates the process of completing a ``dns-01`` challenge by -creating, and subsequently removing, TXT records using the IONOS Remote API. - -Configuration of IONOS ---------------------------- - -In the `System -> Remote Users` you have to have a user, with the following rights - -- Client Functions -- DNS zone functions -- DNS txt functions - - -.. _IONOS: https://www.ionos.de/ -.. _Certbot: https://certbot.eff.org/ - -Installation ------------- - -:: - - pip install certbot-dns-ionos - - -Named Arguments ---------------- - -To start using DNS authentication for ionos, pass the following arguments on -certbot's command line: - -=============================================== =============================================== -``--authenticator dns-ionos`` select the authenticator plugin (Required) - -``--dns-ionos-credentials`` ionos Remote User credentials - INI file. (Required) - -``--dns-ionos-propagation-seconds`` waiting time for DNS to propagate before asking - the ACME server to verify the DNS record. - (Default: 10, Recommended: >= 600) -=============================================== =============================================== - - - -Credentials ------------ - -An example ``credentials.ini`` file: - -.. code-block:: ini - - dns_ionos_prefix = myapikeyprefix - dns_ionos_secret = verysecureapikeysecret - dns_ionos_endpoint = https://api.hosting.ionos.com - -The key can be managed under the following link: https://developer.hosting.ionos.de/?source=IonosControlPanel - -The path to this file can be provided interactively or using the -``--dns-ionos-credentials`` command-line argument. Certbot -records the path to this file for use during renewal, but does not store the -file's contents. - -**CAUTION:** You should protect these API credentials as you would the -password to your ionos account. Users who can read this file can use these -credentials to issue arbitrary API calls on your behalf. Users who can cause -Certbot to run using these credentials can complete a ``dns-01`` challenge to -acquire new certificates or revoke existing certificates for associated -domains, even if those domains aren't being managed by this server. - -Certbot will emit a warning if it detects that the credentials file can be -accessed by other users on your system. The warning reads "Unsafe permissions -on credentials configuration file", followed by the path to the credentials -file. This warning will be emitted each time Certbot uses the credentials file, -including for renewal, and cannot be silenced except by addressing the issue -(e.g., by using a command like ``chmod 600`` to restrict access to the file and -``chmod 700`` to restrict access to the folder). - - -Examples --------- - -To acquire a single certificate for both ``example.com`` and -``*.example.com``, waiting 900 seconds for DNS propagation: - -.. code-block:: bash - - certbot certonly \ - --authenticator dns-ionos \ - --dns-ionos-credentials /etc/letsencrypt/.secrets/domain.tld.ini \ - --dns-ionos-propagation-seconds 900 \ - --server https://acme-v02.api.letsencrypt.org/directory \ - --agree-tos \ - --rsa-key-size 4096 \ - -d 'example.com' \ - -d '*.example.com' - - -Docker ------- - -In order to create a docker container with a certbot-dns-ionos installation, -create an empty directory with the following ``Dockerfile``: - -.. code-block:: docker - - FROM certbot/certbot - RUN pip install certbot-dns-ionos - -Proceed to build the image:: - - docker build -t certbot/dns-ionos . - -Once that's finished, the application can be run as follows:: - - docker run --rm \ - -v /var/lib/letsencrypt:/var/lib/letsencrypt \ - -v /etc/letsencrypt:/etc/letsencrypt \ - --cap-drop=all \ - certbot/dns-ionos certonly \ - --authenticator dns-ionos \ - --dns-ionos-propagation-seconds 900 \ - --dns-ionos-credentials \ - /etc/letsencrypt/.secrets/domain.tld.ini \ - --no-self-upgrade \ - --keep-until-expiring --non-interactive --expand \ - --server https://acme-v02.api.letsencrypt.org/directory \ - -d example.com -d '*.example.com' - -It is suggested to secure the folder as follows:: -chown root:root /etc/letsencrypt/.secrets -chmod 700 /etc/letsencrypt/.secrets - -The file 'domain.tld.ini' must be replaced with the version of the example 'credentials.ini' adapted to your provider. - -Changelog -========= - -- 2024.01.08 - - - Update README.rst - - Add Link to IONOS control panel and reference between credentials.ini and domain.tld.ini - -- 2023.11.13 - - - Fix managed zone lookup to ensure correct domain is selected where there are two domains with the same ending e.g. example.com and thisisanexample.com (PR #22) - -- 2022.11.24 - - - remove zope to fix compatibility with Certbot 2.x (Fixes #19) - - As a reminder, Certbot will default to issuing ECDSA certificates from release 2.0.0. - If you update from a prior certbot release, run the plugin once manually. You will be prompted - to update RSA key type to ECDSA. - -- 2022.05.15 - - Added capability to handle multiple domain validations #16 - -- 2021.09.20.post1 - - - Fix version number - -- 2021.09.20 - - - Fix #9 Domain not known when using subdomain - - -Related Plugins ------------------ - -It's important to note that this plugin targets `IONOS Developer DNS API -`_. -If you are using IONOS `Cloud DNS service `_, -there is a different plugin provided by IONOS: https://github.com/ionos-cloud/certbot-dns-ionos-cloud diff --git a/certbot_dns_ionos/dns_ionos.py b/certbot_dns_ionos/dns_ionos.py index a7f3f3e..33ecec0 100644 --- a/certbot_dns_ionos/dns_ionos.py +++ b/certbot_dns_ionos/dns_ionos.py @@ -26,7 +26,7 @@ def __init__(self, *args, **kwargs): @classmethod def add_parser_arguments(cls, add): # pylint: disable=arguments-differ super(Authenticator, cls).add_parser_arguments( - add, default_propagation_seconds=120 + add, default_propagation_seconds=10 ) add("credentials", help="IONOS credentials INI file.") @@ -122,10 +122,11 @@ def _api_request(self, type, action, data = None): ) logger.debug("API request to URL: %s", url) if resp.status_code != 200: - content = json.loads(resp.content)[0] # on error content is array with 1 element - error_msg = resp.reason + " " + content['message'] + content = json.loads(resp.content) # on error content is array with 1 element + error_msg = "" if content['message'] is None else content['message'] raise errors.PluginError( - "HTTP Error during request {0}:{1}".format(resp.status_code, error_msg) + "HTTP Error during request {0}({1}): {2}".format( + resp.reason, resp.status_code, error_msg) ) result = None if type == 'get': diff --git a/setup.py b/setup.py index 931408b..8d2db41 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,11 @@ from setuptools import setup from setuptools import find_packages -version = "2024.01.08" +version = '2024.10.19' install_requires = [ "acme>=1.8.0", - "certbot>=2.0.0", + "certbot>=2.11.0", "setuptools", "requests", "mock", @@ -16,7 +16,7 @@ from os import path this_directory = path.abspath(path.dirname(__file__)) -with open(path.join(this_directory, "README.rst")) as f: +with open(path.join(this_directory, "README.md")) as f: long_description = f.read() setup( @@ -29,7 +29,7 @@ author="Helge Erbe", author_email="helge@erbehome.de", license="Apache License 2.0", - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", + python_requires=">=3.8", classifiers=[ "Development Status :: 5 - Production/Stable", "Environment :: Plugins", @@ -37,13 +37,12 @@ "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Topic :: Internet :: WWW/HTTP", "Topic :: Security", "Topic :: System :: Installation/Setup", diff --git a/snap-constraints.txt b/snap-constraints.txt new file mode 100644 index 0000000..e78b77f --- /dev/null +++ b/snap-constraints.txt @@ -0,0 +1,189 @@ +# This file was generated by tools/pinning/current/repin.sh and can be updated using +# that script. +# +# It is normally used as constraints to pip, however, it has the name +# requirements.txt so that is scanned by GitHub. See +# https://docs.github.com/en/github/visualizing-repository-data-with-graphs/about-the-dependency-graph#supported-package-ecosystems +# for more info. +alabaster==0.7.13 ; python_version >= "3.8" and python_version < "4.0" +apacheconfig==0.3.2 ; python_version >= "3.8" and python_version < "4.0" +appnope==0.1.4 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "darwin" +astroid==3.0.3 ; python_version >= "3.8" and python_version < "4.0" +asttokens==2.4.1 ; python_version >= "3.8" and python_version < "4.0" +attrs==24.2.0 ; python_version >= "3.8" and python_version < "4.0" +azure-core==1.30.2 ; python_version >= "3.8" and python_version < "4.0" +azure-devops==7.1.0b4 ; python_version >= "3.8" and python_version < "4.0" +babel==2.16.0 ; python_version >= "3.8" and python_version < "4.0" +backcall==0.2.0 ; python_version >= "3.8" and python_version < "4.0" +bcrypt==4.2.0 ; python_version >= "3.8" and python_version < "4.0" +beautifulsoup4==4.12.3 ; python_version >= "3.8" and python_version < "4.0" +boto3==1.35.6 ; python_version >= "3.8" and python_version < "4.0" +botocore==1.35.6 ; python_version >= "3.8" and python_version < "4.0" +build==1.2.1 ; python_version >= "3.8" and python_version < "4.0" +cachecontrol==0.14.0 ; python_version >= "3.8" and python_version < "4.0" +cachetools==5.5.0 ; python_version >= "3.8" and python_version < "4.0" +certifi==2024.7.4 ; python_version >= "3.8" and python_version < "4.0" +cffi==1.17.0 ; python_version >= "3.8" and python_version < "4.0" +chardet==5.2.0 ; python_version >= "3.8" and python_version < "4.0" +charset-normalizer==3.3.2 ; python_version >= "3.8" and python_version < "4.0" +cleo==2.1.0 ; python_version >= "3.8" and python_version < "4.0" +cloudflare==2.19.4 ; python_version >= "3.8" and python_version < "4.0" +colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0" +configargparse==1.7 ; python_version >= "3.8" and python_version < "4.0" +configobj==5.0.8 ; python_version >= "3.8" and python_version < "4.0" +coverage==7.6.1 ; python_version >= "3.8" and python_version < "4.0" +crashtest==0.4.1 ; python_version >= "3.8" and python_version < "4.0" +cryptography==43.0.0 ; python_version >= "3.8" and python_version < "4.0" +cython==0.29.37 ; python_version >= "3.8" and python_version < "4.0" +decorator==5.1.1 ; python_version >= "3.8" and python_version < "4.0" +deprecated==1.2.14 ; python_version >= "3.8" and python_version < "4.0" +dill==0.3.8 ; python_version >= "3.8" and python_version < "4.0" +distlib==0.3.8 ; python_version >= "3.8" and python_version < "4.0" +distro==1.9.0 ; python_version >= "3.8" and python_version < "4.0" +dns-lexicon==3.18.0 ; python_version >= "3.8" and python_version < "4.0" +dnspython==2.6.1 ; python_version >= "3.8" and python_version < "4.0" +docutils==0.20.1 ; python_version >= "3.8" and python_version < "4.0" +dulwich==0.21.7 ; python_version >= "3.8" and python_version < "4.0" +exceptiongroup==1.2.2 ; python_version >= "3.8" and python_version < "3.11" +execnet==2.1.1 ; python_version >= "3.8" and python_version < "4.0" +executing==2.0.1 ; python_version >= "3.8" and python_version < "4.0" +fabric==3.2.2 ; python_version >= "3.8" and python_version < "4.0" +fastjsonschema==2.20.0 ; python_version >= "3.8" and python_version < "4.0" +filelock==3.15.4 ; python_version >= "3.8" and python_version < "4.0" +google-api-core==2.19.1 ; python_version >= "3.8" and python_version < "4.0" +google-api-python-client==2.142.0 ; python_version >= "3.8" and python_version < "4.0" +google-auth-httplib2==0.2.0 ; python_version >= "3.8" and python_version < "4.0" +google-auth==2.34.0 ; python_version >= "3.8" and python_version < "4.0" +googleapis-common-protos==1.64.0 ; python_version >= "3.8" and python_version < "4.0" +httplib2==0.22.0 ; python_version >= "3.8" and python_version < "4.0" +idna==3.8 ; python_version >= "3.8" and python_version < "4.0" +imagesize==1.4.1 ; python_version >= "3.8" and python_version < "4.0" +importlib-metadata==8.4.0 ; python_version >= "3.8" and python_version < "4.0" +importlib-resources==6.4.4 ; python_version >= "3.8" and python_version < "4.0" +iniconfig==2.0.0 ; python_version >= "3.8" and python_version < "4.0" +installer==0.7.0 ; python_version >= "3.8" and python_version < "4.0" +invoke==2.2.0 ; python_version >= "3.8" and python_version < "4.0" +ipdb==0.13.13 ; python_version >= "3.8" and python_version < "4.0" +ipython==8.12.3 ; python_version >= "3.8" and python_version < "4.0" +isodate==0.6.1 ; python_version >= "3.8" and python_version < "4.0" +isort==5.13.2 ; python_version >= "3.8" and python_version < "4.0" +jaraco-classes==3.4.0 ; python_version >= "3.8" and python_version < "4.0" +jedi==0.19.1 ; python_version >= "3.8" and python_version < "4.0" +jeepney==0.8.0 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "linux" +jinja2==3.1.4 ; python_version >= "3.8" and python_version < "4.0" +jmespath==1.0.1 ; python_version >= "3.8" and python_version < "4.0" +josepy==1.14.0 ; python_version >= "3.8" and python_version < "4.0" +jsonlines==4.0.0 ; python_version >= "3.8" and python_version < "4.0" +jsonpickle==3.2.2 ; python_version >= "3.8" and python_version < "4.0" +keyring==24.3.1 ; python_version >= "3.8" and python_version < "4.0" +markdown-it-py==3.0.0 ; python_version >= "3.8" and python_version < "4.0" +markupsafe==2.1.5 ; python_version >= "3.8" and python_version < "4.0" +matplotlib-inline==0.1.7 ; python_version >= "3.8" and python_version < "4.0" +mccabe==0.7.0 ; python_version >= "3.8" and python_version < "4.0" +mdurl==0.1.2 ; python_version >= "3.8" and python_version < "4.0" +more-itertools==10.4.0 ; python_version >= "3.8" and python_version < "4.0" +msgpack==1.0.8 ; python_version >= "3.8" and python_version < "4.0" +msrest==0.7.1 ; python_version >= "3.8" and python_version < "4.0" +mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "4.0" +mypy==1.9.0 ; python_version >= "3.8" and python_version < "4.0" +nh3==0.2.18 ; python_version >= "3.8" and python_version < "4.0" +oauthlib==3.2.2 ; python_version >= "3.8" and python_version < "4.0" +packaging==24.1 ; python_version >= "3.8" and python_version < "4.0" +paramiko==3.4.1 ; python_version >= "3.8" and python_version < "4.0" +parsedatetime==2.6 ; python_version >= "3.8" and python_version < "4.0" +parso==0.8.4 ; python_version >= "3.8" and python_version < "4.0" +pexpect==4.9.0 ; python_version >= "3.8" and python_version < "4.0" +pickleshare==0.7.5 ; python_version >= "3.8" and python_version < "4.0" +pip==24.2 ; python_version >= "3.8" and python_version < "4.0" +pkginfo==1.10.0 ; python_version >= "3.8" and python_version < "4.0" +platformdirs==4.2.2 ; python_version >= "3.8" and python_version < "4.0" +pluggy==1.5.0 ; python_version >= "3.8" and python_version < "4.0" +ply==3.11 ; python_version >= "3.8" and python_version < "4.0" +poetry-core==1.9.0 ; python_version >= "3.8" and python_version < "4.0" +poetry-plugin-export==1.8.0 ; python_version >= "3.8" and python_version < "4.0" +poetry==1.8.3 ; python_version >= "3.8" and python_version < "4.0" +prompt-toolkit==3.0.47 ; python_version >= "3.8" and python_version < "4.0" +proto-plus==1.24.0 ; python_version >= "3.8" and python_version < "4.0" +protobuf==5.27.3 ; python_version >= "3.8" and python_version < "4.0" +ptyprocess==0.7.0 ; python_version >= "3.8" and python_version < "4.0" +pure-eval==0.2.3 ; python_version >= "3.8" and python_version < "4.0" +pyasn1-modules==0.4.0 ; python_version >= "3.8" and python_version < "4.0" +pyasn1==0.6.0 ; python_version >= "3.8" and python_version < "4.0" +pycparser==2.22 ; python_version >= "3.8" and python_version < "4.0" +pygments==2.18.0 ; python_version >= "3.8" and python_version < "4.0" +pylint==3.0.2 ; python_version >= "3.8" and python_version < "4.0" +pynacl==1.5.0 ; python_version >= "3.8" and python_version < "4.0" +pynsist==2.7 ; python_version >= "3.8" and python_version < "4.0" +pyopenssl==24.2.1 ; python_version >= "3.8" and python_version < "4.0" +pyotp==2.9.0 ; python_version >= "3.8" and python_version < "4.0" +pyparsing==3.1.4 ; python_version >= "3.8" and python_version < "4.0" +pyproject-api==1.7.1 ; python_version >= "3.8" and python_version < "4.0" +pyproject-hooks==1.1.0 ; python_version >= "3.8" and python_version < "4.0" +pyrfc3339==1.1 ; python_version >= "3.8" and python_version < "4.0" +pytest-cov==5.0.0 ; python_version >= "3.8" and python_version < "4.0" +pytest-xdist==3.6.1 ; python_version >= "3.8" and python_version < "4.0" +pytest==8.3.2 ; python_version >= "3.8" and python_version < "4.0" +python-augeas==1.1.0 ; python_version >= "3.8" and python_version < "4.0" +python-dateutil==2.9.0.post0 ; python_version >= "3.8" and python_version < "4.0" +python-digitalocean==1.17.0 ; python_version >= "3.8" and python_version < "4.0" +pytz==2024.1 ; python_version >= "3.8" and python_version < "4.0" +pywin32-ctypes==0.2.3 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32" +pywin32==306 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32" +pyyaml==6.0.2 ; python_version >= "3.8" and python_version < "4.0" +rapidfuzz==3.9.6 ; python_version >= "3.8" and python_version < "4.0" +readme-renderer==43.0 ; python_version >= "3.8" and python_version < "4.0" +requests-download==0.1.2 ; python_version >= "3.8" and python_version < "4.0" +requests-file==2.1.0 ; python_version >= "3.8" and python_version < "4.0" +requests-oauthlib==2.0.0 ; python_version >= "3.8" and python_version < "4.0" +requests-toolbelt==1.0.0 ; python_version >= "3.8" and python_version < "4.0" +requests==2.32.3 ; python_version >= "3.8" and python_version < "4.0" +rfc3986==2.0.0 ; python_version >= "3.8" and python_version < "4.0" +rich==13.8.0 ; python_version >= "3.8" and python_version < "4.0" +rsa==4.9 ; python_version >= "3.8" and python_version < "4" +s3transfer==0.10.2 ; python_version >= "3.8" and python_version < "4.0" +secretstorage==3.3.3 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "linux" +semantic-version==2.10.0 ; python_version >= "3.8" and python_version < "4.0" +setuptools-rust==1.10.1 ; python_version >= "3.8" and python_version < "4.0" +setuptools==73.0.1 ; python_version >= "3.8" and python_version < "4.0" +shellingham==1.5.4 ; python_version >= "3.8" and python_version < "4.0" +six==1.16.0 ; python_version >= "3.8" and python_version < "4.0" +snowballstemmer==2.2.0 ; python_version >= "3.8" and python_version < "4.0" +soupsieve==2.6 ; python_version >= "3.8" and python_version < "4.0" +sphinx-rtd-theme==2.0.0 ; python_version >= "3.8" and python_version < "4.0" +sphinx==7.1.2 ; python_version >= "3.8" and python_version < "4.0" +sphinxcontrib-applehelp==1.0.4 ; python_version >= "3.8" and python_version < "4.0" +sphinxcontrib-devhelp==1.0.2 ; python_version >= "3.8" and python_version < "4.0" +sphinxcontrib-htmlhelp==2.0.1 ; python_version >= "3.8" and python_version < "4.0" +sphinxcontrib-jquery==4.1 ; python_version >= "3.8" and python_version < "4.0" +sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.8" and python_version < "4.0" +sphinxcontrib-qthelp==1.0.3 ; python_version >= "3.8" and python_version < "4.0" +sphinxcontrib-serializinghtml==1.1.5 ; python_version >= "3.8" and python_version < "4.0" +stack-data==0.6.3 ; python_version >= "3.8" and python_version < "4.0" +tldextract==5.1.2 ; python_version >= "3.8" and python_version < "4.0" +tomli==2.0.1 ; python_version >= "3.8" and python_full_version <= "3.11.0a6" +tomlkit==0.13.2 ; python_version >= "3.8" and python_version < "4.0" +tox==4.18.0 ; python_version >= "3.8" and python_version < "4.0" +traitlets==5.14.3 ; python_version >= "3.8" and python_version < "4.0" +trove-classifiers==2024.7.2 ; python_version >= "3.8" and python_version < "4.0" +twine==5.1.1 ; python_version >= "3.8" and python_version < "4.0" +types-cffi==1.16.0.20240331 ; python_version >= "3.8" and python_version < "4.0" +types-httplib2==0.22.0.20240310 ; python_version >= "3.8" and python_version < "4.0" +types-pyopenssl==24.1.0.20240722 ; python_version >= "3.8" and python_version < "4.0" +types-pyrfc3339==1.1.1.5 ; python_version >= "3.8" and python_version < "4.0" +types-python-dateutil==2.9.0.20240821 ; python_version >= "3.8" and python_version < "4.0" +types-pytz==2024.1.0.20240417 ; python_version >= "3.8" and python_version < "4.0" +types-pywin32==306.0.0.20240822 ; python_version >= "3.8" and python_version < "4.0" +types-requests==2.31.0.6 ; python_version >= "3.8" and python_version < "4.0" +types-setuptools==73.0.0.20240822 ; python_version >= "3.8" and python_version < "4.0" +types-six==1.16.21.20240513 ; python_version >= "3.8" and python_version < "4.0" +types-urllib3==1.26.25.14 ; python_version >= "3.8" and python_version < "4.0" +typing-extensions==4.12.2 ; python_version >= "3.8" and python_version < "4.0" +uritemplate==4.1.1 ; python_version >= "3.8" and python_version < "4.0" +urllib3==1.26.19 ; python_version >= "3.8" and python_version < "4.0" +virtualenv==20.26.3 ; python_version >= "3.8" and python_version < "4.0" +wcwidth==0.2.13 ; python_version >= "3.8" and python_version < "4.0" +wheel==0.44.0 ; python_version >= "3.8" and python_version < "4.0" +wrapt==1.16.0 ; python_version >= "3.8" and python_version < "4.0" +xattr==1.1.0 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "darwin" +yarg==0.1.10 ; python_version >= "3.8" and python_version < "4.0" +zipp==3.20.1 ; python_version >= "3.8" and python_version < "4.0" diff --git a/snap/hooks/post-refresh b/snap/hooks/post-refresh new file mode 100644 index 0000000..717714c --- /dev/null +++ b/snap/hooks/post-refresh @@ -0,0 +1,21 @@ +#!/bin/sh -e +# This file is generated automatically and should not be edited manually. + +# get certbot version +if [ ! -f "$SNAP/certbot-shared/certbot-version.txt" ]; then + echo "No certbot version available; not doing version comparison check" >> "$SNAP_DATA/debuglog" + exit 0 +fi +cb_installed=$(cat $SNAP/certbot-shared/certbot-version.txt) + +# get required certbot version for plugin. certbot version must be at least the plugin's +# version. note that this is not the required version in setup.py, but the version number itself. +cb_required=$(grep -oP "version = '\K.*(?=')" $SNAP/setup.py) + + +$SNAP/bin/python3 -c "import sys; from packaging import version; sys.exit(1) if version.parse('$cb_installed') < version.parse('$cb_required') else sys.exit(0)" || exit_code=$? +if [ "$exit_code" -eq 1 ]; then + echo "Certbot is version $cb_installed but needs to be at least $cb_required before" \ + "this plugin can be updated; will try again on next refresh." + exit 1 +fi diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 0000000..460e9e5 --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,58 @@ +# This file is generated automatically and should not be edited manually. +name: certbot-dns-ionos +summary: IONOS DNS Authenticator plugin for Certbot +description: IONOS DNS Authenticator plugin for Certbot +confinement: strict +grade: stable +base: core24 +adopt-info: certbot-dns-ionos + +parts: + certbot-dns-ionos: + plugin: python + source: . + override-pull: | + craftctl default + craftctl set version=$(grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]") + build-environment: + # We set this environment variable while building to try and increase the + # stability of fetching the rust crates needed to build the cryptography + # library. + - CARGO_NET_GIT_FETCH_WITH_CLI: "true" + # Constraints are passed through the environment variable PIP_CONSTRAINTS instead of using the + # parts.[part_name].constraints option available in snapcraft.yaml when the Python plugin is + # used. This is done to let these constraints be applied not only on the certbot package + # build, but also on any isolated build that pip could trigger when building wheels for + # dependencies. See https://github.com/certbot/certbot/pull/8443 for more info. + - PIP_CONSTRAINT: $SNAPCRAFT_PART_SRC/snap-constraints.txt + - SNAP_BUILD: "True" + # To build cryptography and cffi if needed + build-packages: + - gcc + - git + - build-essential + - libssl-dev + - libffi-dev + - python3-dev + - cargo + - pkg-config + certbot-metadata: + plugin: dump + source: . + stage: [setup.py, certbot-shared] + override-pull: | + craftctl default + mkdir -p $SNAPCRAFT_PART_SRC/certbot-shared + +slots: + certbot: + interface: content + content: certbot-1 + read: + - $SNAP/lib/python3.12/site-packages + +plugs: + certbot-metadata: + interface: content + content: metadata-1 + target: $SNAP/certbot-shared