From 9596c9bf44716116e7832805e8939be50fd5714c Mon Sep 17 00:00:00 2001 From: Devanarayanan Date: Sat, 23 May 2026 15:56:47 +0000 Subject: [PATCH] fix: broaden security failure error detection and include AppCheck error details in logs --- .example.env | 4 ++-- mobile/lib/config/app_config.dart | 2 +- mobile/lib/screens/splash_screen.dart | 12 ++++++++++-- mobile/lib/services/security_service.dart | 15 +++++++++++++-- mobile/pubspec.yaml | 2 +- package-lock.json | 4 ++-- package.json | 2 +- public/openapi/openapi.yaml | 2 +- 8 files changed, 31 insertions(+), 12 deletions(-) diff --git a/.example.env b/.example.env index b969e7b7..30e71fc8 100644 --- a/.example.env +++ b/.example.env @@ -44,7 +44,7 @@ NEXT_PUBLIC_APP_NAME=GhostClass # âš ī¸ App version displayed in footer and health checks # 🔨 Build-time (Infisical `/build-time` folder) -NEXT_PUBLIC_APP_VERSION=4.4.0 +NEXT_PUBLIC_APP_VERSION=4.4.1 # âš ī¸ Your production domain WITHOUT https:// # All URL-based variables are derived from this. @@ -359,7 +359,7 @@ JWE_PRIVATE_KEY= # âš ī¸ Minimum supported app version required to bypass forced update # 🚀 Runtime (Infisical `/runtime` folder → Server Env Var) -MIN_APP_VERSION=4.4.0 +MIN_APP_VERSION=4.4.1 # â„šī¸ Enforce Firebase App Check for all mobile clients in production # Valid: "true", "false" (default: false in dev, true recommended in prod) diff --git a/mobile/lib/config/app_config.dart b/mobile/lib/config/app_config.dart index 4f10d66c..ccdb16cf 100644 --- a/mobile/lib/config/app_config.dart +++ b/mobile/lib/config/app_config.dart @@ -75,7 +75,7 @@ class AppConfig { /// Current application version (derived from Infisical compilation injection). static String get appVersion => - const String.fromEnvironment('APP_VERSION', defaultValue: '4.4.0'); + const String.fromEnvironment('APP_VERSION', defaultValue: '4.4.1'); /// Commit SHA injected by CI for release builds. static String get appCommitSha => diff --git a/mobile/lib/screens/splash_screen.dart b/mobile/lib/screens/splash_screen.dart index 2178ea9a..4af8fc3d 100644 --- a/mobile/lib/screens/splash_screen.dart +++ b/mobile/lib/screens/splash_screen.dart @@ -208,13 +208,21 @@ class _SplashScreenState extends ConsumerState { appCheckError.toLowerCase().contains('timeout') || appCheckError.toLowerCase().contains('too_many_attempts') || appCheckError.toLowerCase().contains('network') || - appCheckError.toLowerCase().contains('rate limit'))) || + appCheckError.toLowerCase().contains('rate limit') || + appCheckError.toLowerCase().contains('server') || + appCheckError.toLowerCase().contains('internal error') || + appCheckError.toLowerCase().contains('-12') || + appCheckError.toLowerCase().contains('unavailable'))) || (reason.toLowerCase().contains('quota') || reason.toLowerCase().contains('connection') || reason.toLowerCase().contains('timeout') || reason.toLowerCase().contains('too_many_attempts') || reason.toLowerCase().contains('network') || - reason.toLowerCase().contains('rate limit')); + reason.toLowerCase().contains('rate limit') || + reason.toLowerCase().contains('server') || + reason.toLowerCase().contains('internal error') || + reason.toLowerCase().contains('-12') || + reason.toLowerCase().contains('unavailable')); final isGenuineSecurityFailure = !isConnectionOrQuota; diff --git a/mobile/lib/services/security_service.dart b/mobile/lib/services/security_service.dart index 36c732ee..2434cd7c 100644 --- a/mobile/lib/services/security_service.dart +++ b/mobile/lib/services/security_service.dart @@ -169,13 +169,21 @@ class SecurityService { appCheckError.toLowerCase().contains('timeout') || appCheckError.toLowerCase().contains('too_many_attempts') || appCheckError.toLowerCase().contains('network') || - appCheckError.toLowerCase().contains('rate limit'))) || + appCheckError.toLowerCase().contains('rate limit') || + appCheckError.toLowerCase().contains('server') || + appCheckError.toLowerCase().contains('internal error') || + appCheckError.toLowerCase().contains('-12') || + appCheckError.toLowerCase().contains('unavailable'))) || (reason.toLowerCase().contains('quota') || reason.toLowerCase().contains('connection') || reason.toLowerCase().contains('timeout') || reason.toLowerCase().contains('too_many_attempts') || reason.toLowerCase().contains('network') || - reason.toLowerCase().contains('rate limit')); + reason.toLowerCase().contains('rate limit') || + reason.toLowerCase().contains('server') || + reason.toLowerCase().contains('internal error') || + reason.toLowerCase().contains('-12') || + reason.toLowerCase().contains('unavailable')); final isGenuineSecurityFailure = !isConnectionOrQuota; @@ -244,6 +252,8 @@ class SecurityService { (data['action'] as String?) ?? 'Please ensure you are using a genuine version of GhostClass from the Play Store.'; final criticalRisk = data['criticalRisk'] == true; + final appCheckError = + response.requestOptions.extra['appCheckError'] as String?; AppLogger.e( 'SecurityService: Integrity verification failed. Reason: $reason', @@ -258,6 +268,7 @@ class SecurityService { 'reason': reason, 'action': action, 'criticalRisk': criticalRisk, + 'appCheckError': ?appCheckError, }, ); } diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 85c90935..fd1bb9d5 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 4.4.0+1 +version: 4.4.1+1 environment: sdk: ^3.11.4 diff --git a/package-lock.json b/package-lock.json index c318b77a..acdb101f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostclass", - "version": "4.4.0", + "version": "4.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostclass", - "version": "4.4.0", + "version": "4.4.1", "dependencies": { "@hookform/resolvers": "^5.2.2", "@radix-ui/react-alert-dialog": "^1.1.15", diff --git a/package.json b/package.json index 8dfa2430..d72a99d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostclass", - "version": "4.4.0", + "version": "4.4.1", "private": true, "engines": { "node": ">=22.12.0", diff --git a/public/openapi/openapi.yaml b/public/openapi/openapi.yaml index 129a1fa1..a6b718c8 100644 --- a/public/openapi/openapi.yaml +++ b/public/openapi/openapi.yaml @@ -6,7 +6,7 @@ openapi: 3.1.0 info: title: GhostClass API - version: 4.4.0 + version: 4.4.1 description: | **GhostClass API** provides endpoints for authentication, profile synchronization, attendance integrations with EzyGo, telemetry, and build provenance.