#!/bin/sh
# Re-runnable, unprivileged installer for the signed MetriBeacon CLI preview.
set -eu
umask 077

installer_message() {
  installer_key=$1; shift
  case "$cli_language:$installer_key" in
    en:installer.cli.help) printf 'Usage: install.sh [--lang en|de|auto]
Install the signed CLI for the current user. METRIBEACON_LANG sets the default language.
' "$@" ;;
    en:installer.cli.installedMetribeaconCliCliVersionAtCli) printf 'Installed MetriBeacon CLI %s at %s
' "$@" ;;
    en:installer.cli.invalidManifest) printf 'Invalid signed CLI manifest.
' "$@" ;;
    en:installer.cli.metribeaconCliBinaryHashOrSizeMismatch) printf 'MetriBeacon CLI binary hash or size mismatch.
' "$@" ;;
    en:installer.cli.metribeaconCliCliVersionIsAlreadyInstalled) printf 'MetriBeacon CLI %s is already installed at %s
' "$@" ;;
    en:installer.cli.metribeaconCliManifestSignatureIsInvalid) printf 'MetriBeacon CLI manifest signature is invalid.
' "$@" ;;
    en:installer.cli.metribeaconCliPublicKeyFingerprintMismatch) printf 'MetriBeacon CLI public-key fingerprint mismatch.
' "$@" ;;
    en:installer.cli.metribeaconInstallDirMustBeAbsolute) printf 'METRIBEACON_INSTALL_DIR must be absolute.
' "$@" ;;
    en:installer.cli.requiredToolMissingCliTool) printf 'Required tool missing: %s
' "$@" ;;
    en:installer.cli.runTheCliInstallerAsTheTarget) printf 'Run the CLI installer as the target user, without sudo.
' "$@" ;;
    en:installer.cli.thisCliDownloadSupportsLinuxOnly) printf 'This CLI download supports Linux only.
' "$@" ;;
    en:installer.cli.unsupportedCpuArchitecture) printf 'Unsupported CPU architecture.
' "$@" ;;
    en:installer.language.help) printf 'Language: en, de or auto (also METRIBEACON_LANG).
' "$@" ;;
    en:installer.language.invalid) printf 'Language must be en, de or auto.
' "$@" ;;
    en:installer.language.invalidOptions) printf 'Invalid options. Use --help for available options.
' "$@" ;;
    en:installer.language.options) printf 'Options
' "$@" ;;
    en:installer.language.showHelp) printf 'Show this help and exit
' "$@" ;;
    en:installer.language.usage) printf 'Usage
' "$@" ;;
    de:installer.cli.help) printf 'Aufruf: install.sh [--lang en|de|auto]
Das signierte CLI für den aktuellen Benutzer installieren. METRIBEACON_LANG legt die Standardsprache fest.
' "$@" ;;
    de:installer.cli.installedMetribeaconCliCliVersionAtCli) printf 'MetriBeacon CLI %s unter %s installiert
' "$@" ;;
    de:installer.cli.invalidManifest) printf 'Ungültiges signiertes CLI-Manifest.
' "$@" ;;
    de:installer.cli.metribeaconCliBinaryHashOrSizeMismatch) printf 'Prüfsumme oder Größe der MetriBeacon-CLI-Binärdatei stimmt nicht überein.
' "$@" ;;
    de:installer.cli.metribeaconCliCliVersionIsAlreadyInstalled) printf 'MetriBeacon CLI %s ist bereits unter %s installiert
' "$@" ;;
    de:installer.cli.metribeaconCliManifestSignatureIsInvalid) printf 'Die Signatur des MetriBeacon-CLI-Manifests ist ungültig.
' "$@" ;;
    de:installer.cli.metribeaconCliPublicKeyFingerprintMismatch) printf 'Der Fingerprint des öffentlichen MetriBeacon-CLI-Schlüssels stimmt nicht überein.
' "$@" ;;
    de:installer.cli.metribeaconInstallDirMustBeAbsolute) printf 'METRIBEACON_INSTALL_DIR muss ein absoluter Pfad sein.
' "$@" ;;
    de:installer.cli.requiredToolMissingCliTool) printf 'Benötigtes Werkzeug fehlt: %s
' "$@" ;;
    de:installer.cli.runTheCliInstallerAsTheTarget) printf 'Führen Sie den CLI-Installer als Zielbenutzer ohne sudo aus.
' "$@" ;;
    de:installer.cli.thisCliDownloadSupportsLinuxOnly) printf 'Dieser CLI-Download unterstützt nur Linux.
' "$@" ;;
    de:installer.cli.unsupportedCpuArchitecture) printf 'Nicht unterstützte CPU-Architektur.
' "$@" ;;
    de:installer.language.help) printf 'Sprache: en, de oder auto (auch METRIBEACON_LANG).
' "$@" ;;
    de:installer.language.invalid) printf 'Die Sprache muss en, de oder auto sein.
' "$@" ;;
    de:installer.language.invalidOptions) printf 'Ungültige Optionen. Mit --help die verfügbaren Optionen anzeigen.
' "$@" ;;
    de:installer.language.options) printf 'Optionen
' "$@" ;;
    de:installer.language.showHelp) printf 'Diese Hilfe anzeigen und beenden
' "$@" ;;
    de:installer.language.usage) printf 'Aufruf
' "$@" ;;
    *) return 1 ;;
  esac
}

cli_show_help=false
cli_preference=${METRIBEACON_LANG:-auto}
while [ "$#" -gt 0 ]; do
  case "$1" in
    --help|-h) cli_show_help=true ;;
    --lang) shift; cli_preference=${1:-invalid} ;;
    --lang=*) cli_preference=${1#--lang=} ;;
    *) cli_preference=invalid ;;
  esac
  [ "$#" -eq 0 ] || shift
done
case "$cli_preference" in
  en|de) cli_language=$cli_preference ;;
  auto) cli_language=en; cli_os_language=${LC_ALL:-${LC_MESSAGES:-${LANGUAGE:-${LANG:-C}}}}; cli_old_ifs=$IFS; IFS=:; for cli_preferred in $cli_os_language; do cli_base_language=$(printf '%s' "${cli_preferred%%[._-]*}" | tr '[:upper:]' '[:lower:]'); case "$cli_base_language" in en|de) cli_language=$cli_base_language; break ;; esac; done; IFS=$cli_old_ifs ;;
  *) cli_language=en; installer_message installer.language.invalid >&2; exit 2 ;;
esac

if [ "$cli_show_help" = true ]; then
  installer_message installer.cli.help
  exit 0
fi

if [ "$(id -u)" -eq 0 ]; then
  installer_message installer.cli.runTheCliInstallerAsTheTarget >&2
  exit 2
fi
if [ "$(uname -s)" != Linux ]; then
  installer_message installer.cli.thisCliDownloadSupportsLinuxOnly >&2
  exit 2
fi
case "$(uname -m)" in
  x86_64) cli_arch=amd64 ;;
  aarch64|arm64) cli_arch=arm64 ;;
  *) installer_message installer.cli.unsupportedCpuArchitecture >&2; exit 2 ;;
esac
for cli_tool in curl openssl sha256sum python3 mktemp install; do
  command -v "$cli_tool" >/dev/null 2>&1 || { installer_message installer.cli.requiredToolMissingCliTool "$cli_tool" >&2; exit 2; }
done

cli_base=https://metribeacon.com/downloads
cli_expected_fingerprint=2663962bf6e52d694d2e9130e2b96ae1dec0d27bcd2d5811c116dfb79a4655b5
cli_tmp=$(mktemp -d)
trap 'rm -rf -- "$cli_tmp"' EXIT HUP INT TERM
for cli_file in cli-manifest.json cli-manifest.sig cli-signing-public.pem; do
  curl --proto '=https' --tlsv1.2 --location --fail --silent --show-error \
    --max-time 30 --retry 2 -o "$cli_tmp/$cli_file" "$cli_base/$cli_file"
done
cli_fingerprint=$(openssl pkey -pubin -in "$cli_tmp/cli-signing-public.pem" -outform DER 2>/dev/null | sha256sum | cut -d' ' -f1)
if [ "$cli_fingerprint" != "$cli_expected_fingerprint" ]; then
  installer_message installer.cli.metribeaconCliPublicKeyFingerprintMismatch >&2
  exit 1
fi
if ! openssl pkeyutl -verify -rawin -pubin -inkey "$cli_tmp/cli-signing-public.pem" \
    -in "$cli_tmp/cli-manifest.json" -sigfile "$cli_tmp/cli-manifest.sig" >/dev/null 2>&1; then
  installer_message installer.cli.metribeaconCliManifestSignatureIsInvalid >&2
  exit 1
fi

cli_invalid_manifest=$(installer_message installer.cli.invalidManifest)
cli_metadata=$(python3 - "$cli_tmp/cli-manifest.json" "$cli_arch" "$cli_language" "$cli_invalid_manifest" <<'PY'
import json, re, sys
with open(sys.argv[1], encoding='utf-8') as source:
    data = json.load(source)
arch = sys.argv[2]
version = data.get('version')
commit = data.get('commit')
entry = (data.get('files') or {}).get(arch) or {}
name = entry.get('name')
digest = entry.get('sha256')
if data.get('format_version') != 1 or not isinstance(version, str) or not re.fullmatch(r'v0\.4\.0-preview\.[0-9a-f]{12}', version) or not isinstance(commit, str) or not re.fullmatch(r'[0-9a-f]{40}', commit) or not isinstance(name, str) or name != f'metribeacon-{version}-linux-{arch}' or not isinstance(digest, str) or not re.fullmatch(r'[0-9a-f]{64}', digest) or not isinstance(entry.get('size'), int) or entry['size'] < 1 or entry['size'] > 100_000_000:
    raise SystemExit(sys.argv[4])
print(name, digest, entry['size'], version)
PY
)
set -- $cli_metadata
cli_name=$1
cli_sha=$2
cli_size=$3
cli_version=$4
curl --proto '=https' --tlsv1.2 --location --fail --silent --show-error \
  --max-time 120 --retry 2 -o "$cli_tmp/$cli_name" "$cli_base/$cli_name"
if [ "$(wc -c < "$cli_tmp/$cli_name" | tr -d ' ')" != "$cli_size" ] || \
   [ "$(sha256sum "$cli_tmp/$cli_name" | cut -d' ' -f1)" != "$cli_sha" ]; then
  installer_message installer.cli.metribeaconCliBinaryHashOrSizeMismatch >&2
  exit 1
fi

cli_target_dir=${METRIBEACON_INSTALL_DIR:-"$HOME/.local/bin"}
case "$cli_target_dir" in
  /*) ;;
  *) installer_message installer.cli.metribeaconInstallDirMustBeAbsolute >&2; exit 2 ;;
esac
mkdir -p -- "$cli_target_dir"
cli_target="$cli_target_dir/metribeacon"
if [ -f "$cli_target" ] && [ "$(sha256sum "$cli_target" | cut -d' ' -f1)" = "$cli_sha" ]; then
  installer_message installer.cli.metribeaconCliCliVersionIsAlreadyInstalled "$cli_version" "$cli_target"
  exit 0
fi
cli_stage=$(mktemp "$cli_target_dir/.metribeacon.XXXXXX")
trap 'rm -f -- "$cli_stage"; rm -rf -- "$cli_tmp"' EXIT HUP INT TERM
install -m 0755 -- "$cli_tmp/$cli_name" "$cli_stage"
mv -f -- "$cli_stage" "$cli_target"
installer_message installer.cli.installedMetribeaconCliCliVersionAtCli "$cli_version" "$cli_target"
