Repository files, collaboration, releases and project activity.
archforge-external-status / scripts/fix-admin-origin.shmain
▤ scripts/fix-admin-origin.sh3365 bytes
60 lines · Select a line number for a permalink
1
#!/usr/bin/env bash2
# v1.0.5 one-shot safe repair of admin POST 403 Invalid origin.3
# Does not delete/recreate admin accounts, SQLite, monitoring or Caddy.4
set -Eeuo pipefail5
umask 0776
say(){ printf '[*] %s\n' "$*"; }7
fail(){ printf '[ERROR] %s\n' "$*" >&2; exit 1; }8
[[ $EUID -eq 0 ]] || fail 'Run this fix as root: bash ./fix-admin-origin.sh'9
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)10
source "$ROOT/scripts/domain-lib.sh"11
[[ -r "$ROOT/package.json" && -r "$ROOT/src/server.js" ]] || fail 'Missing status project source checkout'12
/usr/bin/node -e 'if(require(process.argv[1]).version!=="1.0.5")process.exit(1)' "$ROOT/package.json" || fail 'Expected ArchForge checkout v1.0.5. Run git pull --ff-only first.'13
CFG=/etc/archforge-status/status.env14
[[ -f "$CFG" && ! -L "$CFG" ]] || fail 'Existing status.env not found (or unsafe symlink)'15
[[ -f /etc/caddy/Caddyfile ]] || fail 'Caddyfile not found'16
DOMAIN=status.archforge.nl17
# Verify that this VPS actually has an intended HTTPS site for our domain.18
if ! grep -Eqs "^[[:space:]]*${DOMAIN//./\\.}[[:space:]]*\\{" /etc/caddy/Caddyfile /etc/caddy/conf.d/*.caddy 2>/dev/null; then19
fail 'Caddy has no configured site for status.archforge.nl. Refusing to change public URL.'20
fi21
if ! curl -fsS --max-time 6 http://127.0.0.1:3000/healthz >/dev/null;then22
fail 'Installed status app is not running at localhost:3000. No changes made.'23
fi24
BACKUP=$(mktemp -d /root/.archforge-origin-fix.XXXXXXXX)25
cp -a -- "$CFG" "$BACKUP/status.env"26
say "Configuration backup: $BACKUP/status.env (private)"27
CHANGED=false28
CURRENT=$(grep -m1 '^STATUS_PUBLIC_URL=' "$CFG" | cut -d= -f2- || true)29
if [[ "$CURRENT" != "https://$DOMAIN" && "$CURRENT" != "https://$DOMAIN/" ]]; then30
say "Synchronizing STATUS_PUBLIC_URL with Caddy's HTTPS domain."31
af_set_public_domain "$CFG" "$DOMAIN" || fail 'Failed updating STATUS_PUBLIC_URL'32
CHANGED=true33
else34
say 'Configured public hostname already matches the domain.'35
fi36
say 'Deploying tested v1.0.5 code with built-in database backup and rollback...'37
if ! bash "$ROOT/scripts/deploy.sh" "$ROOT";then38
say 'Code deployment failed. Restoring original status configuration.'39
cp -a -- "$BACKUP/status.env" "$CFG"40
systemctl restart archforge-status || true41
fail 'Deployment failed and configuration restored.'42
fi43
say 'Checking login POST through HTTPS without sending any credentials...'44
# Invalid CSRF MUST be rejected, but valid Origin MUST NOT receive Invalid origin.45
OUT=$(mktemp "$BACKUP/response.XXXXXXXX")46
if ! curl -sS --max-time 12 --resolve "$DOMAIN:443:127.0.0.1" \47
-H "Origin: https://$DOMAIN" \48
-H 'Content-Type: application/x-www-form-urlencoded' \49
--data 'csrf=deliberately-invalid' "https://$DOMAIN/admin/login" > "$OUT";then50
say 'HTTPS local POST could not be verified; inspect Caddy/SSL separately.'51
elif grep -q 'Invalid origin' "$OUT"; then52
fail 'Origin check still rejects canonical host; see service journal: journalctl -u archforge-status -n 50'53
elif grep -q 'Invalid or expired form token' "$OUT"; then54
say 'PASS: same-origin login form reaches CSRF validation (as intended).'55
else56
say 'The HTTPS response was received but its form result was unexpected; inspect the login page.'57
fi58
say 'Finished. Open https://status.archforge.nl/admin/login and sign in again.'59
say 'All admin credentials, SQLite data and Caddy settings were preserved.'