import logging import os import sys from typing import Optional import tomllib log = logging.getLogger(__name__) class Config: post_acquire: list[str] certificates: list[str] domains: dict[str, str] secrets: dict[str, str] acme_path: str def find_zone(self, domain: str) -> str: parts = domain.split('.') for i in range(len(parts)-1): zone = '.'.join(parts[i:]) if zone in self.domains: return zone log.error('could not find zone for domain %s', domain) sys.exit(1) def get_handler(self, domain: str) -> str: if domain in self.domains: return self.domains[domain] raise Exception(f'domain {domain} not found in the config') def get_secret(self, handler: str) -> str: return self.secrets[handler] def read_config(path: Optional[str]) -> Config: if not path: # should be here only when running from hook path = os.getenv('NYACME_CONFIG', '/etc/nyacme.toml') with open(path, 'rb') as file: raw_conf = tomllib.load(file) for key in raw_conf: if key not in ('domains', 'secrets', 'post_acquire', 'acme_path', 'certificates'): log.warning('unknown config key: %s', key) c = Config() if 'domains' not in raw_conf: log.error('missing "domains"') sys.exit(1) for k, v in raw_conf['domains'].items(): assert isinstance(k, str), f'domain "{k}" is not a string' assert isinstance(v, str), f'domain "{k}" handler {v} is not a string' c.domains = raw_conf['domains'] if 'secrets' not in raw_conf: log.error('missing "secrets"') sys.exit(1) for k, v in raw_conf['secrets'].items(): assert isinstance(k, str), f'secret key "{k}" is not a string' assert isinstance(v, str), f'secret "{k}" value {v} is not a string' c.secrets = raw_conf['secrets'] post_acquire = [] if 'post_acquire' in raw_conf: assert isinstance(raw_conf['post_acquire'], list), 'post_acquire is not a list' for cmd in raw_conf['post_acquire']: assert isinstance(cmd, str), 'post_acquire item has to be a string' post_acquire.append(cmd) c.post_acquire = post_acquire if 'acme_path' in raw_conf: c.acme_path = raw_conf['acme_path'] else: c.acme_path = '/var/www/acme/.well-known/acme-challenge' if 'certificates' not in raw_conf: log.error('missing "certificates"') sys.exit(1) c.certificates = [] for cert in raw_conf['certificates']: assert isinstance(cert, str), 'certificate should be a string' c.certificates.append(cert) return c