#!/bin/sh
# @feature:one-command-install
# ---------------------------------------------------------------------------
# Subrose universal opkg installer — published by the ansible web role to the
# site as /dl/install.sh. Run on the router:
#
#   ssh root@<router>
#   opkg update && opkg install curl     # or rely on busybox wget
#   curl -fsSL https://subrose.co/dl/install.sh | sh
#
# Detects the router (Keenetic/Entware vs OpenWrt + cpu), picks the newest
# matching .ipk from the /dl index (names are versioned:
# subrose_<version>_<env>_<os>_<arch>.ipk — packaging keeps one file per
# target, see opkg.sh), VERIFIES the sha256 sidecar, installs via opkg.
# The package postinst enables and starts the service itself.
# POSIX sh only (busybox ash on routers) — no bashisms.
#
# Overrides (env):
#   SUBROSE_BASE_URL   downloads base (default https://subrose.co/dl)
#   SUBROSE_ENV        testnet | mainnet (default testnet) — env label in the
#                      file name; both configs ship inside every package
#   SUBROSE_PKG        force a specific package file (skip auto-detect)
#   SUBROSE_INSECURE=1 skip checksum verification (NOT recommended)
#
# Security note: the site is plain HTTP and the .sha256 comes from the same
# server — the check protects against download corruption, NOT against MITM.
# Serving the site over HTTPS is the fix for that (Docs/todo.md).
# ---------------------------------------------------------------------------
set -eu

BASE_URL="${SUBROSE_BASE_URL:-https://subrose.co/dl}"
ENV_NAME="${SUBROSE_ENV:-testnet}"
# mktemp when available (unpredictable name); busybox always has it, but keep
# a 0700 fallback for exotic shells.
TMP="$(mktemp -d 2>/dev/null)" || { TMP="${TMPDIR:-/tmp}/subrose-install.$$"; mkdir -m 700 -p "$TMP"; }
# shellcheck disable=SC2064
trap "rm -rf '$TMP'" EXIT INT TERM

say()  { printf '%s\n' "subrose: $*"; }
die()  { printf '%s\n' "subrose: ERROR: $*" >&2; exit 1; }

# --- fetch helpers: prefer wget (busybox always has it), fall back to curl ---
fetch() {  # fetch <url> <out>
  if command -v wget >/dev/null 2>&1; then
    wget -q -O "$2" "$1"
  elif command -v curl >/dev/null 2>&1; then
    curl -fsSL "$1" -o "$2"
  else
    die "neither wget nor curl available"
  fi
}
fetch_stdout() {  # fetch_stdout <url>
  if command -v wget >/dev/null 2>&1; then
    wget -q -O - "$1"
  else
    curl -fsSL "$1"
  fi
}

command -v opkg >/dev/null 2>&1 \
  || die "opkg not found — this installer is for OpenWrt / Keenetic (Entware)"

# --- detect vendor (Keenetic/Entware vs OpenWrt) ----------------------------
vendor=openwrt
if command -v ndmq >/dev/null 2>&1 || [ -d /opt/etc/opkg ] \
   || opkg print-architecture 2>/dev/null | grep -q '_kn'; then
  vendor=keenetic
fi

# --- detect cpu -------------------------------------------------------------
m="$(uname -m 2>/dev/null || echo unknown)"
case "$m" in
  aarch64|arm64)          cpu=aarch64 ;;
  armv7l|armv7|armhf|arm) cpu=armv7l ;;
  mips|mipsel|mips64el)   cpu=mipsel ;;
  *)                      cpu=unknown ;;
esac

# --- map (vendor,cpu) -> package arch label (names produced by opkg.sh) -----
case "${vendor}:${cpu}" in
  keenetic:mipsel)  os=keenetic; arch="mipsel-3.4_kn" ;;
  keenetic:aarch64) os=keenetic; arch="aarch64-3.10_kn" ;;
  openwrt:aarch64)  os=openwrt;  arch="aarch64" ;;
  openwrt:armv7l)   os=openwrt;  arch="armv7l" ;;
  openwrt:mipsel)   os=openwrt;  arch="mips_siflower" ;;
  *) [ -n "${SUBROSE_PKG:-}" ] || die "unsupported router (vendor=${vendor} cpu=${m}). Set SUBROSE_PKG to pick a package manually." ;;
esac

# --- pick the newest matching file from the /dl index -----------------------
if [ -n "${SUBROSE_PKG:-}" ]; then
  pkg="$SUBROSE_PKG"
else
  say "detected: vendor=${vendor} cpu=${cpu} -> ${os}/${arch} (${ENV_NAME})"
  # /dl is an nginx autoindex; file names carry the version, so grep the index
  # rather than hardcode a name. Packaging keeps one file per target; tail -n1
  # is a tie-breaker if several are ever published.
  index="$(fetch_stdout "${BASE_URL}/")" || die "cannot read index ${BASE_URL}/"
  pkg="$(printf '%s\n' "$index" \
    | grep -o "subrose_[^\"/ ]*_${ENV_NAME}_${os}_${arch}\.ipk" \
    | sort -u | tail -n 1)"
  [ -n "$pkg" ] || die "no ${ENV_NAME}/${os}/${arch} package published at ${BASE_URL}/"
fi
# The name came from server HTML — require a flat token before using it in a
# URL and a local path (no path tricks even from a compromised index).
case "$pkg" in
  *[!A-Za-z0-9._-]*|.*) die "suspicious package name from index: ${pkg}" ;;
esac

# --- download package + checksum --------------------------------------------
say "downloading ${BASE_URL}/${pkg}"
fetch "${BASE_URL}/${pkg}" "${TMP}/${pkg}" || die "download failed: ${BASE_URL}/${pkg}"

if [ "${SUBROSE_INSECURE:-0}" = "1" ]; then
  say "WARNING: SUBROSE_INSECURE=1 — skipping checksum verification"
else
  fetch "${BASE_URL}/${pkg}.sha256" "${TMP}/${pkg}.sha256" \
    || die "checksum file not found (${pkg}.sha256). Refusing to install unverified package (set SUBROSE_INSECURE=1 to override)."
  # The .sha256 file is "<hex>  <filename>"; verify against the downloaded file.
  want="$(awk '{print $1}' "${TMP}/${pkg}.sha256")"
  if command -v sha256sum >/dev/null 2>&1; then
    got="$(sha256sum "${TMP}/${pkg}" | awk '{print $1}')"
  elif command -v shasum >/dev/null 2>&1; then
    got="$(shasum -a 256 "${TMP}/${pkg}" | awk '{print $1}')"
  else
    die "no sha256 tool (sha256sum/shasum) to verify the package"
  fi
  [ -n "$want" ] && [ "$want" = "$got" ] || die "checksum mismatch (want=${want:-?} got=${got}). Aborting."
  say "checksum OK"
fi

# --- install ----------------------------------------------------------------
say "installing ${pkg} via opkg"
opkg install "${TMP}/${pkg}" || die "opkg install failed"

say "done — the subrose service is enabled and started by the package postinst"
