from __future__ import annotations import os from pathlib import Path from .settings import DdnsSettings def settings_from_env() -> DdnsSettings: return DdnsSettings( database_path=Path(os.getenv("DDNS_DATABASE", "ddns.sqlite3")), admin_password=os.getenv("DDNS_ADMIN_PASSWORD", ""), admin_path=os.getenv("DDNS_ADMIN_PATH", "/admin"), public_base_url=os.getenv("DDNS_PUBLIC_BASE_URL", "http://localhost:8080"), trusted_hosts=_csv_set("DDNS_TRUSTED_HOSTS"), hostname_suffix=os.getenv("DDNS_HOSTNAME_SUFFIX", ""), rate_limit_per_minute=_env_int("DDNS_RATE_LIMIT_PER_MINUTE", 60), admin_rate_limit_per_minute=_env_int("DDNS_ADMIN_RATE_LIMIT_PER_MINUTE", 20), max_request_body_bytes=_env_int("DDNS_MAX_REQUEST_BODY_BYTES", 16_384), trusted_proxy_ips=_csv_set("DDNS_TRUSTED_PROXY_IPS"), rfc2136_server=os.getenv("DDNS_RFC2136_SERVER") or None, rfc2136_zone=os.getenv("DDNS_RFC2136_ZONE") or None, rfc2136_key_name=os.getenv("DDNS_RFC2136_KEY_NAME") or None, rfc2136_key_secret=os.getenv("DDNS_RFC2136_KEY_SECRET") or None, dns_provider=os.getenv("DDNS_DNS_PROVIDER", ""), dns_zones=_csv_set("DDNS_DNS_ZONES"), require_dns_provider=_env_flag("DDNS_REQUIRE_DNS_PROVIDER"), cloudflare_api_token=os.getenv("DDNS_CLOUDFLARE_API_TOKEN", ""), cloudflare_zone_id=os.getenv("DDNS_CLOUDFLARE_ZONE_ID", ""), cleanup_pending_account_hours=_env_int("DDNS_CLEANUP_PENDING_ACCOUNT_HOURS", 24), cleanup_unused_account_hours=_env_int("DDNS_CLEANUP_UNUSED_ACCOUNT_HOURS", 1080), cleanup_event_history_hours=_env_int("DDNS_CLEANUP_EVENT_HISTORY_HOURS", 24 * 180), cleanup_interval_seconds=_env_int("DDNS_CLEANUP_INTERVAL_SECONDS", 3600), dashboard_unlock_seconds=_env_int("DDNS_DASHBOARD_UNLOCK_SECONDS", 24 * 60 * 60), dashboard_stay_unlocked_seconds=_env_int( "DDNS_DASHBOARD_STAY_UNLOCKED_SECONDS", 30 * 24 * 60 * 60, ), dashboard_cookie_secret=os.getenv("DDNS_DASHBOARD_COOKIE_SECRET", ""), redacted_access_log=_env_flag("DDNS_REDACTED_ACCESS_LOG"), ttl=_env_int("DDNS_TTL", 60), ) def _csv_set(name: str) -> set[str]: return {item.strip().lower() for item in os.getenv(name, "").split(",") if item.strip()} def _env_flag(name: str) -> bool: return os.getenv(name, "0").strip().lower() not in {"0", "false", "no"} def _env_int(name: str, default: int) -> int: try: return int(os.getenv(name, str(default)).strip()) except ValueError as exc: raise ValueError(f"{name} must be an integer") from exc