#!/usr/bin/env bash
set -Eeuo pipefail


TRUSTED_PUBLIC_KEY='p4U5ajS2eGo2uXtI7WDu3CV/Jl0WKbDI6qXVtT6EIFY'

BASE_URL="${NPANEL_BASE_URL:-https://npanel.org}"
VERSION="${1:-latest}"
if [[ $# -gt 0 ]]; then shift; fi

log() { printf '[npanel] %s\n' "$*"; }
fail() { printf '[npanel] ERROR: %s\n' "$*" >&2; exit 1; }

download() {
  local url=$1 dest=$2
  if command -v curl >/dev/null 2>&1; then
    curl -fsSL "$url" -o "$dest"
  elif command -v wget >/dev/null 2>&1; then
    wget -qO "$dest" "$url"
  else
    fail 'neither curl nor wget is available; install one of them and retry'
  fi
}

if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
  fail 'neither curl nor wget is available; install one and retry'
fi
if ! command -v tar >/dev/null 2>&1; then
  fail 'tar is required'
fi
command -v python3 >/dev/null 2>&1 || fail 'python3 is required for signature verification'
command -v openssl >/dev/null 2>&1 || fail 'openssl is required for signature verification'

if [[ "$VERSION" != "latest" && ! "$VERSION" =~ ^v?[0-9][0-9A-Za-z._-]*$ ]]; then
  fail "invalid version: $VERSION"
fi

TMP="$(mktemp -d /tmp/npanel-get.XXXXXX)"
trap 'rm -rf "$TMP"' EXIT
NPB="$TMP/npanel.npb"

log "downloading NPanel bundle (version: ${VERSION})"
download "$BASE_URL/npanel-${VERSION}-linux-amd64.npb" "$NPB" \
  || fail "could not download bundle (version: ${VERSION})"

VERIFY_DIR="$TMP/verify"
mkdir -p "$VERIFY_DIR"
tar -xf "$NPB" -C "$VERIFY_DIR" manifest.json signature.json \
  || fail 'could not read bundle signature envelope'
python3 - "$VERIFY_DIR/signature.json" "$TRUSTED_PUBLIC_KEY" "$VERIFY_DIR" <<'PY' || fail 'invalid bundle signature envelope'
import base64, json, os, sys
sig = json.load(open(sys.argv[1]))
if sig.get('schema') != 'npanel.signature.v1' or sig.get('algorithm') != 'ed25519':
    sys.exit('unsupported signature format')
if sig.get('publicKey') != sys.argv[2]:
    sys.exit('bundle was not signed by the trusted public key')
try:
    raw_pub = sig['publicKey']
    raw_value = sig['value']
    pub = base64.b64decode(raw_pub + '=' * (-len(raw_pub) % 4))
    value = base64.b64decode(raw_value + '=' * (-len(raw_value) % 4))
except Exception:
    sys.exit('invalid signature encoding')
if len(pub) != 32 or len(value) != 64:
    sys.exit('invalid signature length')
der = bytes.fromhex('302a300506032b6570032100') + pub
open(os.path.join(sys.argv[3], 'pub.der'), 'wb').write(der)
open(os.path.join(sys.argv[3], 'sig.bin'), 'wb').write(value)
PY
openssl pkey -pubin -inform DER -in "$VERIFY_DIR/pub.der" -out "$VERIFY_DIR/pub.pem" 2>/dev/null \
  || fail 'could not parse trusted public key'
openssl pkeyutl -verify -pubin -inkey "$VERIFY_DIR/pub.pem" -rawin \
  -in "$VERIFY_DIR/manifest.json" -sigfile "$VERIFY_DIR/sig.bin" >/dev/null 2>&1 \
  || fail 'bundle signature verification failed'
log 'bundle signature verified against the embedded trust anchor'

tar -xf "$NPB" -C "$TMP" "payload/packaging/installer/install.sh" \
  || fail 'could not extract installer from bundle'
INSTALLER="$TMP/payload/packaging/installer/install.sh"

log 'verifying and installing (the installer re-checks every payload hash)'
if [[ "${EUID}" -eq 0 ]]; then
  bash "$INSTALLER" --bundle "$NPB" --public-key "$TRUSTED_PUBLIC_KEY" "$@"
else
  sudo bash "$INSTALLER" --bundle "$NPB" --public-key "$TRUSTED_PUBLIC_KEY" "$@"
fi
