Merge pull request 'haroon_dev' (#361) from haroon_dev into master
Reviewed-on: https://34.17.182.140/Haroon6138/HMG_Patient_App_New/pulls/361master
commit
ee1c7977e2
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:freerasp/freerasp.dart';
|
||||||
|
|
||||||
|
final talsecConfig = TalsecConfig(
|
||||||
|
androidConfig: AndroidConfig(
|
||||||
|
packageName: 'com.cloudsolutions.HMGPatientApp',
|
||||||
|
signingCertHashes: ['6tvWaoN5coG4SnfxGbdQlcLmM0J4ePQwDjrKIg+QkV0=', 'j6VEqVhrypHMIiXiFdRLDdGwjGaMGWY7KAdBJA+Z4Pc='], // Must be the release cert hash
|
||||||
|
supportedStores: ['com.android.vending'], // Google Play Store
|
||||||
|
),
|
||||||
|
iosConfig: IOSConfig(
|
||||||
|
bundleIds: ['com.cloudsolutions.HMGPatientApp'], // iOS Bundle ID
|
||||||
|
teamId: '3A359E86ZF', // Found in Apple Developer portal
|
||||||
|
),
|
||||||
|
watcherMail: '', // Required to receive security alerts
|
||||||
|
isProd: true, // Enforces strict checks for release builds
|
||||||
|
);
|
||||||
@ -0,0 +1,157 @@
|
|||||||
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:freerasp/freerasp.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/app_state.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/talsec_config.dart';
|
||||||
|
import 'package:hmg_patient_app_new/services/logger_service.dart';
|
||||||
|
|
||||||
|
/// Enum to categorize threat severity levels
|
||||||
|
enum ThreatSeverity {
|
||||||
|
critical, // Block app usage
|
||||||
|
warning, // Log only, don't block
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Model to track threat details
|
||||||
|
class ThreatEvent {
|
||||||
|
final String threatType;
|
||||||
|
final ThreatSeverity severity;
|
||||||
|
final DateTime timestamp;
|
||||||
|
final String? additionalInfo;
|
||||||
|
|
||||||
|
ThreatEvent({
|
||||||
|
required this.threatType,
|
||||||
|
required this.severity,
|
||||||
|
this.additionalInfo,
|
||||||
|
}) : timestamp = DateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Callback type for critical threat detection
|
||||||
|
typedef OnCriticalThreatDetected = void Function();
|
||||||
|
|
||||||
|
/// Abstract class defining the security service interface
|
||||||
|
abstract class SecurityService {
|
||||||
|
/// Initialize and start the security monitoring
|
||||||
|
Future<void> initialize();
|
||||||
|
|
||||||
|
/// Check if device is currently safe
|
||||||
|
bool get isSafeDevice;
|
||||||
|
|
||||||
|
/// Get list of detected threats
|
||||||
|
List<ThreatEvent> get detectedThreats;
|
||||||
|
|
||||||
|
/// Set callback for when critical threat is detected
|
||||||
|
void setOnCriticalThreatCallback(OnCriticalThreatDetected callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of SecurityService using Talsec (freeRASP)
|
||||||
|
class SecurityServiceImpl implements SecurityService {
|
||||||
|
final AppState appState;
|
||||||
|
final LoggerService loggerService;
|
||||||
|
|
||||||
|
final List<ThreatEvent> _detectedThreats = [];
|
||||||
|
bool _isInitialized = false;
|
||||||
|
OnCriticalThreatDetected? _onCriticalThreatCallback;
|
||||||
|
|
||||||
|
SecurityServiceImpl({
|
||||||
|
required this.appState,
|
||||||
|
required this.loggerService,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isSafeDevice => appState.isSafeDevice;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<ThreatEvent> get detectedThreats => List.unmodifiable(_detectedThreats);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> initialize() async {
|
||||||
|
if (_isInitialized) {
|
||||||
|
loggerService.logInfo('SecurityService already initialized');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
loggerService.logInfo('Initializing SecurityService with Talsec');
|
||||||
|
|
||||||
|
// Start the RASP engine
|
||||||
|
await Talsec.instance.start(talsecConfig);
|
||||||
|
|
||||||
|
// Setup threat callbacks
|
||||||
|
final callback = ThreatCallback(
|
||||||
|
onAppIntegrity: () => _handleThreat('App Integrity', ThreatSeverity.critical),
|
||||||
|
onObfuscationIssues: () => _handleThreat('Obfuscation Issues', ThreatSeverity.warning),
|
||||||
|
onDebug: () => _handleThreat('Debug Mode', ThreatSeverity.critical),
|
||||||
|
onDeviceBinding: () => _handleThreat('Device Binding', ThreatSeverity.critical),
|
||||||
|
onDeviceID: () => _handleThreat('Device ID Mismatch', ThreatSeverity.critical),
|
||||||
|
onHooks: () => _handleThreat('Hooks Detected', ThreatSeverity.critical),
|
||||||
|
onPasscode: () => _handleThreat('Passcode Not Set', ThreatSeverity.warning),
|
||||||
|
onPrivilegedAccess: () => _handleThreat('Privileged Access (Root/Jailbreak)', ThreatSeverity.critical),
|
||||||
|
onSecureHardwareNotAvailable: () => _handleThreat('Secure Hardware Not Available', ThreatSeverity.warning),
|
||||||
|
onSimulator: () => _handleThreat('Simulator/Emulator Detected', ThreatSeverity.critical),
|
||||||
|
onSystemVPN: () => _handleThreat('System VPN Active', ThreatSeverity.warning),
|
||||||
|
onDevMode: () => _handleThreat('Developer Mode', ThreatSeverity.warning),
|
||||||
|
onADBEnabled: () => _handleThreat('USB Debugging Enabled', ThreatSeverity.warning),
|
||||||
|
onUnofficialStore: () => _handleThreat('Unofficial Store Installation', ThreatSeverity.critical),
|
||||||
|
onScreenshot: () => _handleThreat('Screenshot Detected', ThreatSeverity.warning),
|
||||||
|
onScreenRecording: () => _handleThreat('Screen Recording Active', ThreatSeverity.warning),
|
||||||
|
onMultiInstance: () => _handleThreat('Multiple Instances', ThreatSeverity.warning),
|
||||||
|
onLocationSpoofing: () => _handleThreat('Location Spoofing', ThreatSeverity.warning),
|
||||||
|
onTimeSpoofing: () => _handleThreat('Time Spoofing', ThreatSeverity.warning),
|
||||||
|
onAutomation: () => _handleThreat('Automation Detected', ThreatSeverity.warning),
|
||||||
|
onBootloader: () => _handleThreat('Unlocked Bootloader', ThreatSeverity.critical),
|
||||||
|
onMalware: (suspiciousApps) => _handleThreat('Malware/Suspicious Apps', ThreatSeverity.critical, additionalInfo: suspiciousApps.toString()),
|
||||||
|
);
|
||||||
|
|
||||||
|
Talsec.instance.attachListener(callback);
|
||||||
|
|
||||||
|
_isInitialized = true;
|
||||||
|
loggerService.logInfo('SecurityService initialized successfully');
|
||||||
|
} catch (e) {
|
||||||
|
loggerService.logError('Failed to initialize SecurityService: $e');
|
||||||
|
if (!kDebugMode) {
|
||||||
|
FirebaseCrashlytics.instance.recordError(
|
||||||
|
e,
|
||||||
|
StackTrace.current,
|
||||||
|
reason: 'SecurityService initialization failed',
|
||||||
|
fatal: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setOnCriticalThreatCallback(OnCriticalThreatDetected callback) {
|
||||||
|
_onCriticalThreatCallback = callback;
|
||||||
|
loggerService.logInfo('Critical threat callback registered');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle detected threats with appropriate severity
|
||||||
|
void _handleThreat(String threatType, ThreatSeverity severity, {String? additionalInfo}) {
|
||||||
|
final threat = ThreatEvent(
|
||||||
|
threatType: threatType,
|
||||||
|
severity: severity,
|
||||||
|
additionalInfo: additionalInfo,
|
||||||
|
);
|
||||||
|
|
||||||
|
_detectedThreats.add(threat);
|
||||||
|
|
||||||
|
// Log to console
|
||||||
|
if (severity == ThreatSeverity.critical) {
|
||||||
|
loggerService.logError('🔴 CRITICAL THREAT: $threatType ${additionalInfo != null ? "- $additionalInfo" : ""}');
|
||||||
|
} else {
|
||||||
|
loggerService.logInfo('⚠️ WARNING: $threatType ${additionalInfo != null ? "- $additionalInfo" : ""}');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block app if critical threat
|
||||||
|
if (severity == ThreatSeverity.critical) {
|
||||||
|
appState.setIsSafeDevice = false;
|
||||||
|
loggerService.logError('Device marked as UNSAFE due to: $threatType');
|
||||||
|
|
||||||
|
// Trigger callback to navigate to unsafe device page
|
||||||
|
if (_onCriticalThreatCallback != null) {
|
||||||
|
_onCriticalThreatCallback!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:freerasp/freerasp.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/app_assets.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/dependencies.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
|
||||||
|
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
||||||
|
import 'package:hmg_patient_app_new/services/security_service.dart';
|
||||||
|
import 'package:hmg_patient_app_new/theme/colors.dart';
|
||||||
|
|
||||||
|
class UnsafeDevice extends StatefulWidget {
|
||||||
|
const UnsafeDevice({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<UnsafeDevice> createState() => _UnsafeDeviceState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UnsafeDeviceState extends State<UnsafeDevice> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
Talsec.instance.detachListener();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.whiteColor,
|
||||||
|
body: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24.w),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Logo
|
||||||
|
Utils.buildImgWithAssets(icon: AppAssets.hmgLogo, width: MediaQuery.of(context).size.width * 0.7, height: 90.h, fit: BoxFit.contain),
|
||||||
|
SizedBox(height: 32.h),
|
||||||
|
// Warning Icon
|
||||||
|
Icon(
|
||||||
|
Icons.security,
|
||||||
|
size: 80.h,
|
||||||
|
color: AppColors.primaryRedColor,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
// Title
|
||||||
|
Text(
|
||||||
|
'Unsafe Device Detected',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24.f,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: AppColors.primaryRedColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.h),
|
||||||
|
|
||||||
|
// Description
|
||||||
|
Text(
|
||||||
|
'For your security, this app cannot run on devices with security vulnerabilities.',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.f,
|
||||||
|
color: Colors.black87,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
SizedBox(height: 24.h),
|
||||||
|
// if (getIt.get<SecurityService>().detectedThreats.isNotEmpty) ...[
|
||||||
|
// Text(
|
||||||
|
// 'Detected Issues:',
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontSize: 14.f,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// color: Colors.black87,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 8.h),
|
||||||
|
// Container(
|
||||||
|
// padding: EdgeInsets.all(12.w),
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// color: Colors.red.withOpacity(0.1),
|
||||||
|
// borderRadius: BorderRadius.circular(8.r),
|
||||||
|
// border: Border.all(color: Colors.red.withOpacity(0.3)),
|
||||||
|
// ),
|
||||||
|
// child: Column(
|
||||||
|
// children: getIt
|
||||||
|
// .get<SecurityService>()
|
||||||
|
// .detectedThreats
|
||||||
|
// .where((t) => t.severity == ThreatSeverity.critical)
|
||||||
|
// .take(5) // Show max 5 threats
|
||||||
|
// .map((threat) => Padding(
|
||||||
|
// padding: EdgeInsets.symmetric(vertical: 4.h),
|
||||||
|
// child: Row(
|
||||||
|
// children: [
|
||||||
|
// Icon(Icons.error_outline, size: 16.f, color: Colors.red),
|
||||||
|
// SizedBox(width: 8.w),
|
||||||
|
// Expanded(
|
||||||
|
// child: Text(
|
||||||
|
// threat.threatType,
|
||||||
|
// style: TextStyle(fontSize: 12.f),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ))
|
||||||
|
// .toList(),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SizedBox(height: 24.h),
|
||||||
|
// ],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue