#!/usr/bin/env bash # Apply HTTP basic_auth (Caddy equivalent of "htaccess in front") # to dossiers.ngi / dossiers.2.ngi / dossiers.3.ngi.hacktivism.ch # # Caddy file_server does NOT honor Apache .htaccess — this edits the Caddyfile. # # On koopa (clone admin-log from Forgejo when needed; no home git dump): # sudo bash /path/to/koopa-admin-log/scripts/caddy/apply-dossiers-ngi-basicauth.sh # # Host runtime file (root-only, not under ~): # /etc/caddy/secrets/dossiers-ngi-basicauth.txt # SoT (git-crypt): koopa-admin-secrets-enc → koopa/home-hernani/caddy/ set -euo pipefail if [[ "$(id -u)" -ne 0 ]]; then echo "ERROR: run as root: sudo bash $0" >&2 exit 1 fi CADDY=/etc/caddy/Caddyfile USER_NAME="${DOSSIERS_AUTH_USER:-hernani}" SECRETS_DIR=/etc/caddy/secrets PASS_FILE="${SECRETS_DIR}/dossiers-ngi-basicauth.txt" OLD_PASS_FILE=/home/hernani/koopa-secrets/dossiers-ngi-basicauth.txt SITES=( dossiers.ngi.hacktivism.ch dossiers.2.ngi.hacktivism.ch dossiers.3.ngi.hacktivism.ch ) if [[ ! -f "$CADDY" ]]; then echo "ERROR: missing $CADDY" >&2 exit 1 fi command -v caddy >/dev/null || { echo "ERROR: caddy not in PATH" >&2; exit 1; } mkdir -p "$SECRETS_DIR" chmod 700 "$SECRETS_DIR" if [[ ! -f "$PASS_FILE" && -f "$OLD_PASS_FILE" ]]; then cp -a "$OLD_PASS_FILE" "$PASS_FILE" chmod 600 "$PASS_FILE" echo "OK: migrated $OLD_PASS_FILE → $PASS_FILE" fi if [[ -f "$PASS_FILE" ]]; then # shellcheck disable=SC1090 # file format: USER=... PASS=... HASH=... # PASS may contain spaces; read with grep USER_NAME="$(awk -F= '/^USER=/{print substr($0,6); exit}' "$PASS_FILE")" PASS="$(awk -F= '/^PASS=/{print substr($0,6); exit}' "$PASS_FILE")" HASH="$(awk -F= '/^HASH=/{print substr($0,6); exit}' "$PASS_FILE")" if [[ -z "$USER_NAME" || -z "$HASH" ]]; then echo "ERROR: $PASS_FILE incomplete — move it aside and re-run" >&2 exit 1 fi echo "OK: reusing credentials in $PASS_FILE" else PASS="$(openssl rand -base64 18 | tr -d '/+=' | head -c 20)" HASH="$(caddy hash-password --plaintext "$PASS")" umask 077 cat >"$PASS_FILE" < str: marker = f"{site} {{" i = src.find(marker) if i < 0: raise SystemExit(f"ERROR: site block not found: {site}") # already has basic_auth in this block? j = src.find("\n}", i) if j < 0: raise SystemExit(f"ERROR: unclosed block: {site}") block = src[i:j] if "basic_auth" in block or "basicauth" in block: print(f"OK: {site} already has basic_auth") return src needle = ' header Alt-Svc "clear"\n' k = block.find(needle) auth = ( needle + " basic_auth {\n" + f" {user} {hash_caddy}\n" + " }\n" ) if k >= 0: new_block = block.replace(needle, auth, 1) else: # insert after opening brace nl = block.find("\n") new_block = block[: nl + 1] + auth + block[nl + 1 :] print(f"OK: injected basic_auth in {site}") return src[:i] + new_block + src[j:] for s in sites: text = inject_block(text, s) if text == orig: print("no Caddyfile change") else: path.write_text(text) print(f"wrote {path}") PY echo "== validate ==" caddy validate --config "$CADDY" echo "== reload ==" if systemctl is-active --quiet caddy; then systemctl reload caddy else echo "WARN: caddy unit not active — start it yourself" >&2 fi echo echo "Done. Browser: https://dossiers.ngi.hacktivism.ch/ (and .2. / .3.)" echo "User/pass: $PASS_FILE" echo "Reload later: sudo caddy validate --config $CADDY && sudo systemctl reload caddy"