<div dir="rtl" lang="ar">

# تحليل تدفق تسجيل ودخول السائق (Siro Driver)

## تصفُّل كامل من Flutter إلى PHP Backend

---

## 1. الملفات المشاركة

### تطبيق Flutter — siro_driver

| الملف | الدور |
|-------|--------|
| `controller/auth/captin/login_captin_controller.dart` | كل منطق تسجيل الدخول (Google, Credentials, JWT, OTP) |
| `controller/auth/captin/register_captin_controller.dart` | كل منطق التسجيل (OTP, Verify, إرسال البيانات) |
| `controller/auth/captin/opt_token_controller.dart` | OTP Token |
| `controller/functions/crud.dart` | HTTP client مع NetGuard + JWT refresh |
| `controller/functions/encrypt_decrypt.dart` | تشفير/فك تشفير محلي |
| `controller/functions/device_info.dart` | Fingerprint |

### Backend PHP

| الملف | الرابط المستخدم من التطبيق |
|-------|---------------------------|
| `auth/captin/loginFromGoogle.php` | `loginFromGoogleCaptin` |
| `auth/captin/loginUsingCredentialsWithoutGoogle.php` | `loginUsingCredentialsWithoutGoogle` |
| `loginFirstTimeDriver.php` | `loginFirstTimeDriver` |
| `loginJwtDriver.php` | `loginJwtDriver` |
| `auth/captin/login.php` | تسجيل دخول عادي (email + phone + password) |
| `auth/Tester/` | `getTesterApp`, `updateTesterApp` |
| `auth/otp/` | OTP APIs |

---

## 2. التدفق الكامل — تسجيل حساب جديد (Sign Up)

### 🧩 مسار السجلات: من البداية حتى النهاية

```
┌─────────────────────────────────────────────────────────────────────────┐
│  التطبيق (Flutter)                     │  الباك إند (PHP)              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│ 1. onInit()                                                            │
│    ├── getJWT():                                                        │
│    │   POST /loginFirstTimeDriver.php                                   │
│    │   payload: { id: AK.newId, password: AK.passnpassenger,           │
│    │              aud: "${AK.allowed}$dev", fingerPrint }              │
│    │   ← يحصل على registration JWT (صلاحية 450 ثانية)                  │
│    │   └── يخزّن JWT في box + secure storage                          │
│    │                                                                   │
│ 2. تسجيل الدخول عبر Google (loginWithGoogleCredential)                 │
│    ├── GET /auth/captin/loginFromGoogle.php?driverID=X                 │
│    │   └── هذا الملف يستخدم connect.php (قديم) ← لا JWT check         │
│    │   ← إذا found → يقرأ data من الـ DB                              │
│    │   ← يخزّن بيانات كاملة (firstName, lastName, phone, gender,     │
│    │     carYear, model, bankCode, ...) في GetStorage                  │
│    │   ← يفحص driver token (getDriverToken) ← يقارن مع المخزّن        │
│    │   ← إذا تغيّر fingerprint → يحوّل لصفحة OTP                       │
│    │   ← ينتقل لـ HomeCaptain                                         │
│    └── إذا not found → isPhoneVerified() → RegistrationView           │
│                                                                         │
│ 3. التسجيل (sendOtpMessage)                                            │
│    ├── POST /auth/otp/sendVerifyOtpMessage                             │
│    │   payload: { phone_number, driverId, email }                      │
│    ├── POST /auth/otp/verifyOtpDriver (للسائق)                        │
│    │   payload: { phone_number, token_code }                           │
│    │   ← يخزّن phoneDriver, phoneVerified = 1                         │
│    │   ← ينتقل لـ RegistrationView                                    │
│    │                                                                   │
│ 4. الرفع للمستندات والصور (CarLicense, ID Card, إلخ)                   │
│    ├── POST /addLicense (رخصة القيادة)                                 │
│    ├── POST /addRegisrationCar (تسجيل السيارة)                         │
│    └── CRUD.post /signUpCaptin (إنشاء الحساب النهائي)                  │
│        payload: { first_name, last_name, email, phone, password,       │
│                   gender, site, birthdate }                            │
│        ← يخزّن driverID, dob, sex, phone                              │
│        ← يرسل sendVerifyEmail (OTP للبريد)                            │
│        ← ينتقل لـ VerifyEmailCaptainPage                              │
│                                                                         │
│ 5. بعد التحقق من الإيميل → LoginCaptin (يعيد تسجيل الدخول)             │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 3. التدفق الكامل — تسجيل الدخول (Login)

### مسار تسجيل الدخول بالإيميل وكلمة المرور

```
┌────────────────────────────────────────────────────────────────────┐
│  Flutter                         │  PHP Backend                   │
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│ loginUsingCredentialsWithoutGoogle(email, password):               │
│                                                                    │
│ GET /auth/captin/loginUsingCredentialsWithoutGoogle.php            │
│ ?email=...&password=...                                            │
│                                                                    │
│ ← هذا الملف يستخدم connect.php (قديم، لا JWT check)               │
│                                                                    │
│ خطوات الباك إند:                                                   │
│ 1. filterRequest('email')                                         │
│ 2. تشفير الإيميل: encryptData($email)                              │
│ 3. SELECT من driver LEFT JOIN phone_verification                  │
│    WHERE email = :encryptedEmail                                   │
│    AND phone_verification.is_verified = '1'                        │
│ 4. password_verify($password, $data['password'])                   │
│ 5. فك تشفير جميع الحقول (phone, email, gender, birthdate, ...)    │
│ 6. إرجاع JSON { status: "success", data: {...} }                  │
│                                                                    │
│ في التطبيق:                                                        │
│ 1. يخزّن كل البيانات في box (driverID, email, phone, ...)        │
│ 2. يخزّن fingerprint في secure storage                            │
│ 3. يحصل على driver token (getDriverToken)                         │
│ 4. يقارن الـ token مع المخزّن ← إذا تغير → Dialog "new device"   │
│ 5. إذا matched → Get.off(HomeCaptain)                             │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘
```

### مسار تسجيل الدخول عبر Google

```
┌────────────────────────────────────────────────────────────────────┐
│  Flutter                         │  PHP Backend                   │
├────────────────────────────────────────────────────────────────────┤
│                                                                    │
│ loginWithGoogleCredential(driverID, email):                        │
│                                                                    │
│ GET /auth/captin/loginFromGoogle.php?id=driverID                   │
│                                                                    │
│ ← هذا الملف يستخدم connect.php (قديم، لا JWT check)               │
│ ← لا يستخدم email في البحث (معلق) — يبحث بـ id فقط                │
│                                                                    │
│ خطوات الباك إند:                                                   │
│ 1. filterRequest('id') ← driverID                                 │
│ 2. SELECT مع LEFT JOIN (phone_verification, CarRegistration,       │
│    driver_gifts, invites) WHERE driver.id = :id                    │
│ 3. فك تشفير الحقول الحساسة                                         │
│ 4. إرجاع { status, data: { phone, email, first_name, ... } }      │
│                                                                    │
│ في التطبيق:                                                        │
│ 1. يخزّن بيانات كاملة في box                                      │
│ 2. يحصل على JWT عبر getJWT()                                      │
│ 3. يتحقق من driver token ← إذا تغير fingerprint → OTP Dialog     │
│ 4. يدخل إلى HomeCaptain                                           │
│                                                                    │
└────────────────────────────────────────────────────────────────────┘
```

### مسار الـ JWT (Two-Phase)

```
┌────────────────────────────────────────────────────────────────────┐
│  Phase 1: Registration Token                                      │
│  loginFirstTimeDriver.php                                          │
│  ← Rate Limiter (5/دقيقة) ✅                                       │
│  ← Audience check (allowedDriver1/2) ✅                            │
│  ← password_verify(password, passwordnewpassenger) ✅              │
│  ← Fingerprint + Pepper → SHA-256 ✅                              │
│  ← JWT: token_type='registration', exp=450s (7.5 min)             │
│  ← Secret Key من ملف خارجي (.secret_key) ✅                       │
│                                                                    │
│  Phase 2: Access Token                                             │
│  loginJwtDriver.php                                                │
│  ← Rate Limiter (5/دقيقة) ✅                                       │
│  ← Audience check ✅                                               │
│  ← قراءة driver من DB (SELECT id, phone, national_number, password)│
│  ← فك تشفير phone و national_number                                │
│  ← بناء HMAC: sha256(id|phone|national_number, SECRET_KEY_HMAC)   │
│  ← password_verify(hmacHex, driver.password) ✅                   │
│  ← توليد Access Token (JwtService.generateAccessToken)            │
│  ← إلغاء التوكن القديم عبر Redis (Token Revocation) ✅            │
│  ← إرجاع { jwt, expires_in: 14400 (4h) }                         │
│                                                                    │
│  في التطبيق (getJWT):                                              │
│  إذا firstTimeLoadKey != false → loginFirstTimeDriver             │
│  وإلا → loginJwtDriver                                            │
│  يحفظ JWT في box + secure storage                                 │
└────────────────────────────────────────────────────────────────────┘
```

---

## 4. تحليل تدفق البيانات — من وإلى التطبيق

### 📤 من التطبيق إلى الباك إند

| المعلومة | هل التنظيف صحيح؟ | الطريقة |
|----------|-------------------|---------|
| email | ✅ | `filterRequest('email')` ثم `encryptData()` قبل الاستعلام |
| phone | ✅ | `filterRequest('phone')` ثم `encryptData()` قبل الاستعلام |
| password | ✅ | يُستخدم `password_verify()` مع `password_hash` في DB |
| fingerprint | ✅ | يُهش مع Pepper: `SHA-256(fingerprint + pepper)` |
| driverID | ✅ | `filterRequest('id')` |
| token / otp | ⚠️ | `token_code` يُرسل بدون تشفير في `/verifyOtpDriver` |

### 📥 من الباك إند إلى التطبيق

| المعلومة | هل التسريب آمن؟ | ملاحظة |
|----------|-----------------|---------|
| JWT | ✅ | يُخزَّن في `GetStorage` + `FlutterSecureStorage` |
| HMAC | ✅ | يُستخدم للتوثيق بين الطلبات |
| الاسم (first_name, last_name) | ✅ | يُفك تشفيره للعرض فقط |
| الهاتف والإيميل | ✅ | يُفك تشفيرهما للعرض فقط |
| make, model, year | ✅ | غير حساسة، لا تشفير |
| bankCode, accountBank | ⚠️ | حساسة لكنها تُفك تشفيرها وتُرسل |

---

## 5. النقاط الأمنية والثغرات

### ✅ نقاط القوة

1. **Rate Limiting** في loginJwtDriver.php و loginFirstTimeDriver.php ✅
2. **JWT مع Fingerprint و Pepper** — ربط التوكن بالجهاز ✅
3. **HMAC للمصادقة الداخلية** — مشتق من id\|phone\|national_number ✅
4. **إلغاء التوكن القديم** عبر Redis قبل إصدار جديد ✅
5. **تشفير PII في قاعدة البيانات** — encryptData لكل الحقول الحساسة ✅
6. **password_hash + password_verify** في كل نقاط التحقق ✅
7. **Audience Validation** — التحقق من الـ audience المسموح ✅
8. **NetGuard في CRUD** — التحقق من SSL قبل الاتصال ✅
9. **فصل التوكنات** — registration token (450s) ≠ access token (4h) ✅
10. **فحص صلاحية JWT** — `_isJwtValid()` قبل أي طلب ✅

### ❌ الثغرات والملاحظات

| # | الثغرة | الموقع | التأثير | التصنيف |
|---|--------|--------|---------|---------|
| 1 | **loginFromGoogle.php يقرأ connect.php** (قديم، لا JWT) | `backend/auth/captin/loginFromGoogle.php` | لا يوجد JWT Authentication — يمكن لأي جهة خارجية استدعاء API وسحب بيانات السائق | 🔴 **Critical** |
| 2 | **loginUsingCredentialsWithoutGoogle.php يقرأ connect.php** (قديم) | `backend/auth/captin/loginUsingCredentialsWithoutGoogle.php` | لا يوجد JWT Authentication — يمكن اختراق كلمة المرور بقوة عمياء دون Rate Limiting | 🔴 **Critical** |
| 3 | **login.php (auth/captin) لا يستخدم connect.php الجديد** | `backend/auth/captin/login.php` | لا Rate Limiting ولا JWT Authentication | 🔴 **Critical** |
| 4 | **is_verified = '1' إجباري في loginUsingCredentials** | `loginUsingCredentialsWithoutGoogle.php` سطر 38 | السائق يحتاج التحقق من الهاتف حتى يتمكن من تسجيل الدخول (قد يكون مقصوداً لكنه قاسٍ على المستخدم) | 🟡 **Medium** |
| 5 | **connect.php القديم** | `backend/connect.php` نفسه | لا Rate Limiting ولا JWT — أي API يستخدم connect.php فقط مكشوف للجميع | 🔴 **Critical** |
| 6 | **loginFromGoogle.php لا يتحقق من البريد (معلق)** | سطر 10-18 | البحث فقط بـ `driverID` — أي driverID صحيح يعيد البيانات حتى لو الإيميل مختلف | 🟡 **Medium** |
| 7 | **OTP code يرسل إلى الباك إند نصاً بدون تشفير** | `register_captin_controller.dart` سطر 266 | `token_code` يُرسل كـ plain text | 🟡 **Medium** |
| 8 | **Secure Storage vs GetStorage** | `login_captin_controller.dart` | JWT يُخزَّن في **كلاهما** — GetStorage غير مشفر (plain text على القرص) | 🔴 **Critical** |
| 9 | **password مخزَّن في متغير بيئة (passwordnewpassenger)** | `loginFirstTimeDriver.php` سطر 30 | كلمة مرور عامة لكل السائقين للتسجيل الأولي — إذا سُرّبت، يمكن توليد registration tokens وهمية | 🔴 **Critical** |
| 10 | **لا Validation على الـ id في loginJwtDriver** | `loginJwtDriver.php` | إذا تم إرسال id غير موجود، يعيد "invalid credentials" (وهو صحيح لكن يمكن استغلاله في تحديد IDs) | 🟢 **Low** |

---

## 6. مخطط الـ OTP — كامل

```
┌───────────────────┐         ┌─────────────────────┐
│  Flutter          │         │  PHP Backend         │
├───────────────────┤         ├─────────────────────┤
│                   │         │                      │
│ sendOtpMessage()  │         │                      │
│   │               │         │                      │
│   ├── checkPhoneNumberISVerfiedDriver              │
│   │   POST  ──────┼────────>│  التحقق إذا الرقم   │
│   │               │         │  موثَّق مسبقاً       │
│   │   ← is_verified=1 ──────┤                      │
│   │   ← already verified → loginWithGoogleCredential│
│   │               │         │                      │
│   ├── sendVerifyOtpMessage   │                      │
│   │   POST: {phone_number, driverId, email}        │
│   │   ───────────┼────────>│  إرسال OTP عبر SMS   │
│   │               │         │  + حفظ في DB         │
│   │               │         │                      │
│   ├── verifyOtpDriver (verifySMSCode)              │
│   │   POST: {phone_number, token_code}             │
│   │   ───────────┼────────>│  التحقق من OTP       │
│   │               │         │                      │
│   │   ← success ───────────│                      │
│   │   phoneVerified=1      │                      │
│   │   ├── تخزين phoneDriver │                      │
│   │   └── Get.to(RegistrationView)                │
│                   │         │                      │
└───────────────────┘         └─────────────────────┘
```

### الثغرة في تدفق OTP:

عندما يكون `is_verified=1`، ينتقل التطبيق **مباشرةً** إلى `loginWithGoogleCredential()` دون إعادة إدخال كلمة المرور أو أي تحقق إضافي. هذا يعني أنه إذا تم الوصول إلى جهاز المستخدم مؤقتاً، يمكن تسجيل الدخول فقط بالتحقق من أن الرقم "موثَّق مسبقاً".

---

## 7. الملخص النهائي

| البند | النتيجة |
|-------|---------|
| **إجمالي الملفات المدققة** | 22 ملفاً (Flutter + PHP) |
| **الثغرات الحرجة (Critical)** | 5 |
| **الثغرات المتوسطة (Medium)** | 3 |
| **الثغرات المنخفضة (Low)** | 2 |
| **النقاط الإيجابية** | 10 |

### الثغرات الحرجة (Critical) التي تتطلب إصلاحاً فورياً:

1. **🔴 loginFromGoogle.php** ← يستخدم connect.php القديم (لا JWT, لا Rate Limiting)
2. **🔴 loginUsingCredentialsWithoutGoogle.php** ← يستخدم connect.php القديم
3. **🔴 auth/captin/login.php** ← لا Rate Limiting ولا JWT
4. **🔴 JWT مخزَّن في GetStorage (غير مشفر)** — يجب استخدام FlutterSecureStorage فقط
5. **🔴 passwordnewpassenger عام لكل السائقين في loginFirstTimeDriver.php**

### هل التدفق صحيح؟

- **من التطبيق إلى الباك إند**: ✅ صحيح — `filterRequest()` ينظف المدخلات
- **التشفير في DB**: ✅ صحيح — `encryptData()` لكل الحقول الحساسة
- **التحقق من كلمة المرور**: ✅ صحيح — `password_hash()` + `password_verify()`
- **Fingerprint + Pepper**: ✅ صحيح — يربط التوكن بالجهاز
- **إدارة التوكنات**: ✅ صحيح — Registration ثم Access مع Revocation
- **المصادقة (Authentication)**: ❌ **ضعيف** — الملفات القديمة (connect.php) لا تتطلب JWT
- **تخزين البيانات الحساسة**: ❌ **ضعيف** — GetStorage غير مشفر على Android

### التوصية:

يجب تحويل `loginFromGoogle.php` و `loginUsingCredentialsWithoutGoogle.php` لاستخدام `core/bootstrap.php` مع JWT Authentication بدلاً من `connect.php` القديم، وتوحيد GetStorage إلى FlutterSecureStorage للـ JWT.

---

> **تاريخ التحليل:** 12 يونيو 2026  
> **النسخة:** 1.0  
> **التركيز:** Siro Driver فقط

</div>