
تسجيل الدخول ببصمة الإصبع على سطح مكتب لينكس باستخدام مستشعر Grow R503 + أردوينو + برنامج خفي بديل لـ fprintd مكتوب بلغة Rust
قارئ بصمات 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 للتصميم الكامل، بما في ذلك ما لا يغطيه نموذج التهديد.

ليتني أملك طابعة ثلاثية الأبعاد…``` ┌──────────┐ 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 لنظام لينكس نادرة ومكلفة، والموجودة منها (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/main/SPEC.md) لمعرفة السبب (خط RX في R503 يتحمل 5V عمليًا؛ ورقة البيانات تكذب).
## التوصيلات```
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، فاقطع سلك توصيل (pigtail) من 6 سنون من نوع JST-SH إلى 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. ستعرض بيئة التطوير المتكاملة تثبيته عند أول تجميع.
إذا فشل أمر arduino-cli upload مع ظهور not in sync: resp=0x7e، فإن محمّل الإقلاع (bootloader) لديك هو النوع الآخر — بدّل 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)
المستخدم من قبل بوابة التحقق من هوية المتصل/etc/dbus-1/system.d/net.reactivated.Fprint.conf) — فقط أعضاء root و
wheel يمكنهم التحدث إلى الخفي؛ أي شخص آخر يحصل على AccessDenied
عند الوسيط، قبل أن يرى الخفي الاستدعاءr503d.serviceإنه idempotent — أعد تشغيله بعد كل cargo build --release لإعادة
نشر الثنائي الجديد.
Nano المُومض حديثًا غير مقترن — قد يتحدث الخفي معه لكن البرنامج الثابت سيرفض كل أمر مؤطّر. اختر أحد التدفقين أدناه؛ كلاهما ينتهي بـ Nano مقترن وخفي يعمل. التدفق المُغلّف بـ TPM موصى به إذا كان مضيفك يحتوي على TPM2 (انظر المتطلبات الأساسية للفحص السريع).
ملف الاشتراك الاختياري (/etc/r503d/allow-pair) المستخدم في كلا التدفقين موجود
لمنع مهاجم يندفع إلى مكتبك حاملًا Nano خاصًا به — الاقتران بدون صلاحية root
مستحيل. الأمر r503d --pair يحذف العلامة قبل إرسال المفتاح إلى Nano:
إذا تعطل المضيف بين إتمام الجانب الخاص بـ Nano وحفظ جانب المضيف،
تكون البوابة قد أُغلقت بالفعل، لذا تتطلب محاولة الاقتران التالية
من المسؤول إعادة touch للعلامة. وأي خروج قبل الإرسال
(لا توجد علامة، أو "already paired") يترك العلامة سليمة لإعادة المحاولة.