mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
init work on letsencrypt_dns core plugin
This commit is contained in:
parent
c93759541b
commit
7e8f1ef25d
10 changed files with 2174 additions and 414 deletions
828
docs/settings.md
828
docs/settings.md
File diff suppressed because it is too large
Load diff
380
src/common/core/letsencrypt_dns/jobs/dns-certbot-new.py
Executable file
380
src/common/core/letsencrypt_dns/jobs/dns-certbot-new.py
Executable file
|
|
@ -0,0 +1,380 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from itertools import chain
|
||||
from json import dumps
|
||||
from os import environ, getenv, sep
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
from shutil import rmtree
|
||||
from subprocess import DEVNULL, STDOUT, Popen
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from typing import Dict, List, Literal, Type, Union
|
||||
|
||||
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("db",))]:
|
||||
if deps_path not in sys_path:
|
||||
sys_path.append(deps_path)
|
||||
|
||||
from common_utils import bytes_hash # type: ignore
|
||||
from jobs import Job # type: ignore
|
||||
from logger import setup_logger # type: ignore
|
||||
|
||||
LOGGER = setup_logger("LETS-ENCRYPT-DNS.new", getenv("LOG_LEVEL", "INFO"))
|
||||
LIB_PATH = Path(sep, "var", "lib", "bunkerweb", "letsencrypt_dns")
|
||||
|
||||
deps_path = LIB_PATH.joinpath("python").as_posix()
|
||||
if deps_path not in sys_path:
|
||||
sys_path.append(deps_path)
|
||||
|
||||
CERTBOT_BIN = LIB_PATH.joinpath("python", "bin", "certbot")
|
||||
|
||||
LOGGER_CERTBOT = setup_logger("LETS-ENCRYPT-DNS.new.certbot", getenv("LOG_LEVEL", "INFO"))
|
||||
status = 0
|
||||
|
||||
PLUGIN_PATH = Path(sep, "usr", "share", "bunkerweb", "core", "letsencrypt_dns")
|
||||
JOBS_PATH = PLUGIN_PATH.joinpath("jobs")
|
||||
CACHE_PATH = Path(sep, "var", "cache", "bunkerweb", "letsencrypt_dns")
|
||||
DATA_PATH = CACHE_PATH.joinpath("etc")
|
||||
WORK_DIR = join(sep, "var", "lib", "bunkerweb", "letsencrypt_dns")
|
||||
LOGS_DIR = join(sep, "var", "log", "bunkerweb", "letsencrypt_dns")
|
||||
|
||||
|
||||
class WildcardGenerator:
|
||||
def __init__(self):
|
||||
self.__domain_groups = {}
|
||||
self.__wildcards = {}
|
||||
|
||||
def __generate_wildcards(self, staging: bool = False):
|
||||
self.__wildcards.clear()
|
||||
_type = "staging" if staging else "prod"
|
||||
|
||||
# * Loop through all the domains and generate wildcards
|
||||
for group, types in self.__domain_groups.items():
|
||||
if group not in self.__wildcards:
|
||||
self.__wildcards[group] = {"staging": set(), "prod": set(), "email": types["email"]}
|
||||
for domain in types[_type]:
|
||||
parts = domain.split(".")
|
||||
# ? Only take subdomains into account for wildcards generation
|
||||
if len(parts) > 2:
|
||||
suffix = ".".join(parts[1:])
|
||||
# ? If the suffix is not already in the wildcards, add it
|
||||
if suffix not in self.__wildcards[group][_type]:
|
||||
self.__wildcards[group][_type].add(f"*.{suffix}")
|
||||
self.__wildcards[group][_type].add(suffix)
|
||||
continue
|
||||
|
||||
# ? Add the raw domain to the wildcards
|
||||
self.__wildcards[group][_type].add(domain)
|
||||
|
||||
def extend(self, group: str, domains: List[str], email: str, staging: bool = False):
|
||||
if group not in self.__domain_groups:
|
||||
self.__domain_groups[group] = {"staging": set(), "prod": set(), "email": email}
|
||||
for domain in domains:
|
||||
if domain := domain.strip():
|
||||
self.__domain_groups[group]["staging" if staging else "prod"].add(domain)
|
||||
self.__generate_wildcards(staging)
|
||||
|
||||
def get_wildcards(self) -> Dict[str, Dict[Literal["staging", "prod", "email"], str]]:
|
||||
ret_data = {}
|
||||
for group, data in self.__wildcards.items():
|
||||
ret_data[group] = {"email": data["email"]}
|
||||
for _type, content in data.items():
|
||||
if _type in ("staging", "prod"):
|
||||
# ? Sort domains while favoring wildcards first
|
||||
ret_data[group][_type] = ",".join(sorted(content, key=lambda x: x[0] != "*"))
|
||||
return ret_data
|
||||
|
||||
|
||||
def certbot_new(provider: str, credentials_path: Union[str, Path], domains: str, email: str, propagation: str = "default", staging: bool = False) -> int:
|
||||
if isinstance(credentials_path, str):
|
||||
credentials_path = Path(credentials_path)
|
||||
|
||||
# * Building the certbot command
|
||||
command = [
|
||||
CERTBOT_BIN,
|
||||
"certonly",
|
||||
"--config-dir",
|
||||
DATA_PATH.as_posix(),
|
||||
"--work-dir",
|
||||
WORK_DIR,
|
||||
"--logs-dir",
|
||||
LOGS_DIR,
|
||||
"--preferred-challenges=dns",
|
||||
"-n",
|
||||
"-d",
|
||||
domains,
|
||||
"--email",
|
||||
email,
|
||||
"--agree-tos",
|
||||
"--expand",
|
||||
]
|
||||
|
||||
# * Adding the propagation time to the command
|
||||
if propagation != "default":
|
||||
if not propagation.isdigit():
|
||||
LOGGER.warning(f"Invalid propagation time : {propagation}, using provider's default...")
|
||||
else:
|
||||
command.extend([f"--dns-{provider}-propagation-seconds", propagation])
|
||||
|
||||
env = environ | {"PYTHONPATH": deps_path}
|
||||
|
||||
# * Adding the credentials to the command
|
||||
if provider == "route53":
|
||||
# ? Route53 credentials are different from the others, we need to add them to the environment
|
||||
with credentials_path.open("r") as file:
|
||||
for line in file:
|
||||
key, value = line.strip().split("=", 1)
|
||||
env[key] = value
|
||||
else:
|
||||
command.extend([f"--dns-{provider}-credentials", credentials_path.as_posix()])
|
||||
|
||||
# * Adding plugin argument
|
||||
if provider == "scaleway":
|
||||
# ? Scaleway plugin uses a different argument
|
||||
command.extend(["--authenticator", "dns-scaleway"])
|
||||
else:
|
||||
command.append(f"--dns-{provider}")
|
||||
|
||||
if staging:
|
||||
command.append("--staging")
|
||||
|
||||
current_date = datetime.now()
|
||||
process = Popen(command, stdin=DEVNULL, stderr=STDOUT, universal_newlines=True, env=env)
|
||||
while process.poll() is None:
|
||||
if datetime.now() - current_date > timedelta(seconds=5):
|
||||
LOGGER.info("⏳ Still generating certificate(s)...")
|
||||
current_date = datetime.now()
|
||||
return process.returncode
|
||||
|
||||
|
||||
IS_MULTISITE = getenv("MULTISITE", "no") == "yes"
|
||||
|
||||
try:
|
||||
servers = getenv("SERVER_NAME", "").lower() or []
|
||||
|
||||
if isinstance(servers, str):
|
||||
servers = servers.split(" ")
|
||||
|
||||
if not servers:
|
||||
LOGGER.error("There are no server names, skipping generation...")
|
||||
sys_exit(0)
|
||||
|
||||
use_letsencrypt_dns = False
|
||||
if not IS_MULTISITE:
|
||||
servers = [servers[0]]
|
||||
use_letsencrypt_dns = getenv("AUTO_LETS_ENCRYPT_DNS", "no") == "yes"
|
||||
else:
|
||||
for first_server in servers:
|
||||
if first_server and getenv(f"{first_server}_AUTO_LETS_ENCRYPT_DNS", "no") == "yes":
|
||||
use_letsencrypt_dns = True
|
||||
break
|
||||
|
||||
if not use_letsencrypt_dns:
|
||||
LOGGER.info("Let's Encrypt DNS is not activated, skipping generation...")
|
||||
sys_exit(0)
|
||||
elif not CERTBOT_BIN.is_file():
|
||||
LOGGER.error("Additional dependencies not installed, skipping certificate(s) generation...")
|
||||
sys_exit(2)
|
||||
|
||||
from pydantic import ValidationError
|
||||
from models import (
|
||||
CloudflareProvider,
|
||||
DigitalOceanProvider,
|
||||
GoogleProvider,
|
||||
LinodeProvider,
|
||||
OvhProvider,
|
||||
Rfc2136Provider,
|
||||
Route53Provider,
|
||||
ScalewayProvider,
|
||||
)
|
||||
|
||||
PROVIDER_CLASSES: Dict[
|
||||
str,
|
||||
Union[
|
||||
Type[CloudflareProvider],
|
||||
Type[DigitalOceanProvider],
|
||||
Type[GoogleProvider],
|
||||
Type[LinodeProvider],
|
||||
Type[OvhProvider],
|
||||
Type[Rfc2136Provider],
|
||||
Type[Route53Provider],
|
||||
Type[ScalewayProvider],
|
||||
],
|
||||
] = {
|
||||
"cloudflare": CloudflareProvider,
|
||||
"digitalocean": DigitalOceanProvider,
|
||||
"google": GoogleProvider,
|
||||
"linode": LinodeProvider,
|
||||
"ovh": OvhProvider,
|
||||
"rfc2136": Rfc2136Provider,
|
||||
"route53": Route53Provider,
|
||||
"scaleway": ScalewayProvider,
|
||||
}
|
||||
|
||||
JOB = Job(LOGGER)
|
||||
|
||||
# ? Restore data from db cache of dns-certbot-renew job
|
||||
JOB.restore_cache(job_name="dns-certbot-renew")
|
||||
|
||||
WILDCARD_GENERATOR = WildcardGenerator()
|
||||
credential_paths = set()
|
||||
generated_domains = set()
|
||||
|
||||
for first_server in servers:
|
||||
if getenv(f"{first_server}_AUTO_LETS_ENCRYPT_DNS", getenv("AUTO_LETS_ENCRYPT_DNS", "no")) == "no":
|
||||
LOGGER.info(f"Skipping certificate(s) generation for {first_server} because it is not enabled")
|
||||
continue
|
||||
elif getenv(f"{first_server}_AUTO_LETS_ENCRYPT", getenv("AUTO_LETS_ENCRYPT", "no")) == "yes":
|
||||
LOGGER.warning(f"Skipping certificate(s) generation for {first_server} because it is using regular Let's Encrypt")
|
||||
continue
|
||||
|
||||
# * Getting all the necessary data
|
||||
data = {
|
||||
"domains": getenv(f"{first_server}_SERVER_NAME", getenv("SERVER_NAME", "")).lower() or first_server,
|
||||
"email": getenv(f"{first_server}_LETS_ENCRYPT_DNS_EMAIL", getenv("LETS_ENCRYPT_DNS_EMAIL", "")) or f"contact@{first_server}",
|
||||
"staging": getenv(f"{first_server}_USE_LETS_ENCRYPT_DNS_STAGING", getenv("USE_LETS_ENCRYPT_DNS_STAGING", "no")) == "yes",
|
||||
"provider": getenv(f"{first_server}_LETS_ENCRYPT_DNS_PROVIDER", getenv("LETS_ENCRYPT_DNS_PROVIDER", "")),
|
||||
"use_wildcard": getenv(f"{first_server}_USE_LETS_ENCRYPT_DNS_WILDCARD", getenv("USE_LETS_ENCRYPT_DNS_WILDCARD", "no")) == "yes",
|
||||
"propagation": getenv(f"{first_server}_LETS_ENCRYPT_DNS_PROPAGATION", getenv("LETS_ENCRYPT_DNS_PROPAGATION", "default")),
|
||||
"credential_items": {},
|
||||
}
|
||||
for env_key, env_value in environ.items():
|
||||
if env_value and env_key.startswith(f"{first_server}_LETS_ENCRYPT_DNS_CREDENTIAL_ITEM" if IS_MULTISITE else "LETS_ENCRYPT_DNS_CREDENTIAL_ITEM"):
|
||||
key, value = env_value.split(" ", 1)
|
||||
data["credential_items"][key.lower()] = value
|
||||
|
||||
LOGGER.debug(f"Data for service {first_server} : {dumps(data)}")
|
||||
|
||||
# * Checking if the data is valid
|
||||
if not data["provider"]:
|
||||
LOGGER.warning(
|
||||
f"No provider found for service {first_server} (available providers : {', '.join(PROVIDER_CLASSES.keys())}), skipping certificate(s) generation..." # noqa: E501
|
||||
)
|
||||
continue
|
||||
elif not data["credential_items"]:
|
||||
LOGGER.warning(f"No credentials items found for service {first_server} (you should have at least one), skipping certificate(s) generation...")
|
||||
continue
|
||||
|
||||
# * Validating the credentials
|
||||
try:
|
||||
provider = PROVIDER_CLASSES[data["provider"]](**data["credential_items"])
|
||||
except ValidationError as ve:
|
||||
LOGGER.error(f"Error while validating credentials for service {first_server} :\n{ve}")
|
||||
continue
|
||||
|
||||
content = provider.get_formatted_credentials()
|
||||
|
||||
# * Adding the domains to Wildcard Generator if necessary
|
||||
file_path = (first_server, f"credentials.{provider.get_file_type()}")
|
||||
if data["use_wildcard"]:
|
||||
group = f"{data['provider']}_{bytes_hash(content, algorithm='sha1')}"
|
||||
LOGGER.info(
|
||||
f"Service {first_server} is using wildcard, the propagation time will be the provider's default "
|
||||
+ "and the email will be the same as the first domain that created the group..."
|
||||
)
|
||||
WILDCARD_GENERATOR.extend(group, data["domains"].strip().split(" "), data["email"], data["staging"])
|
||||
file_path = (f"{group}.{provider.get_file_type()}",)
|
||||
|
||||
# * Generating the credentials file
|
||||
credentials_path = CACHE_PATH.joinpath(*file_path)
|
||||
|
||||
if not credentials_path.is_file():
|
||||
cached, err = JOB.cache_file(
|
||||
credentials_path.name, content, job_name="dns-certbot-renew", service_id=first_server if not data["use_wildcard"] else ""
|
||||
)
|
||||
if not cached:
|
||||
LOGGER.error(f"Error while saving service {first_server}'s credentials file in cache : {err}")
|
||||
continue
|
||||
LOGGER.info(f"Successfully saved service {first_server}'s credentials file in cache")
|
||||
elif data["use_wildcard"]:
|
||||
LOGGER.info(f"Service {first_server}'s wildcard credentials file has already been generated")
|
||||
else:
|
||||
old_content = credentials_path.read_bytes()
|
||||
if old_content != content:
|
||||
LOGGER.warning(f"Service {first_server}'s credentials file is outdated, updating it...")
|
||||
cached, err = JOB.cache_file(credentials_path.name, content, job_name="dns-certbot-renew", service_id=first_server)
|
||||
if not cached:
|
||||
LOGGER.error(f"Error while updating service {first_server}'s credentials file in cache : {err}")
|
||||
continue
|
||||
LOGGER.info(f"Successfully updated service {first_server}'s credentials file in cache")
|
||||
else:
|
||||
LOGGER.info(f"Service {first_server}'s credentials file is up to date")
|
||||
|
||||
credential_paths.add(credentials_path)
|
||||
credentials_path.chmod(0o600) # ? Setting the permissions to 600 (this is important to avoid warnings from certbot)
|
||||
|
||||
if data["use_wildcard"]:
|
||||
continue
|
||||
|
||||
domains = data["domains"].replace(" ", ",")
|
||||
LOGGER.info(f"Asking certificates for domain(s) : {domains} (email = {data['email']}) {'using staging ' if data['staging'] else ''}...")
|
||||
if certbot_new(data["provider"], credentials_path, domains, data["email"], data["propagation"], data["staging"]) != 0:
|
||||
status = 2
|
||||
LOGGER.error(f"Certificate generation failed for domain(s) {data['domains']} ...")
|
||||
else:
|
||||
status = 1 if status == 0 else status
|
||||
LOGGER.info(f"Certificate generation succeeded for domain(s) : {data['domains']}")
|
||||
|
||||
generated_domains.update(data["domains"].split(","))
|
||||
|
||||
# * Generating the wildcards if necessary
|
||||
wildcards = WILDCARD_GENERATOR.get_wildcards()
|
||||
if wildcards:
|
||||
for group, data in wildcards.items():
|
||||
if not data:
|
||||
continue
|
||||
# * Generating the certificate from the generated credentials
|
||||
provider = group.split("_", 1)[0]
|
||||
email = data.pop("email")
|
||||
credentials_file = CACHE_PATH.joinpath(f"{group}.{PROVIDER_CLASSES[provider].get_file_type()}")
|
||||
for key, domains in data.items():
|
||||
if not domains:
|
||||
continue
|
||||
staging = key == "staging"
|
||||
LOGGER.info(f"Asking wildcard certificates for domain(s) : {domains} (email = {email}) {'using staging ' if staging else ''}...")
|
||||
if certbot_new(provider, credentials_file, domains, email, staging=staging) != 0:
|
||||
status = 2
|
||||
LOGGER.error(f"Certificate generation failed for domain(s) {domains} ...")
|
||||
else:
|
||||
status = 1 if status == 0 else status
|
||||
LOGGER.info(f"Certificate generation succeeded for domain(s) : {domains}")
|
||||
|
||||
generated_domains.update(domains.split(","))
|
||||
else:
|
||||
LOGGER.info("No wildcard domains found, skipping wildcard certificate(s) generation...")
|
||||
|
||||
# * Clearing all missing credentials files
|
||||
for file in CACHE_PATH.glob("**/*"):
|
||||
if "etc" in file.parts or not file.is_file() or file.suffix not in (".ini", ".env", ".json"):
|
||||
continue
|
||||
# ? If the file is not in the wildcard groups, remove it
|
||||
if file not in credential_paths:
|
||||
LOGGER.debug(f"Removing old credentials file {file}")
|
||||
JOB.del_cache(file.name, job_name="dns-certbot-renew", service_id=file.parent.name if file.parent.name != "letsencrypt_dns" else "")
|
||||
|
||||
# * Clearing all no longer needed certificates
|
||||
if getenv("LETS_ENCRYPT_DNS_CLEAR_OLD_CERTS", "no") == "yes":
|
||||
LOGGER.info("Clear old certificates is activated, removing old / no longer used certificates...")
|
||||
for elem in chain(DATA_PATH.glob("archive/*"), DATA_PATH.glob("live/*"), DATA_PATH.glob("renewal/*")):
|
||||
if elem.name.replace(".conf", "") not in generated_domains and elem.name != "README":
|
||||
LOGGER.warning(f"Removing old certificate {elem}")
|
||||
if elem.is_dir():
|
||||
rmtree(elem, ignore_errors=True)
|
||||
else:
|
||||
elem.unlink(missing_ok=True)
|
||||
|
||||
# * Save data to db cache
|
||||
if DATA_PATH.is_dir() and list(DATA_PATH.iterdir()):
|
||||
cached, err = JOB.cache_dir(DATA_PATH, job_name="dns-certbot-renew")
|
||||
if not cached:
|
||||
LOGGER.error(f"Error while saving data to db cache : {err}")
|
||||
else:
|
||||
LOGGER.info("Successfully saved data to db cache")
|
||||
except SystemExit as e:
|
||||
status = e.code
|
||||
except:
|
||||
status = 1
|
||||
LOGGER.exception("Exception while running certbot-new.py")
|
||||
|
||||
sys_exit(status)
|
||||
91
src/common/core/letsencrypt_dns/jobs/dns-certbot-renew.py
Normal file
91
src/common/core/letsencrypt_dns/jobs/dns-certbot-renew.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from os import environ, getenv, sep
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
from subprocess import DEVNULL, PIPE, Popen
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from traceback import format_exc
|
||||
|
||||
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("db",))]:
|
||||
if deps_path not in sys_path:
|
||||
sys_path.append(deps_path)
|
||||
|
||||
from logger import setup_logger # type: ignore
|
||||
from jobs import Job # type: ignore
|
||||
|
||||
LOGGER = setup_logger("LETS-ENCRYPT-DNS.renew", getenv("LOG_LEVEL", "INFO"))
|
||||
LOGGER_CERTBOT = setup_logger("LETS-ENCRYPT-DNS.renew.certbot", getenv("LOG_LEVEL", "INFO"))
|
||||
status = 0
|
||||
|
||||
LIB_PATH = Path(sep, "var", "lib", "bunkerweb", "letsencrypt_dns")
|
||||
PLUGIN_PATH = Path(sep, "usr", "share", "bunkerweb", "core", "letsencrypt_dns")
|
||||
JOBS_PATH = PLUGIN_PATH.joinpath("jobs")
|
||||
DATA_PATH = Path(sep, "var", "cache", "bunkerweb", "letsencrypt_dns", "etc")
|
||||
WORK_DIR = join(sep, "var", "lib", "bunkerweb", "letsencrypt_dns")
|
||||
LOGS_DIR = join(sep, "var", "log", "bunkerweb", "letsencrypt_dns")
|
||||
|
||||
deps_path = LIB_PATH.joinpath("python")
|
||||
CERTBOT_BIN = deps_path.joinpath("bin", "certbot")
|
||||
|
||||
try:
|
||||
# Check if we're using let's encrypt
|
||||
use_letsencrypt_dns = False
|
||||
if not getenv("MULTISITE", "no") == "yes":
|
||||
use_letsencrypt_dns = getenv("AUTO_LETS_ENCRYPT_DNS", "no") == "yes"
|
||||
else:
|
||||
for first_server in getenv("SERVER_NAME", "").split(" "):
|
||||
if first_server and getenv(f"{first_server}_AUTO_LETS_ENCRYPT_DNS", "no") == "yes":
|
||||
use_letsencrypt_dns = True
|
||||
break
|
||||
|
||||
if not use_letsencrypt_dns:
|
||||
LOGGER.info("Let's Encrypt DNS is not activated, skipping generation...")
|
||||
sys_exit(0)
|
||||
elif not CERTBOT_BIN.is_file():
|
||||
LOGGER.error("Additional dependencies not installed, skipping certificate(s) generation...")
|
||||
sys_exit(2)
|
||||
|
||||
JOB = Job(LOGGER)
|
||||
|
||||
process = Popen(
|
||||
[
|
||||
CERTBOT_BIN,
|
||||
"renew",
|
||||
"--no-random-sleep-on-renew",
|
||||
"--config-dir",
|
||||
DATA_PATH.as_posix(),
|
||||
"--work-dir",
|
||||
WORK_DIR,
|
||||
"--logs-dir",
|
||||
LOGS_DIR,
|
||||
],
|
||||
stdin=DEVNULL,
|
||||
stderr=PIPE,
|
||||
universal_newlines=True,
|
||||
env=environ | {"PYTHONPATH": deps_path.as_posix()},
|
||||
)
|
||||
while process.poll() is None:
|
||||
if process.stderr:
|
||||
for line in process.stderr:
|
||||
LOGGER_CERTBOT.info(line.strip())
|
||||
|
||||
if process.returncode != 0:
|
||||
status = 2
|
||||
LOGGER.error("Certificates renewal failed")
|
||||
|
||||
# Save Let's Encrypt DNS data to db cache
|
||||
if DATA_PATH.is_dir() and list(DATA_PATH.iterdir()):
|
||||
cached, err = JOB.cache_dir(DATA_PATH)
|
||||
if not cached:
|
||||
LOGGER.error(f"Error while saving Let's Encrypt DNS data to db cache : {err}")
|
||||
else:
|
||||
LOGGER.info("Successfully saved Let's Encrypt DNS data to db cache")
|
||||
except SystemExit as e:
|
||||
status = e.code
|
||||
except:
|
||||
status = 2
|
||||
LOGGER.error(f"Exception while running certbot-renew.py :\n{format_exc()}")
|
||||
|
||||
sys_exit(status)
|
||||
167
src/common/core/letsencrypt_dns/jobs/install-lets-encrypt-dns-dependencies.py
Executable file
167
src/common/core/letsencrypt_dns/jobs/install-lets-encrypt-dns-dependencies.py
Executable file
|
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from os import environ, getenv, sep
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
from shutil import rmtree
|
||||
from subprocess import STDOUT, Popen, PIPE, run
|
||||
from sys import exit as sys_exit, path as sys_path, version_info
|
||||
|
||||
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",), ("db",))]:
|
||||
if deps_path not in sys_path:
|
||||
sys_path.append(deps_path)
|
||||
|
||||
from Database import Database # type: ignore
|
||||
from logger import setup_logger # type: ignore
|
||||
|
||||
LOGGER = setup_logger("LETS-ENCRYPT-DNS.install-deps", getenv("LOG_LEVEL", "INFO"))
|
||||
status = 0
|
||||
|
||||
PLUGIN_PATH = Path(sep, "usr", "share", "bunkerweb", "core", "letsencrypt_dns")
|
||||
LIB_PATH = Path(sep, "var", "lib", "bunkerweb", "letsencrypt_dns")
|
||||
PIP_PATH = LIB_PATH.joinpath("pip")
|
||||
PYTHON_DEPS_PATH = LIB_PATH.joinpath("python")
|
||||
|
||||
try:
|
||||
|
||||
# * Check if we're using let's encrypt DNS
|
||||
all_domains = getenv("SERVER_NAME", "")
|
||||
|
||||
if not all_domains:
|
||||
LOGGER.warning("There are no server names, skipping additional dependencies installation...")
|
||||
sys_exit(0)
|
||||
|
||||
use_letsencrypt_dns = False
|
||||
is_multisite = getenv("MULTISITE", "no") == "yes"
|
||||
server_names = all_domains.split(" ")
|
||||
|
||||
if not is_multisite:
|
||||
use_letsencrypt_dns = getenv("AUTO_LETS_ENCRYPT_DNS", "no") == "yes"
|
||||
else:
|
||||
for first_server in server_names:
|
||||
if first_server and getenv(f"{first_server}_AUTO_LETS_ENCRYPT_DNS", getenv("AUTO_LETS_ENCRYPT_DNS", "no")) == "yes":
|
||||
use_letsencrypt_dns = True
|
||||
break
|
||||
|
||||
if not use_letsencrypt_dns:
|
||||
LOGGER.info("Let's Encrypt DNS is not activated, skipping additional dependencies installation...")
|
||||
sys_exit(0)
|
||||
|
||||
if PYTHON_DEPS_PATH.is_dir() and list(PYTHON_DEPS_PATH.iterdir()):
|
||||
LOGGER.info("Additional dependencies already installed, checking for updates...")
|
||||
|
||||
deps = {}
|
||||
with PLUGIN_PATH.joinpath("requirements.in").open("r") as f:
|
||||
for line in f:
|
||||
if (line := line.strip()) and not line.startswith("#"):
|
||||
package, version = line.split("==")
|
||||
deps[package] = version
|
||||
|
||||
all_deps_up_to_date = True
|
||||
process = Popen(
|
||||
["python3", "-m", "pip", "freeze", "--local"],
|
||||
stdout=PIPE,
|
||||
stderr=STDOUT,
|
||||
universal_newlines=True,
|
||||
env=environ | {"PYTHONPATH": PYTHON_DEPS_PATH.as_posix()},
|
||||
)
|
||||
while process.poll() is None:
|
||||
if process.stdout is not None:
|
||||
for line in process.stdout:
|
||||
if (line := line.strip()) and not line.startswith("#"):
|
||||
split = line.split("==")
|
||||
if len(split) != 2:
|
||||
continue
|
||||
package, version = split
|
||||
|
||||
if package in deps and deps[package] != version:
|
||||
LOGGER.info(f"⚠️ {package} is outdated: {version} -> {deps[package]}")
|
||||
all_deps_up_to_date = False
|
||||
|
||||
if process.returncode != 0:
|
||||
LOGGER.error("❌ Error while checking additional python dependencies, updating just in case...")
|
||||
elif all_deps_up_to_date:
|
||||
LOGGER.info("✅ All additional dependencies are up to date")
|
||||
sys_exit(0)
|
||||
else:
|
||||
LOGGER.warning("Some additional dependencies are outdated, updating...")
|
||||
rmtree(PYTHON_DEPS_PATH, ignore_errors=True)
|
||||
else:
|
||||
LOGGER.info("Deps path not found, installing additional dependencies...")
|
||||
|
||||
PYTHON_DEPS_PATH.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
pip_cmd = ["python3", "-m", "pip"]
|
||||
cmd_env = environ | {"PYTHONPATH": PYTHON_DEPS_PATH.as_posix()}
|
||||
|
||||
if PIP_PATH.joinpath("usr", "local", "bin").is_dir() and PIP_PATH.joinpath("usr", "local", "lib").is_dir():
|
||||
pip_cmd = [PIP_PATH.joinpath("usr", "local", "bin", "pip3").as_posix()]
|
||||
cmd_env["PYTHONPATH"] += ":" + PIP_PATH.joinpath("usr", "local", "lib", f"python{version_info.major}.{version_info.minor}", "site-packages").as_posix()
|
||||
else:
|
||||
process = run(pip_cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
|
||||
|
||||
if process.returncode != 0:
|
||||
LOGGER.warning("Pip is not installed, installing pip locally...")
|
||||
process = Popen(
|
||||
["python3", "-m", "ensurepip", "--root", PIP_PATH.as_posix()],
|
||||
stdout=PIPE,
|
||||
stderr=STDOUT,
|
||||
universal_newlines=True,
|
||||
)
|
||||
while process.poll() is None:
|
||||
if process.stdout is not None:
|
||||
for line in process.stdout:
|
||||
LOGGER.debug(line.strip())
|
||||
|
||||
if process.returncode != 0:
|
||||
LOGGER.error("❌ Error while ensuring pip is up to date")
|
||||
sys_exit(1)
|
||||
|
||||
LOGGER.info("✅ Pip installed successfully")
|
||||
|
||||
pip_cmd = [PIP_PATH.joinpath("usr", "local", "bin", "pip3").as_posix()]
|
||||
cmd_env["PYTHONPATH"] += (
|
||||
":" + PIP_PATH.joinpath("usr", "local", "lib", f"python{version_info.major}.{version_info.minor}", "site-packages").as_posix()
|
||||
)
|
||||
|
||||
LOGGER.info("Installing additional python dependencies...")
|
||||
current_date = datetime.now()
|
||||
process = Popen(
|
||||
pip_cmd
|
||||
+ [
|
||||
"install",
|
||||
"--no-cache-dir",
|
||||
"--require-hashes",
|
||||
"--ignore-installed",
|
||||
"--target",
|
||||
PYTHON_DEPS_PATH.as_posix(),
|
||||
"-r",
|
||||
PLUGIN_PATH.joinpath("requirements.txt").as_posix(),
|
||||
],
|
||||
stdout=PIPE,
|
||||
stderr=STDOUT,
|
||||
universal_newlines=True,
|
||||
env=cmd_env,
|
||||
)
|
||||
while process.poll() is None:
|
||||
if process.stdout is not None:
|
||||
for line in process.stdout:
|
||||
if datetime.now() - current_date > timedelta(seconds=5):
|
||||
LOGGER.info("⏳ Still installing additional python dependencies...")
|
||||
current_date = datetime.now()
|
||||
LOGGER.debug(line.strip())
|
||||
|
||||
if process.returncode != 0:
|
||||
LOGGER.error("❌ Error while installing additional python dependencies")
|
||||
sys_exit(1)
|
||||
|
||||
LOGGER.info("✅ Additional dependencies installed successfully")
|
||||
except SystemExit as e:
|
||||
status = e.code
|
||||
except:
|
||||
status = 1
|
||||
LOGGER.exception("Exception while running install-dependencies.py")
|
||||
|
||||
sys_exit(status)
|
||||
116
src/common/core/letsencrypt_dns/jobs/models.py
Normal file
116
src/common/core/letsencrypt_dns/jobs/models.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from os.path import sep
|
||||
from pathlib import Path
|
||||
from sys import path as sys_path
|
||||
from typing import Literal, Optional
|
||||
|
||||
LIB_PATH = Path(sep, "var", "lib", "bunkerweb", "letsencrypt_dns")
|
||||
|
||||
PYTHON_PATH = LIB_PATH.joinpath("python")
|
||||
if PYTHON_PATH.as_posix() not in sys_path:
|
||||
sys_path.append(PYTHON_PATH.as_posix())
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class Provider(BaseModel):
|
||||
"""Base class for DNS providers."""
|
||||
|
||||
# ? Allow extra fields in the model in case there are additional fields that are not defined in the model.
|
||||
model_config = ConfigDict(extra="allow")
|
||||
|
||||
def get_formatted_credentials(self) -> bytes:
|
||||
"""Return the formatted credentials to be written to a file."""
|
||||
return "\n".join(f"{key} = {value}" for key, value in self.model_dump(exclude={"file_type"}).items()).encode("utf-8")
|
||||
|
||||
@staticmethod
|
||||
def get_file_type() -> Literal["ini"]:
|
||||
"""Return the file type that the credentials should be written to."""
|
||||
return "ini"
|
||||
|
||||
|
||||
class CloudflareProvider(Provider):
|
||||
dns_cloudflare_api_token: str
|
||||
|
||||
|
||||
class DigitalOceanProvider(Provider):
|
||||
dns_digitalocean_token: str
|
||||
|
||||
|
||||
class GoogleProvider(Provider):
|
||||
type: str = "service_account"
|
||||
project_id: str
|
||||
private_key_id: str
|
||||
private_key: str
|
||||
client_email: str
|
||||
client_id: str
|
||||
auth_uri: str = "https://accounts.google.com/o/oauth2/auth"
|
||||
token_uri: str = "https://accounts.google.com/o/oauth2/token"
|
||||
auth_provider_x509_cert_url: str = "https://www.googleapis.com/oauth2/v1/certs"
|
||||
client_x509_cert_url: str
|
||||
|
||||
def get_formatted_credentials(self) -> bytes:
|
||||
"""Return the formatted credentials to be written to a file."""
|
||||
return self.model_dump_json(indent=2, exclude={"file_type"}).encode("utf-8")
|
||||
|
||||
@staticmethod
|
||||
def get_file_type() -> Literal["json"]:
|
||||
"""Return the file type that the credentials should be written to."""
|
||||
return "json"
|
||||
|
||||
|
||||
class LinodeProvider(Provider):
|
||||
dns_linode_key: str
|
||||
dns_linode_version: str = "4"
|
||||
|
||||
|
||||
class OvhProvider(Provider):
|
||||
dns_ovh_endpoint: str = "ovh-eu"
|
||||
dns_ovh_application_key: str
|
||||
dns_ovh_application_secret: str
|
||||
dns_ovh_consumer_key: str
|
||||
|
||||
|
||||
class Rfc2136Provider(Provider):
|
||||
dns_rfc2136_server: str
|
||||
dns_rfc2136_port: Optional[str] = None
|
||||
dns_rfc2136_name: str
|
||||
dns_rfc2136_secret: str
|
||||
dns_rfc2136_algorithm: str = "HMAC-MD5"
|
||||
dns_rfc2136_sign_query: str = "false"
|
||||
|
||||
def get_formatted_credentials(self) -> bytes:
|
||||
"""Return the formatted credentials to be written to a file."""
|
||||
# ? Return the formatted credentials as a string. The default values are excluded as they are not required.
|
||||
return "\n".join(f"{key} = {value}" for key, value in self.model_dump(exclude={"file_type"}, exclude_defaults=True).items()).encode("utf-8")
|
||||
|
||||
|
||||
class Route53Provider(Provider):
|
||||
aws_access_key_id: str
|
||||
aws_secret_access_key: str
|
||||
|
||||
def get_formatted_credentials(self) -> bytes:
|
||||
"""Return the formatted credentials to be written to a file."""
|
||||
# ? Return the formatted credentials as a string. The keys are converted to uppercase and the values are represented as a string.
|
||||
return "\n".join(f"{key.upper()}={value!r}" for key, value in self.model_dump(exclude={"file_type"}).items()).encode("utf-8")
|
||||
|
||||
@staticmethod
|
||||
def get_file_type() -> Literal["env"]:
|
||||
"""Return the file type that the credentials should be written to."""
|
||||
return "env"
|
||||
|
||||
|
||||
class ScalewayProvider(Provider):
|
||||
dns_scaleway_application_token: str
|
||||
|
||||
|
||||
__ALL__ = (
|
||||
"CloudflareProvider",
|
||||
"DigitalOceanProvider",
|
||||
"GoogleProvider",
|
||||
"LinodeProvider",
|
||||
"OvhProvider",
|
||||
"Rfc2136Provider",
|
||||
"Route53Provider",
|
||||
"ScalewayProvider",
|
||||
)
|
||||
194
src/common/core/letsencrypt_dns/letsencrypt_dns.lua
Normal file
194
src/common/core/letsencrypt_dns/letsencrypt_dns.lua
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
local class = require("middleclass")
|
||||
local plugin = require("bunkerweb.plugin")
|
||||
local ssl = require("ngx.ssl")
|
||||
local utils = require("bunkerweb.utils")
|
||||
|
||||
local letsencrypt_dns = class("letsencrypt_dns", plugin)
|
||||
|
||||
-- luacheck: globals ngx
|
||||
local ngx = ngx
|
||||
local ERR = ngx.ERR
|
||||
local parse_pem_cert = ssl.parse_pem_cert
|
||||
local parse_pem_priv_key = ssl.parse_pem_priv_key
|
||||
local ssl_server_name = ssl.server_name
|
||||
local get_variable = utils.get_variable
|
||||
local get_multiple_variables = utils.get_multiple_variables
|
||||
local has_variable = utils.has_variable
|
||||
local has_not_variable = utils.has_not_variable
|
||||
local read_files = utils.read_files
|
||||
|
||||
function letsencrypt_dns:initialize(ctx)
|
||||
-- Call parent initialize
|
||||
plugin.initialize(self, "letsencrypt_dns", ctx)
|
||||
end
|
||||
|
||||
function letsencrypt_dns:set()
|
||||
local https_configured = self.variables["AUTO_LETS_ENCRYPT_DNS"]
|
||||
if https_configured == "yes" then
|
||||
self.ctx.bw.https_configured = "yes"
|
||||
end
|
||||
return self:ret(true, "set https_configured to " .. https_configured)
|
||||
end
|
||||
|
||||
function letsencrypt_dns:init()
|
||||
local ret_ok, ret_err = true, "success"
|
||||
if has_variable("AUTO_LETS_ENCRYPT_DNS", "yes") and has_not_variable("LETS_ENCRYPT_DNS_PROVIDER", "") then
|
||||
local multisite, err = get_variable("MULTISITE", false)
|
||||
if not multisite then
|
||||
return self:ret(false, "can't get MULTISITE variable : " .. err)
|
||||
end
|
||||
if multisite == "yes" then
|
||||
local vars
|
||||
vars, err = get_multiple_variables({
|
||||
"AUTO_LETS_ENCRYPT_DNS",
|
||||
"LETS_ENCRYPT_DNS_PROVIDER",
|
||||
"USE_LETS_ENCRYPT_DNS_WILDCARD",
|
||||
"SERVER_NAME",
|
||||
})
|
||||
if not vars then
|
||||
return self:ret(false, "can't get required variables : " .. err)
|
||||
end
|
||||
local credential_items
|
||||
credential_items, err = get_multiple_variables({ "LETS_ENCRYPT_DNS_CREDENTIAL_ITEM" })
|
||||
if not credential_items then
|
||||
return self:ret(false, "can't get credential items : " .. err)
|
||||
end
|
||||
for server_name, multisite_vars in pairs(vars) do
|
||||
if
|
||||
multisite_vars["AUTO_LETS_ENCRYPT_DNS"] == "yes"
|
||||
and multisite_vars["LETS_ENCRYPT_DNS_PROVIDER"] ~= ""
|
||||
and credential_items[server_name]
|
||||
and server_name ~= "global"
|
||||
then
|
||||
local data
|
||||
if multisite_vars["USE_LETS_ENCRYPT_DNS_WILDCARD"] == "yes" then
|
||||
local parts = {}
|
||||
for part in server_name:gmatch("[^.]+") do
|
||||
table.insert(parts, part)
|
||||
end
|
||||
server_name = table.concat(parts, ".", 2)
|
||||
data = self.datastore:get("plugin_letsencrypt_dns_" .. server_name, true)
|
||||
end
|
||||
if not data then
|
||||
-- Load certificate
|
||||
local check
|
||||
check, data = read_files({
|
||||
"/var/cache/bunkerweb/letsencrypt_dns/etc/live/" .. server_name .. "/fullchain.pem",
|
||||
"/var/cache/bunkerweb/letsencrypt_dns/etc/live/" .. server_name .. "/privkey.pem",
|
||||
})
|
||||
if not check then
|
||||
self.logger:log(ERR, "error while reading files : " .. data)
|
||||
ret_ok = false
|
||||
ret_err = "error reading files"
|
||||
else
|
||||
if multisite_vars["USE_LETS_ENCRYPT_DNS_WILDCARD"] == "yes" then
|
||||
check, err = self:load_data(data, server_name)
|
||||
else
|
||||
check, err = self:load_data(data, multisite_vars["SERVER_NAME"])
|
||||
end
|
||||
if not check then
|
||||
self.logger:log(ERR, "error while loading data : " .. err)
|
||||
ret_ok = false
|
||||
ret_err = "error loading data"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local server_name
|
||||
server_name, err = get_variable("SERVER_NAME", false)
|
||||
if not server_name then
|
||||
return self:ret(false, "can't get SERVER_NAME variable : " .. err)
|
||||
end
|
||||
local use_wildcard
|
||||
use_wildcard, err = get_variable("USE_LETS_ENCRYPT_DNS_WILDCARD", false)
|
||||
if not use_wildcard then
|
||||
return self:ret(false, "can't get USE_LETS_ENCRYPT_DNS_WILDCARD variable : " .. err)
|
||||
end
|
||||
server_name = server_name:match("%S+")
|
||||
if use_wildcard == "yes" then
|
||||
local parts = {}
|
||||
for part in server_name:gmatch("[^.]+") do
|
||||
table.insert(parts, part)
|
||||
end
|
||||
server_name = table.concat(parts, ".", 2)
|
||||
end
|
||||
local check, data = read_files({
|
||||
"/var/cache/bunkerweb/letsencrypt_dns/etc/live/" .. server_name .. "/fullchain.pem",
|
||||
"/var/cache/bunkerweb/letsencrypt_dns/etc/live/" .. server_name .. "/privkey.pem",
|
||||
})
|
||||
if not check then
|
||||
self.logger:log(ERR, "error while reading files : " .. data)
|
||||
ret_ok = false
|
||||
ret_err = "error reading files"
|
||||
else
|
||||
check, err = self:load_data(data, server_name)
|
||||
if not check then
|
||||
self.logger:log(ERR, "error while loading data : " .. err)
|
||||
ret_ok = false
|
||||
ret_err = "error loading data"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
ret_err = "let's encrypt dns is not used"
|
||||
end
|
||||
return self:ret(ret_ok, ret_err)
|
||||
end
|
||||
|
||||
function letsencrypt_dns:ssl_certificate()
|
||||
local server_name, err = ssl_server_name()
|
||||
if not server_name then
|
||||
return self:ret(false, "can't get server_name : " .. err)
|
||||
end
|
||||
local use_wildcard
|
||||
use_wildcard, err = get_variable("USE_LETS_ENCRYPT_DNS_WILDCARD", false)
|
||||
if not use_wildcard then
|
||||
return self:ret(false, "can't get USE_LETS_ENCRYPT_DNS_WILDCARD variable : " .. err)
|
||||
end
|
||||
if use_wildcard == "yes" then
|
||||
local parts = {}
|
||||
for part in server_name:gmatch("[^.]+") do
|
||||
table.insert(parts, part)
|
||||
end
|
||||
server_name = table.concat(parts, ".", 2)
|
||||
end
|
||||
local data
|
||||
data, err = self.datastore:get("plugin_letsencrypt_dns_" .. server_name, true)
|
||||
if not data and err ~= "not found" then
|
||||
return self:ret(
|
||||
false,
|
||||
"error while getting plugin_letsencrypt_dns_" .. server_name .. " from datastore : " .. err
|
||||
)
|
||||
elseif data then
|
||||
return self:ret(true, "certificate/key data found", data)
|
||||
end
|
||||
return self:ret(true, "let's encrypt dns is not used")
|
||||
end
|
||||
|
||||
function letsencrypt_dns:load_data(data, server_name)
|
||||
-- Load certificate
|
||||
local cert_chain, err = parse_pem_cert(data[1])
|
||||
if not cert_chain then
|
||||
return false, "error while parsing pem cert : " .. err
|
||||
end
|
||||
-- Load key
|
||||
local priv_key
|
||||
priv_key, err = parse_pem_priv_key(data[2])
|
||||
if not priv_key then
|
||||
return false, "error while parsing pem priv key : " .. err
|
||||
end
|
||||
-- Cache data
|
||||
for key in server_name:gmatch("%S+") do
|
||||
local cache_key = "plugin_letsencrypt_dns_" .. key
|
||||
local ok
|
||||
ok, err = self.datastore:set(cache_key, { cert_chain, priv_key }, nil, true)
|
||||
if not ok then
|
||||
return false, "error while setting data into datastore : " .. err
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return letsencrypt_dns
|
||||
113
src/common/core/letsencrypt_dns/plugin.json
Normal file
113
src/common/core/letsencrypt_dns/plugin.json
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
{
|
||||
"id": "letsencrypt_dns",
|
||||
"name": "Let's Encrypt DNS",
|
||||
"description": "Automatic creation, renewal and configuration of Let's Encrypt certificates using DNS challenges.",
|
||||
"version": "0.7",
|
||||
"stream": "yes",
|
||||
"settings": {
|
||||
"AUTO_LETS_ENCRYPT_DNS": {
|
||||
"context": "multisite",
|
||||
"default": "no",
|
||||
"help": "Activate automatic Let's Encrypt DNS.",
|
||||
"id": "auto-lets-encrypt-dns",
|
||||
"label": "Automatic Let's Encrypt Dns",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"LETS_ENCRYPT_DNS_EMAIL": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "The email address to use for Let's Encrypt notifications.",
|
||||
"id": "lets-encrypt-dns-email",
|
||||
"label": "Email Address for Notifications",
|
||||
"regex": "^([^@ \\t\\r\\n]+@[^@ \\t\\r\\n]+\\.[^@ \\t\\r\\n]+)?$",
|
||||
"type": "text"
|
||||
},
|
||||
"USE_LETS_ENCRYPT_DNS_STAGING": {
|
||||
"context": "multisite",
|
||||
"default": "no",
|
||||
"help": "Use the Let's Encrypt staging environment.",
|
||||
"id": "use-lets-encrypt-dns-staging",
|
||||
"label": "Use Let's Encrypt DNS Staging",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"LETS_ENCRYPT_DNS_PROVIDER": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "The DNS provider to use for DNS challenges.",
|
||||
"id": "auto-lets-encrypt-dns-provider",
|
||||
"label": "DNS Provider",
|
||||
"regex": "^(cloudflare|digitalocean|google|linode|ovh|rfc2136|route53|scaleway)?$",
|
||||
"type": "select",
|
||||
"select": [
|
||||
"",
|
||||
"cloudflare",
|
||||
"digitalocean",
|
||||
"google",
|
||||
"linode",
|
||||
"ovh",
|
||||
"rfc2136",
|
||||
"route53",
|
||||
"scaleway"
|
||||
]
|
||||
},
|
||||
"USE_LETS_ENCRYPT_DNS_WILDCARD": {
|
||||
"context": "multisite",
|
||||
"default": "yes",
|
||||
"help": "Create wildcard certificates for all domains using DNS challenges.",
|
||||
"id": "use-lets-encrypt-dns-wildcard",
|
||||
"label": "Wildcard Certificates",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
},
|
||||
"LETS_ENCRYPT_DNS_PROPAGATION": {
|
||||
"context": "multisite",
|
||||
"default": "default",
|
||||
"help": "The time to wait for DNS propagation in seconds.",
|
||||
"id": "lets-encrypt-dns-propagation",
|
||||
"label": "DNS Propagation",
|
||||
"regex": "^(default|\\d+)$",
|
||||
"type": "text"
|
||||
},
|
||||
"LETS_ENCRYPT_DNS_CREDENTIAL_ITEM": {
|
||||
"context": "multisite",
|
||||
"default": "",
|
||||
"help": "Configuration item that will be added to the credentials.ini file for the DNS provider (e.g. 'cloudflare_api_token 123456').",
|
||||
"id": "lets-encrypt-dns-credential-item",
|
||||
"label": "Credential Item",
|
||||
"regex": "^(\\w+ .+)?$",
|
||||
"type": "password",
|
||||
"multiple": "lets-encrypt-dns-credential-item"
|
||||
},
|
||||
"LETS_ENCRYPT_DNS_CLEAR_OLD_CERTS": {
|
||||
"context": "global",
|
||||
"default": "no",
|
||||
"help": "Clear old certificates when renewing.",
|
||||
"id": "lets-encrypt-dns-clear-old-certs",
|
||||
"label": "Clear old certificates when they are no longer needed",
|
||||
"regex": "^(yes|no)$",
|
||||
"type": "check"
|
||||
}
|
||||
},
|
||||
"jobs": [
|
||||
{
|
||||
"name": "install-lets-encrypt-dns-dependencies",
|
||||
"file": "install-lets-encrypt-dns-dependencies.py",
|
||||
"every": "once",
|
||||
"reload": false
|
||||
},
|
||||
{
|
||||
"name": "dns-certbot-new",
|
||||
"file": "dns-certbot-new.py",
|
||||
"every": "once",
|
||||
"reload": false
|
||||
},
|
||||
{
|
||||
"name": "dns-certbot-renew",
|
||||
"file": "dns-certbot-renew.py",
|
||||
"every": "day",
|
||||
"reload": false
|
||||
}
|
||||
]
|
||||
}
|
||||
9
src/common/core/letsencrypt_dns/requirements.in
Normal file
9
src/common/core/letsencrypt_dns/requirements.in
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
certbot-dns-cloudflare==2.11.0
|
||||
certbot-dns-digitalocean==2.11.0
|
||||
certbot-dns-google==2.11.0
|
||||
certbot-dns-linode==2.11.0
|
||||
certbot-dns-ovh==2.11.0
|
||||
certbot-dns-rfc2136==2.11.0
|
||||
certbot-dns-route53==2.11.0
|
||||
certbot-dns-scaleway==0.0.7
|
||||
pydantic==2.9.2
|
||||
686
src/common/core/letsencrypt_dns/requirements.txt
Normal file
686
src/common/core/letsencrypt_dns/requirements.txt
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.9
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile --allow-unsafe --generate-hashes --strip-extras requirements.in
|
||||
#
|
||||
acme==2.11.0 \
|
||||
--hash=sha256:23213ac3074a78862b219e0a30e141fd53238a8bdcf0668bd4dea59b28873fb8 \
|
||||
--hash=sha256:f4950015cf52ff0de12f37fc28034c7710aca63f64f1696253d2f6cb9f22645e
|
||||
# via
|
||||
# certbot
|
||||
# certbot-dns-cloudflare
|
||||
# certbot-dns-digitalocean
|
||||
# certbot-dns-google
|
||||
# certbot-dns-linode
|
||||
# certbot-dns-ovh
|
||||
# certbot-dns-rfc2136
|
||||
# certbot-dns-route53
|
||||
# certbot-dns-scaleway
|
||||
annotated-types==0.7.0 \
|
||||
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
|
||||
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
|
||||
# via pydantic
|
||||
attrs==24.2.0 \
|
||||
--hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \
|
||||
--hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2
|
||||
# via jsonlines
|
||||
beautifulsoup4==4.12.3 \
|
||||
--hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \
|
||||
--hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed
|
||||
# via dns-lexicon
|
||||
boto3==1.35.24 \
|
||||
--hash=sha256:97fcc1a14cbc759e4ba9535ced703a99fcf652c9c4b8dfcd06f292c80551684b \
|
||||
--hash=sha256:be7807f30f26d6c0057e45cfd09dad5968e664488bf4f9138d0bb7a0f6d8ed40
|
||||
# via certbot-dns-route53
|
||||
botocore==1.35.24 \
|
||||
--hash=sha256:1e59b0f14f4890c4f70bd6a58a634b9464bed1c4c6171f87c8795d974ade614b \
|
||||
--hash=sha256:eb9ccc068255cc3d24c36693fda6aec7786db05ae6c2b13bcba66dce6a13e2e3
|
||||
# via
|
||||
# boto3
|
||||
# s3transfer
|
||||
cachetools==5.5.0 \
|
||||
--hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \
|
||||
--hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a
|
||||
# via google-auth
|
||||
certbot==2.11.0 \
|
||||
--hash=sha256:257ae1cb0a534373ca50dd807c9ae96f27660e41379c45afb9b50cab0e6a7a97 \
|
||||
--hash=sha256:dc4e0a48bcb09448d60362170ca1047cc9a81966da0dd35135f2561f0ea7d5b1
|
||||
# via
|
||||
# certbot-dns-cloudflare
|
||||
# certbot-dns-digitalocean
|
||||
# certbot-dns-google
|
||||
# certbot-dns-linode
|
||||
# certbot-dns-ovh
|
||||
# certbot-dns-rfc2136
|
||||
# certbot-dns-route53
|
||||
# certbot-dns-scaleway
|
||||
certbot-dns-cloudflare==2.11.0 \
|
||||
--hash=sha256:2a3e06a692add6aacdc2dfe7fada695483f5fbf4fed073eabd36f3d7745f0c7a \
|
||||
--hash=sha256:42788044840328de1fe85ea32df1254823f1452e0479a60445fd364f8234a4a9
|
||||
# via -r requirements.in
|
||||
certbot-dns-digitalocean==2.11.0 \
|
||||
--hash=sha256:30e9543baef204e110dacb1e6adf9b1fd04777a14a204bd3cdbfb100c6f6e32a \
|
||||
--hash=sha256:d5166fc7eb3b3e8a8de4b43e7485d60eda4225db1d525b6f096949d1487e1c6c
|
||||
# via -r requirements.in
|
||||
certbot-dns-google==2.11.0 \
|
||||
--hash=sha256:6af70452913e472f74788e76375ff00a6c427e59c896d7b982732ba33a09a199 \
|
||||
--hash=sha256:de5fd15b4b60e652ea41e556fccf09376fdc7f881ec7544cb1e25176b2a1a5bf
|
||||
# via -r requirements.in
|
||||
certbot-dns-linode==2.11.0 \
|
||||
--hash=sha256:4727015830ff048e925d2acee26e9bd727e03cb3ceb29d228d45c6602b6f964f \
|
||||
--hash=sha256:60848af4c336928f0b069d350accae5abd5896118c36920247972b6759aa1ba6
|
||||
# via -r requirements.in
|
||||
certbot-dns-ovh==2.11.0 \
|
||||
--hash=sha256:1a9ccd1d987c0448dd9050a3ac43558569a6d887f2fcde148f2699c4dc624a26 \
|
||||
--hash=sha256:6be4feb03782bf2dc876319df0a54ee567241d777132546785b1f7c072e6a2df
|
||||
# via -r requirements.in
|
||||
certbot-dns-rfc2136==2.11.0 \
|
||||
--hash=sha256:413a80c09e3a00162d9f7833cb2f5ed3690ae0833e09be84c795b7ee5a357c4b \
|
||||
--hash=sha256:aaf9f6b387359734b4138f179f96f480889d9a4e2e44fae60c9ebe4d8715f567
|
||||
# via -r requirements.in
|
||||
certbot-dns-route53==2.11.0 \
|
||||
--hash=sha256:2492bd62fbe514a259d4a0b3455d576b267b9a82f26f396af136d9ec2a9c0ba8 \
|
||||
--hash=sha256:5fd11e3546175574ccc51aaeccb19860e00c633f9bbeb0c4d033bac5553b15bd
|
||||
# via -r requirements.in
|
||||
certbot-dns-scaleway==0.0.7 \
|
||||
--hash=sha256:999dda5b8689277facb77e1757b8a6b207baeecc0ded0c27aea2c51331affc92 \
|
||||
--hash=sha256:bc0833ed71a5cd314a93f8d02144c54e17066ee1e2b950ed868b14b2211f5e9e
|
||||
# via -r requirements.in
|
||||
certifi==2024.8.30 \
|
||||
--hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \
|
||||
--hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9
|
||||
# via requests
|
||||
cffi==1.17.1 \
|
||||
--hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \
|
||||
--hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \
|
||||
--hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \
|
||||
--hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \
|
||||
--hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \
|
||||
--hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
|
||||
--hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \
|
||||
--hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \
|
||||
--hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \
|
||||
--hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
|
||||
--hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \
|
||||
--hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \
|
||||
--hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \
|
||||
--hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \
|
||||
--hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
|
||||
--hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \
|
||||
--hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \
|
||||
--hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \
|
||||
--hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
|
||||
--hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \
|
||||
--hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \
|
||||
--hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \
|
||||
--hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \
|
||||
--hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \
|
||||
--hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \
|
||||
--hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \
|
||||
--hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \
|
||||
--hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \
|
||||
--hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \
|
||||
--hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
|
||||
--hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \
|
||||
--hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \
|
||||
--hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \
|
||||
--hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \
|
||||
--hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
|
||||
--hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
|
||||
--hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
|
||||
--hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
|
||||
--hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \
|
||||
--hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \
|
||||
--hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \
|
||||
--hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \
|
||||
--hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \
|
||||
--hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \
|
||||
--hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \
|
||||
--hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \
|
||||
--hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
|
||||
--hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \
|
||||
--hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \
|
||||
--hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \
|
||||
--hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \
|
||||
--hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \
|
||||
--hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \
|
||||
--hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
|
||||
--hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \
|
||||
--hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \
|
||||
--hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \
|
||||
--hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \
|
||||
--hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \
|
||||
--hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \
|
||||
--hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \
|
||||
--hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \
|
||||
--hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \
|
||||
--hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
|
||||
--hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \
|
||||
--hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \
|
||||
--hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
|
||||
# via cryptography
|
||||
charset-normalizer==3.3.2 \
|
||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||
--hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
|
||||
--hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
|
||||
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
|
||||
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
|
||||
--hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
|
||||
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
|
||||
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
|
||||
--hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
|
||||
--hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
|
||||
--hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
|
||||
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
|
||||
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
|
||||
--hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
|
||||
--hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
|
||||
--hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
|
||||
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
|
||||
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
|
||||
--hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
|
||||
--hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
|
||||
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
|
||||
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
|
||||
--hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
|
||||
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
|
||||
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
|
||||
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
|
||||
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
|
||||
--hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
|
||||
--hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
|
||||
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
|
||||
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
|
||||
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
|
||||
--hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
|
||||
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
|
||||
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
|
||||
--hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
|
||||
--hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
|
||||
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
|
||||
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
|
||||
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
|
||||
--hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
|
||||
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
|
||||
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
|
||||
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
|
||||
--hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
|
||||
--hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
|
||||
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
|
||||
--hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
|
||||
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
|
||||
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
|
||||
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
|
||||
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
|
||||
--hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
|
||||
--hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
|
||||
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
|
||||
--hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
|
||||
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
|
||||
--hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
|
||||
--hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
|
||||
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
|
||||
--hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
|
||||
--hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
|
||||
--hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
|
||||
--hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
|
||||
--hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
|
||||
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
|
||||
--hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
|
||||
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
|
||||
--hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
|
||||
--hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
|
||||
--hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
|
||||
--hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
|
||||
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
|
||||
--hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
|
||||
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
|
||||
--hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
|
||||
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
|
||||
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
|
||||
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
|
||||
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
|
||||
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
|
||||
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
|
||||
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
|
||||
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
|
||||
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
|
||||
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
|
||||
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
|
||||
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
|
||||
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
|
||||
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
|
||||
# via requests
|
||||
cloudflare==2.19.4 \
|
||||
--hash=sha256:3b6000a01a237c23bccfdf6d20256ea5111ec74a826ae9e74f9f0e5bb5b2383f
|
||||
# via certbot-dns-cloudflare
|
||||
configargparse==1.7 \
|
||||
--hash=sha256:d249da6591465c6c26df64a9f73d2536e743be2f244eb3ebe61114af2f94f86b \
|
||||
--hash=sha256:e7067471884de5478c58a511e529f0f9bd1c66bfef1dea90935438d6c23306d1
|
||||
# via certbot
|
||||
configobj==5.0.9 \
|
||||
--hash=sha256:03c881bbf23aa07bccf1b837005975993c4ab4427ba57f959afdd9d1a2386848
|
||||
# via certbot
|
||||
cryptography==43.0.1 \
|
||||
--hash=sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494 \
|
||||
--hash=sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806 \
|
||||
--hash=sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d \
|
||||
--hash=sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062 \
|
||||
--hash=sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2 \
|
||||
--hash=sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4 \
|
||||
--hash=sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1 \
|
||||
--hash=sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85 \
|
||||
--hash=sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84 \
|
||||
--hash=sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042 \
|
||||
--hash=sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d \
|
||||
--hash=sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962 \
|
||||
--hash=sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2 \
|
||||
--hash=sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa \
|
||||
--hash=sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d \
|
||||
--hash=sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365 \
|
||||
--hash=sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96 \
|
||||
--hash=sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47 \
|
||||
--hash=sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d \
|
||||
--hash=sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d \
|
||||
--hash=sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c \
|
||||
--hash=sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb \
|
||||
--hash=sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277 \
|
||||
--hash=sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172 \
|
||||
--hash=sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034 \
|
||||
--hash=sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a \
|
||||
--hash=sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289
|
||||
# via
|
||||
# acme
|
||||
# certbot
|
||||
# dns-lexicon
|
||||
# josepy
|
||||
# pyopenssl
|
||||
distro==1.9.0 \
|
||||
--hash=sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed \
|
||||
--hash=sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2
|
||||
# via certbot
|
||||
dns-lexicon==3.18.0 \
|
||||
--hash=sha256:aabe320093b4f9a7f7e0e430551ae49c38c9cf99b45ef7e28da238c50106b1a0 \
|
||||
--hash=sha256:c2b1005a6621a2ec648131d96ec61304b90b98842af9ff62b1840ddf9d0e2c26
|
||||
# via
|
||||
# certbot-dns-linode
|
||||
# certbot-dns-ovh
|
||||
dnspython==2.6.1 \
|
||||
--hash=sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50 \
|
||||
--hash=sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc
|
||||
# via
|
||||
# certbot-dns-rfc2136
|
||||
# dns-lexicon
|
||||
filelock==3.16.1 \
|
||||
--hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \
|
||||
--hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435
|
||||
# via tldextract
|
||||
google-api-core==2.20.0 \
|
||||
--hash=sha256:ef0591ef03c30bb83f79b3d0575c3f31219001fc9c5cf37024d08310aeffed8a \
|
||||
--hash=sha256:f74dff1889ba291a4b76c5079df0711810e2d9da81abfdc99957bc961c1eb28f
|
||||
# via google-api-python-client
|
||||
google-api-python-client==2.146.0 \
|
||||
--hash=sha256:41f671be10fa077ee5143ee9f0903c14006d39dc644564f4e044ae96b380bf68 \
|
||||
--hash=sha256:b1e62c9889c5ef6022f11d30d7ef23dc55100300f0e8aaf8aa09e8e92540acad
|
||||
# via certbot-dns-google
|
||||
google-auth==2.35.0 \
|
||||
--hash=sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f \
|
||||
--hash=sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a
|
||||
# via
|
||||
# certbot-dns-google
|
||||
# google-api-core
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
google-auth-httplib2==0.2.0 \
|
||||
--hash=sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05 \
|
||||
--hash=sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d
|
||||
# via google-api-python-client
|
||||
googleapis-common-protos==1.65.0 \
|
||||
--hash=sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63 \
|
||||
--hash=sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0
|
||||
# via google-api-core
|
||||
httplib2==0.22.0 \
|
||||
--hash=sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc \
|
||||
--hash=sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81
|
||||
# via
|
||||
# google-api-python-client
|
||||
# google-auth-httplib2
|
||||
idna==3.10 \
|
||||
--hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
|
||||
--hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
|
||||
# via
|
||||
# requests
|
||||
# tldextract
|
||||
importlib-metadata==8.5.0 \
|
||||
--hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \
|
||||
--hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7
|
||||
# via
|
||||
# certbot
|
||||
# dns-lexicon
|
||||
jmespath==1.0.1 \
|
||||
--hash=sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 \
|
||||
--hash=sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe
|
||||
# via
|
||||
# boto3
|
||||
# botocore
|
||||
josepy==1.14.0 \
|
||||
--hash=sha256:308b3bf9ce825ad4d4bba76372cf19b5dc1c2ce96a9d298f9642975e64bd13dd \
|
||||
--hash=sha256:d2b36a30f316269f3242f4c2e45e15890784178af5ec54fa3e49cf9234ee22e0
|
||||
# via
|
||||
# acme
|
||||
# certbot
|
||||
jsonlines==4.0.0 \
|
||||
--hash=sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74 \
|
||||
--hash=sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55
|
||||
# via cloudflare
|
||||
jsonpickle==3.3.0 \
|
||||
--hash=sha256:287c12143f35571ab00e224fa323aa4b090d5a7f086f5f494d7ee9c7eb1a380a \
|
||||
--hash=sha256:ab467e601e5b1a1cd76f1819d014795165da071744ef30bf3786e9bc549de25a
|
||||
# via python-digitalocean
|
||||
mock==5.1.0 \
|
||||
--hash=sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744 \
|
||||
--hash=sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d
|
||||
# via certbot-dns-scaleway
|
||||
parsedatetime==2.6 \
|
||||
--hash=sha256:4cb368fbb18a0b7231f4d76119165451c8d2e35951455dfee97c62a87b04d455 \
|
||||
--hash=sha256:cb96edd7016872f58479e35879294258c71437195760746faffedb692aef000b
|
||||
# via certbot
|
||||
proto-plus==1.24.0 \
|
||||
--hash=sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445 \
|
||||
--hash=sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12
|
||||
# via google-api-core
|
||||
protobuf==5.28.2 \
|
||||
--hash=sha256:2c69461a7fcc8e24be697624c09a839976d82ae75062b11a0972e41fd2cd9132 \
|
||||
--hash=sha256:35cfcb15f213449af7ff6198d6eb5f739c37d7e4f1c09b5d0641babf2cc0c68f \
|
||||
--hash=sha256:52235802093bd8a2811abbe8bf0ab9c5f54cca0a751fdd3f6ac2a21438bffece \
|
||||
--hash=sha256:59379674ff119717404f7454647913787034f03fe7049cbef1d74a97bb4593f0 \
|
||||
--hash=sha256:5e8a95246d581eef20471b5d5ba010d55f66740942b95ba9b872d918c459452f \
|
||||
--hash=sha256:87317e9bcda04a32f2ee82089a204d3a2f0d3c8aeed16568c7daf4756e4f1fe0 \
|
||||
--hash=sha256:8ddc60bf374785fb7cb12510b267f59067fa10087325b8e1855b898a0d81d276 \
|
||||
--hash=sha256:a8b9403fc70764b08d2f593ce44f1d2920c5077bf7d311fefec999f8c40f78b7 \
|
||||
--hash=sha256:c0ea0123dac3399a2eeb1a1443d82b7afc9ff40241433296769f7da42d142ec3 \
|
||||
--hash=sha256:ca53faf29896c526863366a52a8f4d88e69cd04ec9571ed6082fa117fac3ab36 \
|
||||
--hash=sha256:eeea10f3dc0ac7e6b4933d32db20662902b4ab81bf28df12218aa389e9c2102d
|
||||
# via
|
||||
# google-api-core
|
||||
# googleapis-common-protos
|
||||
# proto-plus
|
||||
pyasn1==0.6.1 \
|
||||
--hash=sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629 \
|
||||
--hash=sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034
|
||||
# via
|
||||
# pyasn1-modules
|
||||
# rsa
|
||||
pyasn1-modules==0.4.1 \
|
||||
--hash=sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd \
|
||||
--hash=sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c
|
||||
# via google-auth
|
||||
pycparser==2.22 \
|
||||
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
|
||||
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
|
||||
# via cffi
|
||||
pydantic==2.9.2 \
|
||||
--hash=sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f \
|
||||
--hash=sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12
|
||||
# via -r requirements.in
|
||||
pydantic-core==2.23.4 \
|
||||
--hash=sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36 \
|
||||
--hash=sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05 \
|
||||
--hash=sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071 \
|
||||
--hash=sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327 \
|
||||
--hash=sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c \
|
||||
--hash=sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36 \
|
||||
--hash=sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29 \
|
||||
--hash=sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744 \
|
||||
--hash=sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d \
|
||||
--hash=sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec \
|
||||
--hash=sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e \
|
||||
--hash=sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e \
|
||||
--hash=sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577 \
|
||||
--hash=sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232 \
|
||||
--hash=sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863 \
|
||||
--hash=sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6 \
|
||||
--hash=sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368 \
|
||||
--hash=sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480 \
|
||||
--hash=sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2 \
|
||||
--hash=sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2 \
|
||||
--hash=sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6 \
|
||||
--hash=sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769 \
|
||||
--hash=sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d \
|
||||
--hash=sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2 \
|
||||
--hash=sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84 \
|
||||
--hash=sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166 \
|
||||
--hash=sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271 \
|
||||
--hash=sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5 \
|
||||
--hash=sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb \
|
||||
--hash=sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13 \
|
||||
--hash=sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323 \
|
||||
--hash=sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556 \
|
||||
--hash=sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665 \
|
||||
--hash=sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef \
|
||||
--hash=sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb \
|
||||
--hash=sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119 \
|
||||
--hash=sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126 \
|
||||
--hash=sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510 \
|
||||
--hash=sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b \
|
||||
--hash=sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87 \
|
||||
--hash=sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f \
|
||||
--hash=sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc \
|
||||
--hash=sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8 \
|
||||
--hash=sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21 \
|
||||
--hash=sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f \
|
||||
--hash=sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6 \
|
||||
--hash=sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658 \
|
||||
--hash=sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b \
|
||||
--hash=sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3 \
|
||||
--hash=sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb \
|
||||
--hash=sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59 \
|
||||
--hash=sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24 \
|
||||
--hash=sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9 \
|
||||
--hash=sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3 \
|
||||
--hash=sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd \
|
||||
--hash=sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753 \
|
||||
--hash=sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55 \
|
||||
--hash=sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad \
|
||||
--hash=sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a \
|
||||
--hash=sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605 \
|
||||
--hash=sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e \
|
||||
--hash=sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b \
|
||||
--hash=sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433 \
|
||||
--hash=sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8 \
|
||||
--hash=sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07 \
|
||||
--hash=sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728 \
|
||||
--hash=sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0 \
|
||||
--hash=sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327 \
|
||||
--hash=sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555 \
|
||||
--hash=sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64 \
|
||||
--hash=sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6 \
|
||||
--hash=sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea \
|
||||
--hash=sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b \
|
||||
--hash=sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df \
|
||||
--hash=sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e \
|
||||
--hash=sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd \
|
||||
--hash=sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068 \
|
||||
--hash=sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3 \
|
||||
--hash=sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040 \
|
||||
--hash=sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12 \
|
||||
--hash=sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916 \
|
||||
--hash=sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f \
|
||||
--hash=sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f \
|
||||
--hash=sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801 \
|
||||
--hash=sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231 \
|
||||
--hash=sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5 \
|
||||
--hash=sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8 \
|
||||
--hash=sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee \
|
||||
--hash=sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607
|
||||
# via pydantic
|
||||
pyopenssl==24.2.1 \
|
||||
--hash=sha256:4247f0dbe3748d560dcbb2ff3ea01af0f9a1a001ef5f7c4c647956ed8cbf0e95 \
|
||||
--hash=sha256:967d5719b12b243588573f39b0c677637145c7a1ffedcd495a487e58177fbb8d
|
||||
# via
|
||||
# acme
|
||||
# josepy
|
||||
pyotp==2.9.0 \
|
||||
--hash=sha256:346b6642e0dbdde3b4ff5a930b664ca82abfa116356ed48cc42c7d6590d36f63 \
|
||||
--hash=sha256:81c2e5865b8ac55e825b0358e496e1d9387c811e85bb40e71a3b29b288963612
|
||||
# via dns-lexicon
|
||||
pyparsing==3.1.4 \
|
||||
--hash=sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c \
|
||||
--hash=sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032
|
||||
# via httplib2
|
||||
pyrfc3339==1.1 \
|
||||
--hash=sha256:67196cb83b470709c580bb4738b83165e67c6cc60e1f2e4f286cfcb402a926f4 \
|
||||
--hash=sha256:81b8cbe1519cdb79bed04910dd6fa4e181faf8c88dff1e1b987b5f7ab23a5b1a
|
||||
# via
|
||||
# acme
|
||||
# certbot
|
||||
python-dateutil==2.9.0.post0 \
|
||||
--hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
|
||||
--hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
|
||||
# via botocore
|
||||
python-digitalocean==1.17.0 \
|
||||
--hash=sha256:0032168e022e85fca314eb3f8dfaabf82087f2ed40839eb28f1eeeeca5afb1fa \
|
||||
--hash=sha256:107854fde1aafa21774e8053cf253b04173613c94531f75d5a039ad770562b24
|
||||
# via certbot-dns-digitalocean
|
||||
pytz==2024.2 \
|
||||
--hash=sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a \
|
||||
--hash=sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725
|
||||
# via
|
||||
# acme
|
||||
# certbot
|
||||
# pyrfc3339
|
||||
pyyaml==6.0.2 \
|
||||
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
|
||||
--hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \
|
||||
--hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \
|
||||
--hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \
|
||||
--hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \
|
||||
--hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
|
||||
--hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \
|
||||
--hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
|
||||
--hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \
|
||||
--hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \
|
||||
--hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \
|
||||
--hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \
|
||||
--hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \
|
||||
--hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \
|
||||
--hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
|
||||
--hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \
|
||||
--hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \
|
||||
--hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \
|
||||
--hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \
|
||||
--hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
|
||||
--hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
|
||||
--hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \
|
||||
--hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \
|
||||
--hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \
|
||||
--hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
|
||||
--hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
|
||||
--hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \
|
||||
--hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \
|
||||
--hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \
|
||||
--hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \
|
||||
--hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \
|
||||
--hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \
|
||||
--hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \
|
||||
--hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \
|
||||
--hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \
|
||||
--hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \
|
||||
--hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \
|
||||
--hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \
|
||||
--hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \
|
||||
--hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \
|
||||
--hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \
|
||||
--hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
|
||||
--hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \
|
||||
--hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
|
||||
--hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \
|
||||
--hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \
|
||||
--hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \
|
||||
--hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
|
||||
--hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \
|
||||
--hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \
|
||||
--hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \
|
||||
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
|
||||
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
|
||||
# via
|
||||
# cloudflare
|
||||
# dns-lexicon
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
# via
|
||||
# acme
|
||||
# certbot-dns-scaleway
|
||||
# cloudflare
|
||||
# dns-lexicon
|
||||
# google-api-core
|
||||
# python-digitalocean
|
||||
# requests-file
|
||||
# requests-mock
|
||||
# tldextract
|
||||
requests-file==2.1.0 \
|
||||
--hash=sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658 \
|
||||
--hash=sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c
|
||||
# via tldextract
|
||||
requests-mock==1.12.1 \
|
||||
--hash=sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563 \
|
||||
--hash=sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401
|
||||
# via certbot-dns-scaleway
|
||||
rsa==4.9 \
|
||||
--hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \
|
||||
--hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21
|
||||
# via google-auth
|
||||
s3transfer==0.10.2 \
|
||||
--hash=sha256:0711534e9356d3cc692fdde846b4a1e4b0cb6519971860796e6bc4c7aea00ef6 \
|
||||
--hash=sha256:eca1c20de70a39daee580aef4986996620f365c4e0fda6a86100231d62f1bf69
|
||||
# via importlib-metadata
|
||||
|
||||
# The following packages are considered to be unsafe in a requirements file:
|
||||
setuptools==75.1.0 \
|
||||
--hash=sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2 \
|
||||
--hash=sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538
|
||||
# via boto3
|
||||
six==1.16.0 \
|
||||
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
|
||||
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
|
||||
# via python-dateutil
|
||||
soupsieve==2.6 \
|
||||
--hash=sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb \
|
||||
--hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9
|
||||
# via beautifulsoup4
|
||||
tldextract==5.1.2 \
|
||||
--hash=sha256:4dfc4c277b6b97fa053899fcdb892d2dc27295851ab5fac4e07797b6a21b2e46 \
|
||||
--hash=sha256:c9e17f756f05afb5abac04fe8f766e7e70f9fe387adb1859f0f52408ee060200
|
||||
# via dns-lexicon
|
||||
typing-extensions==4.12.2 \
|
||||
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
|
||||
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
|
||||
# via
|
||||
# pydantic
|
||||
# pydantic-core
|
||||
uritemplate==4.1.1 \
|
||||
--hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \
|
||||
--hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e
|
||||
# via google-api-python-client
|
||||
urllib3==1.26.20 \
|
||||
--hash=sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e \
|
||||
--hash=sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32
|
||||
# via
|
||||
# botocore
|
||||
# requests
|
||||
zipp==3.20.2 \
|
||||
--hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \
|
||||
--hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29
|
||||
# via
|
||||
# acme
|
||||
# certbot
|
||||
# certbot-dns-cloudflare
|
||||
# certbot-dns-digitalocean
|
||||
# certbot-dns-google
|
||||
# certbot-dns-linode
|
||||
# certbot-dns-ovh
|
||||
# certbot-dns-rfc2136
|
||||
# certbot-dns-route53
|
||||
# certbot-dns-scaleway
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
"dnsbl",
|
||||
"customcert",
|
||||
"letsencrypt",
|
||||
"letsencrypt_dns",
|
||||
"selfsigned"
|
||||
],
|
||||
"set": [
|
||||
|
|
@ -21,10 +22,11 @@
|
|||
"whitelist",
|
||||
"letsencrypt",
|
||||
"customcert",
|
||||
"letsencrypt_dns",
|
||||
"selfsigned",
|
||||
"ui"
|
||||
],
|
||||
"ssl_certificate": ["customcert", "letsencrypt", "selfsigned"],
|
||||
"ssl_certificate": ["customcert", "letsencrypt_dns", "letsencrypt", "selfsigned"],
|
||||
"access": [
|
||||
"whitelist",
|
||||
"letsencrypt",
|
||||
|
|
|
|||
Loading…
Reference in a new issue