Compare commits
No commits in common. "master" and "0.0.7" have entirely different histories.
11 changed files with 210 additions and 598 deletions
37
.github/workflows/python-publish.yml
vendored
37
.github/workflows/python-publish.yml
vendored
|
@ -6,33 +6,26 @@ name: Upload Python Package
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [created]
|
types: [created]
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-n-publish:
|
deploy:
|
||||||
name: Build and publish to PyPi
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment:
|
|
||||||
name: pypi
|
|
||||||
url: https://pypi.org/p/certbot-dns-ionos
|
|
||||||
permissions:
|
|
||||||
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout source
|
- uses: actions/checkout@v2
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: '3.12'
|
python-version: '3.x'
|
||||||
|
- name: Install dependencies
|
||||||
- name: Build source and wheel distributions
|
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip build twine
|
python -m pip install --upgrade pip
|
||||||
python -m build
|
pip install setuptools wheel twine
|
||||||
twine check --strict dist/*
|
- name: Build and publish
|
||||||
|
env:
|
||||||
- name: Publish package distributions to PyPI
|
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
|
||||||
uses: pypa/gh-action-pypi-publish@release/v1
|
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
python setup.py sdist bdist_wheel
|
||||||
|
twine upload dist/*
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,6 +1,3 @@
|
||||||
#Snap
|
|
||||||
certbot-dns-ionos_20240108_amd64.snap
|
|
||||||
#snap-constraints.txt
|
|
||||||
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
|
# 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
|
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,python
|
||||||
|
|
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
|
@ -8,9 +8,9 @@
|
||||||
"name": "Python: Current File",
|
"name": "Python: Current File",
|
||||||
"type": "python",
|
"type": "python",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": ".venv/bin/certbot",
|
"program": "/home/pi/dev/certbot/venv3/bin/certbot",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"args": ["certonly", "-a", "dns-ionos", "-d", "*.erbehome.de", "-d", "erbehome.de", "--dns-ionos-credentials", "my_debug/secrets/credentials.ini", "--config-dir", "my_debug/config", "--work-dir", "my_debug/work", "--logs-dir", "my_debug/logs"]
|
"args": ["certonly", "-a", "dns-ionos", "-d", "*.erbehome.de", "--dns-ionos-credentials", "/home/pi/dev/certbot-dns-ionos/my_debug/secrets/credentials.ini", "--config-dir", "my_debug/config", "--work-dir", "my_debug/work", "--logs-dir", "my_debug/logs"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
207
README.md
207
README.md
|
@ -1,207 +0,0 @@
|
||||||
# certbot-dns-ionos
|
|
||||||
|
|
||||||
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 .
|
|
||||||
```
|
|
||||||
if not exit make dir and set as root to secure the folder
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p /etc/letsencrypt/.secrets
|
|
||||||
chown root:root /etc/letsencrypt/.secrets
|
|
||||||
chmod 700 /etc/letsencrypt/.secrets
|
|
||||||
```
|
|
||||||
insert the APY KEY of IONOS in patachina.it.ini and copy
|
|
||||||
```bash
|
|
||||||
sudo cp patachina.it.ini /etc/letsencrypt/.secrets
|
|
||||||
```
|
|
||||||
|
|
||||||
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/patachina.it.ini \
|
|
||||||
--no-self-upgrade \
|
|
||||||
--keep-until-expiring --non-interactive --expand \
|
|
||||||
--server https://acme-v02.api.letsencrypt.org/directory \
|
|
||||||
-d patachina.it -d '*.patachina.it'
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Original git
|
|
||||||
|
|
||||||
[IONOS](https://www.ionos.de/) DNS Authenticator plugin for [Certbot](https://certbot.eff.org/)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
[](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: <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.
|
|
||||||
|
|
||||||
> [!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.11.09
|
|
||||||
- Update for Certbot 3.0.0
|
|
||||||
- 2024.10.20
|
|
||||||
- fix: set long_description_content_type to text/markdown.
|
|
||||||
This error breaks the upload to pypi
|
|
||||||
- 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: <https://github.com/ionos-cloud/certbot-dns-ionos-cloud>
|
|
132
README.rst
Normal file
132
README.rst
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
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 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).
|
||||||
|
|
||||||
|
|
||||||
|
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 600 /etc/letsencrypt/.secrets
|
|
@ -1,15 +1,20 @@
|
||||||
"""DNS Authenticator for IONOS."""
|
"""DNS Authenticator for IONOS."""
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import zope.interface
|
||||||
|
|
||||||
from certbot import errors
|
from certbot import errors
|
||||||
|
from certbot import interfaces
|
||||||
from certbot.plugins import dns_common
|
from certbot.plugins import dns_common
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@zope.interface.implementer(interfaces.IAuthenticator)
|
||||||
|
@zope.interface.provider(interfaces.IPluginFactory)
|
||||||
class Authenticator(dns_common.DNSAuthenticator):
|
class Authenticator(dns_common.DNSAuthenticator):
|
||||||
"""DNS Authenticator for IONOS
|
"""DNS Authenticator for IONOS
|
||||||
|
|
||||||
|
@ -26,7 +31,7 @@ class Authenticator(dns_common.DNSAuthenticator):
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_parser_arguments(cls, add): # pylint: disable=arguments-differ
|
def add_parser_arguments(cls, add): # pylint: disable=arguments-differ
|
||||||
super(Authenticator, cls).add_parser_arguments(
|
super(Authenticator, cls).add_parser_arguments(
|
||||||
add, default_propagation_seconds=10
|
add, default_propagation_seconds=120
|
||||||
)
|
)
|
||||||
add("credentials", help="IONOS credentials INI file.")
|
add("credentials", help="IONOS credentials INI file.")
|
||||||
|
|
||||||
|
@ -48,14 +53,13 @@ class Authenticator(dns_common.DNSAuthenticator):
|
||||||
)
|
)
|
||||||
|
|
||||||
def _perform(self, domain, validation_name, validation):
|
def _perform(self, domain, validation_name, validation):
|
||||||
logger.debug(f"_perform called with: domain: {domain}, validation_name: {validation_name}, validation: {validation}")
|
|
||||||
self._get_ionos_client().add_txt_record(
|
self._get_ionos_client().add_txt_record(
|
||||||
domain, validation_name, validation, self.ttl
|
domain, validation_name, validation, self.ttl
|
||||||
)
|
)
|
||||||
|
|
||||||
def _cleanup(self, domain, validation_name, validation):
|
def _cleanup(self, domain, validation_name, validation):
|
||||||
self._get_ionos_client().del_matching_records(
|
self._get_ionos_client().del_txt_record(
|
||||||
domain, validation_name
|
domain, validation_name, validation, self.ttl
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_ionos_client(self):
|
def _get_ionos_client(self):
|
||||||
|
@ -93,12 +97,6 @@ class _ionosClient(object):
|
||||||
# get the zone id
|
# get the zone id
|
||||||
if zone['name'] == domain:
|
if zone['name'] == domain:
|
||||||
return zone['id'], zone['name']
|
return zone['id'], zone['name']
|
||||||
# if the domain does not exactly match one of the zones, check if it
|
|
||||||
# is a subdomain
|
|
||||||
for zone in zones:
|
|
||||||
# get the zone id
|
|
||||||
if domain.endswith(f".{zone['name']}"):
|
|
||||||
return zone['id'], zone['name']
|
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
def _api_request(self, type, action, data = None):
|
def _api_request(self, type, action, data = None):
|
||||||
|
@ -120,13 +118,12 @@ class _ionosClient(object):
|
||||||
raise errors.PluginError(
|
raise errors.PluginError(
|
||||||
"HTTP Error during request. Unknown type {0}".format(type)
|
"HTTP Error during request. Unknown type {0}".format(type)
|
||||||
)
|
)
|
||||||
logger.debug("API request to URL: %s", url)
|
logger.debug("API REquest to URL: %s", url)
|
||||||
if resp.status_code != 200:
|
if resp.status_code != 200:
|
||||||
content = json.loads(resp.content) # on error content is array with 1 element
|
content = json.loads(resp.content)
|
||||||
error_msg = "" if content['message'] is None else content['message']
|
error_msg = resp.reason + " " + content['message']
|
||||||
raise errors.PluginError(
|
raise errors.PluginError(
|
||||||
"HTTP Error during request {0}({1}): {2}".format(
|
"HTTP Error during request {0}:{1}".format(resp.status_code, error_msg)
|
||||||
resp.reason, resp.status_code, error_msg)
|
|
||||||
)
|
)
|
||||||
result = None
|
result = None
|
||||||
if type == 'get':
|
if type == 'get':
|
||||||
|
@ -161,15 +158,43 @@ class _ionosClient(object):
|
||||||
logger.info("already there, id {0}".format(id))
|
logger.info("already there, id {0}".format(id))
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
logger.info("adding additional record")
|
logger.info("update txt record")
|
||||||
entries = self.clean_entries(self.get_existing_records(zone_id, record_name))
|
self._update_txt_record(
|
||||||
self.add_additional_record(
|
zone_id, id, record_content, record_ttl
|
||||||
zone_id, record_name, record_content, record_ttl, entries
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.info("insert new txt record")
|
logger.info("insert new txt record")
|
||||||
self._insert_txt_record(zone_id, record_name, record_content, record_ttl)
|
self._insert_txt_record(zone_id, record_name, record_content, record_ttl)
|
||||||
|
|
||||||
|
def del_txt_record(self, domain, record_name, record_content, record_ttl):
|
||||||
|
"""
|
||||||
|
Delete a TXT record using the supplied information.
|
||||||
|
|
||||||
|
:param str domain: The domain to use to look up the managed zone.
|
||||||
|
:param str record_name: The record name (typically beginning with '_acme-challenge.').
|
||||||
|
:param str record_content: The record content (typically the challenge validation).
|
||||||
|
:param int record_ttl: The record TTL (number of seconds that the record may be cached).
|
||||||
|
:raises certbot.errors.PluginError: if an error occurs communicating with the IONOS API
|
||||||
|
"""
|
||||||
|
zone_id, zone_name = self._find_managed_zone_id(domain)
|
||||||
|
if zone_id is None:
|
||||||
|
raise errors.PluginError("Domain not known")
|
||||||
|
logger.debug("domain found: %s with id: %s", zone_name, zone_id)
|
||||||
|
content, id = self.get_existing_txt(zone_id, record_name)
|
||||||
|
if content is not None:
|
||||||
|
if content == record_content:
|
||||||
|
logger.debug("delete TXT record: %s", id)
|
||||||
|
self._delete_txt_record(zone_id, id)
|
||||||
|
|
||||||
|
def _update_txt_record(self, zone_id, primary_id, record_content, record_ttl):
|
||||||
|
data = {}
|
||||||
|
data['disabled'] = False
|
||||||
|
data['content'] = record_content
|
||||||
|
data['ttl'] = record_ttl
|
||||||
|
data['prio'] = 0
|
||||||
|
logger.debug("update with data: %s", data)
|
||||||
|
self._api_request(type='put', action='/dns/v1/zones/{0}/records/{1}'.format(zone_id,primary_id), data=data)
|
||||||
|
|
||||||
def _insert_txt_record(self, zone_id, record_name, record_content, record_ttl):
|
def _insert_txt_record(self, zone_id, record_name, record_content, record_ttl):
|
||||||
data = {}
|
data = {}
|
||||||
data['disabled'] = False
|
data['disabled'] = False
|
||||||
|
@ -213,61 +238,3 @@ class _ionosClient(object):
|
||||||
content = content.rstrip('\"')
|
content = content.rstrip('\"')
|
||||||
return content, entry["id"]
|
return content, entry["id"]
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
def get_existing_records(self, zone_id, record_name):
|
|
||||||
"""
|
|
||||||
Pull a list of existing TXT records with the record_name
|
|
||||||
"""
|
|
||||||
zone_data = self._api_request(type='get', action='/dns/v1/zones/{0}'.format(zone_id))
|
|
||||||
results = []
|
|
||||||
for entry in zone_data['records']:
|
|
||||||
if entry["name"] == record_name and entry["type"] == "TXT":
|
|
||||||
results.append(entry)
|
|
||||||
return results
|
|
||||||
|
|
||||||
def clean_entries(self, entries):
|
|
||||||
"""
|
|
||||||
Clean up existing DNS entries to prepare to write them back to the API
|
|
||||||
by only including certain keys and cleaning up the content.
|
|
||||||
"""
|
|
||||||
results = []
|
|
||||||
for entry in entries:
|
|
||||||
results.append({
|
|
||||||
'name': entry['name'],
|
|
||||||
'type': entry['type'],
|
|
||||||
'content': entry['content'].replace('"', ''), # Strip double-quotes
|
|
||||||
'ttl': entry['ttl'],
|
|
||||||
'disabled': entry['disabled'],
|
|
||||||
})
|
|
||||||
return results
|
|
||||||
|
|
||||||
def add_additional_record(self, zone_id, record_name, record_content, record_ttl, existing_records):
|
|
||||||
"""
|
|
||||||
Add another TXT record with the record_name but with new content. This
|
|
||||||
is done to allow multiple domains to be validated at the same time.
|
|
||||||
existing_records is a list of existing records since we need to issue
|
|
||||||
a PATCH and include the existing records.
|
|
||||||
"""
|
|
||||||
data = {}
|
|
||||||
data['disabled'] = False
|
|
||||||
data['type'] = 'TXT'
|
|
||||||
data['name'] = record_name
|
|
||||||
data['content'] = record_content
|
|
||||||
data['ttl'] = record_ttl
|
|
||||||
data['prio'] = 0
|
|
||||||
existing_records.append(data)
|
|
||||||
logger.debug("insert with data: %s", existing_records)
|
|
||||||
self._api_request(type='patch', action='/dns/v1/zones/{0}'.format(zone_id), data=existing_records)
|
|
||||||
|
|
||||||
def del_matching_records(self, domain, record_name):
|
|
||||||
"""
|
|
||||||
Deletes any TXT records with matching record_name. Loops through all
|
|
||||||
records with that name and deletes them.
|
|
||||||
"""
|
|
||||||
zone_id, zone_name = self._find_managed_zone_id(domain)
|
|
||||||
if zone_id is None:
|
|
||||||
raise errors.PluginError("Domain not known")
|
|
||||||
logger.debug("domain found: %s with id: %s", zone_name, zone_id)
|
|
||||||
entries = self.get_existing_records(zone_id, record_name)
|
|
||||||
for entry in entries:
|
|
||||||
self._delete_txt_record(zone_id, entry['id'])
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
dns_ionos_prefix = 855b5080c2434ffc99f23fa20f09f0aa
|
|
||||||
dns_ionos_secret = bcD1lRr5af4UuXUGRSVTj-9uQxrxcj9GKcHo8D3xtaSducnWNxGx35XwqjXOwOSvTO7apFUjDWzbApUShMKPzA
|
|
||||||
dns_ionos_endpoint = https://api.hosting.ionos.com
|
|
25
setup.py
25
setup.py
|
@ -1,11 +1,11 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
from setuptools import find_packages
|
from setuptools import find_packages
|
||||||
|
|
||||||
version = '2024.11.09'
|
version = "0.0.7"
|
||||||
|
|
||||||
install_requires = [
|
install_requires = [
|
||||||
"acme>=3.0.0",
|
"acme>=1.8.0",
|
||||||
"certbot>=3.0.0",
|
"certbot>=0.31.0",
|
||||||
"setuptools",
|
"setuptools",
|
||||||
"requests",
|
"requests",
|
||||||
"mock",
|
"mock",
|
||||||
|
@ -16,7 +16,7 @@ install_requires = [
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
this_directory = path.abspath(path.dirname(__file__))
|
this_directory = path.abspath(path.dirname(__file__))
|
||||||
with open(path.join(this_directory, "README.md")) as f:
|
with open(path.join(this_directory, "README.rst")) as f:
|
||||||
long_description = f.read()
|
long_description = f.read()
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
@ -24,25 +24,26 @@ setup(
|
||||||
version=version,
|
version=version,
|
||||||
description="IONOS DNS Authenticator plugin for Certbot",
|
description="IONOS DNS Authenticator plugin for Certbot",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/x-rst",
|
||||||
url="https://github.com/helgeerbe/certbot-dns-ionos",
|
url="https://github.com/helgeerbe/certbot-dns-ionos",
|
||||||
author="Helge Erbe",
|
author="Helge Erbe",
|
||||||
author_email="helge@erbehome.de",
|
author_email="helge@erbehome.de",
|
||||||
license="Apache License 2.0",
|
license="Apache License 2.0",
|
||||||
python_requires=">=3.8",
|
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
|
||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 3 - Alpha",
|
||||||
"Environment :: Plugins",
|
"Environment :: Plugins",
|
||||||
"Intended Audience :: System Administrators",
|
"Intended Audience :: System Administrators",
|
||||||
"License :: OSI Approved :: Apache Software License",
|
"License :: OSI Approved :: Apache Software License",
|
||||||
"Operating System :: POSIX :: Linux",
|
"Operating System :: POSIX :: Linux",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
|
"Programming Language :: Python :: 2",
|
||||||
|
"Programming Language :: Python :: 2.7",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.4",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.5",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.6",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: 3.12",
|
|
||||||
"Topic :: Internet :: WWW/HTTP",
|
"Topic :: Internet :: WWW/HTTP",
|
||||||
"Topic :: Security",
|
"Topic :: Security",
|
||||||
"Topic :: System :: Installation/Setup",
|
"Topic :: System :: Installation/Setup",
|
||||||
|
|
|
@ -1,189 +0,0 @@
|
||||||
# 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"
|
|
|
@ -1,21 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,58 +0,0 @@
|
||||||
# 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
|
|
Loading…
Reference in a new issue