137 lines
3.9 KiB
Bash
Executable file
137 lines
3.9 KiB
Bash
Executable file
#!/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 (password for sudo):
|
|
# sudo -n true 2>/dev/null || sudo -v
|
|
# sudo bash /home/hernani/koopa-admin-log/scripts/caddy/apply-dossiers-ngi-basicauth.sh
|
|
#
|
|
# Idempotent. Password file is NOT in git:
|
|
# /home/hernani/koopa-secrets/dossiers-ngi-basicauth.txt
|
|
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=/home/hernani/koopa-secrets
|
|
PASS_FILE="${SECRETS_DIR}/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"
|
|
chown hernani:hernani "$SECRETS_DIR"
|
|
chmod 700 "$SECRETS_DIR"
|
|
|
|
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" <<EOF
|
|
USER=${USER_NAME}
|
|
PASS=${PASS}
|
|
HASH=${HASH}
|
|
EOF
|
|
chown hernani:hernani "$PASS_FILE"
|
|
chmod 600 "$PASS_FILE"
|
|
echo "OK: wrote new password to $PASS_FILE (not git)"
|
|
fi
|
|
|
|
# Caddyfile treats $ as env — double it for a literal bcrypt hash
|
|
HASH_CADDY="${HASH//\$/\$\$}"
|
|
|
|
ts=$(date +%Y%m%d-%H%M%S)
|
|
cp -a "$CADDY" "${CADDY}.bak-dossiers-auth-${ts}"
|
|
echo "backup ${CADDY}.bak-dossiers-auth-${ts}"
|
|
|
|
python3 - "$CADDY" "$USER_NAME" "$HASH_CADDY" "${SITES[@]}" <<'PY'
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
path = Path(sys.argv[1])
|
|
user = sys.argv[2]
|
|
hash_caddy = sys.argv[3]
|
|
sites = sys.argv[4:]
|
|
text = path.read_text()
|
|
orig = text
|
|
|
|
def inject_block(src: str, site: str) -> 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"
|