#!/usr/bin/env bash
# Copyright (c) 2026 HostFog Ltd. All rights reserved.
# Proprietary and confidential. Use is subject to the HostFog licence (LICENSE).
# Unauthorised copying, modification or distribution is prohibited.
# HostFog: Let's Encrypt DNS check for wildcard certificates (*.domain). Called by certbot as its
# --manual-auth-hook / --manual-cleanup-hook with CERTBOT_DOMAIN and CERTBOT_VALIDATION set.
# Puts the _acme-challenge TXT record into this server's own BIND zone, waits until it answers, and removes it after.
set -euo pipefail
ZONES=/etc/bind/hf-zones
act="${1:-}"; d="${CERTBOT_DOMAIN:-}"; v="${CERTBOT_VALIDATION:-}"
[[ "$d" =~ ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$ && "$v" =~ ^[A-Za-z0-9_-]{20,100}$ ]] || { echo "bad input" >&2; exit 1; }
# the zone that holds the name: the domain itself or a parent
z="$d"; while [[ ! -f "$ZONES/db.$z" ]]; do [[ "$z" == *.*.* ]] || { echo "no zone on this server for $d" >&2; exit 1; }; z="${z#*.}"; done
f="$ZONES/db.$z"; rel="_acme-challenge"; [[ "$d" != "$z" ]] && rel="_acme-challenge.${d%."$z"}"
bump() { awk '/ IN SOA / && !done { if (match($0, /\( *[0-9]+/)) { n=substr($0, RSTART, RLENGTH); gsub(/[^0-9]/, "", n); $0=substr($0, 1, RSTART-1) "( " (n+1) substr($0, RSTART+RLENGTH) }; done=1 } 1' "$f" > "$f.new" && cat "$f.new" > "$f" && rm -f "$f.new"; }
case "$act" in
  auth)
    echo "$rel 60 IN TXT \"$v\" ; hf-acme" >> "$f"; bump
    named-checkzone -q "$z" "$f" || { grep -v "\"$v\" ; hf-acme" "$f" > "$f.new"; cat "$f.new" > "$f"; rm -f "$f.new"; echo "zone check failed" >&2; exit 1; }
    rndc reload "$z" >/dev/null 2>&1 || true
    for _ in $(seq 1 30); do dig +short @127.0.0.1 TXT "$rel.$z" 2>/dev/null | grep -q "$v" && break; sleep 1; done
    sleep 3;;
  cleanup)
    grep -v "\"$v\" ; hf-acme" "$f" > "$f.new" || true; cat "$f.new" > "$f"; rm -f "$f.new"; bump
    rndc reload "$z" >/dev/null 2>&1 || true;;
  *) echo "usage: auth|cleanup" >&2; exit 2;;
esac
