#!/bin/sh
# One-time bridge for OpenWrt clients whose installed nodebase predates the
# first-class procd updater. The live service is not touched until a copy of the
# old released CLI has used its embedded Ed25519 release key to fetch and verify
# the current binary. That verified binary then owns the bounded procd
# stop/install/start/rollback transaction.
set -eu

usage() {
	echo "usage: openwrt-bootstrap-update.sh --program PATH --state PATH --target-program PATH --backup-dir NEW_DIR" >&2
	exit 2
}

PROGRAM=
STATE=
TARGET_PROGRAM=
BACKUP_DIR=
while [ "$#" -gt 0 ]; do
	case "$1" in
		--program) [ "$#" -ge 2 ] || usage; PROGRAM=$2; shift 2 ;;
		--state) [ "$#" -ge 2 ] || usage; STATE=$2; shift 2 ;;
		--target-program) [ "$#" -ge 2 ] || usage; TARGET_PROGRAM=$2; shift 2 ;;
		--backup-dir) [ "$#" -ge 2 ] || usage; BACKUP_DIR=$2; shift 2 ;;
		*) usage ;;
	esac
done

if [ -z "$PROGRAM" ] || [ -z "$STATE" ] || [ -z "$TARGET_PROGRAM" ] || [ -z "$BACKUP_DIR" ]; then
	usage
fi
[ "$(id -u)" = 0 ] || { echo "OpenWrt bootstrap must run as root" >&2; exit 1; }
[ -f /etc/openwrt_release ] || { echo "this bootstrap is only for OpenWrt" >&2; exit 1; }
[ -x "$PROGRAM" ] || { echo "registered program is not executable: $PROGRAM" >&2; exit 1; }
[ -d "$STATE" ] || { echo "state directory does not exist: $STATE" >&2; exit 1; }
[ ! -e "$BACKUP_DIR" ] || { echo "backup directory must not already exist: $BACKUP_DIR" >&2; exit 1; }

TMP=$(mktemp -d /tmp/nodebase-openwrt-bootstrap.XXXXXX)
trap 'rm -rf "$TMP"' EXIT HUP INT TERM
FETCHER=$TMP/nodebase-verified-fetcher
cp "$PROGRAM" "$FETCHER"
chmod 755 "$FETCHER"
mkdir -m 700 "$TMP/empty-state" "$TMP/update-cache"

OLD_VERSION=$($FETCHER --version 2>/dev/null || true)
echo "verifying the current signed Nodebase release without touching $PROGRAM"
# Never pass --pubkey: the old official client must authenticate manifest.json
# with the release key compiled into it. An invalid manifest/artifact exits here
# while the old procd daemon and live executable remain unchanged.
HOME=/root NODEBASE_UPDATE_CACHE_DIR=$TMP/update-cache \
	"$FETCHER" update --state "$TMP/empty-state"
NEW_VERSION=$($FETCHER --version 2>/dev/null || true)
[ -n "$NEW_VERSION" ] || { echo "verified candidate did not report a version" >&2; exit 1; }

echo "signed candidate ready: $OLD_VERSION -> $NEW_VERSION"
# The old updater's daemon sweep matches the basename of its own executable.
# Keep the fetcher basename distinct so its post-download housekeeping cannot
# see the live `nodebase` daemon. After verification, make a byte-identical
# `nodebase`-named applier: the new transaction then deliberately can see and
# clear any leftover legacy daemon after the bounded procd stop.
mkdir -m 700 "$TMP/apply"
APPLIER=$TMP/apply/nodebase
ln "$FETCHER" "$APPLIER"
chmod 755 "$APPLIER"
cmp -s "$FETCHER" "$APPLIER" || { echo "verified candidate copy changed" >&2; exit 1; }
HOME=/root "$APPLIER" openwrt bootstrap-update \
	--program "$PROGRAM" \
	--target-program "$TARGET_PROGRAM" \
	--state "$STATE" \
	--backup-dir "$BACKUP_DIR"
