Repository files, collaboration, releases and project activity.
archforge-external-status / scripts/repair-admin-login.shmain
▤ scripts/repair-admin-login.sh4219 bytes
67 lines · Select a line number for a permalink
1
#!/usr/bin/env bash2
# ArchForge External Status 1.0.6 - ArchForge-based admin login recovery.3
# Never resets admin accounts, sessions, tokens, Caddy or SQLite data.4
set -Eeuo pipefail5
umask 0776
log(){ printf '[*] %s\n' "$*"; }7
fail(){ printf '[ERROR] %s\n' "$*" >&2; exit 1; }8
[[ $EUID -eq 0 ]] || fail 'Run as root: bash ./repair-admin-login.sh'9
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)10
[[ -f "$ROOT/package.json" && -f "$ROOT/src/server.js" ]] || fail 'Start from your ArchForge checkout'11
[[ "$(/usr/bin/node -p 'require(process.argv[1]).version' "$ROOT/package.json")" == '1.0.6' ]] || fail 'ArchForge checkout is not 1.0.6; commit/push/pull the update first'12
[[ "$ROOT" != '/opt/archforge-status/app' ]] || fail 'Run this from the ArchForge checkout, not from /opt'13
CFG=/etc/archforge-status/status.env14
[[ -f "$CFG" && ! -L "$CFG" ]] || fail 'Missing /etc/archforge-status/status.env'15
[[ -r "$ROOT/scripts/domain-lib.sh" ]] || fail 'Missing domain configuration helper'16
source "$ROOT/scripts/domain-lib.sh"17
DOMAIN='status.archforge.nl'18
if ! grep -Eqs "^[[:space:]]*${DOMAIN//./\\.}[[:space:]]*\\{" /etc/caddy/Caddyfile /etc/caddy/conf.d/*.caddy 2>/dev/null; then19
fail 'Caddy is not configured for status.archforge.nl; no changes made'20
fi21
if ! curl --fail --silent --show-error --max-time 5 http://127.0.0.1:3000/healthz >/dev/null;then22
fail 'Status service unavailable on 127.0.0.1:3000; check systemctl status archforge-status'23
fi24
SNAP=$(mktemp -d /root/.archforge-login-repair.XXXXXXXX)25
cp -a -- "$CFG" "$SNAP/status.env"26
log "Private .env backup created ($SNAP/status.env)"27
CURRENT=$(grep -m1 '^STATUS_PUBLIC_URL=' "$CFG" | cut -d= -f2- || true)28
if [[ "$CURRENT" != "https://$DOMAIN" && "$CURRENT" != "https://$DOMAIN/" ]];then29
log 'Synchronizing public URL with the Caddy HTTPS domain'30
af_set_public_domain "$CFG" "$DOMAIN" || fail 'Cannot safely update public URL'31
fi32
log 'Deploying version 1.0.6 via the existing backup/rollback installer'33
if ! bash "$ROOT/scripts/deploy.sh" "$ROOT";then34
log 'Deployment failed; restoring the previous status.env'35
cp -a -- "$SNAP/status.env" "$CFG"36
systemctl restart archforge-status || true37
fail 'Deployment was rolled back. The old release should still be in service.'38
fi39
version=$(curl --fail --silent --show-error --max-time 5 http://127.0.0.1:3000/healthz | /usr/bin/node -p 'try { JSON.parse(require("fs").readFileSync(0,"utf8")).version } catch { "" }')40
[[ "$version" == '1.0.6' ]] || fail "Installed version verification failed (${version:-unknown}); inspect journalctl -u archforge-status"41
log 'Running safe login tests locally (no passwords or 2FA codes needed)'42
# Reuse a freshly issued double-submit cookie, with a dummy username.43
curl --silent --show-error --max-time 5 -D "$SNAP/headers" -o /dev/null http://127.0.0.1:3000/admin/login44
CSRF=$(sed -nE 's/^[Ss]et-[Cc]ookie: af_csrf=([^;]+).*/\1/p' "$SNAP/headers" | tr -d '\r' | head -n 1)45
[[ "$CSRF" =~ ^[A-Za-z0-9_-]{32,100}$ ]] || fail 'Could not obtain form token from local status app'46
post_login(){47
local output_name=$1 site=$2 origin=$3 expected=$4 code48
code=$(curl --silent --show-error --max-time 6 -o "$SNAP/$output_name" -w '%{http_code}' \49
-H "Cookie: af_csrf=$CSRF" \50
-H "Origin: $origin" \51
-H "Sec-Fetch-Site: $site" \52
-H 'Content-Type: application/x-www-form-urlencoded' \53
--data-urlencode "csrf=$CSRF" \54
--data-urlencode 'username=__archforge_test_nonexistent__' \55
--data-urlencode 'password=never-a-valid-password' \56
--data-urlencode 'totp=000000' \57
http://127.0.0.1:3000/admin/login)58
[[ "$code" == "$expected" ]] || fail "Login $output_name returned HTTP $code (expected $expected); inspect installed version and logs"59
}60
post_login canonical 'same-origin' "https://$DOMAIN" 40161
post_login privacy 'same-origin' 'null' 40162
post_login blocked 'cross-site' "https://$DOMAIN" 40363
log 'PASS: canonical and privacy-protected same-origin login reach credential validation'64
log 'PASS: cross-site login is still blocked; CSRF verification remains mandatory'65
log 'Installed release: 1.0.6. Refresh https://status.archforge.nl/admin/login and try again.'66
log 'No credentials, monitoring database or Caddy configuration changed.'