diff --git a/docs/superpowers/specs/2026-05-25-fingerprint-reader-design.md b/docs/superpowers/specs/2026-05-25-fingerprint-reader-design.md new file mode 100644 index 0000000..759ea0f --- /dev/null +++ b/docs/superpowers/specs/2026-05-25-fingerprint-reader-design.md @@ -0,0 +1,105 @@ +# Framework 13 Fingerprint Reader Design + +**Date:** 2026-05-25 +**Status:** Approved + +## Summary + +Enable the Framework 13 (AMD 7040) Goodix fingerprint reader for `sudo` and `gtklock` (lockscreen). Three-phase setup: package install via the existing `packages.txt` manifest, interactive enrollment (one-time, user-driven), and a small idempotent bootstrap script that adds `pam_fprintd.so` to the two PAM stacks if not already present. + +## Current State + +- **Hardware:** Goodix `27c6:609c` USB fingerprint reader (well-supported by libfprint's `goodix.MOC` driver) +- **Software:** `fprintd` and `libfprint` are NOT installed +- **PAM:** No `pam_fprintd.so` line in any `/etc/pam.d/` file +- **Enrollments:** none + +## Target State + +After install + enrollment + bootstrap script: + +| Service | Behaviour | +|---|---| +| `sudo` | Prompt offers fingerprint first; falls back to password if it fails / times out | +| `gtklock` (lockscreen) | Same — touch the reader to unlock; type password if it fails | +| `login`, `system-local-login`, `polkit-1` | Untouched — password only (boot-time fingerprint is finicky; polkit-1 has no existing PAM file) | + +## Implementation + +### Phase 1: Package install + +Add to `packages.txt`: +``` +fprintd +``` + +`libfprint` is pulled in as a dependency. `fprintd.service` auto-starts via dbus activation — no `systemctl enable` needed. + +### Phase 2: Enrollment (interactive, user-driven) + +After install, the user runs: +``` +fprintd-enroll +``` + +Default enrolls right-index. Additional fingers via `fprintd-enroll -f left-thumb` (or `right-thumb`, `left-index`, etc.). Verify with `fprintd-list $USER`. + +This step is interactive and not scriptable — documented in the README. + +### Phase 3: PAM wiring via bootstrap script + +**`scripts/enable-fingerprint.sh`** — new, idempotent, requires sudo, run once. + +For each of `/etc/pam.d/sudo` and `/etc/pam.d/gtklock`, inserts this exact line at the top of the auth stack (before the first existing `auth` directive), if not already present: + +``` +auth sufficient pam_fprintd.so +``` + +`sufficient` means: fingerprint success → skip password; fingerprint missing/failure → fall through to the existing password auth. Never blocks login on fingerprint failure. + +The script: +1. Checks each target file for `pam_fprintd` (already present → skip with message) +2. Backs up the file to `.bak.` before editing +3. Inserts the new line on a fresh line directly before the first `auth ` line +4. Prints what changed + +Why a script vs tracking the PAM files in the repo: `/etc/pam.d/sudo` is owned by the `sudo` pacman package and `/etc/pam.d/gtklock` by `gtklock`. Tracking modified copies and `sudo install`-ing them via `install.sh` would clobber pacman updates of those packages. An idempotent one-time edit is the cleanest path. + +### Phase 4: README documentation + +Append a `### One-time fingerprint setup` subsection under `## Setup`, alongside the existing hibernation + NetworkManager subsections. Three steps documented: +1. Run `install.sh` (gets `fprintd` installed via packages.txt) +2. Enroll a finger: `fprintd-enroll` +3. Wire up PAM: `sudo bash scripts/enable-fingerprint.sh` + +## Files Touched + +| File | Action | +|---|---| +| `packages.txt` | add `fprintd` | +| `scripts/enable-fingerprint.sh` | created | +| `README.md` | append `### One-time fingerprint setup` subsection | + +## Verification + +After all three phases: +``` +fprintd-list $USER # lists enrolled fingers +fprintd-verify # touch reader → "verify-match" +grep pam_fprintd /etc/pam.d/sudo /etc/pam.d/gtklock # both have the line +``` + +Behavioural checks: +1. Run `sudo true` — prompts for fingerprint first; if you touch the reader → no password requested. +2. Lock screen (`Mod+Shift+E`) → touch reader → unlocks without typing password. +3. Disconnect the fingerprint reader (theoretically; you can't physically with a built-in one — instead `pkill fprintd; sudo systemctl mask fprintd` temporarily): both services should still accept the password, proving the fallback works. Restore with `sudo systemctl unmask fprintd`. + +## Out of Scope + +- **Tracking PAM files in the repo** — would clobber pacman-owned files. Bootstrap script edits in place instead. +- **Adding fingerprint to login/system-local-login/polkit-1** — boot-time fingerprint is finicky (USB device may not be ready); polkit-1 has no existing PAM file. Easy follow-up if desired. +- **Automatic enrollment** — `fprintd-enroll` is inherently interactive. +- **Custom enrollment of multiple fingers** — user runs `fprintd-enroll -f ` as needed. +- **Removing fingerprint from PAM** — manual `sudo sed -i '/pam_fprintd/d' /etc/pam.d/sudo /etc/pam.d/gtklock` reverses it; not scripted. +- **Backwards-compatible PAM stack** that survives package updates of `sudo`/`gtklock`. Acceptable risk: pacman package updates of these are rare; if it happens, the script is idempotent — run it again to re-add the line.