#!/bin/sh
# Draco Linux client auto-updater — root oneshot, driven by draco-update.timer (every 6h).
#
# WHY A ROOT TIMER, not the GUI's self-update: the .deb installs draco-connect + the desktop GUI
# root-owned under /usr/{bin,lib}/draco. The GUI is a USER process, so it cannot replace its own
# root binary (the rename fails EACCES) — which is why desktop auto-update silently never worked.
# A root timer that reinstalls the newer signed .deb is the correct path (connector + GUI + tools
# updated atomically by the package manager). Same model SIGMA uses. General Linux — no Kali deps.
#
# VERIFIES: reads /dl/latest.json (SHA-256 + size per artifact) and refuses any .deb whose sha
# does not match. An unverified download is exactly what a VPN must not install.
set -eu

BASE="https://draco.ursamobile.com/dl"
MANIFEST="$BASE/latest.json"
log() { echo "draco-update: $*"; }

command -v curl >/dev/null 2>&1 || { log "curl not found — skipping"; exit 0; }
command -v python3 >/dev/null 2>&1 || { log "python3 not found — skipping"; exit 0; }

ARCH=$(dpkg --print-architecture 2>/dev/null || echo amd64)
case "$ARCH" in
  amd64) KEY="linux-deb";       DEB="draco-linux.deb" ;;
  arm64) KEY="linux-deb-arm64"; DEB="draco-linux-arm64.deb" ;;
  *) log "unsupported arch '$ARCH' — skipping"; exit 0 ;;
esac

MJSON=$(curl -fsSL --max-time 60 "$MANIFEST" 2>/dev/null) || { log "manifest fetch failed (offline?)"; exit 0; }
LATEST=$(printf '%s' "$MJSON" | python3 -c "import sys,json;print(json.load(sys.stdin)['artifacts'].get('$KEY',{}).get('version',''))" 2>/dev/null || echo "")
SHA=$(printf '%s' "$MJSON" | python3 -c "import sys,json;print(json.load(sys.stdin)['artifacts'].get('$KEY',{}).get('sha256',''))" 2>/dev/null || echo "")
[ -n "$LATEST" ] || { log "no '$KEY' in manifest — skipping"; exit 0; }

CUR=$(dpkg-query -f '${Version}' -W draco-connect 2>/dev/null || echo "0")

if ! dpkg --compare-versions "$LATEST" gt "$CUR"; then
  log "up to date (installed $CUR, latest $LATEST)"
  exit 0
fi

log "update available: $CUR -> $LATEST — downloading"
TMP=$(mktemp /tmp/draco-update-XXXXXX.deb)
trap 'rm -f "$TMP"' EXIT
curl -fsSL --max-time 600 -o "$TMP" "$BASE/$DEB" || { log "download failed"; exit 0; }

if [ -n "$SHA" ]; then
  GOT=$(sha256sum "$TMP" | cut -d' ' -f1)
  if [ "$GOT" != "$SHA" ]; then log "SHA-256 mismatch (got $GOT want $SHA) — refusing to install"; exit 0; fi
fi

export DEBIAN_FRONTEND=noninteractive
if apt-get install -y --allow-downgrades -o Dpkg::Options::=--force-confold "$TMP" >/dev/null 2>&1 \
   || { dpkg -i "$TMP" >/dev/null 2>&1 && apt-get -y -f install >/dev/null 2>&1; }; then
  log "installed $LATEST"
  # The running GUI keeps the old binary until relaunched; a running mesh data plane picks up the
  # new connector on its next restart. Nudge the mesh service so the fix takes effect promptly.
  systemctl try-restart draco-mesh.service 2>/dev/null || true
else
  log "install failed"
  exit 1
fi
