
Вход в систему Linux по отпечатку пальца с использованием датчика Grow R503 + Arduino + демона на Rust, заменяющего fprintd
Самодельный USB-сканер отпечатков пальцев для Linux. Общая стоимость компонентов менее $15. Замена для штатного fprintd — PAM, настройки KDE, настройки GNOME, fprintd-verify, sudo с пальцем, разблокировка экрана пальцем — всё работает.
Начиная с fw=1.0 / r503d 1.0.0 провод Arduino↔хост аутентифицирован: каждая команда и ответ содержат MAC SipHash-2-4, привязанный к секрету, установленному по принципу TOFU в EEPROM. Атаки повторного воспроизведения и горячей замены на последовательный USB-канал блокируются. Полное описание, включая то, что не покрывает угрозная модель, см. в SPEC.md §13.

жаль, что у меня нет 3D-принтера…``` ┌──────────┐ UART ┌─────────────┐ USB-CDC ┌──────────────────┐ │ Grow │ 57600 8N1│ Arduino │ /dev/r503 │ r503d daemon │ │ R503 │◀─────────▶│ (firmware) │◀──────────▶│ net.reactivated │ │ sensor │ 3.3V TTL │ │ framed, │ .Fprint on D-Bus│ └──────────┘ └─────────────┘ MAC'd └──────────────────┘ │ ▼ PAM, KDE, GNOME, fprintd-verify, …
## Зачем
Аппаратные USB-сканеры отпечатков пальцев для Linux — редкость, дороги, а те,
что существуют (Validity, Synaptics и т.д.), работают через обратно разработанные
нестабильные драйверы libfprint, которые ломаются при обновлениях прошивки вендора.
Протокол Grow R503 **открыт**, сторона Arduino — ваш собственный код,
а уровень совместимости с libfprint — просто D-Bus.
В итоге вы получаете сканер отпечатков пальцев, код которого можно прочитать
от корки до корки.
## Список материалов
| Деталь | Примечания | Примерная цена |
|--------|------------|------|
| Ёмкостный датчик отпечатков пальцев Grow R503 | Круглый с RGB-кольцом | ~$10 |
| Плата Arduino Uno R3 / Nano / Mega / любая на ATmega328 | Любая, поддерживающая SoftwareSerial | $5–$25 |
| 4–6 перемычек | Dupont / макетная плата | копейки |
Вот и всё. **Никакого преобразователя уровней, никакого делителя напряжения** — см. [`SPEC.md` §3.1](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md)
почему (линия RX у R503 на практике терпит 5 В; даташит врёт).
## Подключение```
R503 Arduino (Uno R3 / Nano / etc.)
---- ------------------------------
Red (VCC) 3V3
White (3.3VT) 3V3 (touch-IC supply; shares rail with red)
Black (GND) GND
Yellow (TXD) D2 ── SoftwareSerial RX
Brown (RXD) D3 ── SoftwareSerial TX (direct — no divider!)
Blue (WAKEUP) D4 (optional; not used by firmware yet)
Если ваш R503 поставляется с разъемом JST-SH, отрежьте 6-контактный переходник JST-SH-to-Dupont, чтобы разделить провода. Коричневый иногда бывает зеленым в зависимости от продавца — проверяйте по проводу, который идет в контакт RXD разъема JST, а не по цвету.
Протестировано на Fedora 44 KDE; должно работать на любом дистрибутиве на основе systemd с fprintd, pam_fprintd и актуальной цепочкой инструментов Rust.
Системные пакеты:
| Дистрибутив | Сборка | Среда выполнения |
|---|---|---|
| Fedora / RHEL | rust cargo arduino-cli tpm2-tss-devel | fprintd pam fprintd-pam tpm2-tss |
| Debian / Ubuntu | rustc cargo arduino-cli libtss2-dev | fprintd libpam-fprintd libtss2-esys-3.0.2-0 |
Пакеты tss-esapi нужны только в том случае, если вы планируете использовать --pair --seal-tpm (SPEC §13.12). В остальных случаях демон собирается и запускается без TPM — tss-esapi является жесткой зависимостью сборки, но мягкой зависимостью времени выполнения (код запускается только когда существует /var/lib/r503d/key.tpm).
Rust 1.95+, arduino-cli в вашем $PATH.
У вас есть TPM2?```bash ls /dev/tpmrm0 && tpm2_pcrread sha256:7 | head -3
Если обе операции успешны, ваш хост может использовать путь с запечатанным ключом. Если `/dev/tpmrm0` отсутствует (старое оборудование, TPM отключен в BIOS или виртуальная машина без виртуального TPM), придерживайтесь стандартного потока с открытым ключом.
## Сборка и установка
### 1. Прошейте прошивку
Откройте `firmware/r503fp/r503fp.ino` в Arduino IDE и загрузите. Или с помощью `arduino-cli`:```bash
# Uno R3:
arduino-cli compile --fqbn arduino:avr:uno firmware/r503fp/
arduino-cli upload --fqbn arduino:avr:uno --port /dev/ttyACM0 firmware/r503fp/
# Nano (modern Optiboot, including most Elegoo / WAVGAT clones):
arduino-cli compile --fqbn arduino:avr:nano:cpu=atmega328 firmware/r503fp/
arduino-cli upload --fqbn arduino:avr:nano:cpu=atmega328 --port /dev/ttyUSB0 firmware/r503fp/
# Nano with legacy 57600-baud bootloader (older clones):
# replace `cpu=atmega328` with `cpu=atmega328old`
Прошивка использует Adafruit_Fingerprint. IDE предложит установить её
при первой компиляции.
Если arduino-cli upload завершается ошибкой not in sync: resp=0x7e, ваш загрузчик
— другой вариант — замените atmega328 ↔ atmega328old и повторите попытку. Оба
работают; разница лишь в скорости загрузчика.
Требуется Rust 1.95+.```bash cd pcside/daemon cargo build --release
### 3. Установка```bash
sudo bash pcside/daemon/dist/install.sh
That script:
target/release/r503d в /usr/local/bin/r503d/var/lib/r503d/ (режим 0700 root:root) для ключа, состояния и реестра пользовательских слотов/dev/r503 и блокирует узел устройства с правами root:root 0600 (только демону, работающему от root, он нужен; это закрывает путь по умолчанию 0660 root:dialout, так что ни один другой локальный пользователь не сможет открыть порт — аудит безопасности 2026-05-28 / H1). Следствие: после установки любая ручная команда arduino-cli/serial-monitor для /dev/r503 требует sudo./etc/systemd/system/r503d.service)net.reactivated.Fprint/usr/share/polkit-1/actions/net.reactivated.fprint.device.r503d.policy), используемое шлюзом идентификации вызывающегоОн идемпотентен — повторно запускайте его после каждого cargo build --release, чтобы развернуть новый бинарник.
Недавно прошитый Nano не сопряжён — демон будет с ним общаться, но прошивка будет отклонять каждую команду. Выберите один из двух описанных ниже способов; оба приводят к сопряжённому Nano и работающему демону. Способ с TPM-запечатыванием рекомендуется, если на вашем хосте есть TPM2 (см. раздел «Предварительные требования» для быстрой проверки).
Файл разрешения (/etc/r503d/allow-pair), используемый в обоих способах, существует для предотвращения атаки, при которой злоумышленник спешит к вашему рабочему месту со своим собственным Nano — сопряжение без root невозможно. r503d --pair удаляет маркер до отправки ключа на Nano: если хост выйдет из строя между подтверждением на стороне Nano и сохранением на стороне хоста, шлюз уже будет закрыт, поэтому следующая попытка сопряжения потребует от администратора снова создать маркер с помощью touch. Досрочное завершение (нет маркера или «уже сопряжено») оставляет маркер нетронутым для повторной попытки.
Используйте это, если у вас нет устройства TPM2 или если вам не нужна защита от атак на офлайн-диск.```bash sudo systemctl stop r503d sudo mkdir -p /etc/r503d sudo touch /etc/r503d/allow-pair # opt-in (see SPEC §13.5) sudo r503d --pair # 128-bit key → /var/lib/r503d/key sudo systemctl start r503d
Приложение также позволяет настраивать переключатели подсказок и меток при отображении результатов. Кроме того, вы можете экспортировать результаты в нескольких форматах, включая Markdown, CSV и обычный текст.
## Возможности
- **Многоформатный экспорт**: Сохраняйте извлеченные данные в формате Markdown, CSV или обычного текста.
- **Переключатель подсказок и меток**: Настройте поведение подсказок и меток при просмотре данных.
- **Интерфейс командной строки (CLI)**: Автоматизируйте процесс извлечения с помощью встроенного инструмента CLI.
- **Обновления в реальном времени**: Отслеживайте ход и обновления во время процесса извлечения.
- **Удобный интерфейс**: Навигация по данным с помощью четкого и организованного пользовательского интерфейса.
## Использование CLI
После установки вы можете запустить инструмент из командной строки:
```bash
extract-scan -i input.txt -o output.csv
Полный список доступных опций можно получить командой:
extract-scan --help
Если вы предпочитаете интегрировать этот инструмент в свои сценарии Python, вы можете импортировать основной модуль:
from core import extract_data
data = extract_data('input.txt', format='csv')
Для получения дополнительных сведений обратитесь к документации.
Этот проект лицензирован по лицензии MIT — подробности см. в файле LICENSE.```bash sudo r503d --status
#### 4b. TPM-опечатанное связывание (рекомендуется на хостах с TPM2, SPEC §13.12)
Тот же процесс, плюс `--seal-tpm`. Сгенерированный ключ опечатывается для **PCR7** (политика Secure Boot + ключи) и записывается в `/var/lib/r503d/key.tpm` вместо файла `key` в открытом виде. Атакующие с offline-доступом к диску (`dd` несмонтированного раздела, замена SSD во враждебный хост) получат только шифротекст.```bash
sudo systemctl stop r503d
sudo mkdir -p /etc/r503d
sudo touch /etc/r503d/allow-pair
sudo r503d --pair --seal-tpm # seals new key to current PCR7
sudo systemctl start r503d
hexway или отправьте pull request.
# Build Docker image
docker build -t apple_bleee .
# Run in an interactive mode
docker run -it --net=host --privileged apple_bleee
# Run in "headless" mode
# Using the predefined SSID and WIFI password of the desired network
docker run -it --net=host --privileged apple_bleee -m headless --ssid <SSID> --wifi-password <WIFI_PASSWORD>
# Run in "headless" mode with specific Actions on triggers:
# If Apple device is discovered, show db.py contents
docker run -it --net=host --privileged apple_bleee -m headless -at show_db -d </path/to/db>
# If the victim connected to the Wi-Fi, log a specific message
docker run -it --net=host --privileged apple_bleee -m headless -ac log -c "Hello, World!"
# To perform BLE DoS attack run:
docker run -it --net=host --privileged apple_bleee -m dos
# To perform BLE Spam attack run:
docker run -it --net=host --privileged apple_bleee -m spam
# To perform Password Phishing attack:
docker run --rm --net=host -v </path/to/save/passwords/>:/root/captures/ -e DISPLAY=host.docker.internal:0 --privileged apple_bleee -m phishing -p /root/captures
# AppleJuice attack:
docker run -it --net=host --privileged apple_bleee -m juice
Первоначальная настройка:
sudo -i
apt update && apt install -y python3-pip libglib2.0-dev libbluetooth-dev
git clone https://github.com/hexway/apple_bleee.git && cd apple_bleee
Установка зависимостей:
# Install requirements for the tool
pip3 install -r requirements.txt
# Install utils for Wi-Fi and DoS attacks
sudo apt install -y aircrack-ng
Скопируйте конфигурацию или добавьте её вручную:
config.json пример с учетными данными WiFi для DoS-атаки (опционально):
{
sudo r503d --status
# port: /dev/r503
# firmware: fw=1.1 fmt=2
# firmware paired: true
# firmware counter: 12
# host key.tpm: /var/lib/r503d/key.tpm
# host key: (missing)
# host key.bak: (missing)
# tpm device: /dev/tpmrm0
# allow-pair: (absent)
```
Обновления ядра, обновления initrd, обновления прошивки UEFI через `fwupd` и обновления grub2 **не** изменяют PCR7 и не требуют перезапечатывания. PCR7 изменяется только при редактировании политики Secure Boot, регистрации MOK или перемещении диска на другой хост — в этом случае демон отказывается запускаться с ошибкой `TPM_RC_POLICY_FAIL`, и `dist/reseal-tpm.sh` восстанавливает работу примерно за 90 секунд. См. раздел [Восстановление: PCR7 изменён](#recovery-pcr7-changed-need-to-reseal).
### 5. Регистрация и проверка```bash
# Enroll a finger (use KDE Settings → Users → Fingerprint Auth for a GUI):
fprintd-enroll mat
# Verify:
fprintd-verify mat
# sudo with finger:
sudo whoami
```
Оба диалога — Настройки KDE (Plasma 6) и диалог учётной записи пользователя в GNOME Control Center — управляют `r503d` точно так же, как они управляют вышестоящим `fprintd`.
### Повторная привязка / ротация ключа
Если вам нужен новый ключ (компрометация ключа, плановая замена оборудования, паранойя):```bash
sudo systemctl stop r503d
sudo r503d --unpair # framed; wipes Nano EEPROM + host key
sudo touch /etc/r503d/allow-pair
sudo r503d --pair # plaintext-key rotation
# - or -
sudo r503d --pair --seal-tpm # TPM-sealed rotation
sudo systemctl start r503d
```
**Совпадайте с вашим исходным путем сопряжения.** Если вы изначально использовали `--seal-tpm`, выполняйте ротацию с помощью `--seal-tpm` — в противном случае ротация незаметно понизит вас до ключа в открытом виде на диске.
### Восстановление: PCR7 изменился, требуется повторное запечатывание
Если вы использовали `--pair --seal-tpm` и позже изменили что-то, что измеряет PCR7 (Secure Boot выключен/включен, зарегистрирован новый MOK, диск перемещен на другую машину), демон откажется запускаться с сообщением в журнале о `TPM_RC_POLICY_FAIL`. Восстановление — одна команда:```bash
sudo bash pcside/daemon/dist/reseal-tpm.sh
```
Скрипт останавливает `r503d`, перепрошивает `firmware/r503fp_wipe/` для очистки EEPROM Nano, перепрошивает основную прошивку, создаёт `/etc/r503d/allow-pair`, запускает `r503d --reseal-tpm` для генерации нового ключа, запечатанного к *текущему* PCR7, и снова запускает демон. Примерное время: ~90 секунд. Зарегистрированные отпечатки сохраняются — шаблоны хранятся во флеш-памяти датчика R503, а не Nano.
Скрипту требуется наличие `arduino-cli`. Если он установлен в `$HOME/.local/bin` пользователя, он определяется автоматически через `$SUDO_USER`; в противном случае установите `ARDUINO_CLI=/full/path/to/arduino-cli` перед запуском.
### Восстановление: утерян `state.json` (рассинхронизация счётчика)
Если хост-ключ цел, но `/var/lib/r503d/state.json` отсутствует или откатился (восстановлена старая резервная копия, случайное удаление), счётчик демона отстаёт от `last_seen` Nano, и каждая кадрированная команда возвращает `ERR replay`. `r503d --status` сообщает об этом; исправление — одна команда:```bash
sudo systemctl stop r503d
sudo r503d --resync # reads Nano last_seen, sets host counter to last_seen+1
sudo systemctl start r503d
```
Без повторной привязки, без перепрошивки — ключ никогда не перемещается. Запрос `status`, на который полагается `--resync`, не требует аутентификации, но он может только *переместить* счётчик хоста вперёд, чтобы он соответствовал тому, что уже зафиксировал Nano, поэтому он никогда не может сделать старый кадр воспроизводимым (в худшем случае лгущий MITM вызывает ещё один `ERR replay`, что он мог бы сделать и так, искажая кадры). См. [`SPEC.md` §13.11](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md).
### Восстановление: хост-ключ полностью утерян
Аутентифицированная команда `--unpair` требует ключ для авторизации. Если все копии на диске утеряны (сбой диска, случайное удаление, оба файла `key` + `key.bak` удалены, или потерян `key.tpm` blob), вам понадобится запасной выход **reflash-to-wipe** — та же процедура, которую автоматизирует `dist/reseal-tpm.sh` для случая с изменённым PCR7 выше:```bash
sudo systemctl stop r503d
# /dev/r503 is root:root 0600 since install (audit H1), so the uploads need root.
sudo arduino-cli upload --fqbn arduino:avr:nano:cpu=atmega328 --port /dev/r503 firmware/r503fp_wipe/
# Wait ~1s for the wipe to complete (LED starts blinking — that's the wipe sketch).
sudo arduino-cli upload --fqbn arduino:avr:nano:cpu=atmega328 --port /dev/r503 firmware/r503fp/
sudo touch /etc/r503d/allow-pair
sudo r503d --pair
sudo systemctl start r503d
```
Если `sudo arduino-cli` сообщает «команда не найдена» (arduino-cli находится в вашем `~/.local/bin`, а не в `PATH` пользователя root), запустите его как `sudo env "PATH=$PATH" arduino-cli …` или укажите абсолютный путь.
Это не бэкдор, которым может воспользоваться злоумышленник: повторное сопряжение требует прав root на хосте (файл опционального согласия и CLI-флаг `--pair` требуют root), поэтому перепрошитый Nano не может быть доверенным, если у вас нет прав root.
### Удаление```bash
sudo bash pcside/daemon/dist/uninstall.sh
```
Отменяет всё, снимает маскировку `fprintd`, оставляет `/var/lib/r503d/` (ключ, состояние, пользователи) на месте на случай, если вы захотите переустановить позже. Удалите этот каталог вручную, если хотите получить полностью чистую установку.
## Как это работает
Arduino запускает небольшую прошивку с ASCII-протоколом (`firmware/r503fp/`), которая общается с нативным двоичным протоколом R30x ("Sync Word") R503 на своей стороне UART и обменивается построчными текстовыми командами с хостом через USB-CDC: `ping`, `info`, `enroll N`, `verify`, `delete N`, `clear`, `led off`. Полный протокол v1 в [`SPEC.md` §5](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md).
Начиная с `fw=1.0` (Milestone E работы с аутентифицированным каналом v2), каждая команда и ответ обёрнуты в кадр `C <counter> <body> M <mac>` / `R <counter> <seq> <body> M <mac>`, MAC-кодированные с помощью SipHash-2-4 поверх TOFU-сопоставленного 128-битного ключа. Nano хранит монотонный счётчик с выравниванием износа в EEPROM; демон хранит соответствующий счётчик в `/var/lib/r503d/state.json`. Попытки воспроизведения (на стороне прошивки `incoming <= last_seen`) отклоняются как `ERR replay`; подделанные кадры отклоняются как `ERR mac_invalid`. Полные спецификация, модель угроз и известные ограничения в [`SPEC.md` §13](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md).
Демон на Rust (`r503d`) общается через D-Bus на `net.reactivated.Fprint` — бит-в-бит тем же интерфейсом, который предоставляет upstream `fprintd` — так что каждый клиент `fprintd` работает без изменений. JSON-файл рядом с `/var/lib/r503d/users.json` сопоставляет (пользователь, палец) с индексами слотов во внутренней flash R503.
Структура:```
firmware/r503fp/ Arduino firmware (v2 framed ASCII protocol)
firmware/r503fp_wipe/ Emergency one-shot EEPROM wipe (lost-key recovery)
firmware/* Diagnostic / development sketches (ping, loopback, ...)
pcside/daemon/ Rust daemon (the fprintd replacement)
pcside/daemon/src/{crypto,framing,keystore,state,pairing}.rs
v2 wire protocol implementation
pcside/daemon/src/auth.rs caller-identity gating for D-Bus methods
pcside/daemon/dist/ udev rule, systemd unit, polkit + bus policy,
install scripts
docs/ Decision logs + troubleshooting
SPEC.md Full architecture + protocol spec (§13 = v2 auth)
```
## Модель безопасности — краткое резюме
Аутентификация на уровне проводов нацелена на конкретную угрозу — **«злая горничная с пятью минутами и запасным Nano»** плюс враждебный локальный процесс на `/dev/r503` — а не на национальные государства или аппаратных атакующих с лабораториями. Развёртывание на однопользовательском десктопе с задокументированным списком того, что не входит в область действия. Полная модель угроз находится в [`SPEC.md` §13.1](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md); доказательства реализации и проверки находятся в [`docs/REVIEW-2026-05-28.md`](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/docs/REVIEW-2026-05-28.md). Отдельный аудит эскалации привилегий от злоумышленника (2026-05-28) и его проход по проверке/исправлению каждого утверждения находятся в [`docs/SECURITY-AUDIT-2026-05-28.html`](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/docs/SECURITY-AUDIT-2026-05-28.html) и [`docs/SECURITY-AUDIT-2026-05-28-VALIDATION.html`](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/docs/SECURITY-AUDIT-2026-05-28-VALIDATION.html).
**Защищено:**
- Горячая замена Nano на враждебное устройство (нет ключа → все кадры не проходят MAC).
- Локальный процесс, внедряющий поддельные ответы match на `/dev/r503`. Два уровня: узел устройства имеет права `root:root 0600` (правило udev), и демон удерживает его с помощью `TIOCEXCL`, поэтому не-root процесс не может его открыть — и даже если бы мог, у него нет ключа, поэтому кадр не проходит проверку MAC.
- Повторное воспроизведение записанных кадров `OK match=...` в будущем сеансе.
- Повреждение любого поля кадра путём изменения битов (постоянное по времени сравнение MAC).
- Исчерпание счётчика: пир (или одноразовый MITM во время `--resync`), доводящий монотонный счётчик до `u64::MAX` и навсегда блокирующий канал, блокируется зарезервированным потолком счётчика, применяемым на обоих концах (`fw=1.1+`; SPEC §13.4 / аудит от 2026-05-28 DoS-2).
- Отказ в обслуживании датчика локальным пользователем: один шлюз слотов захвата ограничивает текущую работу по enroll/verify, а пути удаления заблокированы действиями, поэтому поток `Start`/`Stop` (или одновременных удалений) не может заблокировать аутентификацию.
- Подмена, удаление или перечисление отпечатков пальцев другим пользователем локальным не-root пользователем (например, `mallory` вызывает `Claim "root"`, а затем записывает свой палец) — идентификатор вызывающего проверяется на каждом методе D-Bus, принимающем `username`, и политика системной шины запрещает не-`wheel` вызывающим на уровне брокера.
- **Атаки на ключ хоста с офлайн-диска** *в сочетании с `--seal-tpm`*: ключ на диске запечатан TPM2 в PCR7, поэтому `dd` размонтированного раздела или замена SSD во враждебный хост даёт только зашифрованный текст. Распаковывается только на той же машине при той же политике Secure Boot. См. [SPEC §13.12](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md).
**Не защищено:**
- Компрометация root на хосте (ключ находится в `/var/lib/r503d/key`, `0600 root:root`). Root на работающем хосте также может распечатать вариант, запечатанный TPM — запечатывание ослабляет *офлайн*-атаки, не онлайн.
- Физическая атака на Nano (чтение EEPROM ~30 сек с ISP; вскрытие чипа; и т.д.).
- Атака перепрошивкой прошивки (загрузчик Arduino не имеет подписи — но повторное сопряжение требует root на хосте, поэтому перепрошитый Nano невозможно ввести в доверие без компрометации хоста).
- Компрометация со стороны R503 (протокол R30x вообще не имеет аутентификации; вне нашей области охвата).
- **Криптостойкость.** MAC на SipHash-2-4, 128-битный общий ключ, 64-битный вывод MAC, разделённые по доменам входы MAC. Две независимые реализации (самописный C++ на AVR с самотестированием KAT при загрузке; самописный Rust на хосте, побитно перекрёстно проверенный против стороннего крейта `siphasher` на 1024 случайных векторах в CI). Сравнение MAC на хосте использует `subtle::ConstantTimeEq`. Парсеры провода подвергаются property-fuzzing на каждом запуске CI (~135 000 входов). `cargo audit` чист. Ключ SipHash обёрнут в `zeroize::Zeroizing<...>`, так что он стирается при удалении (как и буферы MAC-входа для каждого кадра). Цель libFuzzer для `cargo fuzz` поставляется в `pcside/daemon/fuzz/` для запусков с длинным корпусом на nightly. Платного стороннего аукта человеком нет — он всё ещё был бы ценен, PR приветствуются.
Полная модель угроз с обоснованием: [`SPEC.md` §13.1](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md).
## Ограничения
- **Многопользовательский режим работает, но только для членов группы `wheel`.** Идентификатор вызывающего проверяется на каждом методе D-Bus, который принимает `username` (`Claim`, `EnrollStart`, `VerifyStart`, `ListEnrolledFingers`, `DeleteEnrolledFingers`); запросы от самого себя и `uid 0` (PAM) успешны, запросы от другого пользователя от не-root вызывающего отклоняются с `net.reactivated.Fprint.Error.PermissionDenied`. Политика системной шины дополнительно ограничивает, какие учётные записи могут даже начать диалог: только `root` и члены `wheel` достигают демона, все остальные получают `org.freedesktop.DBus.Error.AccessDenied` на уровне брокера. Нужно записать отпечаток другого пользователя? Станьте root: `sudo fprintd-enroll target-user`. Нужно ослабить ограничение межпользовательского доступа для киоска / многопользовательской лаборатории? Поместите правило JS в `/etc/polkit-1/rules.d/`, нацеленное на [`net.reactivated.fprint.device.setusername`](https://gitlab.freedesktop.org/libfprint/fprintd/-/blob/master/src/net.reactivated.fprint.device.policy.in) — имя действия полностью соответствует upstream fprintd.
- **Одно устройство чтения.** Демон выставляет один объект Device на D-Bus. Настройки с несколькими устройствами чтения требуют расширения Manager.
- **Нет отправки `PropertiesChanged`** для подсказок свойств `finger-present` / `finger-needed`. Каждый распространённый клиент fprintd (PAM, KDE Settings, GNOME) работает от сигналов `EnrollStatus` / `VerifyStatus` (которые отправляются), а не от этих опрашиваемых подсказок — но строгий клиент, использующий `Get + PropertiesChanged`, увидит устаревшие значения.
- **Один Nano = единственная точка отказа.** Если Nano выйдет из строя, вход по отпечатку пальца будет недоступен, пока вы не перепрошьёте запасной и не выполните повторное сопряжение. Оставьте включённым метод аутентификации по паролю как резервный.
- **Потерю State.json можно восстановить одной командой.** Если `state.json` потерян, а в прошивке всё ещё высокий `last_seen`, демон при первой отправке выдаст `ERR replay`. Запустите `sudo r503d --resync` для чтения счётчика Nano и выравнивания хоста — повторное сопряжение не требуется. См. [`SPEC.md` §13.11](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md).
## Устранение неполадок```bash
# Daemon logs:
sudo journalctl -u r503d.service -f
# Confirm the sensor enumerates correctly:
ls -l /dev/r503
busctl --system call net.reactivated.Fprint /net/reactivated/Fprint/Device/0 \
net.reactivated.Fprint.Device ListEnrolledFingers s ""
# Confirm fprintd is masked and r503d owns the bus name:
systemctl is-enabled fprintd # should print "masked"
busctl --system list | grep -i fprint
```
Если демон не запускается или сенсор никогда не отвечает, наиболее распространённое решение — это проводка — см. [`SPEC.md` §3](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/SPEC.md), особенно примечание **"без делителя напряжения"** в §3.1. Более подробная инструкция находится в [`docs/TROUBLESHOOTING.md`](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/docs/TROUBLESHOOTING.md).
## License
MIT — см. [LICENSE](https://github.com/matpb/linux-fingerprint-r503/blob/HEAD/LICENSE).
## Credits
- [Adafruit_Fingerprint](https://github.com/adafruit/Adafruit-Fingerprint-Sensor-Library) — реализация протокола R30x на стороне Arduino.
- [zbus](https://github.com/dbus2/zbus),
[serialport-rs](https://github.com/serialport/serialport-rs),
[tokio](https://tokio.rs/) — стек Rust для D-Bus / последовательного порта / асинхронности.
- Проект `fprintd` — за разработку чистого интерфейса D-Bus, под который этот демон мог быть реализован, не читая исходный код `libfprint`.
/etc/dbus-1/system.d/net.reactivated.Fprint.conf) — только члены групп root и wheel могут общаться с демоном; все остальные получают AccessDenied от брокера, прежде чем демон увидит вызовfprintd.servicer503d.service