The vendor-ID guess rejects any device with a driver bound, on the reasoning that libfprint drives readers from userspace so a real one sits there unbound. But libusb claims interfaces through a synthetic usbfs driver, so the reader binds one for as long as fprintd holds the claim — which is exactly while it is being enrolled or verified against. Readers that name themselves take the product-string branch and never reach this, so the exposure is the ones that don't: Goodix 27c6:6594 reports "Goodix USB2.0 MISC", matches on vendor ID alone, and drops out of detection mid-authentication. The menu entry disappears and the first-run invitation stops firing while the reader is in use. Ignore a driver link that resolves to usbfs, and keep rejecting the real ones — usbio-bridge, usbhid, uvcvideo — including on a device that has both. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
57 lines
2.6 KiB
Bash
Executable File
57 lines
2.6 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Returns true when a fingerprint reader is present
|
|
# omarchy:hidden=true
|
|
|
|
# Detect straight from sysfs so this works before fprintd/usbutils are
|
|
# installed (the fingerprint setup pulls those in). USB vendor IDs listed here
|
|
# ship fingerprint readers; multi-purpose vendors (e.g. Elan/STMicro, which
|
|
# also make USB touchscreens) are left out to avoid nagging laptops with no
|
|
# reader — those still match on the product string below when present.
|
|
fingerprint_vendors=" 27c6 138a 06cb 08ff 1c7a 147e "
|
|
usb_devices_path="${OMARCHY_USB_DEVICES_PATH:-/sys/bus/usb/devices}"
|
|
|
|
# libfprint drives every reader it supports from userspace over libusb, so a
|
|
# real reader sits there with no kernel driver bound to any of its interfaces.
|
|
# The other things these vendors build — Synaptics webcam bridges (usbio-bridge
|
|
# on the Dell XPS 14), touchpads and touchscreens (usbhid), cameras (uvcvideo)
|
|
# — all bind one. Only the vendor-ID guess needs this; a device that names
|
|
# itself a fingerprint reader is trusted outright.
|
|
has_kernel_driver() {
|
|
local intf driver
|
|
for intf in "$1"/*:*; do
|
|
[[ -e $intf/driver ]] || continue
|
|
# usbfs is the exception: libusb claims an interface through it, so a reader
|
|
# fprintd is enrolling or verifying against binds a driver for as long as it
|
|
# holds the claim. That is userspace driving the device — what a reader is
|
|
# supposed to look like — so it must not read as a kernel driver here.
|
|
driver=$(readlink -f "$intf/driver")
|
|
[[ ${driver##*/} == "usbfs" ]] || return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
for dev in "$usb_devices_path"/*; do
|
|
# The device's own product descriptor usually names it, e.g. "Goodix
|
|
# Fingerprint USB Device" — driver-independent and vendor-agnostic.
|
|
if [[ -r $dev/product ]]; then
|
|
product=$(<"$dev/product")
|
|
product=${product,,}
|
|
# Elan's match-on-chip readers report "ELAN:ARM-M4" and Fingerprint Cards'
|
|
# report "FPC Sensor Controller" or "FPC L:0000 FW:1425046" — the family or
|
|
# the manufacturer rather than the function. Both vendors are left out of
|
|
# the list above on purpose (Elan also makes touchscreens), so without these
|
|
# they match nothing. FPC leads the string on every reader on record, and
|
|
# three letters are little to match on, so require the prefix.
|
|
[[ $product == *fingerprint* || $product == *biometric* || $product == *elan:arm-m4* || $product == "fpc "* ]] && exit 0
|
|
fi
|
|
|
|
if [[ -r $dev/idVendor ]]; then
|
|
vendor=$(<"$dev/idVendor")
|
|
[[ $fingerprint_vendors == *" $vendor "* ]] &&
|
|
! has_kernel_driver "$dev" && exit 0
|
|
fi
|
|
done
|
|
|
|
exit 1
|