The installer gains --tag to install a specific release (gateway route /fpagent/releases/tags/:tag), derives the git hash from the asset name, and hands it to the bundle installer as VERSION so upgrades are reported and the installed version is recorded. Service restart on upgrade lives in the bundle installer, which owns the systemd unit.
143 lines
5.2 KiB
Bash
Executable File
143 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# install.sh — download and install the latest YOUreka Fingerprint Agent
|
|
# (fpagent) release on this machine.
|
|
#
|
|
# Hosted at https://tools.yrka.app/fpagent/install.sh and meant to be piped
|
|
# straight into bash on a field laptop:
|
|
#
|
|
# curl -fsSL https://tools.yrka.app/fpagent/install.sh | bash
|
|
#
|
|
# It downloads the bundle, verifies its sha256, then hands off to the bundle's
|
|
# own installer, which handles libfprint, the udev rule, plugdev and the
|
|
# systemd service. Every flag is forwarded to that installer, e.g.:
|
|
#
|
|
# curl -fsSL https://tools.yrka.app/fpagent/install.sh | bash -s -- --enable-service
|
|
# curl -fsSL https://tools.yrka.app/fpagent/install.sh | bash -s -- --check
|
|
#
|
|
# The private release is reached through the tools app, so no credentials are
|
|
# needed here.
|
|
set -euo pipefail
|
|
|
|
BASE="${FPAGENT_BASE_URL:-https://tools.yrka.app/fpagent}"
|
|
|
|
say() { printf '%s\n' "$*"; }
|
|
die() { printf '[FAIL] %s\n' "$*" >&2; exit 1; }
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: curl -fsSL ${BASE}/install.sh | bash -s -- [installer options]
|
|
|
|
Downloads the fpagent release, verifies it, and runs its installer.
|
|
|
|
Options:
|
|
--tag TAG release tag to install (default: latest)
|
|
|
|
Options below are forwarded to the bundled installer:
|
|
--check preflight and report only; change nothing
|
|
--offline never touch the network; fail if dependencies are missing
|
|
--enable-service install and enable a systemd service (starts at boot)
|
|
--service-user NAME user for the service (default: the invoking user)
|
|
--install-path PATH binary destination (default: /usr/local/bin/fpagent)
|
|
--uninstall remove the binary, the udev rule and the service
|
|
-h, --help the installer's help
|
|
|
|
Environment:
|
|
FPAGENT_BASE_URL override the download base (default: ${BASE})
|
|
EOF
|
|
}
|
|
|
|
RELEASE_TAG="latest"
|
|
FORWARD=()
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
-h | --help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--tag)
|
|
RELEASE_TAG="${2:?--tag needs a release tag}"
|
|
shift
|
|
;;
|
|
--tag=*)
|
|
RELEASE_TAG="${1#--tag=}"
|
|
;;
|
|
*)
|
|
FORWARD+=("$1")
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
for cmd in curl tar sha256sum python3 find; do
|
|
command -v "$cmd" >/dev/null 2>&1 || die "$cmd is required but not installed"
|
|
done
|
|
|
|
tmpbase="${TMPDIR:-/tmp}"
|
|
# Sweep scratch left by an earlier run that was SIGKILLed: the EXIT trap cannot
|
|
# run then (that is the one signal it cannot catch). Scoped to our own prefix,
|
|
# this user, and dirs older than a day, so a concurrent install is never touched.
|
|
# Runs before any network work so cleanup is not skipped when the fetch fails.
|
|
find "$tmpbase" -maxdepth 1 -mindepth 1 -type d -uid "$(id -u)" \
|
|
-name 'fpagent-install.*' -mtime +0 -exec rm -rf {} + 2>/dev/null || true
|
|
|
|
# Offline bundles ship the libfprint .deb closure for a specific Ubuntu
|
|
# release; prefer the one matching this machine, else fall back to the generic
|
|
# online bundle (whose installer apt-get's the dependency).
|
|
codename="$(sed -n 's/^VERSION_CODENAME=//p' /etc/os-release 2>/dev/null | tr -d '"')"
|
|
|
|
if [ "$RELEASE_TAG" = "latest" ]; then
|
|
meta_url="${BASE}/releases/latest"
|
|
else
|
|
meta_url="${BASE}/releases/tags/${RELEASE_TAG}"
|
|
fi
|
|
|
|
say "Fetching the Fingerprint Agent release (${RELEASE_TAG})..."
|
|
meta="$(curl -fsSL "$meta_url")" || die "could not fetch the release list from ${BASE}"
|
|
|
|
readout="$(python3 -c '
|
|
import json, re, sys
|
|
codename = sys.argv[1]
|
|
release = json.loads(sys.argv[2])
|
|
assets = [a["name"] for a in release.get("assets", [])]
|
|
|
|
def pick(suffix):
|
|
return next((n for n in assets if n.endswith(suffix) and not n.endswith(".sha256")), "")
|
|
|
|
name = pick("-ubuntu-" + codename + "-x86_64.tar.gz") if codename else ""
|
|
if not name:
|
|
name = pick("-linux-x86_64.tar.gz")
|
|
# The git hash is baked into the asset name (bundle.sh --version) and into
|
|
# the binary itself; it is the version we record and later compare against.
|
|
m = re.match(r"^fpagent-(.+)-(?:linux-x86_64|ubuntu-[a-z0-9]+-x86_64)\.tar\.gz$", name)
|
|
version = m.group(1) if m else ""
|
|
print(release.get("tag", "") + "\t" + name + "\t" + version)
|
|
' "$codename" "$meta")" || die "could not parse the release metadata"
|
|
|
|
IFS=$'\t' read -r tag asset version <<<"$readout"
|
|
[ -n "$tag" ] && [ -n "$asset" ] || die "no compatible bundle in release ${RELEASE_TAG} (x86_64 required)"
|
|
|
|
say " release ${tag}"
|
|
say " bundle ${asset}"
|
|
[ -n "$version" ] && say " version ${version}"
|
|
|
|
tmp="$(mktemp -d "$tmpbase/fpagent-install.XXXXXXXX")"
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
|
|
get() { curl -fsSL "$1" -o "$2" || die "download failed: $1"; }
|
|
|
|
say "Downloading and verifying..."
|
|
get "${BASE}/releases/download/${tag}/${asset}" "${tmp}/${asset}"
|
|
get "${BASE}/releases/download/${tag}/${asset}.sha256" "${tmp}/${asset}.sha256"
|
|
(cd "$tmp" && sha256sum -c "${asset}.sha256") || die "checksum verification failed for ${asset}"
|
|
|
|
tar xzf "${tmp}/${asset}" -C "$tmp" || die "could not extract ${asset}"
|
|
[ -x "${tmp}/install.sh" ] || die "the bundle does not contain install.sh"
|
|
|
|
# Hand the version to the bundle installer so it can record it and report an
|
|
# upgrade. Bundles built by bundle.sh already carry VERSION; this also covers
|
|
# older bundles and other packagers, using the hash from the asset name.
|
|
[ -n "$version" ] && printf '%s\n' "$version" >"${tmp}/VERSION"
|
|
|
|
say "Running the installer (pass --enable-service to start at boot)..."
|
|
"${tmp}/install.sh" "${FORWARD[@]}"
|