#!/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 </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 '"')" say "Fetching the latest Fingerprint Agent release..." meta="$(curl -fsSL "${BASE}/releases/latest")" || die "could not fetch the release list from ${BASE}" readout="$(python3 -c ' import json, 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") print(release.get("tag", "") + "\t" + name) ' "$codename" "$meta")" || die "could not parse the release metadata" tag="${readout%%$'\t'*}" asset="${readout#*$'\t'}" [ -n "$tag" ] && [ -n "$asset" ] || die "no compatible bundle in the latest release (x86_64 required)" say " release ${tag}" say " bundle ${asset}" 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" say "Running the installer (pass --enable-service to start at boot)..." "${tmp}/install.sh" "$@"