
دردشة طرفية آمنة. مشفرة من طرف إلى طرف، خادم إعادة توجيه أعمى بدون بيانات وصفية. PyNaCl XSalsa20-Poly1305 + Ed25519 + forward secrecy. متعدد المنصات بلغة Python.
دردشة جماعية مشفرة من النهاية إلى النهاية، ورسائل خاصة، ونقل ملفات في طرفيتك. الخادم هو مُمرِّر أعمى: لا يمكنه قراءة رسائلك، ولا يعرف اسم المستخدم الخاص بك، ولا يعرف الغرفة التي أنت فيها، ولا يمكنه ربط أي رسالتين بنفس الشخص، حتى لو تم اختراقه بالكامل.
https://github.com/user-attachments/assets/d9faabfb-73bd-46dd-92b2-23f63daf5b06
https://github.com/user-attachments/assets/e8e0220d-cd7d-45a2-9443-9a5f20b57f12
https://github.com/user-attachments/assets/15fb383d-a02a-433e-bbd9-8ebadecf9481
https://github.com/user-attachments/assets/bca10cb1-6959-425d-96d6-fc1fbf845538
NoEyes هي أداة محادثة طرفية بلغة Python للمجموعات الصغيرة الموثوقة. الخادم لا يفك تشفير أي شيء أبدًا ولا يرى هويتك أبدًا - فهو يتعامل فقط مع الرموز المعتمة ويُمرِّر البايتات المشفرة.
أنت تُنشئ المفتاح، وتشاركه خارج النطاق، ولا يعلم الخادم شيئًا عن محادثاتك.
مفيد للمجموعات الصغيرة الموثوقة التي تريد اتصالات مشفرة دون الثقة بأي خادم طرف ثالث، أو لاستضافة محادثة خاصة ذات تشفير حقيقي من النهاية إلى النهاية، أو لأي شخص يريد أن يفهم بالضبط ما يمكن للخادم رؤيته وما لا يمكنه رؤيته.
python ui/setup.py
python ui/launch.py
`ui/launch.py` يرشدك خلال بدء خادم أو الاتصال بأحدها.
---
### الخيار ب - إذا لم يتم تثبيت بايثون بعد
| المنصة | شغل هذا أولاً |
|---|---|
| Linux / macOS / Termux / iSH | `sh install/install.sh` |
| Windows | `install\install.bat` |
كلا البرنامجين النصيين يقومان بتثبيت بايثون إذا كان مفقودًا، ثم يحولان المهمة إلى `setup.py` تلقائيًا.
---
### الخيار ج - يدوي```bash
# 1. Install dependencies
pip install cryptography PyNaCl
# 2. On the server machine — generate the access key
python noeyes.py --generate-access-key
# Prints an access code hex string — share with clients via USB
# 3. On a client machine — generate chat.key from the access code
python noeyes.py --generate-chat-key <ACCESS_CODE_HEX> --key-file ./chat.key
# Distribute chat.key to all other clients via USB. Never put it on the server.
# 4. Start the server (does NOT need the key file)
python noeyes.py --server --port 5000
# Start without bore tunnel (LAN / static IP / custom tunnel)
python noeyes.py --server --port 5000 --no-bore
# Start without adding a firewall rule (not needed when using bore tunnel)
python noeyes.py --server --port 5000 --no-firewall
# 5. Connect clients - each person needs their own identity file
python noeyes.py --connect SERVER_IP --port 5000 --username alice --key-file ./chat.key --identity-path ~/.noeyes/identity_alice.key
python noeyes.py --connect SERVER_IP --port 5000 --username bob --key-file ./chat.key --identity-path ~/.noeyes/identity_bob.key
مهم: يجب أن يكون لكل مستخدم ملف هوية خاص به. عند مشاركة عميلين لنفس ملف الهوية، يحصلان على نفس رمز صندوق الوارد وسيرفض الخادم الثاني كجلسة مكررة. يتم إنشاء ملف الهوية تلقائيًا عند التشغيل الأول، فقط مرر
--identity-pathفريدًا لكل مستخدم.
قم بتنزيل Termux من F-Droid (موصى به): https://f-droid.org/packages/com.termux/
حافظ على استمرارية الجلسة - قم بتثبيت tmux حتى يستمر NoEyes في العمل عند تبديل التطبيقات:```bash pkg install tmux -y tmux python ui/launch.py
**أذونات التخزين** - سيفشل نقل الملفات بدون هذا:```bash
termux-setup-storage
▶.كل نصف يُمرّر بشكل مستقل. اضغط ^P لإخفاء اللوحة للحصول على عرض دردشة بعرض كامل.
أضف بادئة لأي رسالة باستخدام !tag لتلوينها للجميع وتشغيل صوت إشعار. الوسوم تنتقل داخل الحمولة المشفرة، ولا يراها الخادم أبداً.
أمثلة:``` !danger server is going down in 5 minutes !ok deployment successful !req can someone review my PR?
تصدر الأصوات من مجلد `sfx/`. ضع ملفات `.wav` أو `.mp3` أو `.ogg` أو `.aiff` أو `.flac` أو `.m4a` مسماة حسب الوسم (مثال: `sfx/danger.wav`). يرجع إلى جرس الطرفية إذا لم يُعثر عليها. استخدم `/notify off` لتعطيل جميع الأصوات.
---
## البنية
> 🗺️ **[خريطة الأمان التفاعلية الحية](https://ymsniper.github.io/NoEyes/)** — تفصيل مرئي لهندسة التشفير الكاملة، نموذج التهديد، والتوجيه بدون بيانات وصفية في رسم تخطيطي تفاعلي.```
┌──────────────────────────────────────────────────────────────────────┐
│ Alice ──────────────────────────────────────────── Bob │
│ │ Encrypted payload (opaque) │ │
│ │ │ │ │
│ └────────────► SERVER ─┴◄──────────────────────────┘ │
│ │ │
│ Zero-metadata blind forwarder: │
│ routes by opaque inbox tokens only │
│ { "to": "3f9a1c...", "type": "privmsg" } │
│ forwards encrypted bytes verbatim │
└──────────────────────────────────────────────────────────────────────┘
WHAT THE SERVER SEES: WHAT THE SERVER NEVER SEES:
· Encrypted bytes it can't read · Usernames or display names
· Opaque inbox tokens (blake2s) · Room names
· Opaque room tokens (blake2s) · Who is messaging whom
· Frame byte length · Message content
· Connection timing · File contents
· Ed25519 public keys
· DH key exchange values
يقوم كل عميل بحساب رمزين معتمين محليًا قبل الاتصال:``` inbox_token = blake2s(identity_vk_bytes, digest_size=16) room_token = blake2s((room_name + group_key_hex).encode(), digest_size=16)
يقوم الخادم بتوجيه جميع الإطارات بواسطة هذه الرموز فقط. لا يخزن أبدًا أسماء العرض أو أسماء الغرف أو المفاتيح العمومية. تنتقل هوية المرسل **داخل** الحمولة المشفرة (مرسل مغلق)، وليس في عنوان التوجيه.
### سلسلة اشتقاق المفاتيح```
chat.key (shared secret)
│
├─ BLAKE2b("general") ──► room_key["general"] (isolated per room)
├─ BLAKE2b("dev") ──► room_key["dev"]
└─ BLAKE2b("ops") ──► room_key["ops"]
X25519 DH (per user pair, automatic on first /msg)
alice_ephemeral + bob_ephemeral ──► shared_secret
│
BLAKE2b
│
pairwise_key (private messages)
│
BLAKE2b(transfer_id) ──► chacha20_key (files)
password + random_salt (32 bytes, os.urandom) │ └─ BLAKE2b(password, key=salt, person="identity_v2") │ derived_key ──► encrypts Ed25519 signing key at rest
كل ملف هوية يحصل على ملح عشوائي فريد، جداول قوس قزح عديمة الفائدة.
---
## ملخص الأمان
| الطبقة | الآلية | ملاحظات |
|---|---|---|
| السرية التامة للأمام (الترس) | مفاتيح المرسل — سلسلة BLAKE2b KDF + XSalsa20-Poly1305 لكل رسالة | مفتاح فريد لكل رسالة، تقدم سريع للرسائل الفائتة |
| الدردشة الجماعية | XSalsa20-Poly1305 (PyNaCl secretbox) | مفتاح لكل غرفة عبر BLAKE2b |
| الرسائل الخاصة | XSalsa20-Poly1305 مع مفتاح X25519 زوجي | موقعة بـ Ed25519، تم التحقق منها عبر TOFU |
| نقل الملفات | ChaCha20-Poly1305 | مفتاح لكل نقل عبر BLAKE2b، موقعة بـ Ed25519، إيقاف مؤقت/استئناف عبر إعادة الاتصالات |
| هوية المرسل | مرسل مختوم | اسم المستخدم + التوقيع داخل الحمولة المشفرة، أبدًا في رأس التوجيه |
| الهوية | زوج مفاتيح Ed25519 | ملف هوية لكل مستخدم، مشفر بكلمة مرور مع BLAKE2b + ملح عشوائي |
| اشتقاق المفاتيح | BLAKE2b (PyNaCl) | مفصولة المجال عبر معامل التخصيص، لا توجد جداول قوس قزح |
| توجيه الخادم | رموز blake2s غير شفافة | الخادم لا يخزن أبدًا أسماء المستخدمين أو أسماء الغرف أو المفاتيح العامة |
| النقل | TLS (مفعل افتراضيًا) | تثبيت شهادة TOFU، عدم تطابق البصمة يقطع الاتصال |
| تكامل DH | مفاتيح DH العامة الموقعة بـ Ed25519 | يمنع هجوم الوسيط على تبادل المفاتيح الزوجية |
| حماية إعادة التشغيل | deque معرف الرسالة لكل غرفة | الرسائل المعاد تشغيلها تُسقط بصمت |
| حماية DoS | حد الاتصال + مهلة الانضمام + تحديد المعدل | حد أقصى 200 اتصال، مهلة انضمام 10 ثوانٍ |
| عزل الغرفة | `BLAKE2b(master_key, room_name)` | معزولة تشفيريًا لكل غرفة |
### نموذج التهديد
تم تصميم NoEyes لـ **المجموعات الصغيرة الموثوقة**. يوفر حماية قوية ضد:
- مراقبي الشبكة السلبيين - جميع حركة المرور مشفرة بـ TLS + E2E
- مرحل bore.pub المخترق - يرى المرحل فقط البايتات المشفرة وتوقيت الاتصال
- آلة الخادم المخترقة - الخادم خالٍ من المعرفة، لا شيء مفيد في الذاكرة العشوائية
- هجوم الوسيط على الاتصال - تثبيت شهادة TLS + مفاتيح DH الموقعة بـ Ed25519
- سرقة جهازك - مفتاح الهوية مشفر بكلمة مرور عند التخزين
- هجمات إعادة التشغيل - حماية إعادة التشغيل لكل غرفة تعتمد على MID
---
## تشغيل خادم عبر الإنترنت (bore pub)
عند بدء تشغيل خادم NoEyes في المنزل، يحصل جهازك على عنوان IP محلي. لكي يتمكن شخص خارج شبكتك من الاتصال بك، ستحتاج عادةً إلى إعادة توجيه منفذ على جهاز التوجيه الخاص بك، وهو ما يفشل غالبًا بسبب CGNAT أو الحظر على مستوى الناقل.
**bore pub** يحل هذه المشكلة باستخدام نفق آمن من جهازك إلى مرحل عام، مما يمنح خادمك عنوانًا عامًا فوريًا دون لمس جهاز التوجيه الخاص بك.
**bore** هي أداة نفق TCP مفتوحة المصدر من [إريك تشانغ (@ekzhang)](https://github.com/ekzhang/bore). عند تشغيل خادم NoEyes، يبدأ تلقائيًا:```
bore local 5000 --to bore.pub
يقوم التتابع بتعيين منفذ عشوائي ويطبع عنوانًا مثل bore.pub:12345. شارك ذلك مع مجموعتك:```bash
python noeyes.py --connect bore.pub --port 12345 --key-file ./chat.key --username alice --identity-path ~/.noeyes/identity_alice.key
كل شيء لا يزال مشفرًا من طرف إلى طرف، و bore يقوم فقط بإعادة توجيه البايتات الخام.
### إعادة الاتصال التلقائي عبر تغييرات منفذ bore
يقوم bore.pub بتعيين **منفذ عشوائي عند كل إعادة تشغيل للخادم**. في العادة، هذا يعني ضرورة مشاركة العنوان مع الجميع في كل مرة. يتعامل NoEyes مع هذا تلقائيًا بثلاث طبقات استرداد:
**1. حدث الترحيل (فوري)**
عندما يعيد bore تعيين منفذ، يبث الخادم حدث `migrate` موقع إلى جميع العملاء المتصلين مع رقم المنفذ الجديد. يقوم العملاء بفصل الاتصال بصمت، وتحديث المنفذ، وإعادة الاتصال تلقائيًا. نافذة هدوء مدتها 15 ثانية تكتم ضوضاء الانضمام/المغادرة حتى لا تفلتر شاشة الدردشة.
**2. خدمة الاكتشاف (العملاء الذين فاتهم حدث الترحيل)**
إذا كان العميل غير متصل عند تغيير المنفذ، فإنه يستقصي خدمة مجانية للمفتاح-القيمة مجهولة (`keyvalue.immanuel.co`) عند كل محاولة إعادة اتصال. يقوم الخادم بنشر منفذ bore الجديد هناك تلقائيًا في كل مرة يعاد فيها تشغيل bore. مفتاح البحث مشتق من مفتاح مجموعتك، لا حاجة لحساب أو تسجيل، مجهول بالكامل.
**3. المنفذ في `auth_ok` (استرداد بعد التعطل)**
إذا فات العميل كل شيء (تعطل الخادم، لم يُبث حدث الترحيل)، يقوم الخادم بتضمين منفذ bore الحالي في استجابة المصافحة `auth_ok`. يقوم العميل بتصحيح نفسه تلقائيًا عند الاتصال الناجح التالي.
تغييرات منفذ bore.pub شفافة بالنسبة للمستخدمين. تستمر الدردشة تلقائيًا في غضون ثوان، وتتوقف عمليات نقل الملفات مؤقتًا وتستأنف من حيث توقفت.
لتعطيل الاكتشاف (إعداد معزول عن الشبكة أو مرحل خاص):```bash
python noeyes.py --connect bore.pub --port 12345 --key-file ./chat.key --no-discovery
| القيد | التفاصيل |
|---|---|
| لا ضمان لوقت التشغيل | bore.pub هي خدمة تطوعية، قد تنقطع |
| المنفذ عشوائي | كل بدء تشغيل للخادم يحصل على منفذ مختلف، أعد مشاركة العنوان |
| ليست للإنتاج | لإعداد دائم، استخدم VPS مع --no-bore |
لأكثر من ~10 مستخدمين، أو تشغيل على مدار الساعة، أو اسم مضيف مستقر، قم بالتشغيل على VPS رخيص (Hetzner €4/شهر، DigitalOcean $4/شهر، الطبقة المجانية لـ Oracle Cloud):```bash python noeyes.py --server --port 5000 --no-bore
### ملاحظات حول جدار الحماية
لا تحتاج **إلى** قاعدة جدار حماية عند استخدام bore tunnel. تحتاج إليها فقط للاتصالات المباشرة (شبكة محلية، عنوان IP ثابت، إعادة توجيه المنفذ يدويًا):```bash
python noeyes.py --server --port 5000 --no-firewall # bore tunnel, skip firewall rule
python noeyes.py --server --port 5000 --no-bore --no-firewall # VPS, manage firewall separately
python noeyes.py --generate-access-key
python noeyes.py --generate-chat-key <ACCESS_CODE_HEX> --key-file ./chat.key
python ui/launch.py # → Generate Key
cp ~/.noeyes/identity.key /backup/identity.key
cat ~/.noeyes/tofu_pubkeys.json
## هيكل المشروع```
NoEyes/
├── noeyes.py Entry point and CLI argument parser
├── requirements.txt pip dependencies (just: cryptography)
│
├── core/
│ ├── encryption.py All crypto: XSalsa20-Poly1305, ChaCha20-Poly1305, X25519, Ed25519, BLAKE2b
│ ├── ratchet.py Sender Keys forward secrecy: SenderChain + RatchetState
│ ├── animation.py CRT boot and ratchet activation animations with SFX
│ ├── sounds.py Cross-platform sound playback (WAV/MP3, Linux/macOS/Windows)
│ ├── identity.py Ed25519 keypair generation and TOFU pubkey store
│ ├── utils.py Terminal output, ANSI colours, TUI chrome
│ └── config.py Configuration loading and CLI parsing
│
├── network/
│ ├── server.py Async zero-metadata blind-forwarder server
│ ├── client.py Terminal chat client (E2E, DH, TOFU, file transfer)
│ ├── client_ratchet.py RatchetMixin — /ratchet command flow, migration wait
│ ├── client_dh.py X25519 DH handshake mixin
│ ├── client_send.py Outgoing message encryption (static + ratchet paths)
│ ├── client_recv.py Incoming frame routing and decryption
│ └── client_commands.py Input loop, command dispatch, help
│
├── ui/
│ ├── launch.py Guided launcher, arrow-key menu UI
│ └── setup.py Dependency wizard, auto-installs what's needed
│
├── install/
│ ├── install.sh Bootstrap for Linux / macOS / Termux / iSH
│ ├── install.bat Bootstrap for Windows (CMD and PowerShell)
│ ├── install.py Cross-platform Python installer
│ └── uninstall.py Remove all NoEyes dependencies for clean reinstall
│
├── docs/
│ ├── README.md This file
│ └── CHANGELOG.md Version history
│
├── update.py Self-updater, pulls latest from GitHub
└── sfx/ Notification sounds
PyNaCl (XSalsa20-Poly1305, BLAKE2b) + cryptography (ChaCha20-Poly1305, X25519, Ed25519, TLS)threading (خيوط الاستلام + الإدخال + الإرسال لكل عميل)، asyncio على الخادمtermios لإدخال ضغط المفاتيح الخام⚠️ لأغراض البحث والتعليم فقط - مشروع تجريبي.
| الميزة | التفاصيل |
|---|
| خادم بدون بيانات وصفية | الخادم لا يرى أسماء المستخدمين، أو أسماء الغرف، أو المفاتيح العامة، فقط رموزًا معتمة |
| مرسل مختوم | هوية المرسل موجودة داخل الحمولة المشفرة، وليس في رأس التوجيه |
| خادم مُمرِّر أعمى | بدون فك تشفير، الخادم يُمرِّر الكتل المشفرة التي لا يستطيع قراءتها |
| سرية توجيهية | /ratchet start — بروتوكول مفاتيح المرسل، كل رسالة تُشفَّر بمفتاح مشتق فريد، الرسائل السابقة آمنة حتى لو تسرب المفتاح الحالي |
| دردشة جماعية | مفاتيح لكل غرفة باستخدام XSalsa20-Poly1305 مستمدة عبر BLAKE2b، الغرف معزولة تشفيريًا |
| رسائل خاصة | مصافحة X25519 DH عند أول اتصال، مفتاح زوجي لا يملكه إلا الطرفان |
| نقل ملفات | بث ChaCha20-Poly1305، أي حجم، استخدام منخفض للذاكرة، إيقاف مؤقت/استئناف عبر إعادة الاتصال |
| هوية Ed25519 | مفتاح توقيع مولّد تلقائيًا، جميع الرسائل والملفات موقعة |
| TOFU | المفاتيح التي تُرى أولاً تُوثق؛ عدم تطابق المفاتيح يظهر تحذيرًا أمنيًا مرئيًا |
| ملح PBKDF2 عشوائي | كل نشر يحصل على ملح عشوائي فريد، جداول قوس قزح عديمة الفائدة |
| TLS + تثبيت الشهادة | النقل مشفر، شهادة الخادم تُثبت عند أول اتصال عبر TOFU |
| حماية من إعادة التشغيل | قائمة معرفات الرسائل لكل غرفة، الرسائل المُعاد لعبها تُسقط بصمت |
| لوحة جانبية مقسمة | الغرف (أعلى) والمستخدمون (أسفل) مرئيان دائمًا، كل نصف يتحرك بشكل مستقل |
| رسوم متحركة CRT عند بدء التشغيل | تأثير فوسفوري ملء الشاشة مع صوت عند بدء التشغيل |
| رسوم متحركة لتفعيل الراتشيت | تأثير CRT ملء الشاشة مع فن ميكانيكي من البرايل، وميض خلل، ومسح كشاف ضوئي، ومؤثرات صوتية متزامنة، وانتقال واجهة النص إلى اللون الأحمر |
| مُشغِّل موجه | قائمة لوحة المفاتيح باستخدام مفاتيح الأسهم، لا حاجة لخبرة سطر الأوامر |
| مثبت تبعيات تلقائي | يكتشف نظامك، يُثبِّت المفقود، يطلب الإذن قبل تغيير أي شيء |
| الأمر | الوصف |
|---|
/help | عرض جميع الأوامر |
/quit | قطع الاتصال والخروج |
/clear | مسح الرسائل من الشاشة |
/users | عرض قائمة المستخدمين في الغرفة الحالية |
/join <room> | التبديل إلى غرفة (تحذير إذا كان في راتشيت نشط) |
/leave | العودة إلى الغرفة العامة (تحذير إذا كان في راتشيت نشط) |
/msg <user> <text> | إرسال رسالة خاصة مشفرة من طرف إلى طرف |
/send <user> <file> | إرسال ملف مشفر |
/whoami | عرض بصمة هويتك |
/trust <user> | الوثوق بمفتاح جديد لمستخدم بعد إعادة تثبيته |
/notify on|off | تبديل أصوات الإشعارات |
/ratchet start | اقتراح مفاتيح دوارة ذات سرية أمامية لجميع أعضاء الغرفة (يجب أن يؤكد الجميع) |
/ratchet invite <u> | إعادة دعوة مستخدم إلى الراتشيت بعد عودته (يؤدي إلى إعادة تشغيل كاملة - لا يتم تمرير مفاتيح السلسلة) |
/proceed | أثناء انتظار الترحيل، التصويت على إسقاط نظير غير متصل واستئناف العمل |
| المفتاح | الإجراء |
|---|
↑ / ↓ | التمرير لأعلى/لأسفل في الدردشة |
PgUp / PgDn | تمرير الدردشة صفحة كاملة |
^P (Ctrl+P) | إظهار/إخفاء اللوحة الجانبية |
^C | الخروج |
| الوسم | اللون | الاستخدام |
|---|
!ok <msg> | 🟢 أخضر | نجاح، تأكيد، تم |
!warn <msg> | 🟡 أصفر | تحذير، تنبيه |
!danger <msg> | 🔴 أحمر | حرج، عاجل، طارئ |
!info <msg> | 🔵 أزرق | تحديث حالة، للإعلام |
!req <msg> | 🟣 أرجواني | طلب، يحتاج إجراء |
!? <msg> | 🩵 سماوي | سؤال، طلب إدخال |
| المنصة | مدير الحزم المستخدم |
|---|
| Ubuntu / Debian / Mint | apt-get |
| Fedora / RHEL / CentOS | dnf / yum |
| Arch / Manjaro | pacman |
| Alpine / iSH (iOS) | apk |
| openSUSE | zypper |
| Void Linux | xbps-install |
| macOS | Homebrew (مثبت تلقائيًا إذا كان مفقودًا) |
| Android (Termux) | pkg |
| ويندوز | winget / Chocolatey / Scoop |