diff --git a/INFRASTRUCTURE_REPORT.md b/INFRASTRUCTURE_REPORT.md new file mode 100644 index 0000000..45e78db --- /dev/null +++ b/INFRASTRUCTURE_REPORT.md @@ -0,0 +1,460 @@ +# تقرير البنية التحتية لنظام سيرو (Siro) - النشر في سوريا + +**التاريخ:** 16 يونيو 2026 +**المشروع:** Siro - تطبيق نقل الركاب +**الموقع:** سوريا + +--- + +## 📊 ملخص الخدمات المطلوبة + +| الخدمة | الدور | بروتوكول | بوابات | +|--------|-------|-----------|--------| +| **Load Balancer** | توزيع الأحمال على API | HTTP/HTTPS | 80, 443 | +| **API Server x2** | المعالجة الرئيسية | HTTP/HTTPS | 8080 (داخلي) | +| **MySQL Server** | قاعدة البيانات الرئيسية | MySQL | 3306 (داخلي) | +| **Redis Server** | كاش + مواقع السائقين | Redis | 6379 (داخلي) | +| **Driver Socket** | WebSocket للسائقين | WS/WSS + HTTP | 2020, 2021 | +| **Passenger Socket** | WebSocket للركاب | WS/WSS + HTTP | 3030, 3031 | +| **Wallet Server** | نظام المحفظة والمدفوعات | HTTP/HTTPS | 8081 (داخلي) | +| **OSRM Server (1-2)** | محرك التوجيه والخرائط | HTTP | 5000 (داخلي) | +| **Map SaaS** | خدمات الخرائط المخصصة | HTTP/HTTPS | 8082 | + +--- + +## 🖥️ 1. Load Balancer (موازن الأحمال) + +**الجهاز/السيرفر: جهاز واحد - عقدة أمامية** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 2 Core (Xeon / AMD EPYC) | لا يحتاج طاقة معالجة، فقط توجيه الطلبات | +| **الرام** | 4 GB | HAProxy/Nginx يستهلك القليل | +| **التخزين** | 50 GB SSD | نظام تشغيل + سجلات | +| **الشبكة** | 1 Gbps | استيعاب حجم الطلبات | +| **نظام التشغيل** | Ubuntu 22.04 LTS أو Rocky Linux 9 | | + +**البرامج المطلوبة:** +- Nginx ( reverse proxy + SSL termination + load balancing upstream للـ API servers ) +- HAProxy (اختياري للـ TCP load balancing للسوكتات) +- Keepalived (لـ High Availability إذا أردت أكثر من موازن) +- Certbot / Let's Encrypt (لشهادات SSL) + +**نظام التوزيع المقترح:** +``` +Nginx upstream → API Server 1 (weight=5) + API Server 2 (weight=5) + └── Round Robin أو Least Connections +``` + +--- + +## 🖥️ 2. API Backend Server (سيرفر الباك إند الرئيسي) + +**العدد: 2 سيرفرات خلف الـ Load Balancer** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 8 Core (Xeon / AMD EPYC) | PHP-FPM يحتاج عدة عمال لكل نواة؛ 8cores = 16-24 worker | +| **الرام** | 16 GB | PHP worker ~50MB/worker + نظام + كاش | +| **التخزين** | 100 GB NVMe SSD | كود المصدر + صور السائقين + سجلات | +| **الشبكة** | 1 Gbps | اتصال مع الـ DB والخدمات الأخرى | +| **نظام التشغيل** | Ubuntu 22.04 LTS | | + +**البرامج المطلوبة:** +- PHP 8.2/8.3 (مع extensions: pdo_mysql, redis, openssl, mbstring, gd) +- PHP-FPM (مع pm.max_children = 40-50 لكل سيرفر) +- Nginx للمحتوى الثابت +- Supervisor (لإدارة العمليات) + +**توجيه الطلبات من كل سيرفر:** +- `api-syria.siromove.com/siro_v3` → Main API +- `ride-syria.siromove.com/siro` → Ride API +- `location-syria.siromove.com/siro/ride/location` → Location API +- كل هذه على نفس السيرفر، نفس قاعدة البيانات الرئيسية + +**PHP-FPM Configuration:** +```ini +pm = dynamic +pm.max_children = 50 +pm.start_servers = 8 +pm.min_spare_servers = 4 +pm.max_spare_servers = 12 +pm.max_requests = 1000 +``` + +--- + +## 🗄️ 3. MySQL Database Server (سيرفر قاعدة البيانات الرئيسية) + +**العدد: 1 + 1 Replica (اختياري للنسخ الاحتياطي)** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 16 Core (Xeon / AMD EPYC) | MySQL يتوسع أفقياً مع عدد النوى | +| **الرام** | 64 GB | InnoDB Buffer Pool يحتاج ذاكرة كبيرة للأداء | +| **التخزين** | 1 TB NVMe SSD | 3 قواعد بيانات (intaleqDB1, ridesDB, locationDB) ~ 100-300 GB + سجلات | +| **الشبكة** | 10 Gbps | عمليات كتابة/قراءة مكثفة من سيرفرين API + سوكتات | +| **نظام التشغيل** | Ubuntu 22.04 LTS | | + +**ضبط MySQL المقترح:** +```ini +innodb_buffer_pool_size = 40G # 60-70% من الرام +innodb_log_file_size = 2G +innodb_flush_log_at_trx_commit = 2 # أداء أفضل للتحديثات +innodb_flush_method = O_DIRECT +max_connections = 300 # 150 لكل API server + 50 للسوكتات +tmp_table_size = 256M +max_heap_table_size = 256M +query_cache_type = 0 # OFF (MySQL 8.0 ألغاه) +``` + +**الجداول الحساسة للأداء:** +- `car_locations` - يستخدم SPATIAL indexes + GEOMETRY - تأكد من `SRID=4326` +- `car_tracks` - 2.5M+ سجل - يحتاج أرشفة دورية أو partitioning +- `ride` + `waitingRides` - استعلامات متكررة مع SPATIAL +- `palces11` - FULLTEXT search + +**ملاحظة: قاعدة بيانات الخرائط والتتبع (locationDB) هي الأكبر من حيث حجم الكتابة، يمكن وضعها على NVMe منفصل.** + +--- + +## ⚡ 4. Redis Server (سيرفر الكاش والمواقع اللحظية) + +**العدد: 1 (أو 1 + 1 Sentinel للتبديل التلقائي)** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 8 Core | Redis single-threaded للعمليات الأساسية لكن له عمليات خلفية | +| **الرام** | 32 GB | بيانات GEO (مواقع السائقين) + كاش الجلسات + rate limiting | +| **التخزين** | 100 GB NVMe | RDB/AOF persistence | +| **الشبكة** | 10 Gbps | زمن استجابة منخفض جداً مطلوب | +| **نظام التشغيل** | Ubuntu 22.04 LTS | | + +**ملاحظات هامة:** +- يجب أن يكون Redis على نفس الشبكة الداخلية (Latency < 1ms) +- الـ Socket servers (driver + passenger) يعتمدان على Redis بشكل كبير (GEOADD/GEORADIUS كل 500ms) +- حجم الذاكرة المطلوب يعتمد على عدد السائقين النشطين: كل موقع سائق ~ 200 bytes → 1M سجل = 200MB فقط +- لكن الكاش الإضافي (driver:profile:*، الجلسات) يحتاج مساحة إضافية + +**نظام الكاش:** +``` +driver_socket → Redis GEO (GEOADD) +passenger_socket → Redis GEORADIUS +API servers → Redis GET/SET (profile cache) +Rate Limiting → Redis INCR + EXPIRE +Session Store → Redis SETEX +``` + +--- + +## 🔌 5. WebSocket Servers (سيرفرات السوكت) + +### 5.1 Driver Socket Server + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 8 Core | Workerman PHP event loop مع 500ms batch | +| **الرام** | 16 GB | كل اتصال WebSocket يستهلك ذاكرة + buffer | +| **التخزين** | 50 GB SSD | سجلات فقط | +| **الشبكة** | 1 Gbps | | + +**البوابات:** `2020` (WebSocket للسائقين)، `2021` (Internal HTTP بين السوكتات) + +### 5.2 Passenger Socket Server + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 4-8 Core | أقل تحميلاً من driver socket | +| **الرام** | 8 GB | | +| **التخزين** | 50 GB SSD | | +| **الشبكة** | 1 Gbps | | + +**البوابات:** `3030` (WebSocket للركاب)، `3031` (Internal HTTP) + +**ملاحظة:** يمكن دمج السوكتين في سيرفر واحد (Driver + Passenger على نفس الجهاز) لتوفير التكاليف إذا كان عدد المستخدمين متوسطاً. أما إذا توقعتم نمواً كبيراً، فالأفضل فصلهما. + +**نظام التشغيل للسوكتات:** يفضل Ubuntu 22.04 LTS ويحتاج PHP-CLI وليس PHP-FPM + +--- + +## 💳 6. Wallet / Payment Server (سيرفر المحفظة والمدفوعات) + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 4 Core | طلبات أقل تواتراً لكنها حسّاسة | +| **الرام** | 8 GB | | +| **التخزين** | 50 GB SSD | كود + سجلات | +| **الشبكة** | 1 Gbps | | + +**ملاحظات:** +- يمكن فصله كخدمة مستقلة أو وضعه على أحد API servers +- يحتاج اتصال مع بوابات الدفع (PayMob، MTN، Syriatel Cash) +- **هام:** يحتاج HTTPS إلزامي (ضروري لأمان المدفوعات) +- إذا كانت المدفوعات محليّة في سوريا فقط، قد تحتاج بوابات دفع سورية (MTN Cash, Syriatel Cash) + +--- + +## 🗺️ 7. OSRM Routing Server (محرك التوجيه) + +**العدد: 1-2 سيرفر (حسب عدد المسارات المطلوبة)** + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 16 Core | OSRM routing requests تستهلك CPU عالٍ | +| **الرام** | 32 GB | OSRM يحمل خريطة كاملة في الذاكرة | +| **التخزين** | 200 GB NVMe | بيانات OSM لسوريا + ملفات OSRM processed | +| **الشبكة** | 1 Gbps | | + +**حجم OSM لسوريا:** +- ملف الخريطة (syria-latest.osm.pbf) ~ 100-200 MB +- بعد معالجة OSRM (contracted graph) ~ 500 MB - 1 GB +- الذاكرة المطلوبة للتشغيل ~ 8-16 GB للخريطة نفسها + +**يمكنك تشغيله على Docker:** +```bash +docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-extract -p /opt/car.lua /data/syria-latest.osm.pbf +docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-contract /data/syria-latest.osrm +docker run -t -i -p 5000:5000 -v "${PWD}:/data" osrm/osrm-backend osrm-routed --algorithm mld /data/syria-latest.osrm +``` + +--- + +## 🗺️ 8. Map SaaS Server (سيرفر الخرائط المخصص) + +| المواصفة | المطلوب | السبب | +|----------|---------|-------| +| **المعالج** | 4-8 Core | | +| **الرام** | 16 GB | للـ tile caching والـ geocoding | +| **التخزين** | 200 GB SSD | Tile cache + بيانات جغرافية | +| **الشبكة** | 1 Gbps | | + +هذا السيرفر يقوم بـ: +- Reverse Geocoding (تحويل إحداثيات إلى عنوان) +- Place Search (البحث عن الأماكن) +- Route calculation (قد يمرر طلبات إلى OSRM) +- يمكن استخدام Nominatim + PostgreSQL/PostGIS للتجيكودينغ + +--- + +## 🌐 9. الشبكة (Network Topology) + +### 9.1 الشبكة الداخلية (Internal Network) + +**مفضّلة**: شبكة داخلية خاصة (VLAN / Private Subnet) + +``` + ┌─────────────┐ + │ Internet │ + └──────┬──────┘ + │ + ┌──────┴──────┐ + │ Firewall │ + │ (iptables/ │ + │ nftables) │ + └──────┬──────┘ + │ + ┌──────┴──────┐ + │Load Balancer │ + │(Nginx/HAProxy)│ + │ Public IP │ + └──────┬──────┘ + │ + ┌────────────────┼────────────────┐ + │ │ │ + ┌──────┴──────┐ ┌─────┴──────┐ ┌─────┴──────┐ + │ API SRV 1 │ │ API SRV 2 │ │ Socket SV │ + │ 10.0.1.10 │ │ 10.0.1.11 │ │10.0.1.20-21 │ + └──────┬──────┘ └─────┬──────┘ └──────┬──────┘ + │ │ │ + └────────────────┼────────────────┘ + │ + ┌────────────────┼────────────────┐ + │ │ │ + ┌──────┴──────┐ ┌─────┴──────┐ ┌─────┴──────┐ + │ MySQL DB │ │ Redis │ │ OSRM │ + │ 10.0.1.30 │ │ 10.0.1.31 │ │ 10.0.1.40 │ + └─────────────┘ └────────────┘ └────────────┘ + + ┌─────────────┐ ┌────────────┐ + │ Wallet SV │ │ Map SaaS │ + │ 10.0.1.50 │ │ 10.0.1.60 │ + └─────────────┘ └────────────┘ +``` + +**نطاق الشبكة الداخلية:** `10.0.1.0/24` (أي نطاق خاص) + +### 9.2 الشبكة الخارجية + +- السيرفرات التي تحتاج IP عام: **Load Balancer فقط** +- Socket Servers: يمكن تشغيل WebSocket على نفس Load Balancer (رفع بروتوكول WS إلى WSS) +- OSRM و Map SaaS: داخليان فقط (API servers تتصل بهم داخلياً) +- قاعدة البيانات: **ليست عامة أبداً** - فقط وصلات داخلية + +### 9.3 الإجراءات الأمنية + +- **Firewall**: فتح المنافذ التالية فقط من الخارج: + - 80 (HTTP → redirect to 443) + - 443 (HTTPS) + - 2020 (WebSocket driver - اختياري إذا прямо WS) + - 3030 (WebSocket passenger - اختياري) + - 22 (SSH - فقط من IPs محددة) + +- **Fail2ban**: على Load Balancer لحماية SSH و API +- **UFW/iptables**: على كل سيرفر لحجب المنافذ غير المستخدمة +- **VPN**: للوصول إلى الإدارة (Tailscale أو WireGuard) +- **SSL/TLS**: جميع الاتصالات الخارجية مشفرة + +### 9.4 هل شبكة داخلية أم خارجية؟ + +| الخدمة | المفضل | +|--------|--------| +| API ↔ Database | **داخلي** (VLAN 10.0.1.x) | +| API ↔ Redis | **داخلي** | +| Socket ↔ Database | **داخلي** | +| API ↔ Wallet | **داخلي** (أو خارجي إذا wallet على سيرفر مختلف كلياً) | +| API ↔ OSRM | **داخلي** | +| API ↔ Map SaaS | **داخلي** | +| Internet ↔ Load Balancer | **خارجي** | +| Driver App ↔ Socket | **خارجي** (لكن عبر Load Balancer أيضاً) | + +--- + +## 📍 10. اعتبارات خاصة لسوريا + +### 10.1 استضافة السيرفرات + +**الخيارات الموصى بها (بالترتيب):** + +1. **مراكز البيانات السورية:** + - **شركة الاتصالات السورية (STE)** - خدمات hosting واستضافة + - **Ayaa Cloud** - مزود خدمات سحابية سوري + - **SNS (Syrian Network Systems)** - colocation واستضافة + +2. **السيرفرات في دول مجاورة (للأداء):** + - **لبنان** (IDM، Ogero) - أقرب وأقل زمن استجابة (< 30ms) + - **الأردن** - خيار ممتاز (زمن استجابة ~ 30-50ms) + - **تركيا** - أقرب لشمال سوريا + - **الإمارات / السعودية** - استقرار أكبر لكن زمن استجابة أعلى (~ 80-100ms) + +3. **سيرفرات عالمية:** + - **Hetzner (ألمانيا/فنلندا)** - أفضل قيمة مقابل سعر (~ 150-200ms latency) + - **OVH (فرنسا)** - جيد + - **DigitalOcean / Linode** - للاستضافة السحابية + +### 10.2 مشاكل الإنترنت في سوريا + +| المشكلة | الحل | +|---------|------| +| **انقطاع الكهرباء** | UPS لكل سيرفر + مولد كهربائي للمركز | +| **ضعف سرعة الإنترنت** | استخدام Content Delivery (CDN) للملفات الثابتة | +| **الحجب (بعض الخدمات)** | استخدام VPN أو proxy للاتصال بخدمات خارجية (PayMob، Firebase) إذا لزم الأمر | +| **تكاليف النطاق العالي** | ضغط البيانات (gzip) + تحجيم الصور + lazy loading | +| **تذبذب الاتصال (Packet Loss)** | TCP tuning, BBR congestion control على السيرفرات | + +### 10.3 سرعة الإنترنت في سوريا + +| الخدمة | السرعة المتوقعة | ملاحظة | +|--------|-----------------|--------| +| ADSL | 4-16 Mbps | الأكثر انتشاراً | +| Fiber (FTTH) | 20-100 Mbps | متوفرة في المدن الكبرى | +| 4G/LTE | 10-50 Mbps | جيد للمستخدمين النهائيين | +| Business Line | 50-200 Mbps | المطلوب للسيرفرات | + +**لتطبيق مثالي في سوريا:** +- حجم API response يجب أن يكون < 50 KB +- حجم الصور مضغوط (WebP) +- استخدام Lazy loading للخرائط +- تفعيل HTTP/2 على الـ Load Balancer + +### 10.4 استهلاك النطاق الترددي المقدر + +| الخدمة | الاستهلاك التقريبي (شهرياً) | +|--------|---------------------------| +| API Requests (REST) | 200-500 GB | +| WebSocket Data | 500 GB - 2 TB | +| Map Tiles & Routing | 200-500 GB | +| Uploads (صور، وثائق) | 100-200 GB | +| **المجموع التقريبي** | **1-3 TB شهرياً** | + +--- + +## 📐 11. الترتيب المقترح للتنفيذ + +``` +المرحلة 1: البنية الأساسية +├── تجهيز Load Balancer (Nginx + SSL) +├── تجهيز MySQL Server (تركيب + ضبط + تحميل البيانات) +└── تجهيز Redis Server + +المرحلة 2: السيرفرات الأساسية +├── تجهيز API Server 1 (PHP + Nginx + FPM) +├── تجهيز API Server 2 (clone من 1) +└── ربط API Servers مع Load Balancer + +المرحلة 3: السيرفرات المساعدة +├── تجهيز Socket Server (Driver Socket + Passenger Socket) +├── تجهيز Wallet Server +└── ربط الكل مع قاعدة البيانات و Redis + +المرحلة 4: الخرائط +├── تجهيز OSRM Server (تحميل OSM سوريا + معالجة) +├── تجهيز Map SaaS Server +└── اختبار التوجيه والتجيكودينغ + +المرحلة 5: الاختبار والإطلاق +├── اختبار تحميل (Load Testing) - استخدام K6 أو Locust +├── اختبار WebSocket مع 1000+ مستخدم وهمي +├── مراقبة (Prometheus + Grafana) +└── الإطلاق التدريجي +``` + +--- + +## 💰 12. التكلفة التقديرية الشهرية (للسيرفرات) + +| السيرفر | المواصفات | التكلفة التقريبية (شهرياً) | +|---------|-----------|--------------------------| +| Load Balancer | 2 Core, 4GB | $20 - $40 | +| API Server x2 | 8 Core, 16GB (لكل) | $100 - $200 (لكل) | +| MySQL Server | 16 Core, 64GB, 1TB NVMe | $300 - $600 | +| Redis Server | 8 Core, 32GB | $100 - $200 | +| Socket Server(s) | 8 Core, 16GB | $80 - $150 | +| Wallet Server | 4 Core, 8GB | $40 - $80 | +| OSRM Server | 16 Core, 32GB | $200 - $400 | +| Map SaaS | 4 Core, 16GB | $60 - $120 | +| **المجموع التقريبي** | | **$900 - $1,890 شهرياً** | + +**ملاحظة:** الأسعار تقديرية وقد تختلف حسب المزود. السيرفرات داخل سوريا قد تكون أرخص ولكن بجودة شبكة أقل. + +--- + +## ✅ 13. الخلاصة والتوصيات + +1. **أفضل نموذج لنشر سيرفرات سوريا هو:** + - استضافة السيرفرات في **مركز بيانات سوري** أو **لبناني/أردني** + - استخدام **شبكة داخلية (VLAN)** لكل الاتصالات بين السيرفرات + - وضع **Load Balancer** واحد أمام API Servers (2) + - قاعدة البيانات الرئيسية + Redis على نفس الشبكة الداخلية مع اتصال 10 Gbps + +2. **توزيع الأدوار:** + - API Servers: 8 Cores + 16 GB RAM ✅ (كافٍ) + - Database: 16 Cores + 64 GB RAM ✅ (ضروري) + - Redis: 8 Cores + 32 GB RAM ✅ (ضروري للأداء اللحظي) + - Socket: 8 Cores + 16 GB RAM ✅ (كحد أدنى) + +3. **توفير التكاليف:** + - يمكن دمج Socket Servers في جهاز واحد (Driver + Passenger) لتوفير سيرفر + - يمكن دمج Wallet مع أحد API Servers + - يمكن استخدام OSRM Server واحد لسوريا (الخريطة صغيرة نسبياً) + +4. **أولوية الأداء في سوريا:** + - **Redis** هو أهم عنصر لأداء التطبيق (مواقع السائقين + كاش) + - **MySQL Buffer Pool** يحدد سرعة الاستعلامات + - **الـ Load Balancer** يوزع الضغط عن API servers + +5. **الأمان:** + - API Servers → قاعدة البيانات عبر مستخدم MySQL مخصص بصلاحيات محدودة + - Redis محمي بكلمة مرور (requirepass + rename-command FLUSHALL) + - جميع المفاتيح السرية في `.env` مع صلاحيات 600 + - JWT + HMAC للمدفوعات +--- diff --git a/scratch/payment_simulation.py b/scratch/payment_simulation.py new file mode 100644 index 0000000..83d1772 --- /dev/null +++ b/scratch/payment_simulation.py @@ -0,0 +1,289 @@ +import hmac +import hashlib +import json +import base64 +import uuid + +# Simulation configuration / Secrets +SECRET_KEY = "siro_super_secret_jwt_key" +SECRET_KEY_HMAC = "siro_super_secret_hmac_key" +FP_PEPPER = "siro_fp_pepper_salt" +S2S_SHARED_KEY = "s2s_shared_key_12345" + +# Mock Database +db = { + "payments": [], + "passengerWallet": {}, + "driverWallet": {}, + "invoices": {}, + "security_logs": [] +} + +def init_user(user_id, balance, is_driver=False): + if is_driver: + db["driverWallet"][user_id] = balance + else: + db["passengerWallet"][user_id] = balance + +# Helper functions for Client +def generate_jwt(user_id, device_fp): + # Mock JWT creation payload + header = base64.b64encode(json.dumps({"alg": "HS256", "typ": "JWT"}).encode()).decode().replace("=", "") + hashed_fp = hashlib.sha256((device_fp + FP_PEPPER).encode()).hexdigest() + payload = base64.b64encode(json.dumps({ + "iss": "Tripz-Wallet", + "user_id": user_id, + "fingerPrint": hashed_fp, + "exp": 1900000000 # future exp + }).encode()).decode().replace("=", "") + signature = hmac.new(SECRET_KEY.encode(), f"{header}.{payload}".encode(), hashlib.sha256).digest() + encoded_signature = base64.b64encode(signature).decode().replace("=", "").replace("+", "-").replace("/", "_") + return f"{header}.{payload}.{encoded_signature}" + +def calculate_hmac_header(user_id): + return hmac.new(SECRET_KEY_HMAC.encode(), user_id.encode(), hashlib.sha256).hexdigest() + +# Helper functions for Server Authentication +def authenticate_request(headers, payload_user_id): + # 1. JWT verification + auth_header = headers.get("Authorization", "") + if not auth_header.startswith("Bearer "): + return False, "Authorization token required" + token = auth_header.split(" ")[1] + + try: + parts = token.split(".") + if len(parts) != 3: + return False, "Invalid token structure" + # Parse payload + payload_b64 = parts[1] + payload_b64 += "=" * ((4 - len(payload_b64) % 4) % 4) + payload = json.loads(base64.b64decode(payload_b64).decode()) + except Exception as e: + return False, f"JWT decode failed: {str(e)}" + + # Check Issuer + if payload.get("iss") != "Tripz-Wallet": + return False, "Invalid token issuer" + + # Check User ID match + token_user_id = payload.get("user_id") + if token_user_id != payload_user_id: + return False, "User ID mismatch with token" + + # 2. Device Fingerprint verification + device_fp_header = headers.get("X-Device-FP") + fp_in_token = payload.get("fingerPrint") + if device_fp_header and fp_in_token: + expected_fp = hashlib.sha256((device_fp_header + FP_PEPPER).encode()).hexdigest() + if not hmac.compare_digest(expected_fp, fp_in_token): + db["security_logs"].append(f"[WARNING] Device mismatch for user {payload_user_id}!") + return False, "Device mismatch (possible Session Hijacking)" + + # 3. HMAC Auth verification + hmac_header = headers.get("X-HMAC-Auth") + if hmac_header: + expected_hmac = hmac.new(SECRET_KEY_HMAC.encode(), payload_user_id.encode(), hashlib.sha256).hexdigest() + if not hmac.compare_digest(expected_hmac, hmac_header): + db["security_logs"].append(f"[WARNING] HMAC mismatch for user {payload_user_id}!") + return False, "Invalid HMAC (possible payload/identity tampering)" + + return True, "Authenticated" + +# AI verification simulation (Mocking Gemini API) +def mock_gemini_verify_payment(invoice_number, amount, proof_text): + print(f"[Gemini AI Processing] Verifying proof for Invoice {invoice_number} of amount {amount}...") + print(f"[Gemini AI Input Proof] '{proof_text}'") + # Mocking semantic check on proof text + success = False + reason = "" + + proof_lower = proof_text.lower() + amount_str = str(int(amount)) if amount == int(amount) else str(amount) + + if amount_str in proof_lower and ("successful" in proof_lower or "transferred" in proof_lower or "تم تحويل" in proof_lower or "نجاح" in proof_lower): + success = True + reason = "Proof text verified successfully. Amount matches invoice." + else: + reason = f"Verification failed: Proof text does not indicate successful transfer of {amount}." + + print(f"[Gemini AI Output] Verified: {success}, Reason: {reason}") + return {"verified": success, "reason": reason} + +# Atomic transaction simulation for ride payment +def process_ride_payment(ride_id, driver_id, passenger_id, amount, payment_method, wallet_checked, s2s_key): + # S2S auth check + if s2s_key != S2S_SHARED_KEY: + return {"status": "failure", "message": "Unauthorized S2S call"} + + print(f"\n--- Database Transaction Initiated for Ride {ride_id} ---") + + # Save a rollback point + rollback_db = { + "payments": list(db["payments"]), + "passengerWallet": dict(db["passengerWallet"]), + "driverWallet": dict(db["driverWallet"]) + } + + try: + # 1. Insert payment record + final_method = payment_method + "Ride" if wallet_checked else payment_method + payment_record = { + "id": str(uuid.uuid4().int)[:15], + "amount": amount, + "payment_method": final_method, + "passengerID": passenger_id, + "rideId": ride_id, + "driverID": driver_id + } + db["payments"].append(payment_record) + print(f"[DB] Inserted payment record: {payment_record}") + + # 2. Deduct from passenger wallet + if wallet_checked: + if passenger_id not in db["passengerWallet"]: + db["passengerWallet"][passenger_id] = 0.0 + + db["passengerWallet"][passenger_id] -= amount + print(f"[DB] Deducted {amount} from Passenger {passenger_id}. New balance: {db["passengerWallet"][passenger_id]}") + + # Settle debt if balance was negative before (example scenario) + # here we just apply deduction. + + # 3. Deduct driver points (8% platform commission) + commission = amount * 0.08 + if driver_id not in db["driverWallet"]: + db["driverWallet"][driver_id] = 0.0 + db["driverWallet"][driver_id] -= commission + print(f"[DB] Subtracted 8% commission ({commission}) from Driver {driver_id} points. New points balance: {db["driverWallet"][driver_id]}") + + print(f"[DB] Transaction Committed successfully.") + return {"status": "success", "message": "Transaction committed"} + + except Exception as e: + # Rollback + db["payments"] = rollback_db["payments"] + db["passengerWallet"] = rollback_db["passengerWallet"] + db["driverWallet"] = rollback_db["driverWallet"] + print(f"[DB ERROR] Transaction Failed. Rolled back changes. Error: {str(e)}") + return {"status": "failure", "message": f"Transaction failed: {str(e)}"} + +# Run Scenario Simulations +def run_egypt_simulation(): + print("\n" + "="*50) + print("SCENARIO 1: EGYPT - CREDIT CARD / PAYMOB (Ahmed)") + print("="*50) + user_id = "egypt_passenger_101" + driver_id = "egypt_driver_501" + device_fp = "ahmed_iphone_13_fp_hash" + + init_user(user_id, 500.0) # passenger wallet balance + init_user(driver_id, 100.0, is_driver=True) # driver wallet points + + # 1. Client signs request + jwt = generate_jwt(user_id, device_fp) + hmac_header = calculate_hmac_header(user_id) + + headers = { + "Authorization": f"Bearer {jwt}", + "X-Device-FP": device_fp, + "X-HMAC-Auth": hmac_header + } + + print(f"Passenger {user_id} initiating payment for Egypt ride. Ride cost: 120 EGP.") + + # 2. Server authenticates headers + auth_ok, msg = authenticate_request(headers, user_id) + print(f"[Server Auth] Result: {auth_ok}, Message: {msg}") + + if auth_ok: + # S2S transaction + res = process_ride_payment( + ride_id="ride_eg_999", + driver_id=driver_id, + passenger_id=user_id, + amount=120.0, + payment_method="PayMob", + wallet_checked=True, + s2s_key=S2S_SHARED_KEY + ) + print(f"[Final Result] {res}") + +def run_syria_simulation(): + print("\n" + "="*50) + print("SCENARIO 2: SYRIA - MTN CASH WITH AI VERIFICATION (Bassel)") + print("="*50) + user_id = "syria_passenger_202" + driver_id = "syria_driver_602" + device_fp = "bassel_galaxy_s22_fp_hash" + + init_user(user_id, 0.0) # passenger starts with 0.0 + init_user(driver_id, 50.0, is_driver=True) # driver starts with 50 points + + jwt = generate_jwt(user_id, device_fp) + hmac_header = calculate_hmac_header(user_id) + headers = { + "Authorization": f"Bearer {jwt}", + "X-Device-FP": device_fp, + "X-HMAC-Auth": hmac_header + } + + invoice_number = "INV-MTN-8877" + amount = 50000.0 # 50,000 SYP for the ride/wallet load + + print(f"Passenger {user_id} loads wallet via MTN Cash for invoice {invoice_number} of {amount} SYP.") + print("User transfers money and uploads transaction SMS proof.") + + proof_text = "MTN Cash: You have successfully transferred 50000 SYP to SIRO system. Ref: 9812739182." + + # 1. Server authenticates headers + auth_ok, msg = authenticate_request(headers, user_id) + print(f"[Server Auth] Result: {auth_ok}, Message: {msg}") + + if auth_ok: + # 2. AI verifies proof text + ai_res = mock_gemini_verify_payment(invoice_number, amount, proof_text) + + if ai_res["verified"]: + print(f"[Server] AI verified payment. Settle wallet.") + # Atomic settlement + print(f"\n--- Wallet Settlement Transaction Initiated (Syria) ---") + db["passengerWallet"][user_id] += amount + print(f"[DB] Added {amount} SYP to passenger {user_id} wallet. New balance: {db["passengerWallet"][user_id]} SYP") + print("[DB] Transaction Committed.") + else: + print(f"[Server] Payment rejected: {ai_res['reason']}") + +def run_jordan_simulation(): + print("\n" + "="*50) + print("SCENARIO 3: JORDAN - CLIQ WITH TAMPERED DEVICE FINGERPRINT (Rania)") + print("="*50) + user_id = "jordan_passenger_303" + device_fp = "rania_oneplus_11_fp_hash" + tampered_fp = "hijacked_device_fp_hash" # Attacker trying to reuse Rania's token from a different device + + # 1. Client token generated for Rania on her real device + jwt = generate_jwt(user_id, device_fp) + hmac_header = calculate_hmac_header(user_id) + + # Attacker sends request with correct JWT but hijacked/different device fingerprint header + headers = { + "Authorization": f"Bearer {jwt}", + "X-Device-FP": tampered_fp, # Hijacked device header + "X-HMAC-Auth": hmac_header + } + + print(f"Attacker attempts to trigger payment under Rania's user_id using hijacked token on different device.") + + # 2. Server authenticates headers + auth_ok, msg = authenticate_request(headers, user_id) + print(f"[Server Auth] Result: {auth_ok}, Message: {msg}") + + if not auth_ok: + print("[Server Alert] Attack blocked successfully! Session Hijacking thwarted.") + print(f"Security logs: {db['security_logs']}") + +if __name__ == "__main__": + run_egypt_simulation() + run_syria_simulation() + run_jordan_simulation() diff --git a/siro_admin/android/build/reports/problems/problems-report.html b/siro_admin/android/build/reports/problems/problems-report.html index 7eb1b63..36e7f14 100644 --- a/siro_admin/android/build/reports/problems/problems-report.html +++ b/siro_admin/android/build/reports/problems/problems-report.html @@ -650,7 +650,7 @@ code + .copy-button { diff --git a/walletintaleq.intaleq.xyz/WalletDB.sql b/walletintaleq.intaleq.xyz/WalletDB.sql new file mode 100644 index 0000000..c746303 --- /dev/null +++ b/walletintaleq.intaleq.xyz/WalletDB.sql @@ -0,0 +1,970 @@ +-- phpMyAdmin SQL Dump +-- version 5.2.2 +-- https://www.phpmyadmin.net/ +-- +-- Host: 127.0.0.1:3306 +-- Generation Time: Jun 16, 2026 at 05:29 PM +-- Server version: 8.0.43-0ubuntu0.22.04.2 +-- PHP Version: 8.1.33 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `WalletIntaleqDB` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `adminUser` +-- + +CREATE TABLE `adminUser` ( + `id` int NOT NULL, + `device_number` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, + `name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cliq_invoices` +-- + +CREATE TABLE `cliq_invoices` ( + `id` int NOT NULL, + `invoice_number` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, + `user_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, + `user_type` varchar(20) COLLATE utf8mb4_general_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `cliq_phone` varchar(50) COLLATE utf8mb4_general_ci NOT NULL, + `status` varchar(20) COLLATE utf8mb4_general_ci DEFAULT 'pending', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driver` +-- + +CREATE TABLE `driver` ( + `id` varchar(100) NOT NULL, + `phone` varchar(20) NOT NULL, + `email` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `gender` varchar(10) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT 'Male', + `license_type` varchar(255) DEFAULT NULL, + `national_number` varchar(255) DEFAULT NULL, + `name_arabic` varchar(255) DEFAULT NULL, + `name_english` varchar(255) DEFAULT NULL, + `issue_date` date DEFAULT NULL, + `expiry_date` date DEFAULT NULL, + `license_categories` varchar(255) DEFAULT NULL, + `address` text, + `card_id` varchar(255) DEFAULT NULL, + `occupation` varchar(255) DEFAULT NULL, + `licenseIssueDate` varchar(50) DEFAULT NULL, + `religion` varchar(255) DEFAULT NULL, + `status` varchar(20) NOT NULL DEFAULT 'notDeleted', + `birthdate` varchar(20) NOT NULL, + `site` varchar(255) NOT NULL, + `first_name` varchar(255) NOT NULL, + `last_name` varchar(255) NOT NULL, + `accountBank` varchar(55) NOT NULL DEFAULT 'yet', + `bankCode` varchar(20) NOT NULL DEFAULT 'CIB', + `education` varchar(255) DEFAULT NULL, + `employmentType` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `maritalStatus` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `fullNameMaritial` varchar(255) DEFAULT NULL, + `expirationDate` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driverToken` +-- + +CREATE TABLE `driverToken` ( + `id` int NOT NULL, + `token` varchar(255) NOT NULL, + `captain_id` varchar(255) NOT NULL, + `fingerPrint` varchar(100) NOT NULL, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driverWallet` +-- + +CREATE TABLE `driverWallet` ( + `id` int NOT NULL, + `driverID` varchar(100) NOT NULL, + `paymentID` varchar(200) NOT NULL, + `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `amount` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL, + `paymentMethod` varchar(20) NOT NULL, + `dateUpdated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `driver_withdrawal_requests` +-- + +CREATE TABLE `driver_withdrawal_requests` ( + `id` int NOT NULL, + `driver_id` varchar(255) NOT NULL, + `driver_name` varchar(255) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `wallet_type` varchar(50) NOT NULL, + `wallet_number` varchar(50) NOT NULL, + `status` varchar(50) NOT NULL DEFAULT 'pending', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ecash_transactions` +-- + +CREATE TABLE `ecash_transactions` ( + `id` bigint UNSIGNED NOT NULL, + `order_ref` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `user_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `passenger_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', + `ecash_transaction_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `ecash_transactions_driver` +-- + +CREATE TABLE `ecash_transactions_driver` ( + `id` bigint UNSIGNED NOT NULL, + `order_ref` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `driver_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', + `ecash_transaction_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_shamcash` +-- + +CREATE TABLE `invoices_shamcash` ( + `id` int NOT NULL, + `invoice_number` int NOT NULL, + `driverID` varchar(44) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending', + `transaction_id` varchar(50) DEFAULT NULL COMMENT 'رقم عملية شام كاش لمنع التكرار', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `paid_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_shamcash_passenger` +-- + +CREATE TABLE `invoices_shamcash_passenger` ( + `id` int NOT NULL, + `invoice_number` int NOT NULL, + `passengerID` varchar(33) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending', + `transaction_id` varchar(50) DEFAULT NULL, + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `paid_at` datetime DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_sms` +-- + +CREATE TABLE `invoices_sms` ( + `id` int NOT NULL, + `invoice_number` varchar(20) NOT NULL, + `user_phone` varchar(20) NOT NULL, + `amount` decimal(10,3) NOT NULL, + `status` enum('pending','completed','failed') NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `driverID` varchar(33) DEFAULT NULL, + `currency` varchar(8) DEFAULT 'SYP' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `invoices_sms_passenger` +-- + +CREATE TABLE `invoices_sms_passenger` ( + `id` int NOT NULL, + `invoice_number` varchar(20) NOT NULL, + `user_phone` varchar(20) NOT NULL, + `amount` decimal(10,0) NOT NULL, + `status` enum('pending','completed','failed') NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `passengerID` varchar(33) NOT NULL, + `currency` varchar(8) NOT NULL DEFAULT 'SYP' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `kazan` +-- + +CREATE TABLE `kazan` ( + `id` int NOT NULL, + `country` varchar(30) NOT NULL, + `kazan` varchar(10) NOT NULL, + `comfortPrice` varchar(10) NOT NULL, + `speedPrice` varchar(10) NOT NULL, + `deliveryPrice` varchar(11) NOT NULL, + `freePrice` varchar(11) NOT NULL, + `latePrice` varchar(10) NOT NULL, + `heavyPrice` varchar(10) NOT NULL, + `adminId` varchar(100) NOT NULL, + `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `naturePrice` varchar(10) NOT NULL, + `fuelPrice` varchar(6) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `mtn_invoices` +-- + +CREATE TABLE `mtn_invoices` ( + `id` int NOT NULL, + `invoice_number` varchar(20) NOT NULL, + `user_id` varchar(50) NOT NULL, + `user_type` enum('driver','passenger') NOT NULL COMMENT 'يحدد هل المستخدم سائق أم راكب', + `amount` decimal(10,2) NOT NULL, + `mtn_phone` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'رقم MTN الذي سيتم الدفع منه', + `status` enum('pending','completed','failed','expired') NOT NULL DEFAULT 'pending', + `mtn_transaction_id` varchar(255) DEFAULT NULL COMMENT 'معرّف العملية من طرف MTN بعد الدفع', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `passengers` +-- + +CREATE TABLE `passengers` ( + `id` varchar(100) NOT NULL, + `phone` varchar(15) NOT NULL, + `email` varchar(255) NOT NULL, + `password` varchar(100) NOT NULL, + `gender` varchar(25) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL, + `status` varchar(20) NOT NULL DEFAULT 'notDeleted', + `birthdate` varchar(44) NOT NULL, + `site` varchar(255) NOT NULL, + `first_name` varchar(255) NOT NULL, + `last_name` varchar(255) NOT NULL, + `sosPhone` varchar(33) NOT NULL DEFAULT 'sos', + `education` varchar(30) NOT NULL DEFAULT 'none', + `employmentType` varchar(30) NOT NULL DEFAULT 'none', + `maritalStatus` varchar(30) NOT NULL DEFAULT 'none', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `passengerWallet` +-- + +CREATE TABLE `passengerWallet` ( + `id` int NOT NULL, + `passenger_id` varchar(100) NOT NULL, + `balance` decimal(10,2) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payments` +-- + +CREATE TABLE `payments` ( + `id` varchar(111) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `payment_method` varchar(255) NOT NULL, + `passengerID` varchar(100) NOT NULL, + `rideId` varchar(100) NOT NULL, + `driverID` varchar(100) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `isGiven` varchar(20) NOT NULL DEFAULT 'waiting' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsDriverPoints` +-- + +CREATE TABLE `paymentsDriverPoints` ( + `id` int NOT NULL, + `amount` decimal(10,2) NOT NULL, + `payment_method` varchar(50) NOT NULL, + `driverID` varchar(60) NOT NULL, + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsLog` +-- + +CREATE TABLE `paymentsLog` ( + `id` int NOT NULL, + `payment_id` varchar(255) NOT NULL, + `user_id` char(40) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` tinyint NOT NULL DEFAULT '0', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsLogSyria` +-- + +CREATE TABLE `paymentsLogSyria` ( + `id` int NOT NULL, + `user_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` tinyint NOT NULL DEFAULT '0', + `order_ref` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'ecash', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `paymentsLogSyriaDriver` +-- + +CREATE TABLE `paymentsLogSyriaDriver` ( + `id` int NOT NULL, + `user_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `amount` decimal(10,2) NOT NULL DEFAULT '0.00', + `status` tinyint NOT NULL DEFAULT '2', + `processed_wallet` tinyint(1) NOT NULL DEFAULT '0', + `order_ref` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, + `payment_method` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'ecash', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payment_log_driver` +-- + +CREATE TABLE `payment_log_driver` ( + `id` int NOT NULL, + `payment_id` varchar(255) NOT NULL, + `user_id` char(70) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `amount` decimal(10,2) NOT NULL, + `status` tinyint(1) NOT NULL DEFAULT '0', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payment_tokens` +-- + +CREATE TABLE `payment_tokens` ( + `id` int NOT NULL, + `token` varchar(255) NOT NULL, + `driverID` varchar(255) NOT NULL, + `dateCreated` datetime NOT NULL, + `amount` decimal(10,2) NOT NULL, + `isUsed` tinyint(1) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payment_tokens_passenger` +-- + +CREATE TABLE `payment_tokens_passenger` ( + `id` int NOT NULL, + `token` varchar(255) NOT NULL, + `passengerId` varchar(255) NOT NULL, + `dateCreated` datetime NOT NULL, + `amount` decimal(10,2) NOT NULL, + `isUsed` tinyint(1) DEFAULT '0' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `payout_requests` +-- + +CREATE TABLE `payout_requests` ( + `id` int NOT NULL, + `driver_id` varchar(35) NOT NULL, + `driver_phone` varchar(20) NOT NULL, + `amount` decimal(10,2) NOT NULL, + `wallet_type` varchar(50) DEFAULT NULL, + `status` enum('pending','completed','failed') NOT NULL DEFAULT 'pending', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `completed_at` timestamp NULL DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `phone_verification` +-- + +CREATE TABLE `phone_verification` ( + `id` int NOT NULL, + `phone_number` varchar(20) NOT NULL, + `driverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'yet', + `email` varchar(50) NOT NULL DEFAULT 'yet', + `token_code` varchar(10) NOT NULL, + `expiration_time` datetime NOT NULL, + `is_verified` tinyint(1) DEFAULT '0', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `phone_verification_passenger` +-- + +CREATE TABLE `phone_verification_passenger` ( + `id` int NOT NULL, + `phone_number` varchar(15) NOT NULL, + `token` varchar(6) NOT NULL, + `expiration_time` datetime NOT NULL, + `verified` tinyint(1) DEFAULT '0', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `raw_sms_log` +-- + +CREATE TABLE `raw_sms_log` ( + `id` int NOT NULL, + `sender` varchar(50) NOT NULL, + `message_body` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `status` enum('pending','processed','failed') NOT NULL DEFAULT 'pending', + `gemini_result` json DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `siroWallet` +-- + +CREATE TABLE `siroWallet` ( + `id` int NOT NULL, + `driverId` varchar(100) NOT NULL, + `passengerId` varchar(100) NOT NULL, + `amount` varchar(10) NOT NULL, + `paymentMethod` varchar(50) NOT NULL, + `token` varchar(100) NOT NULL, + `createdAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `smsSender` +-- + +CREATE TABLE `smsSender` ( + `id` int NOT NULL, + `senderId` varchar(20) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `tokens` +-- + +CREATE TABLE `tokens` ( + `id` int NOT NULL, + `token` varchar(333) NOT NULL, + `passengerID` varchar(111) NOT NULL, + `fingerPrint` varchar(300) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `adminUser` +-- +ALTER TABLE `adminUser` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `cliq_invoices` +-- +ALTER TABLE `cliq_invoices` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `invoice_number` (`invoice_number`); + +-- +-- Indexes for table `driver` +-- +ALTER TABLE `driver` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `phone` (`phone`,`email`), + ADD UNIQUE KEY `national_number` (`national_number`); + +-- +-- Indexes for table `driverToken` +-- +ALTER TABLE `driverToken` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `driverWallet` +-- +ALTER TABLE `driverWallet` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `driver_withdrawal_requests` +-- +ALTER TABLE `driver_withdrawal_requests` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `ecash_transactions` +-- +ALTER TABLE `ecash_transactions` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_ref_unique` (`order_ref`), + ADD KEY `user_id_index` (`user_id`), + ADD KEY `passenger_id_index` (`passenger_id`); + +-- +-- Indexes for table `ecash_transactions_driver` +-- +ALTER TABLE `ecash_transactions_driver` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `order_ref_unique_driver` (`order_ref`), + ADD KEY `driver_id_index` (`driver_id`); + +-- +-- Indexes for table `invoices_shamcash` +-- +ALTER TABLE `invoices_shamcash` + ADD PRIMARY KEY (`id`), + ADD KEY `invoice_number` (`invoice_number`), + ADD KEY `status` (`status`); + +-- +-- Indexes for table `invoices_shamcash_passenger` +-- +ALTER TABLE `invoices_shamcash_passenger` + ADD PRIMARY KEY (`id`), + ADD KEY `invoice_number` (`invoice_number`), + ADD KEY `status` (`status`); + +-- +-- Indexes for table `invoices_sms` +-- +ALTER TABLE `invoices_sms` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `invoice_number` (`invoice_number`), + ADD KEY `idx_user_phone` (`user_phone`), + ADD KEY `idx_status` (`status`); + +-- +-- Indexes for table `invoices_sms_passenger` +-- +ALTER TABLE `invoices_sms_passenger` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `uniq_invoice_number_passenger` (`invoice_number`); + +-- +-- Indexes for table `kazan` +-- +ALTER TABLE `kazan` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `mtn_invoices` +-- +ALTER TABLE `mtn_invoices` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `invoice_number` (`invoice_number`), + ADD KEY `idx_user` (`user_id`,`user_type`), + ADD KEY `idx_status` (`status`); + +-- +-- Indexes for table `passengers` +-- +ALTER TABLE `passengers` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `phone` (`phone`,`email`); + +-- +-- Indexes for table `passengerWallet` +-- +ALTER TABLE `passengerWallet` + ADD PRIMARY KEY (`id`), + ADD KEY `passenger_id` (`passenger_id`); + +-- +-- Indexes for table `payments` +-- +ALTER TABLE `payments` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `rideId` (`rideId`); + +-- +-- Indexes for table `paymentsDriverPoints` +-- +ALTER TABLE `paymentsDriverPoints` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `paymentsLog` +-- +ALTER TABLE `paymentsLog` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `payment_id` (`payment_id`); + +-- +-- Indexes for table `paymentsLogSyria` +-- +ALTER TABLE `paymentsLogSyria` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `paymentsLogSyriaDriver` +-- +ALTER TABLE `paymentsLogSyriaDriver` + ADD PRIMARY KEY (`id`), + ADD KEY `order_ref_index` (`order_ref`); + +-- +-- Indexes for table `payment_log_driver` +-- +ALTER TABLE `payment_log_driver` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `payment_id` (`payment_id`); + +-- +-- Indexes for table `payment_tokens` +-- +ALTER TABLE `payment_tokens` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `payment_tokens_passenger` +-- +ALTER TABLE `payment_tokens_passenger` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `payout_requests` +-- +ALTER TABLE `payout_requests` + ADD PRIMARY KEY (`id`), + ADD KEY `driver_id_status` (`driver_id`,`status`); + +-- +-- Indexes for table `phone_verification` +-- +ALTER TABLE `phone_verification` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `phone_verification_passenger` +-- +ALTER TABLE `phone_verification_passenger` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `phone_number` (`phone_number`); + +-- +-- Indexes for table `raw_sms_log` +-- +ALTER TABLE `raw_sms_log` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `siroWallet` +-- +ALTER TABLE `siroWallet` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `smsSender` +-- +ALTER TABLE `smsSender` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `tokens` +-- +ALTER TABLE `tokens` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `passengerID` (`passengerID`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `adminUser` +-- +ALTER TABLE `adminUser` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `cliq_invoices` +-- +ALTER TABLE `cliq_invoices` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `driverToken` +-- +ALTER TABLE `driverToken` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `driverWallet` +-- +ALTER TABLE `driverWallet` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `driver_withdrawal_requests` +-- +ALTER TABLE `driver_withdrawal_requests` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `ecash_transactions` +-- +ALTER TABLE `ecash_transactions` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `ecash_transactions_driver` +-- +ALTER TABLE `ecash_transactions_driver` + MODIFY `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_shamcash` +-- +ALTER TABLE `invoices_shamcash` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_shamcash_passenger` +-- +ALTER TABLE `invoices_shamcash_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_sms` +-- +ALTER TABLE `invoices_sms` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `invoices_sms_passenger` +-- +ALTER TABLE `invoices_sms_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `kazan` +-- +ALTER TABLE `kazan` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `mtn_invoices` +-- +ALTER TABLE `mtn_invoices` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `passengerWallet` +-- +ALTER TABLE `passengerWallet` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsDriverPoints` +-- +ALTER TABLE `paymentsDriverPoints` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsLog` +-- +ALTER TABLE `paymentsLog` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsLogSyria` +-- +ALTER TABLE `paymentsLogSyria` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `paymentsLogSyriaDriver` +-- +ALTER TABLE `paymentsLogSyriaDriver` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payment_log_driver` +-- +ALTER TABLE `payment_log_driver` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payment_tokens` +-- +ALTER TABLE `payment_tokens` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payment_tokens_passenger` +-- +ALTER TABLE `payment_tokens_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `payout_requests` +-- +ALTER TABLE `payout_requests` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `phone_verification` +-- +ALTER TABLE `phone_verification` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `phone_verification_passenger` +-- +ALTER TABLE `phone_verification_passenger` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `raw_sms_log` +-- +ALTER TABLE `raw_sms_log` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `siroWallet` +-- +ALTER TABLE `siroWallet` + ADD AUTO_INCREMENT = 1; + + +-- +-- AUTO_INCREMENT for table `smsSender` +-- +ALTER TABLE `smsSender` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `tokens` +-- +ALTER TABLE `tokens` + MODIFY `id` int NOT NULL AUTO_INCREMENT; +-- +-- Table structure for table `admin_audit_log` +-- + +CREATE TABLE `admin_audit_log` ( + `id` int NOT NULL AUTO_INCREMENT, + `admin_id` varchar(150) NOT NULL, + `action` varchar(255) NOT NULL, + `table_name` varchar(255) DEFAULT NULL, + `record_id` varchar(255) DEFAULT NULL, + `details` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php b/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php index 4151d2d..abda192 100755 --- a/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php +++ b/walletintaleq.intaleq.xyz/v2/main/jwtconnect.php @@ -1,4 +1,21 @@ + * + * أي طلب بدون أي مصادقة → يُرفض تلقائياً من authenticateJWT() + * ═══════════════════════════════════════════════════════════════ + */ + // Load environment variables from .env file require_once realpath(__DIR__ . '/../vendor/autoload.php'); require_once 'load_env.php'; @@ -10,7 +27,7 @@ $secretKey = getenv('SECRET_KEY'); // Only need the secret key now // --- CORS Headers --- $allowedOrigins = [ - 'https://walletintaleq.intaleq.xyz', + 'https://wallet.siromove.com', 'https://wallet-syria.siromove.com', 'https://wallet-egypt.siromove.com', @@ -22,17 +39,19 @@ if (in_array($origin, $allowedOrigins)) { } else { header("Access-Control-Allow-Origin: https://walletintaleq.intaleq.xyz"); } -header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // Adjust as needed -header("Access-Control-Allow-Headers: Content-Type, Authorization"); -header('Content-Type: application/json'); // Set content type to JSON +header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); +header("Access-Control-Allow-Headers: Content-Type, Authorization, X-S2S-Api-Key, PAYMENT_KEY, X-Auth-Token, X-Cron-Key, X-HMAC-Auth, X-Device-FP"); +header('Content-Type: application/json'); // Handle preflight requests (OPTIONS) if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { http_response_code(200); exit; } - $dbname = getenv('dbname'); -// --- Database Connection (Still needed for your application logic) --- + +$dbname = getenv('dbname'); + +// --- Database Connection --- try { $dsn = "mysql:host=localhost;dbname=$dbname;charset=utf8mb4"; $options = [ @@ -41,19 +60,75 @@ try { PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8" ]; - $user = getenv('USER'); // Still used for DB connection - $pass = getenv('PASS'); // Still used for DB connection + $user = getenv('USER'); + $pass = getenv('PASS'); $con = new PDO($dsn, $user, $pass, $options); - // --- JWT Authentication --- - include "functions.php"; // Include the functions file + // --- Load Functions --- + include "functions.php"; - + // ═══════════════════════════════════════════════════════════ + // UNIFIED AUTHENTICATION GATEWAY (بوابة المصادقة الموحدة) + // ═══════════════════════════════════════════════════════════ + $authMethod = null; + $decodedToken = null; + + // --- Path 1: S2S API Key (server-to-server calls) --- + $s2sKey = $_SERVER['HTTP_X_S2S_API_KEY'] ?? ''; + $expectedS2s = getenv('S2S_SHARED_KEY'); + + if (!empty($s2sKey) && !empty($expectedS2s) && hash_equals($expectedS2s, $s2sKey)) { + $authMethod = 'S2S'; + } + + // --- Path 2: Payment Key (transfer endpoint) --- + if (!$authMethod) { + $paymentKey = $_SERVER['HTTP_PAYMENT_KEY'] ?? ''; + $expectedPayment = getenv('PAYMENT_KEY'); + + if (!empty($paymentKey) && !empty($expectedPayment) && hash_equals($expectedPayment, $paymentKey)) { + $authMethod = 'PAYMENT_KEY'; + } + } + + // --- Path 3: Webhook Auth Token (MTN/Cliq external services) --- + // ملاحظة: البوابة تعترف بوجود الهيدر فقط. كل webhook يتحقق من القيمة الفعلية بنفسه. + if (!$authMethod) { + $webhookToken = $_SERVER['HTTP_X_AUTH_TOKEN'] ?? ''; + + if (!empty($webhookToken)) { + $authMethod = 'WEBHOOK'; + } + } + + // --- Path 4: Cron Key / CLI execution --- + if (!$authMethod) { + // 4a: CLI execution (php script.php directly) + if (php_sapi_name() === 'cli' || php_sapi_name() === 'cli-server') { + $authMethod = 'CLI'; + } else { + // 4b: HTTP cron call with key header + $cronKey = $_SERVER['HTTP_X_CRON_KEY'] ?? ''; + $expectedCron = getenv('CRON_KEY'); + + if (!empty($cronKey) && !empty($expectedCron) && hash_equals($expectedCron, $cronKey)) { + $authMethod = 'CRON'; + } + } + } + + // --- Path 5 (DEFAULT): JWT Authentication --- + // إذا لم يتم التعرف على أي مسار آخر، يُفرض JWT. + // authenticateJWT() ستُرجع 401 وتوقف التنفيذ إذا لم يكن هناك JWT صالح. + if (!$authMethod) { + $decodedToken = authenticateJWT(); + $authMethod = 'JWT'; + } } catch (PDOException $e) { error_log($e->getMessage()); - http_response_code(500); // Internal Server Error + http_response_code(500); echo json_encode(['error' => 'A database error occurred.']); exit; } diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php b/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php index baaf782..adb7862 100755 --- a/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/cliq/finalize_payment.php @@ -64,9 +64,9 @@ function finalizeForDriver(PDO $con, int $driverId, float $amount, string $payme if ($stmtDriver->rowCount() === 0) throw new Exception('Insert to driverWallet failed.'); // إضافة سجل محاسبي لمحفظة سفر - $stmtSefer = $con->prepare("INSERT INTO seferWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)"); - $stmtSefer->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); - if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet failed.'); + $stmtSiro = $con->prepare("INSERT INTO siroWallet (driverId, passengerId, amount, paymentMethod) VALUES (:driverId, 'driver', :amount, :paymentMethod)"); + $stmtSiro->execute([':driverId' => $driverId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); + if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet failed.'); return ['success' => true, 'message' => 'Driver wallets updated.']; } @@ -90,9 +90,9 @@ function finalizeForPassenger(PDO $con, string $passengerId, float $amount, stri if ($stmtPassenger->rowCount() === 0) throw new Exception('Update passengerWallet failed.'); // إضافة سجل محاسبي لمحفظة سفر - $stmtSefer = $con->prepare("INSERT INTO seferWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)"); - $stmtSefer->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); - if ($stmtSefer->rowCount() === 0) throw new Exception('Insert to seferWallet for passenger failed.'); + $stmtSiro = $con->prepare("INSERT INTO siroWallet (passengerId, driverId, amount, paymentMethod) VALUES (:passengerId, 'passenger', :amount, :paymentMethod)"); + $stmtSiro->execute([':passengerId' => $passengerId, ':amount' => $amount, ':paymentMethod' => $paymentMethod]); + if ($stmtSiro->rowCount() === 0) throw new Exception('Insert to siroWallet for passenger failed.'); return ['success' => true, 'message' => 'Passenger wallets updated.']; } diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php index 90a31a3..e6a207f 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/add.php @@ -1,58 +1,104 @@ user_id ?? $decodedToken->sub ?? null; + +// ── 2. استخراج والتحقق من البيانات ────────────────────────── +$driverID = filterRequest("driverID"); +$paymentID = filterRequest("paymentID"); +$amount = filterRequest("amount"); $paymentMethod = filterRequest("paymentMethod"); -$token = filterRequest("token"); +$token = filterRequest("token"); -// Retrieve token details from the database -$stmt = $con->prepare("SELECT * FROM payment_tokens WHERE token = :token AND isUsed = FALSE"); -$stmt->execute(array( - ':token' => $token -)); - -$tokenData = $stmt->fetch(); - -if ($tokenData) { - // Add payment to the driver's wallet table - $sql = "INSERT INTO `driverWallet` ( - `driverID`, - `paymentID`, - `amount`, - `paymentMethod` - ) VALUES ( - :driverID, - :paymentID, - :amount, - :paymentMethod - );"; - - $stmt = $con->prepare($sql); - $stmt->execute(array( - ':driverID' => $driverID, - ':paymentID' => $paymentID, - ':amount' => $amount, - ':paymentMethod' => $paymentMethod - )); - - if ($stmt->rowCount() > 0) { - // Print a success message - printSuccess("Record saved successfully"); - - // Mark the token as used in the database - $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID"); - $stmt->execute(array( - ':tokenID' => $tokenData['id'] - )); - } else { - // Print a failure message - printFailure("Failed to save record"); - } -} else { - printFailure("Invalid or already used token"); +if (empty($driverID) || !isset($amount) || empty($paymentMethod) || empty($token)) { + printFailure("Missing required parameters"); + exit; } + +// ── 3. التحقق من ملكية الحساب ──────────────────────────────── +// السائق المصادق يمكنه فقط إضافة رصيد لمحفظته الشخصية +if ($jwtUserId !== null && $driverID !== $jwtUserId) { + error_log(sprintf( + '⚠️ [SECURITY] Ownership mismatch in add.php | jwt_user=%s | requested_driverID=%s | IP=%s', + $jwtUserId, $driverID, $_SERVER['REMOTE_ADDR'] ?? 'unknown' + )); + http_response_code(403); + printFailure("Forbidden: You can only modify your own wallet"); + exit; +} + +// ── 4. التحقق من المبلغ ───────────────────────────────────── +$amount = floatval($amount); +if ($amount <= 0 || $amount > 1000000) { + printFailure("Invalid amount"); + exit; +} + +// ── 5. العملية الذرية ───────────────────────────────────────── +try { + $con->beginTransaction(); + + // التحقق من التوكن مع قفل السجل (FOR UPDATE) لمنع Race Condition + $stmt = $con->prepare("SELECT * FROM payment_tokens WHERE token = :token AND isUsed = FALSE FOR UPDATE"); + $stmt->execute([':token' => $token]); + $tokenData = $stmt->fetch(); + + if ($tokenData) { + // إدخال سجل المحفظة + $sql = "INSERT INTO `driverWallet` ( + `driverID`, + `paymentID`, + `amount`, + `paymentMethod` + ) VALUES ( + :driverID, + :paymentID, + :amount, + :paymentMethod + );"; + + $stmt = $con->prepare($sql); + $stmt->execute([ + ':driverID' => $driverID, + ':paymentID' => $paymentID, + ':amount' => $amount, + ':paymentMethod' => $paymentMethod + ]); + + if ($stmt->rowCount() > 0) { + // تحديث حالة التوكن + $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID"); + $stmt->execute([':tokenID' => $tokenData['id']]); + + $con->commit(); + printSuccess("Record saved successfully"); + } else { + $con->rollBack(); + printFailure("Failed to save record"); + } + } else { + $con->rollBack(); + printFailure("Invalid or already used token"); + } +} catch (Exception $e) { + if ($con->inTransaction()) { + $con->rollBack(); + } + error_log("[driverWallet/add] " . $e->getMessage()); + printFailure("An error occurred"); +} + diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php index 94bf50b..803653b 100755 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/addFromAdmin.php @@ -1,17 +1,67 @@ user_id ?? $decodedToken->sub ?? null; +$adminRole = $decodedToken->role ?? null; + +// ── 2. التحقق من صلاحيات المسؤول ──────────────────────────── +// فقط المسؤول يمكنه إضافة رصيد يدوياً +if ($adminRole !== 'admin' && $adminRole !== 'super_admin') { + error_log(sprintf( + '⚠️ [SECURITY] Non-admin attempted addFromAdmin | user=%s | role=%s | IP=%s', + $adminUserId, + $adminRole ?? '(null)', + $_SERVER['REMOTE_ADDR'] ?? 'unknown' + )); + http_response_code(403); + printFailure("Forbidden: Admin access required"); + exit; +} + +// ── 3. استخراج والتحقق من البيانات ────────────────────────── +$driverID = filterRequest("driverID"); +$paymentID = filterRequest("paymentID"); +$amount = filterRequest("amount"); $paymentMethod = filterRequest("paymentMethod"); -$phone = filterRequest("phone"); +$phone = filterRequest("phone"); +if (empty($driverID) || !isset($amount) || empty($paymentMethod)) { + printFailure("Missing required parameters: driverID, amount, paymentMethod"); + exit; +} - // Add payment to the driver's wallet table +// ── 4. التحقق من المبلغ ───────────────────────────────────── +$amount = floatval($amount); +if ($amount <= 0 || $amount > 1000000) { + error_log(sprintf( + '⚠️ [SECURITY] Invalid amount in addFromAdmin | admin=%s | amount=%s | driverID=%s', + $adminUserId, $amount, $driverID + )); + printFailure("Invalid amount: must be between 0 and 1,000,000"); + exit; +} + +// ── 5. العملية الذرية ───────────────────────────────────────── +try { + $con->beginTransaction(); + + // إدخال سجل المحفظة $sql = "INSERT INTO `driverWallet` ( `driverID`, `paymentID`, @@ -25,27 +75,51 @@ $phone = filterRequest("phone"); );"; $stmt = $con->prepare($sql); - $stmt->execute(array( - ':driverID' => $driverID, - ':paymentID' => $paymentID, - ':amount' => $amount, + $stmt->execute([ + ':driverID' => $driverID, + ':paymentID' => $paymentID ?? ('admin_' . time() . '_' . bin2hex(random_bytes(4))), + ':amount' => $amount, ':paymentMethod' => $paymentMethod - )); + ]); if ($stmt->rowCount() > 0) { - // Print a success message + // ── 6. تسجيل تدقيق (Audit Log) ───────────────────────── + $auditStmt = $con->prepare( + "INSERT INTO `admin_audit_log` (`admin_id`, `action`, `table_name`, `record_id`, `details`) + VALUES (:admin_id, :action, :table_name, :record_id, :details)" + ); + $auditStmt->execute([ + ':admin_id' => $adminUserId, + ':action' => 'addFromAdmin_wallet', + ':table_name' => 'driverWallet', + ':record_id' => $driverID, + ':details' => json_encode([ + 'amount' => $amount, + 'paymentMethod' => $paymentMethod, + 'phone' => $phone, + 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown', + 'timestamp' => date('Y-m-d H:i:s') + ], JSON_UNESCAPED_UNICODE) + ]); + + $con->commit(); + printSuccess("Record saved successfully"); - $messageBody = "تم إضافة رصيد بقيمة $amount إلى محفظتك بنجاح."; // "Balance of $amount added successfully." - - sendWhatsAppFromServer($phone, $messageBody); - - // Mark the token as used in the database - /* $stmt = $con->prepare("UPDATE payment_tokens SET isUsed = TRUE WHERE id = :tokenID"); - $stmt->execute(array( - ':tokenID' => $tokenData['id'] - ));*/ + + // إرسال إشعار واتساب للسائق + if (!empty($phone)) { + $messageBody = "تم إضافة رصيد بقيمة $amount إلى محفظتك بنجاح."; + sendWhatsAppFromServer($phone, $messageBody); + } } else { - // Print a failure message + $con->rollBack(); printFailure("Failed to save record"); } +} catch (Exception $e) { + if ($con->inTransaction()) { + $con->rollBack(); + } + error_log("[addFromAdmin] Error: " . $e->getMessage()); + printFailure("An error occurred"); +} diff --git a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php index acbe062..6df9668 100644 --- a/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php +++ b/walletintaleq.intaleq.xyz/v2/main/ride/driverWallet/sendEmailTransfer.php @@ -91,28 +91,28 @@ if ($language === 'ar') {
Thank you for using our service. We hope you have a great day!
We want to inform you that an amount of $amount has been transferred from your account to the new driver: $newDriverName (Phone: $driverPhone).
-Regards,
SEFER Team
Regards,
SIRO Team