From c8c8275da3346346ef141faad3713a4402f2d023 Mon Sep 17 00:00:00 2001 From: ptrcnull Date: Wed, 12 Jun 2024 12:01:26 +0200 Subject: [PATCH] feat: add WIP Cloudflare handler --- nyacme/handlers/__init__.py | 2 ++ nyacme/handlers/cloudflare.py | 50 +++++++++++++++++++++++++++++++++++ nyacme/hook.py | 3 ++- 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 nyacme/handlers/cloudflare.py diff --git a/nyacme/handlers/__init__.py b/nyacme/handlers/__init__.py index 4072a46..4047715 100644 --- a/nyacme/handlers/__init__.py +++ b/nyacme/handlers/__init__.py @@ -1,7 +1,9 @@ +from .cloudflare import CloudflareHandler from .hetzner import HetznerHandler from .http import HTTPHandler __all__ = [ + 'CloudflareHandler', 'HetznerHandler', 'HTTPHandler' ] diff --git a/nyacme/handlers/cloudflare.py b/nyacme/handlers/cloudflare.py new file mode 100644 index 0000000..fa950e7 --- /dev/null +++ b/nyacme/handlers/cloudflare.py @@ -0,0 +1,50 @@ +import json +import os +import subprocess +from typing import Any + +import dns.resolver + +from ..config import Config +from .base import Handler + + +class CloudflareHandler(Handler): + nameservers: list[str] + + def __init__(self, zone_name: str, config: Config, token: str) -> None: + super().__init__(zone_name, config, token) + self.secret = config.get_secret('cloudflare') + + servers = dns.resolver.resolve(zone_name, 'NS') + self.nameservers = list(map(lambda rdata: str(rdata.target).strip('.'), servers)) + + def run(self, args: list[str]) -> Any: + env = os.environ.copy() + env['CF_API_TOKEN'] = self.secret + res = subprocess.run(['flarectl', '--json'] + args, check=True, stdout=subprocess.PIPE) + return json.loads(res.stdout) + + def create(self, record_name: str, record_value: str) -> None: + full_record_name = record_name + '.' + self.zone + self.remove(record_name) + self.log.info('creating %s with value %s', full_record_name, record_value) + self.run([ + 'dns', 'create', + '--zone', self.zone, + '--type', 'TXT', + '--name', full_record_name, + '--content', record_value, + ]) + + def remove(self, record_name: str) -> None: + records = self.run(['dns', 'list', '--zone', self.zone]) + full_record_name = record_name + '.' + self.zone + for record in records: + if record['Name'] == full_record_name: + self.log.info('removing %s', full_record_name) + self.run([ + 'dns', 'delete', + '--zone', self.zone, + '--id', record['ID'] + ]) diff --git a/nyacme/hook.py b/nyacme/hook.py index 2a64691..e2fb34c 100644 --- a/nyacme/hook.py +++ b/nyacme/hook.py @@ -7,13 +7,14 @@ from itertools import chain import dns.resolver from .config import read_config -from .handlers import HetznerHandler, HTTPHandler +from .handlers import CloudflareHandler, HetznerHandler, HTTPHandler logging.basicConfig(level=logging.INFO, format='> [%(levelname)s] %(name)s: %(message)s') log = logging.getLogger('nyacme_hook') handlers = { + 'cloudflare': CloudflareHandler, 'hetzner': HetznerHandler, 'http': HTTPHandler, }