refactor: optimize wallet JWT management, update security checks for debug builds, and improve pricing data parsing

This commit is contained in:
Hamza-Ayed
2026-06-27 22:50:28 +03:00
parent 43e3f8c939
commit a87cb7c082
7 changed files with 93 additions and 18 deletions

View File

@@ -122,7 +122,7 @@ dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
implementation 'com.scottyab:rootbeer-lib:0.1.0' implementation 'com.scottyab:rootbeer-lib:0.1.2'
// تمت الترقية لتطابق تطبيق الراكب // تمت الترقية لتطابق تطبيق الراكب
implementation 'com.google.android.gms:play-services-safetynet:18.1.0' implementation 'com.google.android.gms:play-services-safetynet:18.1.0'

View File

@@ -2,6 +2,7 @@ package com.siro.siro_driver
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.widget.LinearLayout import android.widget.LinearLayout
@@ -134,11 +135,17 @@ class MainActivity : FlutterFragmentActivity() {
// --- بقية كود الحماية الخاص بك --- // --- بقية كود الحماية الخاص بك ---
private fun isDeviceCompromised(): Boolean { private fun isDeviceCompromised(): Boolean {
val isDebug = (applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0
if (isDebug) {
Log.d("MainActivity", "Debug build: bypassing root check")
return false
}
return try { return try {
val isRootedByRootBeer = RootBeer(this).isRooted val isRootedByRootBeer = RootBeer(this).isRooted
isRootedByRootBeer isRootedByRootBeer
} catch (e: Exception) { } catch (t: Throwable) {
true Log.e("MainActivity", "RootBeer check failed: ", t)
false
} }
} }

View File

@@ -6,6 +6,7 @@ class BoxName {
static const String initializationVector = 'initializationVector'; static const String initializationVector = 'initializationVector';
static const String firstTimeLoadKey = 'firstTimeLoadKey'; static const String firstTimeLoadKey = 'firstTimeLoadKey';
static const String jwt = "jwt"; static const String jwt = "jwt";
static const String walletJwt = "walletJwt";
static const String blockUntilDate = "blockUntilDate"; static const String blockUntilDate = "blockUntilDate";
static const String rideId = "rideId"; static const String rideId = "rideId";
static const String rideArgumentsFromBackground = static const String rideArgumentsFromBackground =

View File

@@ -142,11 +142,55 @@ class LoginDriverController extends GetxController {
} }
var dev = ''; var dev = '';
Future<String>? _walletJwtFuture;
getJwtWallet() async { getJwtWallet() async {
if (_walletJwtFuture != null) {
Log.print('⏳ getJwtWallet: Request already in progress, reusing future.');
return _walletJwtFuture!;
}
_walletJwtFuture = _getJwtWalletInternal();
try {
return await _walletJwtFuture!;
} finally {
_walletJwtFuture = null;
}
}
Future<String> _getJwtWalletInternal() async {
if (box.read(BoxName.security_check).toString() != 'passed') { if (box.read(BoxName.security_check).toString() != 'passed') {
Log.print('Security check failed'); Log.print('Security check failed');
return; return '';
} }
// 1. Check GetStorage first to avoid redundant API calls
String? cachedJwt = box.read(BoxName.walletJwt)?.toString();
if (cachedJwt != null && cachedJwt.isNotEmpty) {
bool isTokenValid = false;
try {
final parts = cachedJwt.split('.');
if (parts.length == 3) {
var payload = parts[1];
switch (payload.length % 4) {
case 2: payload += '=='; break;
case 3: payload += '='; break;
}
final decoded = jsonDecode(utf8.decode(base64Url.decode(payload)));
final exp = decoded['exp'];
if (exp != null) {
// Check if token has at least 10 seconds remaining
isTokenValid = DateTime.now().millisecondsSinceEpoch < (exp * 1000 - 10000);
}
}
} catch (_) {}
if (isTokenValid) {
Log.print('🔑 Valid Wallet JWT found in storage. Skipping generation.');
return cachedJwt;
}
}
Log.print('Security check passed'); Log.print('Security check passed');
dev = Platform.isAndroid ? 'android' : 'ios'; dev = Platform.isAndroid ? 'android' : 'ios';
var fingerPrint = box.read(BoxName.deviceFingerprint)?.toString() ?? var fingerPrint = box.read(BoxName.deviceFingerprint)?.toString() ??
@@ -172,8 +216,12 @@ class LoginDriverController extends GetxController {
: decoded['hmac']; : decoded['hmac'];
Log.print('payment["jwt"]: $jwt'); Log.print('payment["jwt"]: $jwt');
await box.write(BoxName.hmac, hmac); if (jwt != null) {
return jwt.toString(); await box.write(BoxName.walletJwt, jwt.toString());
await box.write(BoxName.hmac, hmac);
return jwt.toString();
}
return '';
} }
getJWT() async { getJWT() async {

View File

@@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:ui'; import 'dart:ui';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:jailbreak_root_detection/jailbreak_root_detection.dart'; import 'package:jailbreak_root_detection/jailbreak_root_detection.dart';
import 'package:siro_driver/constant/box_name.dart'; import 'package:siro_driver/constant/box_name.dart';
import 'package:siro_driver/constant/colors.dart'; import 'package:siro_driver/constant/colors.dart';
@@ -204,6 +205,11 @@ class DeviceHelper {
class SecurityHelper { class SecurityHelper {
/// Performs security checks and handles potential risks /// Performs security checks and handles potential risks
static Future<void> performSecurityChecks() async { static Future<void> performSecurityChecks() async {
if (kDebugMode) {
debugPrint("Debug mode: skipping security helper check");
box.write(BoxName.security_check, 'passed');
return;
}
bool isNotTrust = false; bool isNotTrust = false;
bool isJailBroken = false; bool isJailBroken = false;
bool isRealDevice = true; bool isRealDevice = true;

View File

@@ -770,17 +770,30 @@ class HomeCaptainController extends GetxController {
payload: {'country': box.read(BoxName.countryCode).toString()}, payload: {'country': box.read(BoxName.countryCode).toString()},
); );
if (res != 'failure') { if (res != 'failure') {
var json = jsonDecode(res); try {
kazan = double.parse(json['message'][0]['kazan']); var json = jsonDecode(res);
naturePrice = double.parse(json['message'][0]['naturePrice']); if (json['message'] is List && json['message'].isNotEmpty) {
heavyPrice = double.parse(json['message'][0]['heavyPrice']); final item = json['message'][0];
latePrice = double.parse(json['message'][0]['latePrice']);
comfortPrice = double.parse(json['message'][0]['comfortPrice']); double parseDouble(dynamic val) {
speedPrice = double.parse(json['message'][0]['speedPrice']); if (val == null) return 0.0;
deliveryPrice = double.parse(json['message'][0]['deliveryPrice']); return double.tryParse(val.toString()) ?? 0.0;
mashwariPrice = double.parse(json['message'][0]['freePrice']); }
familyPrice = double.parse(json['message'][0]['familyPrice']);
fuelPrice = double.parse(json['message'][0]['fuelPrice']); kazan = parseDouble(item['kazanPercent'] ?? item['kazan']);
naturePrice = parseDouble(item['normalMinPrice'] ?? item['naturePrice']);
heavyPrice = parseDouble(item['peakMinPrice'] ?? item['heavyPrice']);
latePrice = parseDouble(item['lateMinPrice'] ?? item['latePrice']);
comfortPrice = parseDouble(item['comfortPrice']);
speedPrice = parseDouble(item['speedPrice']);
deliveryPrice = parseDouble(item['deliveryPrice']);
mashwariPrice = parseDouble(item['freePrice'] ?? item['mishwarVipPrice']);
familyPrice = parseDouble(item['familyPrice'] ?? item['ladyPrice']);
fuelPrice = parseDouble(item['fuelPrice']);
}
} catch (e) {
Log.print("Error parsing kazan percent: $e");
}
} }
update(); update();
} }

View File

@@ -26,7 +26,7 @@ class AboutPage extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Text( child: Text(
'Siro LLC\n${'Syria'.tr}', 'Siro LLC\n${(box.read(BoxName.countryCode)?.toString() ?? 'Syria').tr}',
style: AppStyle.headTitle2, style: AppStyle.headTitle2,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),