# سير عمل تسجيل الدخول في نظام Siro ## توثيق شامل لتدفق المصادقة للمشرفين (Super Admin / Admin) وموظفي خدمة العملاء (Service Staff) --- ## 📋 فهرس المحتويات 1. [نظرة عامة على النظام](#نظرة-عامة-على-النظام) 2. [المكونات الرئيسية](#المكونات-الرئيسية) 3. [سير عمل تسجيل حساب مشرف جديد](#سير-عمل-تسجيل-حساب-مشرف-جديد) 4. [سير عمل تسجيل الدخول (المشرف - siro_admin)](#سير-عمل-تسجيل-الدخول-المشرف---siro_admin) 5. [سير عمل تسجيل الدخول (موظف الخدمة - siro_service)](#سير-عمل-تسجيل-الدخول-موظف-الخدمة---siro_service) 6. [سير عمل إضافة الموظفين من قبل المشرف العام](#سير-عمل-إضافة-الموظفين-من-قبل-المشرف-العام) 7. [سير عمل تفعيل الحسابات المعلقة](#سير-عمل-تفعيل-الحسابات-المعلقة) 8. [مقارنة بين تدفق siro_admin و siro_service](#مقارنة-بين-تدفق-siro_admin-و-siro_service) 9. [الجوانب الأمنية (Security)](#الجوانب-الأمنية-security) 10. [قائمة الإصلاحات الأمنية المُنفَّذة](#قائمة-الإصلاحات-الأمنية-المنفذة) 11. [الإجراءات الموصى بها للتحسين (Recommendations)](#الإجراءات-الموصى-بها-للتحسين-recommendations) --- ## نظرة عامة على النظام نظام Siro يستخدم بنية متعددة التطبيقات (Multi-App Architecture): | التطبيق | الدور | ملفات المصادقة | |---------|-------|-----------------| | **siro_admin** | المشرفون (Admin / Super Admin) | `siro_admin/lib/views/auth/login_page.dart`, `otp_helper.dart` | | **siro_service** | موظفو خدمة العملاء | `siro_service/lib/controller/login_controller.dart` | | **Backend (PHP)** | الخادم المركزي | `backend/Admin/auth/login.php`, `backend/serviceapp/login.php` | المبدأ الأساسي: **المصادقة متعددة العوامل (MFA)** تعتمد على: 1. **بصمة الجهاز (Fingerprint)** — يتم إنشاؤها في التطبيق وإرسالها مع كل طلب 2. **كلمة المرور** — مشفرة باستخدام `password_hash` 3. **OTP عبر WhatsApp** — للتحقق الإضافي (للمشرفين حصراً) 4. **JWT** — التوكن النهائي للوصول --- ## المكونات الرئيسية ### تطبيق siro_admin (المشرفون) | الملف | المسار | الوظيفة | |-------|--------|---------| | `login_page.dart` | `siro_admin/lib/views/auth/` | واجهة تسجيل الدخول (كلمة مرور + هاتف اختياري) | | `register_page.dart` | `siro_admin/lib/views/auth/` | واجهة طلب حساب مشرف جديد | | `otp_helper.dart` | `siro_admin/lib/controller/auth/` | منطق OTP وجدولة إعادة الدخول (Auto Login) | | `register_controller.dart` | `siro_admin/lib/controller/auth/` | منطق التسجيل | ### تطبيق siro_service (خدمة العملاء) | الملف | المسار | الوظيفة | |-------|--------|---------| | `login_controller.dart` | `siro_service/lib/controller/` | منطق تسجيل الدخول مع OTP | | (لا يوجد register) | | التسجيل يتم عبر `backend/serviceapp/register.php` أو عبر `add.php` | ### الباك إند (PHP) | الملف | المسار | الوظيفة | |-------|--------|---------| | `login.php` | `backend/Admin/auth/` | تسجيل دخول المشرف (الخطوة الأولى) | | `verify_login.php` | `backend/Admin/auth/` | التحقق من OTP للمشرف (الخطوة الثانية) | | `register.php` | `backend/Admin/auth/` | تسجيل مشرف جديد | | `login.php` | `backend/serviceapp/` | تسجيل دخول موظف الخدمة | | `register.php` | `backend/serviceapp/` | تسجيل موظف خدمة جديد | | `add.php` | `backend/Admin/Staff/` | إضافة موظف/مشرف من قبل المشرف العام | | `pending.php` | `backend/Admin/Staff/` | جلب الحسابات المعلقة | | `activate.php` | `backend/Admin/Staff/` | تفعيل الحسابات المعلقة | | `jwtService.php` | `backend/Admin/jwtService.php` | إصدار JWT لخدمة العملاء (قديم) | | `JwtService.php` | `backend/core/Auth/` | خدمة JWT الأساسية مع Authentication | --- ## سير عمل تسجيل حساب مشرف جديد ### 📍 يبدأ من تطبيق siro_admin ← `register_page.dart` ``` [المستخدم] [التطبيق (Flutter)] [الباك إند (PHP)] [قاعدة البيانات] | | | | |── يدخل الاسم، الهاتف، | | | | كلمة المرور | | | |─────────────────────────────>| | | | | | | | |── قراءة بصمة الجهاز (fingerprint) | | | | من `box.read('fingerprint')` | | | | | | | |── POST `/Admin/auth/register.php` | | | | مع: name, phone, password, fingerprint | | | |──────────────────────────────────────────>| | | | | | | | |── التحقق من القائمة البيضاء | | | | `AUTHORIZED_ADMIN_PHONES` | | | | في متغيرات البيئة (.env) | | | | | | | |── التحقق من التكرار: | | | | phone OR fingerprint_hash | | | | | | | |── تشفير البيانات: | | | | • name ← encryptData() | | | | • phone ← encryptData() | | | | • fingerprint ← encrypt() | | | | • fingerprint_hash = | | | | SHA-256(fingerprint) | | | | • password ← password_hash | | | | | | | |── توليد UUID آمن: | | | | bin2hex(random_bytes(16)) | | | | | | | |── INSERT INTO adminUser | | | | status = 'pending' | | | | role = 'admin' | | | |─────────────────────────────>| (id, fingerprint, fingerprint_hash, | | | | name, phone, password, role, | | | | status='pending', created_at) | | | | | |<── { status: "pending", message: "..." } | | | | | | |<── رسالة "تم تقديم الطلب" | | | ``` ### ملاحظات أمنية حول التسجيل: - ✅ القائمة البيضاء (`AUTHORIZED_ADMIN_PHONES`) تمنع أي شخص من التسجيل دون إذن مسبق - ✅ الاسم والهاتف والبصمة مشفرة في قاعدة البيانات - ✅ بصمة الجهاز محولة إلى SHA-256 Hash للبحث السريع - ✅ **`bin2hex(random_bytes(16))`** لتوليد UUID آمن — تم إصلاحه من `rand()` - 🔴 الحساب ينشأ بحالة `pending` ولا يمكنه الدخول حتى يتم تفعيله يدوياً --- ## سير عمل تسجيل الدخول (المشرف - siro_admin) ### 📍 يبدأ من `login_page.dart` ← `OtpHelper.loginWithPassword()` #### الخطوة الأولى: إرسال طلب الدخول ``` [المستخدم] [otp_helper.dart] [login.php (Backend)] [Redis / DB] | | | | |── يدخل كلمة المرور | | | | (ورقم الهاتف لأول | | | | مرة) | | | |──────────────────────>| | | | | | | | |── POST /Admin/auth/login.php | | | | payload: fingerprint, | | | | password, phone (اختياري), | | | | aud (اختياري), is_renewal | | | |──────────────────────────────────>| | | | | | | | |── Rate Limiting: | | | | 5 محاولات/دقيقة لكل IP | | | | | | | |── البحث بـ fingerprint_hash | | | | (SHA-256 للبصمة) | | | | | | | [إذا لم يوجد بالبصمة والهاتف موجود] | | | |── البحث بالهاتف المشفر | | | | (لأول مرة أو جهاز جديد) | | | | | | | |── التحقق من status: | | | | • pending → رفض مع رسالة | | | | • suspended → رفض | | | | • rejected → رفض | | | | • active → متابعة | | | | | | | |── التحقق من كلمة المرور: | | | | password_verify(password) | | | | | ``` #### التفرع حسب `is_renewal`: ``` | ┌───────────────┴───────────────┐ | | is_renewal=1 is_renewal=0 أو missing (إعادة دخول تلقائي) (تسجيل دخول يدوي) | | | ├── توليد OTP عشوائي | | (100000-999999) ← 6 أرقام | | | ├── فك تشفير رقم الهاتف | | ← إرسال OTP عبر WhatsApp | | | ├── حفظ OTP مشفراً: | | `token_verification_admin` | | (phone مشفر، token مشفر، | | expiration 10 دقائق) | | | └── رد: { status: "otp_required", | phone: masked } | ├── إلغاء التوكن القديم من Redis | (Token Revocation) | ├── توليد JWT جديد: | generateAccessToken(id, role, aud, fingerprint) | └── رد مباشر: { jwt, admin, expires_in } ``` ### الخطوة الثانية (عند طلب OTP): التحقق ← `verify_login.php` ``` [otp_helper.dart] [verify_login.php] [DB / Redis] | | | |── POST /Admin/auth/ | | | verify_login.php | | | payload: otp, | | | fingerprint, phone | | |────────────────────────────>| | | | | | |── Rate Limiting: | | | 3 محاولات OTP/5 دقائق لكل IP | | | | | |── البحث بالـ fingerprint_hash | | | من جدول adminUser | | | | | |── تشفير OTP المدخل | | | encryptData(otp) | | | | | |── البحث في token_verification: | | | phone_number = encryptedPhone | | | AND token = encryptedOtp | | | AND expiration >= NOW() | | | | | [غير صالح أو منتهي] | | |<── "رمز التحقق غير صالح" | | | | | | [صالح] | | | |── حذف OTP (استخدام لمرة واحدة) | | | DELETE FROM token_verification | | | | | |── إلغاء التوكن القديم من Redis | | | | | |── توليد JWT جديد: | | | generateAccessToken(id, role, | | | aud, fingerprint) | | | | |<── { jwt, admin, expires_in }| | | | | |── حفظ البيانات محلياً: | | | • JWT ← box.write(jwt) | | | • admin_id ← box.write | | | • admin_role ← box.write | | | • phoneVerified ← true | | | • admin_password ← حفظ | | | | | |── Get.offAll(AdminHomePage())| | ``` ### مخطط الحالة الكامل للمشرف (State Machine): ``` ┌───────────┐ │ Pending │ ← بعد التسجيل، بحاجة تفعيل └─────┬─────┘ │ Activate.php (يتطلب JWT مع role=admin) ▼ ┌─────────────────┐ │ Active │ ← يمكنه تسجيل الدخول └────────┬────────┘ │ ┌─────────┴──────────┐ │ │ ▼ ▼ ┌───────────┐ ┌───────────┐ │ Suspended │ │ Rejected │ └───────────┘ └───────────┘ ``` --- ## سير عمل تسجيل الدخول (موظف الخدمة - siro_service) ### 📍 يبدأ من `login_controller.dart` ← `login()` ``` [LoginController] [serviceapp/login.php] [DB / Redis] | | | |── قراءة البصمة من | | | box.read(fingerprint) | | | | | |── POST /serviceapp/login.php | | | payload: fingerprint, | | | password, email, | | | aud = "service" | | |────────────────────────────>| | | | | | |── Rate Limiting: | | | 5 محاولات/دقيقة لكل IP | | | | | |── البحث بـ fingerprint_hash | | | في `users` WHERE user_type | | | = 'service' | | | | | [إذا لم يوجد, والإيميل موجود] | | |── البحث بالإيميل المشفر | | | | | |── التحقق من status: | | | • pending → "قيد المراجعة" | | | • suspended → "معلق" | | | • approved → متابعة | | | | | |── التحقق من كلمة المرور | | | | | |── فك تشفير البيانات للعرض: | | | first_name, last_name, | | | email, phone | | | | | |── إدارة التوكنات: | | | 1. البحث عن توكن موجود في | | | Redis (active_token) | | | 2. إذا وجد وصالح ← استخدامه | | | 3. إذا لم يوجد ← إلغاء القديم | | | وتوليد جديد | | | | | |── توليد HMAC Key: | | | hmac = hash_hmac(sha256, | | | userId, SECRET_KEY_HMAC) | | | | |<── { message, data, jwt, | | | hmac, expires_in } | | | | | |── إرسال OTP: | | | POST /auth/otp/request.php | | | payload: receiver=phone, | | | user_type='service' | | | | | |── عرض Dialog OTP | | | | | |── التحقق من OTP: | | | POST /auth/otp/verify.php | | | payload: phone_number, | | | token_code, user_type | | | | | |── حفظ JWT + HMAC محلياً | | | | | |── Get.offAll(Main()) | | ``` --- ## سير عمل إضافة الموظفين من قبل المشرف العام ### 📍 `backend/Admin/Staff/add.php` يستخدم هذا الملف لإضافة موظفين جدد من قبل المشرف العام (Super Admin أو Admin فقط). ``` ┌─────────────────────────────────────┐ │ add.php │ │ │ │ ✅ JWT Authentication: │ │ $jwtService = new JwtService │ │ $auth = $jwtService->authenticate│ │ $authRole = $auth->role │ │ if role ≠ super_admin || admin → │ │ رفض الطلب │ └──────────────────┬──────────────────┘ │ ──────────────┼────────────── role='admin' │ role='service' │ ┌─────────────────────────┴──────────────────────────┐ ▼ ▼ ┌────────────────┐ ┌──────────────────┐ │ adminUser │ │ users │ │ table │ │ table │ ├────────────────┤ ├──────────────────┤ │ id (bin2hex) │ │ id (bin2hex) │ │ fingerprint │ │ fingerprint │ │ fingerprint_ │ │ fingerprint_hash │ │ hash │ │ phone (مشفر) │ │ name (مشفر) │ │ email (مشفر) │ │ phone (مشفر) │ │ gender │ │ password │ │ password │ │ role 'admin' │ │ birthdate │ │ created_at │ │ user_type │ └────────────────┘ │ 'service' │ │ first_name (مشفر) │ │ last_name │ │ site │ │ created_at │ └──────────────────┘ ``` ### 🔐 آلية التحقق في add.php (بعد الإصلاح): ```php $jwtService = new JwtService($redis); $auth = $jwtService->authenticate(); // يقرأ Bearer token من Authorization header $authRole = $auth->role ?? ''; // يستخرج الدور من JWT payload if ($authRole !== 'super_admin' && $authRole !== 'admin') { jsonError("غير مصرح لك. فقط المشرفون يمكنهم إضافة موظفين."); exit; } ``` ### نقاط مهمة في add.php: - ✅ `bin2hex(random_bytes(16))` لتوليد UUID آمن - ✅ البيانات الحساسة مشفرة قبل الحفظ - ✅ `fingerprint` اختياري — يمكن إضافة موظف بدون بصمة مسبقة - ✅ **التحقق من JWT Authentication** مطلوب قبل الإضافة --- ## سير عمل تفعيل الحسابات المعلقة ### 📍 `pending.php` → `activate.php` #### استعراض الحسابات المعلقة: ``` [pending.php] [قاعدة البيانات] │ │ │── SELECT FROM adminUser │ │ WHERE status='pending' │ │ │ │── SELECT FROM users │ │ WHERE status='pending' │ │ AND user_type='service' │ │ │ │── فك تشفير الأسماء والأرقام │ │ │ │── دمج النتائج (array_merge) │ │ │ │<── { data: [all_pending] } │ ``` #### تفعيل حساب: ``` [activate.php] [قاعدة البيانات] │ │ │── التحقق من JWT: │ │ $jwtService = new JwtService │ │ $auth = $jwtService->authenticate│ │ $authRole = $auth->role │ │ if ≠ super_admin && ≠ admin → │ │ رفض │ │ │ │── POST مع: user_id, type │ │ │ │ type='admin': │ │ UPDATE adminUser │ │ SET status='active' │ │ WHERE id=user_id │ │ AND status='pending' │ │ │ │ type='service': │ │ UPDATE users │ │ SET status='approved' │ │ WHERE id=user_id │ │ AND status='pending' │ │ AND user_type='service' │ │ │ │<── "تم التفعيل بنجاح" │ ``` ### 🔐 آلية التحقق في activate.php (بعد الإصلاح): ```php $jwtService = new JwtService($redis); $auth = $jwtService->authenticate(); $authRole = $auth->role ?? ''; if ($authRole !== 'super_admin' && $authRole !== 'admin') { jsonError("غير مصرح لك. فقط المشرف العام يمكنه تفعيل الحسابات."); exit; } ``` --- ## مقارنة بين تدفق siro_admin و siro_service | الخاصية | siro_admin (المشرف) | siro_service (خدمة العملاء) | |---------|---------------------|-----------------------------| | **جدول البيانات** | `adminUser` | `users` | | **مفتاح البحث** | بصمة الجهاز ← الهاتف | بصمة الجهاز ← الإيميل | | **آلية OTP** | OTP عبر WhatsApp كخطوة قبل JWT | JWT يصدر أولاً ثم OTP كخطوة تأكيد | | **Auto Login** | Yes (is_renewal=1) + JWT غير منتهي | Yes (كلمة مرور مخزنة) | | **إلغاء التوكن القديم** | قبل إصدار الجديد (Redis) | قبل إصدار الجديد (Redis) | | **عدد أرقام OTP** | 6 أرقام (مُحسَّن) | لا يوجد OTP مدمج بالـ login | | **HMAC Key** | غير مستخدم | يستخدم للتوافق مع CRUD | | **نوع التسجيل** | تسجيل ذاتي + قائمة بيضاء | إضافة يدوية أو تسجيل ذاتي | | **الحالة عند الإنشاء** | `pending` | `pending` / `active` | --- ## الجوانب الأمنية (Security) ### ✅ نقاط القوة 1. **تشفير البيانات الحساسة** — جميع PII (الاسم، الهاتف، الإيميل، البصمة) مشفرة في قاعدة البيانات بواسطة `encryptData()` 2. **بصمة الجهاز (Fingerprint)** — ربط الحساب بجهاز معين يمنع الوصول من أجهزة غير معروفة 3. **إلغاء التوكن (Token Revocation)** — التوكن القديم يُلغى قبل إصدار الجديد عبر Redis 4. **OTP لمدة محدودة** — صلاحية 10 دقائق فقط للرمز 5. **استخدام لمرة واحدة** — OTP يُحذف بعد التحقق 6. **القائمة البيضاء** — التسجيل الذاتي مقيد بأرقام مصرح بها من `.env` 7. **Hash للبصمة** — `SHA-256` للبحث السريع دون تخزين البصمة كما هي 8. **قناع رقم الهاتف** — في الاستجابة، يظهر فقط `07XX***XXX` 9. **UUID آمن** — `bin2hex(random_bytes(16))` بدلاً من `rand()` (تم الإصلاح) 10. **JWT Authentication** — لملفي add.php و activate.php (تم الإصلاح) 11. **Rate Limiting** — على login و OTP (تم الإضافة) ### ✅ الإصلاحات الأمنية المُنفَّذة | # | الثغرة | الملف | الحالة | |---|--------|-------|--------| | 1 | `rand()` لتوليد ID (ضعيف) | `Admin/auth/register.php` | ✅ تم الاستبدال بـ `bin2hex(random_bytes(16))` | | 2 | التحقق من الصلاحيات معلق (Commented Out) | `Admin/Staff/add.php` | ✅ تم التفعيل عبر `JwtService::authenticate()` | | 3 | لا يوجد تحقق من صلاحية المشرف العام | `Admin/Staff/activate.php` | ✅ تم إضافة JWT + التحقق من role | | 4 | لا يوجد Rate Limiting على login | `Admin/auth/login.php` | ✅ تم الإضافة (5 محاولات/دقيقة) | | 5 | لا يوجد Rate Limiting على login | `serviceapp/login.php` | ✅ تم الإضافة (5 محاولات/دقيقة) | | 6 | لا يوجد Rate Limiting على OTP | `Admin/auth/verify_login.php` | ✅ تم الإضافة (3 محاولات/5 دقائق) | | 7 | OTP 5 أرقام (ضعيف) | `Admin/auth/login.php` | ✅ تم الرفع إلى 6 أرقام (100000-999999) | ### ❌ الثغرات المتبقية (لم تُعالَج بعد) | الثغرة | الموقع | التأثير | |--------|--------|---------| | **كلمات مرور plain text (قديمة)** | `Admin/jwtService.php` (السطر 49) | دعم كلمات المرور غير المشفرة للتوافق القديم | | **JWT Service مكرر** | `Admin/jwtService.php` و `core/Auth/JwtService.php` | يوجد ملفان باسم JwtService بوظائف مختلفة | | **Auto Login بدون OTP** | `Admin/auth/login.php` مع `is_renewal=1` | إذا سُرقت البصمة وكلمة المرور، يمكن الدخول بدون OTP | | **كشف البصمة في الأخطاء** | `otp_helper.dart` | لا يوجد تدقيق كافٍ في التقاط الأخطاء | --- ## قائمة الإصلاحات الأمنية المُنفَّذة ### 1. ✅ `Admin/auth/register.php` — استبدال ID الضعيف **قبل الإصلاح:** ```php $uniqueId = rand(100000000, 999999999); // غير آمن، قد يتكرر ``` **بعد الإصلاح:** ```php $uniqueId = bin2hex(random_bytes(16)); // UUID آمن (32 حرف hex عشوائي) ``` ### 2. ✅ `Admin/Staff/add.php` — تفعيل التحقق من الصلاحيات **قبل الإصلاح:** ```php // التحقق معلق (Commented Out) // $auth = JwtService::authenticate($redis); // if ($auth['role'] !== 'super_admin' && $auth['role'] !== 'admin') { ... } ``` **بعد الإصلاح:** ```php $jwtService = new JwtService($redis); $auth = $jwtService->authenticate(); $authRole = $auth->role ?? ''; if ($authRole !== 'super_admin' && $authRole !== 'admin') { jsonError("غير مصرح لك. فقط المشرفون يمكنهم إضافة موظفين."); exit; } ``` ### 3. ✅ `Admin/Staff/activate.php` — إضافة JWT Authentication **قبل الإصلاح:** ```php // يجب التأكد من صلاحيات الـ Super Admin هنا // (عادةً يتم التحقق من التوكن أو الـ Session) ``` **بعد الإصلاح:** ```php $jwtService = new JwtService($redis); $auth = $jwtService->authenticate(); $authRole = $auth->role ?? ''; if ($authRole !== 'super_admin' && $authRole !== 'admin') { jsonError("غير مصرح لك. فقط المشرف العام يمكنه تفعيل الحسابات."); exit; } ``` ### 4. ✅ `Admin/auth/login.php` — إضافة Rate Limiting + رفع OTP إلى 6 أرقام ```php // Rate Limiting قبل بدء المعالجة $rateLimiter = new RateLimiter($redis); $rateLimiter->enforce(RateLimiter::identifier(), 'login'); // ... لاحقاً عند توليد OTP ... $otp = rand(100000, 999999); // 6 أرقام بدلاً من 5 ``` ### 5. ✅ `serviceapp/login.php` — إضافة Rate Limiting ```php $rateLimiter = new RateLimiter($redis); $rateLimiter->enforce(RateLimiter::identifier(), 'login'); ``` ### 6. ✅ `Admin/auth/verify_login.php` — إضافة Rate Limiting لـ OTP ```php $rateLimiter = new RateLimiter($redis); $rateLimiter->enforce(RateLimiter::identifier(), 'otp'); // 3 محاولات/5 دقائق ``` --- ## خلاصة ```mermaid graph TD subgraph "siro_admin (تطبيق المشرف)" A[Login Page] --> B[OtpHelper.loginWithPassword] B --> C{is_renewal?} C -->|نعم| D[JWT مباشر] C -->|لا| E[طلب OTP - 6 أرقام] E --> F[Verify OTP - Rate Limited] F --> G[JWT نهائي] end subgraph "Backend PHP - مؤمَّن" H[Admin/auth/login.php] --> RL1[Rate Limiter ✅] RL1 --> I[بحث بالبصمة/هاتف] I --> J[فحص الحالة] J --> K[التحقق من كلمة المرور] K --> L[توليد OTP 6-digits ✅ / JWT] M[verify_login.php] --> RL2[Rate Limiter (OTP) ✅] RL2 --> N[التحقق من OTP] N --> O[إصدار JWT] P[add.php] --> AUTH1[JWT Authentication ✅] Q[activate.php] --> AUTH2[JWT Authentication ✅] end subgraph "siro_service (تطبيق الخدمة)" R[LoginController.login] --> S[serviceapp/login.php] S --> RL3[Rate Limiter ✅] RL3 --> T[JWT + HMAC] T --> U[OTP للتأكيد] U --> V[تسجيل دخول نهائي] end B --> H F --> M R --> S ``` النظام مبني على أساس أمني قوي مع تشفير متعدد الطبقات. تم إصلاح 7 ثغرات أمنية: 1. **UUID آمن** بدلاً من `rand()` في تسجيل المشرفين 2. **JWT Authentication** في add.php — يمنع أي شخص غير مصرح له من إضافة موظفين 3. **JWT Authentication** في activate.php — يضمن أن المشرف العام فقط هو من يمكنه التفعيل 4. **Rate Limiting** (5 محاولات/دقيقة) على login.php للمشرفين 5. **Rate Limiting** (5 محاولات/دقيقة) على login.php لخدمة العملاء 6. **Rate Limiting** (3 محاولات/5 دقائق) على verify_login.php (OTP) 7. **رفع OTP إلى 6 أرقام** لزيادة صعوبة التخمين --- > **تاريخ التوثيق:** 12 يونيو 2026 > **آخر تحديث:** 12 يونيو 2026 (تم تنفيذ الإصلاحات) > **الإصدار:** 2.0 > **المراجعة القادمة:** — > **المعنيون:** فريق التطوير — Siro