Update: 2026-08-02 18:28:40
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -284,9 +284,64 @@ class LoginController extends GetxController {
|
||||
// • يرجع hmac مع الـ jwt ويخزنه في GetStorage
|
||||
// • الـ JWT لا يُشفَّر ثلاثياً (يُستخدم مباشرة في الـ header)
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// • يُخزَّن التوكن ويُعاد استخدامه ما دام أمامه أكثر من 10 ثوانٍ
|
||||
// (عمره 300ث)، فلا نُسجّل دخولاً مع كل طلب محفظة.
|
||||
static Future<String?>? _walletJwtFuture;
|
||||
|
||||
Future<String?> 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<String?> _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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<dynamic> postWallet({
|
||||
required String link,
|
||||
Map<String, dynamic>? 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<dynamic> 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;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user