Guard debug logs in release and remove device-check bypass

Log.print used developer.log with no kDebugMode guard, so release
builds emitted wallet JWTs, the HMAC secret, phone numbers and full
API responses to os_log/logcat on the user's device. Both the rider
and driver apps were affected.

Also removes a hardcoded test-account condition in the rider login
flow that skipped the entire FCM-token/fingerprint comparison — and
therefore the device-change OTP — for one email address.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-08-02 18:19:50 +03:00
co-authored by Claude Opus 5
parent 4620e84d34
commit 3b4b4639a6
3 changed files with 43 additions and 29 deletions
+7
View File
@@ -1,9 +1,16 @@
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'package:flutter/foundation.dart' show kDebugMode;
class Log { class Log {
Log._(); Log._();
/// ⚠️ يُطبع في وضع التطوير فقط.
/// `developer.log` لا يُحذف في نسخة الإصدار — يذهب إلى os_log على iOS
/// و logcat على أندرويد، وكان يسرّب الـ JWT وسر الـ HMAC وأرقام الهواتف
/// وردود الـ API كاملة إلى سجلّ النظام على جهاز المستخدم.
static void print(String value, {StackTrace? stackTrace}) { static void print(String value, {StackTrace? stackTrace}) {
if (!kDebugMode) return;
developer.log(value, name: 'LOG', stackTrace: stackTrace); developer.log(value, name: 'LOG', stackTrace: stackTrace);
} }
@@ -418,39 +418,39 @@ class LoginController extends GetxController {
force: true); // Fetch access token after clearing firstTimeLoadKey force: true); // Fetch access token after clearing firstTimeLoadKey
// ── 5. المقارنة: FCM token + fingerprint ────────────────────── // ── 5. المقارنة: FCM token + fingerprint ──────────────────────
if (email != '962798583052@intaleqapp.com') { // ملاحظة: كان هنا استثناء لحساب اختبار بعينه يتخطى الفحص بالكامل.
if (serverFCM == null && // حُذف — لا استثناءات على التحقق من تغيّر الجهاز.
tokenResp != null && if (serverFCM == null &&
tokenResp != 'failure' && tokenResp != null &&
tokenResp != 'error' && tokenResp != 'failure' &&
tokenResp != 'token_expired') { tokenResp != 'error' &&
final tokenJson = tokenResp != 'token_expired') {
tokenResp is String ? jsonDecode(tokenResp) : tokenResp; final tokenJson =
final serverData = tokenJson['data'] ?? tokenJson['message']; tokenResp is String ? jsonDecode(tokenResp) : tokenResp;
if (serverData is Map) { final serverData = tokenJson['data'] ?? tokenJson['message'];
serverFCM = serverData['token']?.toString() ?? ''; if (serverData is Map) {
serverFP = serverData['fingerPrint']?.toString() ?? ''; serverFCM = serverData['token']?.toString() ?? '';
} serverFP = serverData['fingerPrint']?.toString() ?? '';
} }
}
if (serverFCM != null && serverFCM.isNotEmpty) { if (serverFCM != null && serverFCM.isNotEmpty) {
final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString(); final localFCM = (box.read(BoxName.tokenFCM) ?? '').toString();
// ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ───────── // ── اختلاف أي منهما = جهاز مختلف أو تثبيت جديد ─────────
final fcmChanged = serverFCM != localFCM; final fcmChanged = serverFCM != localFCM;
final fpChanged = final fpChanged =
serverFP != null && serverFP.isNotEmpty && serverFP != localFP; serverFP != null && serverFP.isNotEmpty && serverFP != localFP;
if (fcmChanged || fpChanged) { if (fcmChanged || fpChanged) {
mySnackbarInfo('Device Change Detected'.tr); mySnackbarInfo('Device Change Detected'.tr);
await Get.to(() => OtpVerificationPage( await Get.to(() => OtpVerificationPage(
phone: data['phone'].toString(), phone: data['phone'].toString(),
deviceToken: localFP, deviceToken: localFP,
token: tokenResp ?? '', token: tokenResp ?? '',
ptoken: serverFCM ?? '', // نمرر FCM القديم للـ OTP controller ptoken: serverFCM ?? '', // نمرر FCM القديم للـ OTP controller
)); ));
return; return;
}
} }
} }
+7
View File
@@ -1,9 +1,16 @@
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'package:flutter/foundation.dart' show kDebugMode;
class Log { class Log {
Log._(); Log._();
/// ⚠️ يُطبع في وضع التطوير فقط.
/// `developer.log` لا يُحذف في نسخة الإصدار — يذهب إلى os_log على iOS
/// و logcat على أندرويد، وكان يسرّب الـ JWT وسر الـ HMAC وأرقام الهواتف
/// وردود الـ API كاملة إلى سجلّ النظام على جهاز المستخدم.
static void print(String value, {StackTrace? stackTrace}) { static void print(String value, {StackTrace? stackTrace}) {
if (!kDebugMode) return;
developer.log(value, name: 'LOG', stackTrace: stackTrace); developer.log(value, name: 'LOG', stackTrace: stackTrace);
} }