#!/bin/sh
# factory-flash.sh — install Kahf firmware from ON the router itself.
#
# Runs on the ROUTER (busybox ash), not on a host. This is the factory
# provisioning path: no host tooling, no sshpass, no 39 SSH round-trips —
# paste one block into the unit's shell and it flashes itself.
#
# ── This file is a TEMPLATE ────────────────────────────────────────────────
# The three placeholder values below are substituted by `firmware-promote`
# (.gitlab-ci.yml) at publish time, which uploads the pinned result to
#   https://router.kahf.co/router/<channel>/factory-flash.sh
# THAT published copy is what the factory runs — it is pinned to one exact
# image + hash. This repo copy deliberately REFUSES to run unsubstituted, so
# nobody can flash a batch from a stale checkout.
#
# ── Why plain HTTP, not HTTPS ──────────────────────────────────────────────
# A factory-fresh unit has no NTP yet, so its clock is wrong, so TLS rejects
# the cert (measured window: Jul 30 – Oct 28 2026) — the same stuck-clock
# deadlock oaf-bootstrap.sh's _bs_force_time exists to break. Stock OpenWrt
# may also lack the TLS libs entirely. Integrity therefore comes from the
# SHA256 pinned in this file and delivered out-of-band, which is a STRONGER
# guarantee than trusting transit for an image whose hash we already know.
# Verified: the HTTP body hashes byte-identical to the HTTPS one.
#
# ── Why the commit-pinned image, not openwrt-sysupgrade.bin ────────────────
# openwrt-sysupgrade.bin is mutable — it moves the moment the next release
# promotes. Mid-run that would silently split a batch across two firmware
# versions with no signal. openwrt-<sha>.bin is never overwritten.
#
# Usage on the router:
#   sh factory-flash.sh                 # fetch from the CDN
#   sh factory-flash.sh <mirror-url>    # fetch from a factory LAN mirror
#
# The mirror form is the right call for a batch of thousands: host the image
# on a factory box and pass its URL. The SHA256 check below is unchanged, so
# every integrity guarantee still holds.

FW_VERSION="2.4.29"
IMAGE_URL="http://router.kahf.co/router/router-prod-tenbay-wr3000k/firmware/openwrt-4d5b0bf4.bin"
SHA256="db29eefdcfad9333f07cd0e67865f1b1c5fe21570a29cafe5560c04c67b309e4"
BUILD_DATE="2026-09-15T14:54:00Z"

# A caller-supplied mirror replaces only the URL — never the hash.
[ -n "$1" ] && IMAGE_URL="$1"

IMG=/tmp/kahf-firmware.bin

# Accepted models. The stock/ODM firmware reports the DTS model; a router
# already running Kahf firmware reports the Kahf name (set at preinit).
# Same pair lab/flash.sh gates on.
MODEL_STOCK="Tenbay WR3000K"
MODEL_KAHF="KAHF BURAQ6"

_say()  { echo "[..] $*"; }
_ok()   { echo "[ok] $*"; }
_fail() { echo "[ABORT] $*" >&2; }

# Refuse to run as an unsubstituted template. Guards against someone copying
# this file straight out of the repo and flashing a batch with a literal
# "db29eefdcfad9333f07cd0e67865f1b1c5fe21570a29cafe5560c04c67b309e4" that no image can ever match.
case "${SHA256}" in
*@*)
    _fail "this is the unsubstituted TEMPLATE, not a release artifact."
    echo "       Fetch the pinned copy CI publishes:" >&2
    echo "       http://router.kahf.co/router/router-prod-tenbay-wr3000k/factory-flash.sh" >&2
    exit 1
    ;;
esac

echo "=== Kahf factory flash — firmware ${FW_VERSION} (built ${BUILD_DATE}) ==="

# ── 1. Model guard ─────────────────────────────────────────────────────────
# The one thing standing between a mis-picked SKU and a brick. Deliberately
# NOT bypassable by a flag: a factory line has no reason to flash any other
# board, and lab/flash.sh's --yes (which DOES bypass its equivalent) is the
# behaviour this path exists to avoid.
MODEL="$(cat /tmp/sysinfo/model 2>/dev/null)"
echo "  Model: ${MODEL:-unknown}"
case "${MODEL}" in
"${MODEL_STOCK}" | "${MODEL_KAHF}") _ok "model recognised" ;;
*)
    _fail "unexpected model '${MODEL:-unknown}' — expected '${MODEL_STOCK}' or '${MODEL_KAHF}'."
    _fail "Refusing to flash. Flashing the wrong board can brick the unit."
    exit 1
    ;;
esac

# ── 2. Space ───────────────────────────────────────────────────────────────
# /tmp is tmpfs (RAM). A short write produces a truncated image that would
# fail the hash check anyway, but failing here is clearer and cheaper.
FREE_KB="$(df -k /tmp 2>/dev/null | awk 'NR==2{print $4}')"
case "${FREE_KB}" in
'' | *[!0-9]*) _fail "could not read free space on /tmp"; exit 1 ;;
esac
if [ "${FREE_KB}" -lt 20000 ]; then
    _fail "/tmp has ${FREE_KB} KB free, need ~20000 KB"
    exit 1
fi
_ok "space on /tmp: ${FREE_KB} KB"

# ── 3. Download ────────────────────────────────────────────────────────────
# busybox wget: present on every OpenWrt build, unlike curl/uclient-fetch.
_say "downloading ${IMAGE_URL}"
rm -f "${IMG}"
if ! wget -q -T 120 -O "${IMG}" "${IMAGE_URL}" || [ ! -s "${IMG}" ]; then
    _fail "download failed — check the unit has internet on its WAN port"
    rm -f "${IMG}"
    exit 1
fi
_ok "downloaded $(($(wc -c < "${IMG}") / 1024)) KB"

# ── 4. Integrity ───────────────────────────────────────────────────────────
# Compared directly rather than via `sha256sum -c`, whose -c applet is not
# guaranteed to be compiled into every vendor busybox.
ACTUAL="$(sha256sum "${IMG}" 2>/dev/null | awk '{print $1}')"
if [ "${ACTUAL}" != "${SHA256}" ]; then
    _fail "SHA256 MISMATCH — refusing to flash"
    _fail "  expected: ${SHA256}"
    _fail "  actual:   ${ACTUAL:-<none>}"
    rm -f "${IMG}"
    exit 1
fi
_ok "sha256 verified"

# ── 5. Board compatibility ─────────────────────────────────────────────────
# sysupgrade's own metadata check, independent of the model string above.
if ! sysupgrade --test "${IMG}"; then
    _fail "sysupgrade --test rejected this image for this board"
    rm -f "${IMG}"
    exit 1
fi
_ok "image valid for this board"

# ── 6. Flash ───────────────────────────────────────────────────────────────
# -n wipes config: the correct choice for factory prep, and it sidesteps the
# config-preserving-flash deadlocks (dnsmasq log-path wedge, mesh-agent
# orphan) documented in CLAUDE.md — none of which can occur from a clean
# first boot. -F matches the flash path already proven on real units; the
# model guard and --test above run BEFORE it, so it forces nothing unchecked.
echo ""
_say "flashing — DO NOT power off. The unit reboots in ~90s."
echo ""
sysupgrade -F -n "${IMG}"
