Commit Graph
18 Commits
Author SHA1 Message Date
879d6583da Fix fingerprint enrollment and lock-screen recovery (#7158)
* Restart fprintd after resume to clear a claim wedged by suspend

A fingerprint verify still open when the machine suspends leaves fprintd
unable to hand the reader back: the verify dies with "Cannot run while
suspended" and the follow-up ReleaseDevice fails on the still-busy device.
The wedged claim then rejects every lock-screen attempt after resume until
fprintd exits on its own 30-second idle timer -- and the retry loop keeps
it from ever reaching that timer, so the reader stays dead until the user
gives up and types a password.

Install a system-sleep hook that restarts fprintd on resume, dropping the
claim so the reader answers on the first touch. It is installed by
omarchy-setup-security-fingerprint and removed by its teardown, so it is
present exactly when a fingerprint reader is configured. try-restart is a
no-op when fprintd is not running, so a healthy resume pays nothing.

Approach suggested in #7229 and measured by @paracycle: 45 stray PAM
sessions after resume down to 2.

* Pace fingerprint retries and show when the reader is unavailable

The lock screen retried fingerprint auth on a flat 250ms timer with no
sign to the user, so a reader it could not reach -- a claim wedged across
suspend, one held by another client, or a sensor gone from the bus --
spun PAM sessions at four per second behind an icon still inviting
touches that could never unlock.

Pace and report on one signal: whether an attempt reached the reader at
all. pam_fprintd relays a finger prompt only once the claim lands, so an
attempt that ends without prompting never reached the device. Those
advance a streak that backs the retry off exponentially (to a ceiling
above fprintd's 30s idle exit) and, past a few in a row, crosses out the
icon and shows a "Fingerprint reader unavailable" notice. An attempt that
did prompt proves the reader works -- a finger that merely did not match
still reaches it -- so it clears the streak and the loop stays responsive.

User presence (a keypress or touch) collapses a backed-off wait to a
prompt retry, rate-limited so a moving cursor cannot respin the storm. An
attempt that never reaches the reader within a few seconds is aborted and
settled as unreached, so a claim orphaned by the resume restart surfaces
the notice and retries a fresh daemon rather than hanging silently.

The pacing, streak, nudge, and reach-timeout logic live in
FingerprintModel.js with Node coverage; the new Text elements declare
textFormat; lock status reports fingerprintUnavailable.

The attempt state machine tracks the open attempt with fingerprintAuthenticating alone; the first settle closes it, and one PAM attempt raising both onError and onCompleted still folds into the streak exactly once.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Install the fprintd resume hook root-owned and keep it with the PAM file

cp -p carried the checkout's owner and mode into
/usr/lib/systemd/system-sleep/, so under dev-link the root-executed hook
was user-owned, and a tree whose exec bit had been stripped installed a
hook that systemd-sleep silently never ran. Use install -Dm755 -o root
-g root, as the migration that installs the same file already does.

The hook also belongs exactly where the fingerprint PAM file does:
omarchy-apply-lock creates and removes /etc/pam.d/omarchy-lock-fingerprint
on its own, and any apply-lock run after enrollment left PAM without the
hook while its removal branch left a hook behind without PAM. Have
apply-lock install and remove the hook together with the PAM file, and
teach apply-lock-test.sh to redirect the hook into its scratch tree and
assert the hardened run lands it beside the PAM fixtures.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Only treat fingerprint as configured when a print is enrolled

The lock screen and omarchy-apply-lock decided fingerprint was set up with
fprintd-list | grep -qi finger, which also matches "has no fingers enrolled"
and "ListEnrolledFingers failed". A second account on a machine where one
user enrolled, or anyone who ran fprintd-delete, was therefore handed the
fingerprint loop: every attempt bailed before the claim, and with the new
pacing that showed up as a crossed icon and "Fingerprint reader unavailable"
for a reader the account simply has no print on. Match the per-print
" - #N:" lines instead.

apply-lock-test.sh follows: its fprintd-list stubs answer with a real enrolled-print row and its helper patcher matches the new probe line.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Exercise the migration's default hook source in its test

Every case overrode OMARCHY_FPRINTD_RESUME_SRC, so the path the migration
really reads from was never checked, while its -f guard turns a missing
source into a clean exit and a permanent per-user marker. Add a case that
runs against the shipped hook under the repo, and adopt set -euo pipefail
like the sibling tests.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Take the fprintd restart off the thaw and bound its stop timeout

The resume hook ran systemctl try-restart synchronously while user
sessions were still frozen, so its cost landed on the wake path: half a
second when fprintd answers SIGTERM, but a wedged fprintd on a stale
device handle (the reader re-enumerated across the sleep) does not, and
then the desktop stayed frozen for the whole stop timeout -- precisely in
the case the hook exists for.

Enqueue the restart with --no-block instead, as the unmount-fuse hook
already does for the same reason, and ship a drop-in capping fprintd's
TimeoutStopSec at 3s so the restart lands within seconds either way. The
drop-in is numbered 10-stop-timeout.conf, as the other Omarchy system
drop-ins are, so an administrator's override.conf sorts after it and
wins. It is installed and removed wherever the hook is (setup, teardown,
apply-lock, migration), and apply-lock-test.sh redirects it into its
scratch tree alongside the hook.

The hook's comments now say what actually happens on a locked resume --
Omarchy locks before every suspend and the lock screen opens a verify at
once, so the restart is real, not a no-op -- and name the upstream
defects this works around, fprintd#173 and fprintd#216, so the hook and
the drop-in can be retired when upstream fixes them.

Measured by MaxMad75 on an X390 Yoga (S3): 2 of 10 fprintd stops rode out
the timeout to SIGKILL; the 3s cap verified with systemctl show.

Co-authored-by: Omabot <omabot@omarchy.org>
Co-authored-by: MaxMad75 <44462964+MaxMad75@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Close the status-check and start-failure exits through settle

Two paths left the fingerprint loop stuck or misreporting. A mid-lock status check that found fingerprint unconfigured aborted the PAM context directly; abort() delivers no signal, so fingerprintAuthenticating stayed true and every later attempt and nudge returned on it until the password unlock. And a fingerprintPam.start() that fails synchronously means the PAM file is gone -- a configuration problem, not a reader miss -- yet it fed the reader streak and reported "Fingerprint reader unavailable".

Route the abort through settleFingerprintAttempt like the reach timeout does, drop the pending retry with it, and on a start failure re-check the configuration so the icon disappears instead; a pending retry owns the next attempt when a status check comes back configured.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Pace fingerprint nudges by the pending tier and the cap's idle stretch

The nudge cooldown was a flat 2s, shorter than every backoff step, so a
user moving the mouse at a wedged reader collapsed each wait to 2s --
thirty claims a minute against the cap's 1.5 -- and each claim re-armed
fprintd's 30s idle timer, so the hook-less recovery the cap exists for
never happened while anyone was present.

Grow the cooldown with the pending wait, so presence collapses each
backed-off wait once and repeat nudges are paced by the tier. At the cap
the wait itself is the cure -- it is what lets fprintd idle out and drop
a wedged claim -- so there the idle stretch is measured from the last
settle, not the last nudge: a nudged attempt that hung until the reach
timeout would otherwise eat most of the window, and under continuous
input fprintd would never be left alone long enough to exit.

Wall-clock steps are handled in both directions: a clock stepped back
past the last nudge does not hold a fresh nudge back, and one stepped
back past the last settle counts as no idle time at the cap rather than
as enough. The retry test drives continuous input against attempts that
hang to the reach bound and checks the gap fprintd is left.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Give a slow fingerprint claim time to land before aborting it

The reach bound aborted any attempt that had not prompted within 5s by
SIGKILLing the PAM child mid-Claim. A reader whose device open takes
longer than that (out-of-tree drivers, and any reader right after the
resume hook forces a re-open) could then never prompt: each kill left
fprintd tearing the claim down until the open finished, the 1s retry hit
"already claimed", and three misses later the reader was reported
unavailable for good. Raise the bound to 20s, under GDBus's 25s Claim
timeout and pam_fprintd's 30s verify timeout (whose "Verification timed
out" is a non-error message that would read as reached), and name the
hazard the bound actually covers: a daemon restarted under the verify
fails the attempt promptly, a stuck device open does not.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Detect resume and hold the streak through the restart window

Monotonic timers pause across suspend, so a backed-off wait armed before
the sleep picked up mid-count afterwards: with the streak at the cap the
"Fingerprint reader unavailable" notice stayed up for the remaining wait
after the resume hook had already freed the reader, and misses collected
around the suspend edge carried across it, so a healthy reader could
cross the notice threshold in the first seconds after waking. With the
restart enqueued off the thaw, the loop's first attempts after a wake can
also land on the old daemon while it is being stopped -- up to ~3s when
it ignores SIGTERM -- and three of those would show the notice for a
reader that was merely being restarted underneath.

Notice a resume from any of three signals -- a sleep watch ticking the
wall clock for the whole lock, a retry that fired late, or an unreached
attempt whose settle finds the watch's last tick far in the past (so a
suspend shorter than the reach bound is caught before the tick itself
gets a chance to) -- and open a grace window: the stale streak is
dropped, a pending wait retries the fresh daemon at once, and misses
inside the window hold the streak at the first tier without ever counting
toward the notice. Detection is idempotent within the window, since more
than one timer can notice the same resume.

Pinned by MaxMad75's reading: the window is armed by the resume, not by
the first miss. Verified on his X390 (S3, frozen sessions): six lid-close
cycles, fingerprint-resume at +15ms, streak held, notice never fired.

Co-authored-by: MaxMad75 <44462964+MaxMad75@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Only let a definitive probe change whether fingerprint is configured

The status probe collapsed every fprintd-list result into yes or no, so
an unreachable fprintd -- restarting under the resume hook, or failing a
D-Bus activation mid-resume -- read as "not configured": the icon
vanished, the retry loop and the sleep watch stopped, and nothing asked
again for the rest of the lock. One transient miss killed fingerprint
until the next lock, with the password as the only clue. MaxMad75 hit it
on hardware in run 6 of the X390 series; osborng filed the stock repro as
#9453 (mask fprintd, lock, unmask -- fingerprint never returns).

Classify the probe's output instead: an enrolled-print row is yes,
fprintd's explicit no-prints answer (or a missing PAM file or binary) is
no, and anything else is unknown -- the probe could not tell, so nothing
changes and it is retried on the attempt-retry pacing. The unavailable
notice, backoff, and resume detection all sit downstream of this flag;
now only an answer that actually means something can clear it.

Fixes #9453.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Log the fingerprint loop's misses, notice, and recovery as lock events

The reach timeout, an unreached settle, the streak crossing into the
notice, a resume restart, and the recovery all changed lock state without
touching logEvent, so a report of "Fingerprint reader unavailable" left
no omarchy lock line to line up with suspend and resume timestamps in
omarchy-debug-idle output. Log those transitions; reached attempts are
the steady state and stay quiet. A match that unlocks after a run of
misses is the recovery too -- the unlock resets the streak without
settling, so it logs fingerprint-recovered there as well.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Abort an attempt stranded in flight when a resume is detected

A verify that survived into the suspend still prompted comes back to a
daemon the resume hook has already replaced, and the loop's resume
handling deliberately left it alone: the reach timer stopped at the
prompt, so nothing bounded it but pam_fprintd's own ~25s timeout, and
until that ran out the icon invited touches that could not work. Most
visible where user sessions are not frozen across sleep and the lock
races the hook.

Abort the stranded session when the resume is detected and route it
through settle: it lands inside the grace window, so the kill never
counts toward the notice, and the settle arms the fast retry against the
fresh daemon itself.

Suggested by sliekens in review.

Claude-Session: https://claude.ai/code/session_0168egYTXrVBVg16ugszGzQt

* Simplify fingerprint recovery and consolidate enrollment checks

Use the enrolled-entry matcher from #9551 while retaining the lock's tri-state probe recovery and the privileged /usr/bin/fprintd-list call. Unknown enrollment probes must preserve existing PAM and resume recovery rather than deleting the machinery needed to recover. Preserve administrator-owned unnumbered timeout files during migration.

Remove presence-driven retry overrides and their cooldown, clock, and idle-window state: resume has its own fast recovery path, while other errors can follow the bounded automatic backoff. Let the existing sleep watcher detect resume instead of also tracking the age of each retry. Setup now uses apply-lock so PAM and recovery installation have one implementation. Keep the restart, stop bound, unreachable-attempt pacing, unavailable feedback, reach watchdog, and probe rechecks because each handles a distinct failure.

Co-Authored-By: Karl Ahlin <kalle.ahlin@gmail.com>
Co-Authored-By: Codex Medium <noreply@openai.com>

* Preserve failed-enrollment coverage in the setup fixture

The successful-enrollment fixture accepts PAM commands, so failure checks must explicitly reject those commands instead of relying on an unexpected-command error. Log both sed and tee and stub apply-lock for every case so premature authentication setup is detected without reaching live PAM files.

Co-Authored-By: Codex Medium <noreply@openai.com>

* Complete fingerprint recovery and setup reporting

Back off immediate device errors after the verification prompt as well as failed claims, while retaining fast retries for mismatches and normal scan timeouts. Measure from the prompt so a slow claim cannot hide a fast failure. Paced user activity retries preserve the daemon idle window required to clear a wedged claim. Initial probe outages remain visible without inventing enrollment, and setup cannot claim lock-screen success when the PAM configuration was not installed. Exercise the real QML service rather than a copy of its state machine.

Co-Authored-By: GPT-6 <noreply@openai.com>

Co-Authored-By: Claude Opus 5.5 Medium <noreply@anthropic.com>

* Avoid competing fingerprint probes and partial setup

Known enrollment is recovered by the PAM retry loop, so failed status probes must not raise a false unavailable notice or interrupt its daemon idle window. Initial unknown enrollment still gets paced probes. Install recovery files before enabling fingerprint PAM so a missing source cannot leave a new partial configuration.

Co-Authored-By: GPT-6 <noreply@openai.com>

Co-Authored-By: Claude Opus 5.5 Medium <noreply@anthropic.com>

* Keep the fingerprint error clock at the first prompt

pam_fprintd also sends Verification timed out as an informational message. Updating the prompt timestamp on that message made a normal full scan window look like an immediate device error and caused unnecessary backoff. Record the first prompt of each PAM attempt so later status messages cannot move the error window.

Co-Authored-By: GPT-6 <noreply@openai.com>

---------

Co-authored-by: Omabot <omabot@omarchy.org>
Co-authored-by: MaxMad75 <44462964+MaxMad75@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Karl Ahlin <kalle.ahlin@gmail.com>
Co-authored-by: Omarchy Bot <omarchybot@users.noreply.github.com>
2026-10-04 12:49:44 -04:00
David Heinemeier Hansson cb865c2fa4 Merge pull request #9873 from Wheel-Smith/fix/polkit-faillock-system-auth
Defer to system-auth in the polkit stack written by fingerprint/FIDO2 setup
2026-10-04 07:37:24 -04:00
LM 21cf0db6e9 Update shell tests for operand delimiters 2026-09-12 20:10:41 +02:00
adcc96a782 Install libfprint-git for every fingerprint reader (#10442)
* Use updated libfprint-git for fingerprint setup on edge

* Pick the fingerprint driver from the reader, not the release channel

The channel gate blocked every edge and dev user until the newer
libfprint-git pin is published, misrouted dev checkouts on the stable
mirror, and left the stock-libfprint migration reverting the driver on
accounts without its marker. Key both the setup and the migration on
omarchy-hw-fingerprint-git, a USB ID table of readers stock libfprint
cannot drive, so the git snapshot only goes where it is needed on any
channel. Qualify the package with the omarchy repo, and skip pacman
entirely when the packages are already current so a rerun cannot become
a partial upgrade.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Install libfprint-git for every fingerprint reader

Stock libfprint lags upstream on new readers, and gating the git
snapshot per reader or per channel only added machinery to keep in sync
with the package repo. Install libfprint-git unconditionally instead:
the omarchy-pkgs pin is the single place a new reader gets enabled. The
migration that swapped it back to stock goes away with the policy it
enforced; late updaters keep the driver they have and pick up the new
pin as a normal package upgrade.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: powderluv <powderluv@powderluv.org>
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 11:58:30 +02:00
rattatuiandClaude Opus 4.8 8a13eac872 Defer to system-auth in the polkit stack written by fingerprint/FIDO2 setup
The fingerprint and FIDO2 setup commands create /etc/pam.d/polkit-1 from
scratch on Arch, where the polkit package ships its stack in
/usr/lib/pam.d/polkit-1 and /etc/pam.d/polkit-1 does not exist. The
hand-rolled stack listed pam_unix directly instead of including system-auth,
which dropped pam_faillock from the polkit path: polkit prompts had no
brute-force lockout, their failures were not recorded, and they did not count
toward the lockout protecting login and sudo. Defer to system-auth, matching
the vendor file and the sudo stack, keeping the clamshell gate and the
pam_fprintd / pam_u2f sufficient lines in front.

Add a migration to repair installs the old setup already configured, since the
forward fix does not rewrite an existing polkit-1. It acts only on an
Omarchy-created polkit-1 that lacks the system-auth include and carries a
hardware-auth marker, preserves the configured auth lines, backs up the
original, and is idempotent.

Add a test asserting the stack each setup creates defers to system-auth; the
created polkit content was previously untested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 21:41:53 +03:00
Ryan Hughes 58c399de30 Revert "Drop unrelated privileged heredoc scanner"
This reverts commit 4c23077f80.
2026-08-30 11:54:31 -04:00
Ryan Hughes 4c23077f80 Drop unrelated privileged heredoc scanner 2026-08-30 11:49:50 -04:00
acrogenesis d593847728 Fail the suite on privileged writes through unquoted heredocs
An installer that writes a root-owned file through a heredoc with an
unquoted delimiter (<<EOF rather than <<'EOF') has the installing user's
shell expand the body first, so a user-controlled value is baked in as a
literal. Send that into /etc and root later reads or executes a path the
unprivileged user picked: a udev rule carrying
$HOME/.local/share/omarchy/bin/... resolves through a symlink that user
owns, so replacing the symlink gets their code run as root.

Add the static check. A heredoc is flagged when its delimiter is
unquoted, its body contains an install-time expansion (escaped \$VAR does
not count, since that is left for a root daemon to expand at runtime),
and its output reaches /etc, /usr, /opt, /srv, /boot or /var/lib via sudo
tee, sudo dd, a redirect, or an install/cp/mv of the generated scratch
file. Destinations written as variables are resolved from the file's own
assignments.

Sites that genuinely need install-time expansion declare it inline:

  # omarchy:heredoc-expands paths=none -- $servers is a validated IP list

paths= is machine-checked against the expansions the scanner finds to be
path-shaped, so this cannot become a rubber stamp: adding a $HOME/... to
an already-annotated heredoc makes the declaration false and trips the
check again. Path expansions anchored under a root-owned prefix, as in
"/etc/systemd/system/$unit", are correctly not path-shaped.

Annotate the sites the scan reports, each of which expands a scalar: DNS
addresses in omarchy-dns, a literal PAM line in
omarchy-setup-security-fingerprint, kernel cmdline parameters and
usernames in omarchy-upgrade-to-quattro. omarchy-provision-owner expanded
a unit name that was already a constant, so its delimiter is now quoted
and the name hardcoded; the generated unit file is byte-identical.
omarchy-windows-vm declares paths=storage,shared, the only site that
interpolates a user-chosen path.

Fixtures prove non-vacuity in both directions: the write routes other
than a pipe into sudo tee, the shapes that must stay quiet, udev rules
and a shutdown unit taken verbatim from this repository's history, and
the rubber-stamp case where a paths=none annotation on a baked $HOME path
still fails.
2026-08-29 19:23:02 -06:00
9b03f15b4f Detect Elan match-on-chip fingerprint readers again (#6578)
* Detect Elan match-on-chip fingerprint readers again

Elan readers report "ELAN:ARM-M4" as their product string, so the
*fingerprint* and *biometric* checks miss them. Elan's 04f3 is also left
out of the vendor list on purpose, because Elan makes touchscreens too.
Both checks fail, so the machine looks like it has no reader.

Add "elan:arm-m4" to the product string check. The comment above the
vendor list already says the excluded vendors should still match there,
so this makes that true. The vendor list and its has_kernel_driver guard
are unchanged, and touchscreens still cannot cause a false positive.

The string is a family name, not one device. libfprint uses it for
04f3:0c9c and 04f3:0ca7 as well as 04f3:0ca8.

Tested on an HP EliteBook X G2i with 04f3:0ca8.

* Point the Elan comment at the vendor list above it

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Configure PAM only after a fingerprint enrolls and verifies

Detection proves a reader is present, not that libfprint can drive it.
Elan MOC sensors outside the elanmoc table pass the gate and then fail
to enroll, which left pam_fprintd in the sudo and polkit stacks with no
print to match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 21:54:01 +02:00
David Heinemeier HanssonandClaude Fable 5 f01acc1de9 Go back to stock libfprint now that 1.94.100 ships FocalTech MOC
libfprint-git only existed to carry the focaltech_moc driver and the
FocalTech FT9349 (2808:a97a) ID ahead of a release. libfprint 1.94.100
has both and is in the Arch repos, so fingerprint setup installs stock
libfprint again and a migration swaps existing installs back.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 12:31:04 -07:00
David Heinemeier HanssonandClaude Opus 4.8 cb9485f216 Gate sudo fingerprint behind lid state too
Extend the clamshell gate to /etc/pam.d/sudo, not just polkit-1. When the
lid is shut the reader is unreachable, so a terminal sudo would block on
"Place your finger" until pam_fprintd timed out before letting you type the
password. The same pam_exec gate (success=1 skips fingerprint when the lid
is closed) now runs ahead of pam_fprintd in the sudo stack as well.

setup and removal share one gate definition across sudo and polkit; the
migration now gates both stacks on existing installs.

Resolves the clamshell case in #856 and supersedes #6003.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 15:29:22 -07:00
David Heinemeier HanssonandClaude Opus 4.8 e2bf0daaa8 Invite fingerprint setup on first run when a reader is present
Add a first-run notification, alongside the keybindings/Wi-Fi toasts, that
invites anyone with a fingerprint sensor to enable it. Clicking launches
omarchy-setup-security-fingerprint in a floating terminal.

Detection lives in a new omarchy-hw-fingerprint helper that reads sysfs
(device product descriptor plus a fingerprint-vendor allowlist), so it
works before fprintd/usbutils are installed and without nagging machines
that have no reader. The setup script reuses the same helper as an early
gate, bailing before installing any packages when no reader is found
(replacing the old post-install fprintd-list probe).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 14:05:31 -07:00
David Heinemeier HanssonandClaude Opus 4.8 540e411edf Show fingerprint on lock screen and polkit, gated by lid state
Bring the fingerprint affordance to the Quickshell lock screen and polkit
dialog, matching what hyprlock did on master.

Lock screen: render the md-fingerprint glyph inside the password field's
right edge when a sensor is enrolled, reserving space so long passwords
never run under it.

Polkit dialog: show one method at a time. When a sensor is enrolled and
the reader is reachable, the dialog is just the centered fingerprint icon
(square card); the moment PAM asks for a password it switches to the
password field. Detects pam_fprintd anywhere in the auth stack now that a
gate can precede it.

Lid awareness: a closed lid means the reader is unreachable, so both
surfaces fall back to the password. polkit gets a pam_exec clamshell gate
(auth [success=1 default=ignore] before pam_fprintd) so a shut lid drops
straight to the password prompt instead of blocking on the reader for the
pam_fprintd timeout; the lock screen hides the icon and skips scanning.

The gate points at the fixed /usr/bin path the package always provides so
it survives switching between package installs and dev-link. A migration
adds the gate for existing fingerprint setups.

New helper omarchy-hw-laptop-closed (pure lid state); omarchy-hw-clamshell
now composes it with the external-monitor check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 13:51:07 -07:00
David Heinemeier Hansson 6cec42d97d Merge branch 'omarchy-4' into quattro 2026-06-08 16:28:52 +02:00
David Heinemeier Hansson ae7365f937 Fix repeated fingerprint setup 2026-05-27 21:20:39 +02:00
David Heinemeier Hansson 7ea4e1ab04 Switch hyprlock to QS 2026-05-19 17:08:14 +02:00
David Heinemeier Hansson 30f9a8da54 Not worth the extraction 2026-05-08 20:52:29 +02:00
David Heinemeier Hansson 45db959daf Split fido2 and fingerprint setups into setup and remove (#5670)
* Split fido2 and fingerprint setups into setup and remove

Don't make one thing do two things

* Extract helpers and clean up

* No need to hide them

* Don't need these
2026-05-08 16:41:20 +02:00