From 02e652a78672808ed5908294e237f581c61aa7f5 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sun, 2 Aug 2026 18:28:40 +0300 Subject: [PATCH] Update: 2026-08-02 18:28:40 --- backend/food/connect_admin.php | 2 + backend/food/connect_app.php | 2 + backend/food/connect_courier.php | 2 + backend/food/connect_merchant.php | 2 + docker/mysql/init/00-databases.sql | 5 ++ siro_rider/lib/constant/box_name.dart | 1 + .../lib/controller/auth/login_controller.dart | 60 +++++++++++++++++++ siro_rider/lib/controller/functions/crud.dart | 21 ++++++- siro_rider/pubspec.lock | 12 ++-- 9 files changed, 98 insertions(+), 9 deletions(-) diff --git a/backend/food/connect_admin.php b/backend/food/connect_admin.php index af8c63b3..cd1ba0ca 100644 --- a/backend/food/connect_admin.php +++ b/backend/food/connect_admin.php @@ -22,6 +22,8 @@ $food_admin_id = (string)($decoded->user_id ?? ''); try { $food_con = Database::get('food'); } catch (Exception $e) { + // السبب الحقيقي في اللوج فقط — الرد يبقى عاماً. + error_log('[FOOD] DB connection failed in ' . basename(__FILE__) . ': ' . $e->getMessage()); http_response_code(503); echo json_encode(['status' => 'failure', 'message' => 'Food service unavailable']); exit; diff --git a/backend/food/connect_app.php b/backend/food/connect_app.php index e70d2fec..914a5e05 100644 --- a/backend/food/connect_app.php +++ b/backend/food/connect_app.php @@ -31,6 +31,8 @@ $food_passenger_id = (string)($decoded->user_id ?? ''); try { $food_con = Database::get('food'); } catch (Exception $e) { + // السبب الحقيقي في اللوج فقط — الرد يبقى عاماً. + error_log('[FOOD] DB connection failed in ' . basename(__FILE__) . ': ' . $e->getMessage()); http_response_code(503); echo json_encode(['status' => 'failure', 'message' => 'Food service unavailable']); exit; diff --git a/backend/food/connect_courier.php b/backend/food/connect_courier.php index 780a7216..11c81088 100644 --- a/backend/food/connect_courier.php +++ b/backend/food/connect_courier.php @@ -28,6 +28,8 @@ $food_courier_id = (string)($decoded->user_id ?? ''); try { $food_con = Database::get('food'); } catch (Exception $e) { + // السبب الحقيقي في اللوج فقط — الرد يبقى عاماً. + error_log('[FOOD] DB connection failed in ' . basename(__FILE__) . ': ' . $e->getMessage()); http_response_code(503); echo json_encode(['status' => 'failure', 'message' => 'Food service unavailable']); exit; diff --git a/backend/food/connect_merchant.php b/backend/food/connect_merchant.php index 561197a7..cd288c51 100644 --- a/backend/food/connect_merchant.php +++ b/backend/food/connect_merchant.php @@ -30,6 +30,8 @@ $limiter->enforce(RateLimiter::identifier(), 'api'); try { $food_con = Database::get('food'); } catch (Exception $e) { + // السبب الحقيقي في اللوج فقط — الرد يبقى عاماً. + error_log('[FOOD] DB connection failed in ' . basename(__FILE__) . ': ' . $e->getMessage()); http_response_code(503); echo json_encode(['status' => 'failure', 'message' => 'Food service unavailable']); exit; diff --git a/docker/mysql/init/00-databases.sql b/docker/mysql/init/00-databases.sql index b26a8085..6a847926 100644 --- a/docker/mysql/init/00-databases.sql +++ b/docker/mysql/init/00-databases.sql @@ -5,6 +5,7 @@ CREATE DATABASE IF NOT EXISTS `intaleqDB1` CHARACTER SET utf8mb4 COLLATE utf8mb4 CREATE DATABASE IF NOT EXISTS `locationDB` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS `intaleq-ridesDB` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS `siroTransitDb` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE DATABASE IF NOT EXISTS `siro_food` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- إنشاء المستخدمين وإعطائهم الصلاحيات لكي تتطابق البيئة مع اللايف 100% CREATE USER IF NOT EXISTS 'intaleqapp-jordan-siro'@'%' IDENTIFIED BY '7B7skfibrexQrGCUG1Y8'; @@ -22,4 +23,8 @@ GRANT ALL PRIVILEGES ON `intaleq-ridesDB`.* TO 'intaleq-rides'@'%'; CREATE USER IF NOT EXISTS 'siroTransitUser'@'%' IDENTIFIED BY 'eZiDYxCJ2yyGfC32zG0Z'; GRANT ALL PRIVILEGES ON `siroTransitDb`.* TO 'siroTransitUser'@'%'; +-- ⚠️ كلمة المرور هنا يجب أن تطابق DB_FOOD_PASS في ملف .env وإلا فشل الاتصال. +CREATE USER IF NOT EXISTS 'siro_food'@'%' IDENTIFIED BY 'CHANGE_ME_STRONG_PASSWORD'; +GRANT ALL PRIVILEGES ON `siro_food`.* TO 'siro_food'@'%'; + FLUSH PRIVILEGES; diff --git a/siro_rider/lib/constant/box_name.dart b/siro_rider/lib/constant/box_name.dart index 6b5f5e6e..1458230f 100644 --- a/siro_rider/lib/constant/box_name.dart +++ b/siro_rider/lib/constant/box_name.dart @@ -10,6 +10,7 @@ class BoxName { static const String gender = "gender"; static const String themeMode = "themeMode"; static const String jwt = "jwt"; + static const String walletJwt = "walletJwt"; static const String lowEndMode = "lowEndMode"; static const String deviceFpEncrypted = "deviceFpEncrypted"; static const String appVersionChecked = "appVersionChecked"; diff --git a/siro_rider/lib/controller/auth/login_controller.dart b/siro_rider/lib/controller/auth/login_controller.dart index 27c3fc36..f0f2a054 100644 --- a/siro_rider/lib/controller/auth/login_controller.dart +++ b/siro_rider/lib/controller/auth/login_controller.dart @@ -284,9 +284,64 @@ class LoginController extends GetxController { // • يرجع hmac مع الـ jwt ويخزنه في GetStorage // • الـ JWT لا يُشفَّر ثلاثياً (يُستخدم مباشرة في الـ header) // ───────────────────────────────────────────────────────────── + // • يُخزَّن التوكن ويُعاد استخدامه ما دام أمامه أكثر من 10 ثوانٍ + // (عمره 300ث)، فلا نُسجّل دخولاً مع كل طلب محفظة. + static Future? _walletJwtFuture; + Future getJwtWallet() async { + // طلب قيد التنفيذ؟ شارك نتيجته بدل إطلاق طلب ثانٍ. + if (_walletJwtFuture != null) { + Log.print('⏳ getJwtWallet: طلب قيد التنفيذ — إعادة استخدام نفس الـ future.'); + return _walletJwtFuture!; + } + _walletJwtFuture = _getJwtWalletInternal(); + try { + return await _walletJwtFuture!; + } finally { + _walletJwtFuture = null; + } + } + + /// هل التوكن المخزَّن صالح ويخصّ الراكب الحالي؟ + /// نتحقق من `user_id` أيضاً كي لا يُعاد استخدام توكن حساب سابق + /// على نفس الجهاز بعد تبديل المستخدم. + bool _isWalletJwtUsable(String jwt, String passengerId) { + try { + final parts = jwt.split('.'); + if (parts.length != 3) return false; + String payload = parts[1]; + while (payload.length % 4 != 0) { + payload += '='; + } + final decoded = jsonDecode(utf8.decode(base64Url.decode(payload))); + + if ((decoded['user_id'] ?? '').toString() != passengerId) return false; + + final exp = decoded['exp']; + if (exp == null) return false; + // هامش 10 ثوانٍ حتى لا ينتهي التوكن أثناء الطلب نفسه + return DateTime.now().millisecondsSinceEpoch < (exp * 1000 - 10000); + } catch (_) { + return false; + } + } + + Future _getJwtWalletInternal() async { dev = Platform.isAndroid ? 'android' : 'ios'; + final String passengerId = box.read(BoxName.passengerID)?.toString() ?? ''; + + // ── إعادة استخدام التوكن المخزَّن إن كان صالحاً ──────────────── + final String cachedJwt = box.read(BoxName.walletJwt)?.toString() ?? ''; + final String cachedHmac = box.read(BoxName.hmac)?.toString() ?? ''; + if (cachedJwt.isNotEmpty && + cachedHmac.isNotEmpty && + passengerId.isNotEmpty && + _isWalletJwtUsable(cachedJwt, passengerId)) { + Log.print('🔑 توكن محفظة صالح في التخزين — تخطّي طلب السيرفر.'); + return cachedJwt; + } + // نعيد حساب البصمة أولاً كي لا نرسل قيمة GCM قديمة عالقة في التخزين // من نسخة سابقة من التطبيق (مثل getJWT تماماً). await DeviceHelper.getDeviceFingerprint(); @@ -323,6 +378,11 @@ class LoginController extends GetxController { box.write(BoxName.hmac, hmac); } + // نخزّن التوكن ليُعاد استخدامه حتى قرب انتهائه بدل طلب جديد كل مرة + if (jwt != null) { + box.write(BoxName.walletJwt, jwt); + } + return jwt; } diff --git a/siro_rider/lib/controller/functions/crud.dart b/siro_rider/lib/controller/functions/crud.dart index 08baa631..66774f81 100644 --- a/siro_rider/lib/controller/functions/crud.dart +++ b/siro_rider/lib/controller/functions/crud.dart @@ -284,6 +284,16 @@ class CRUD { // التغيير: إضافة X-Device-FP header // 3 headers معاً: JWT + HMAC + FP // ═══════════════════════════════════════════════════════════════ + /// توكن المحفظة صار يُخزَّن ويُعاد استخدامه. لو رفضه السيرفر (توكن + /// مُلغى أو تغيّر سرّ التوقيع) نمسح النسخة المخزّنة كي يُطلب توكن + /// جديد في المحاولة التالية بدل أن نعلق على توكن ميت. + void _invalidateWalletJwtIfRejected(dynamic result) { + if (result == 'token_expired') { + Log.print('🗑️ توكن المحفظة مرفوض — مسح النسخة المخزّنة.'); + box.remove(BoxName.walletJwt); + } + } + Future postWallet({ required String link, Map? payload, @@ -297,11 +307,13 @@ class CRUD { 'X-HMAC-Auth': hmac.toString(), 'X-Device-FP': _getFpHeader(), }; - Log.print('headers: $headers'); Log.print('payload: $payload'); Log.print('link: $link'); - return await _makeRequest(link: link, payload: payload, headers: headers); + final result = + await _makeRequest(link: link, payload: payload, headers: headers); + _invalidateWalletJwtIfRejected(result); + return result; } Future getWallet({ @@ -318,7 +330,10 @@ class CRUD { 'X-Device-FP': _getFpHeader(), }; - return await _makeRequest(link: link, payload: payload, headers: headers); + final result = + await _makeRequest(link: link, payload: payload, headers: headers); + _invalidateWalletJwtIfRejected(result); + return result; } // ======================================================================= diff --git a/siro_rider/pubspec.lock b/siro_rider/pubspec.lock index def65d08..1b8d51ce 100644 --- a/siro_rider/pubspec.lock +++ b/siro_rider/pubspec.lock @@ -1297,10 +1297,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.18" material_color_utilities: dependency: transitive description: @@ -1313,10 +1313,10 @@ packages: dependency: transitive description: name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.0" mime: dependency: "direct main" description: @@ -1901,10 +1901,10 @@ packages: dependency: transitive description: name: test_api - sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.11" + version: "0.7.9" timezone: dependency: transitive description: