#!/usr/bin/env bash # Fingerprint login, which is two systems that must be kept honest with each # other: fprintd holds the enrolled prints, authselect decides whether PAM # asks the reader. A print enrolled while with-fingerprint is off does # nothing, and that silence -- "I enrolled a finger and nothing happened" -- # is the failure this card exists to name. # # The helper is the parse surface, so it runs for real against stub fprintd # and authselect; the page and service checks are structural. set -uo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" helper="$repo_dir/config/dot/quickshell/scripts/panama-fingerprint" service="$repo_dir/config/dot/quickshell/services/Fingerprint.qml" page="$repo_dir/config/dot/quickshell/modules/settings/UsersPage.qml" fail() { printf 'fingerprint contract: %s\n' "$1" >&2 exit 1 } # ── Wiring ─────────────────────────────────────────────────────────────────── rg -Fq 'visible: Fingerprint.readerPresent' "$page" \ || fail 'the card is not hidden on machines with no reader' rg -Fq 'onToggled: value => Fingerprint.setUnlockEnabled(value)' "$page" \ || fail 'the unlock switch does not drive authselect' rg -Fq 'SystemSettings.openGnomePanel("system", "users")' "$page" \ || fail 'enrollment does not hand off to the GNOME Users panel' rg -Fq 'Fingerprint.refresh()' "$page" \ || fail 'the page never reads the fingerprint state' rg -Fq 'authselect' "$helper" && rg -Fq 'with-fingerprint' "$helper" \ || fail 'the helper does not manage the authselect feature' rg -Fq -- '--reason' "$helper" \ || fail 'the privileged change carries no stated reason' rg -Fq 'function fingerLabel' "$service" \ || fail 'finger names have no single place to be presented from' # ── The helper against stub fprintd and authselect ─────────────────────────── stub_dir="$(mktemp -d)" state_dir="$(mktemp -d)" trap 'rm -rf "$stub_dir" "$state_dir"' EXIT cat >"$stub_dir/fprintd-list" <"$stub_dir/authselect" <>"$state_dir/authselect-log" if [[ "\$1" == "current" ]]; then echo 'Profile ID: local' [[ -e "$state_dir/pam-on" ]] && echo '- with-fingerprint' exit 0 fi STUB # PANAMA_PATH pointed at an empty directory forces the plain-sudo fallback, # which the stub records instead of escalating. cat >"$stub_dir/sudo" <>"$state_dir/sudo-log" exec "\$@" STUB chmod +x "$stub_dir"/fprintd-list "$stub_dir"/authselect "$stub_dir"/sudo run() { PANAMA_PATH="$state_dir" PATH="$stub_dir:$PATH" "$helper" "$@"; } status="$(run status)" jq -e '.reader and .readerName == "Goodix MOC Fingerprint Sensor"' <<<"$status" >/dev/null \ || fail "the reader name did not parse: $status" jq -e '.enrolled == ["right-index-finger", "left-thumb"]' <<<"$status" >/dev/null \ || fail "enrolled fingers did not parse: $status" jq -e '.pamEnabled == false and .error == ""' <<<"$status" >/dev/null \ || fail "authselect state misread as enabled: $status" touch "$state_dir/pam-on" jq -e '.pamEnabled == true' <<<"$(run status)" >/dev/null \ || fail 'with-fingerprint enabled was not detected' # No reader is a normal machine, not an error. touch "$state_dir/no-reader" jq -e '.reader == false and .error == ""' <<<"$(run status)" >/dev/null \ || fail "a readerless machine was reported as a problem: $(run status)" rm -f "$state_dir/no-reader" # The privileged change goes through, with the right feature name. run set-unlock on >/dev/null grep -Fq 'authselect enable-feature with-fingerprint' "$state_dir/sudo-log" \ || fail 'set-unlock on did not enable the authselect feature' run set-unlock off >/dev/null grep -Fq 'authselect disable-feature with-fingerprint' "$state_dir/sudo-log" \ || fail 'set-unlock off did not disable the authselect feature' printf 'fingerprint contract: ok\n'