Files
tools-legacy/tools/public/fpagent/install.sh
T
adebisi-fa fa33c6e179 feat(fpagent): pick the installer bundle for the host architecture
The hosted installer only ever chose the x86_64 bundle, so a 32-bit field
laptop running the public one-liner failed with "no compatible bundle" even
though fingerprint-agent v1.5.0 publishes fpagent-<version>-linux-i386.tar.gz.

Resolve the host architecture from uname -m (x86_64 or i386, else fail before
any download), then prefer -ubuntu-<codename>-<arch>.tar.gz and fall back to
-linux-<arch>.tar.gz. The version regex now derives the git hash for every
supported architecture, so a 32-bit install records and reports it too.

The help text matches the bundle installer: the systemd service and the
self-update timer are on by default, with --no-service, --no-updates and
--update-base documented.
2026-10-06 19:19:07 +01:00

158 lines
6.0 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 -- --service-user alice
# 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
--no-service do not install the systemd service (also disables updates)
--no-updates do not install the self-update timer
--update-base URL release base for self-update
(default: https://tools.yrka.app/fpagent)
--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
The systemd service and the self-update timer are installed and enabled by
default; --no-service and --no-updates turn them off.
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 '"')"
# Releases are named for the target architecture; only these two are published.
# Mirrors the bundled installer's own preflight so both reject the same hosts.
host_machine="$(uname -m)"
case "$host_machine" in
x86_64 | amd64) arch="x86_64" ;;
i386 | i486 | i586 | i686) arch="i386" ;;
*) die "unsupported architecture: ${host_machine} (x86_64 or i386 required)" ;;
esac
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, arch = sys.argv[1], sys.argv[2]
release = json.loads(sys.argv[3])
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 + "-" + arch + ".tar.gz") if codename else ""
if not name:
name = pick("-linux-" + arch + ".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|ubuntu-[a-z0-9]+)-" + re.escape(arch) + r"\.tar\.gz$", name)
version = m.group(1) if m else ""
print(release.get("tag", "") + "\t" + name + "\t" + version)
' "$codename" "$arch" "$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} (${arch} 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[@]}"