#!/bin/sh
# TenChat's .deb auto-update (desktop auto-update spec 4), run as root by
# tenchat-update.timer: a newer release from tenchat.mn's signed manifest,
# installed with apt-get, never while the app runs (the next boot or check
# does it then).
set -eu
BASE=https://tenchat.mn/download
KEY=${TENCHAT_UPDATE_KEY:-/opt/tenchat/update/update-key.pem}
PROC=${TENCHAT_PROC:-/proc}

# The app is running: a process whose program is /opt/tenchat/tenchat (by
# path, so another program named tenchat cannot hold updates back).
app_running() {
  for exe in "$PROC"/[0-9]*/exe; do
    case "$(readlink "$exe" 2>/dev/null)" in
      /opt/tenchat/tenchat | "/opt/tenchat/tenchat (deleted)") return 0 ;;
    esac
  done
  return 1
}

# Bounded downloads: a server that never stops sending cannot fill the disk
# or hold the timer up.
get() { # max-bytes max-seconds file url
  curl -fsS --proto =https --max-filesize "$1" --max-time "$2" -o "$3" "$4"
}

if app_running; then exit 0; fi
if ! openssl version | grep -q '^OpenSSL [3-9]'; then
  echo "tenchat-update: needs OpenSSL 3 to check the release's signature" >&2
  exit 0
fi

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
get 65536 60 "$work/update.txt" "$BASE/update.txt"
get 1024 60 "$work/update.txt.sig" "$BASE/update.txt.sig"
if ! openssl pkeyutl -verify -pubin -inkey "$KEY" -rawin -in "$work/update.txt" -sigfile "$work/update.txt.sig" >/dev/null; then
  echo "tenchat-update: the manifest's signature does not match" >&2
  exit 1
fi

version=$(sed -n 's/^version \([0-9]\{1,6\}\.[0-9]\{1,6\}\.[0-9]\{1,6\}\)$/\1/p' "$work/update.txt")
line=$(sed -n 's/^linux-deb //p' "$work/update.txt")
url=${line% *}
sha=${line##* }
name=${url#"$BASE/"}
case "$name" in
  "$url" | "" | *[!A-Za-z0-9._+-]* | .*) echo "tenchat-update: bad .deb in the manifest" >&2; exit 1 ;;
esac
if [ -z "$version" ] || ! printf '%s' "$sha" | grep -qx '[0-9a-f]\{64\}'; then
  echo "tenchat-update: bad manifest" >&2
  exit 1
fi

installed=$(dpkg-query -W -f='${Version}' tenchat 2>/dev/null || echo 0)
if ! dpkg --compare-versions "$version" gt "$installed"; then exit 0; fi

get 524288000 1800 "$work/$name" "$url"
if ! echo "$sha  $work/$name" | sha256sum -c --quiet - >/dev/null 2>&1; then
  echo "tenchat-update: $name does not match its hash" >&2
  exit 1
fi
# The app may have been opened during the download.
if app_running; then exit 0; fi
DEBIAN_FRONTEND=noninteractive apt-get install -y -q --no-remove "$work/$name"
