diff --git a/android/doctor_app_key b/android/doctor_app_key new file mode 100644 index 00000000..ae5bdbbc Binary files /dev/null and b/android/doctor_app_key differ diff --git a/android/gradle.properties b/android/gradle.properties index d19a07c3..da298deb 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -4,3 +4,7 @@ android.useAndroidX=true android.enableJetifier=true org.gradle.jvmargs=-Xmx4608m kotlin.jvm.target.validation.mode = IGNORE +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 37132798..27f7bfa6 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -14,8 +14,9 @@ 30F70E6C266F56FD005D8F8E /* MainAppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */; }; 30F70E6F266F6509005D8F8E /* VideoCallRequestParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 41B879757CC2D190BA52BEC5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D9222C8F78B892C013C44A6 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 7645621A848A5D0B29B97C46 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4E9718EA62661304F55A32D /* Pods_Runner.framework */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -46,8 +47,13 @@ 30F70E6B266F56FD005D8F8E /* MainAppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainAppViewController.swift; sourceTree = ""; }; 30F70E6E266F6509005D8F8E /* VideoCallRequestParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallRequestParameters.swift; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 5CEDB0C437E96DCB175D44FA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 624621692EF4C03F0724C4A9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 6946B309E20CA63FE3258287 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 6D9222C8F78B892C013C44A6 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -58,10 +64,6 @@ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 9CE61EBC24AB366E008D68DD /* VideoCallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoCallViewController.swift; sourceTree = ""; }; 9CE61ECC24ADBB4C008D68DD /* ICallProtocoll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICallProtocoll.swift; sourceTree = ""; }; - C55D4AE245B71956447BA22F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - C8801C5E6B82B6CB497CA5C7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - E333B59AA5538E0304102FD2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - E4E9718EA62661304F55A32D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -69,7 +71,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7645621A848A5D0B29B97C46 /* Pods_Runner.framework in Frameworks */, + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + 41B879757CC2D190BA52BEC5 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -104,9 +107,9 @@ 7D66D387293CE5376A07EC5F /* Pods */ = { isa = PBXGroup; children = ( - C55D4AE245B71956447BA22F /* Pods-Runner.debug.xcconfig */, - C8801C5E6B82B6CB497CA5C7 /* Pods-Runner.release.xcconfig */, - E333B59AA5538E0304102FD2 /* Pods-Runner.profile.xcconfig */, + 5CEDB0C437E96DCB175D44FA /* Pods-Runner.debug.xcconfig */, + 624621692EF4C03F0724C4A9 /* Pods-Runner.release.xcconfig */, + 6946B309E20CA63FE3258287 /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -114,6 +117,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, @@ -129,7 +133,7 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 7D66D387293CE5376A07EC5F /* Pods */, - A9562A4C43D78E443FA8BFD1 /* Frameworks */, + CE522434458EBA14DCAE751B /* Frameworks */, ); sourceTree = ""; }; @@ -171,10 +175,10 @@ name = "Supporting Files"; sourceTree = ""; }; - A9562A4C43D78E443FA8BFD1 /* Frameworks */ = { + CE522434458EBA14DCAE751B /* Frameworks */ = { isa = PBXGroup; children = ( - E4E9718EA62661304F55A32D /* Pods_Runner.framework */, + 6D9222C8F78B892C013C44A6 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,21 +190,24 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 4CBD0CB2C106C3E696B88FDB /* [CP] Check Pods Manifest.lock */, + 3F8132D0B1477379229A46EF /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - C21500C474806845DCE7C12A /* [CP] Embed Pods Frameworks */, - 24EE7472FCD545118644D8C4 /* [CP] Copy Pods Resources */, + CD1E4AEFF4CC6FD150483363 /* [CP] Embed Pods Frameworks */, + 6BD71B7017878A134266DEFC /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; @@ -217,7 +224,6 @@ TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = 3A359E86ZF; LastSwiftMigration = 1100; }; }; @@ -231,6 +237,9 @@ Base, ); mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; @@ -256,24 +265,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 24EE7472FCD545118644D8C4 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/permission_handler_apple/permission_handler_apple_privacy.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/permission_handler_apple_privacy.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -290,7 +281,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 4CBD0CB2C106C3E696B88FDB /* [CP] Check Pods Manifest.lock */ = { + 3F8132D0B1477379229A46EF /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -312,6 +303,24 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 6BD71B7017878A134266DEFC /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/permission_handler_apple/permission_handler_apple_privacy.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/permission_handler_apple_privacy.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -327,7 +336,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - C21500C474806845DCE7C12A /* [CP] Embed Pods Frameworks */ = { + CD1E4AEFF4CC6FD150483363 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -352,7 +361,6 @@ "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", "${BUILT_PRODUCTS_DIR}/Try/Try.framework", "${BUILT_PRODUCTS_DIR}/barcode_scan2/barcode_scan2.framework", - "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", "${BUILT_PRODUCTS_DIR}/flutter_inappwebview_ios/flutter_inappwebview_ios.framework", "${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework", @@ -361,11 +369,7 @@ "${BUILT_PRODUCTS_DIR}/maps_launcher/maps_launcher.framework", "${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework", "${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework", - "${BUILT_PRODUCTS_DIR}/pointer_interceptor_ios/pointer_interceptor_ios.framework", - "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", "${BUILT_PRODUCTS_DIR}/speech_to_text/speech_to_text.framework", - "${BUILT_PRODUCTS_DIR}/sqflite_darwin/sqflite_darwin.framework", - "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ZoomVideoSDK/CptShare/CptShare.framework/CptShare", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ZoomVideoSDK/ZoomVideoSDK/ZoomVideoSDK.framework/ZoomVideoSDK", "${PODS_XCFRAMEWORKS_BUILD_DIR}/ZoomVideoSDK/zm_annoter_dynamic/zm_annoter_dynamic.framework/zm_annoter_dynamic", @@ -391,7 +395,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Try.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan2.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework", @@ -400,11 +403,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/maps_launcher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pointer_interceptor_ios.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/speech_to_text.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite_darwin.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CptShare.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZoomVideoSDK.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/zm_annoter_dynamic.framework", @@ -748,6 +747,20 @@ defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1a6f2553..078f9dc2 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -5,6 +5,24 @@ + + + + + + + + + + initialize(); + + /// Check if device is currently safe + bool get isSafeDevice; + + /// Get list of detected threats + List get detectedThreats; + + /// Set callback for when critical threat is detected + void setOnCriticalThreatCallback(OnCriticalThreatDetected callback); +} + +/// Implementation of SecurityService using Talsec (freeRASP) +class SecurityServiceImpl implements SecurityService { + Logger logger = Logger( + printer: PrettyPrinter( + methodCount: 2, + errorMethodCount: 5, + lineLength: 1000, + colors: true, + printEmojis: true, + ), + ); + + final List _detectedThreats = []; + bool _isInitialized = false; + OnCriticalThreatDetected? _onCriticalThreatCallback; + + SecurityServiceImpl(); + + @override + bool get isSafeDevice => config.isSafeDevice; + + @override + List get detectedThreats => [..._detectedThreats]; + + @override + Future initialize() async { + if (_isInitialized) { + logger.d('SecurityService already initialized'); + return; + } + + try { + logger.d('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; + logger.d('SecurityService initialized successfully'); + } catch (e) { + logger.e('Failed to initialize SecurityService: $e'); + rethrow; + } + } + + @override + void setOnCriticalThreatCallback(OnCriticalThreatDetected callback) { + _onCriticalThreatCallback = callback; + logger.d('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) { + logger.e('🔴 CRITICAL THREAT: $threatType ${additionalInfo != null ? "- $additionalInfo" : ""}'); + } else { + logger.d('⚠️ WARNING: $threatType ${additionalInfo != null ? "- $additionalInfo" : ""}'); + } + + // Block app if critical threat + if (severity == ThreatSeverity.critical) { + config.isSafeDevice = false; + logger.e('Device marked as UNSAFE due to: $threatType'); + _onCriticalThreatCallback?.call(); + } + } +} diff --git a/lib/core/service/talsec_config.dart b/lib/core/service/talsec_config.dart new file mode 100644 index 00000000..e0c7a946 --- /dev/null +++ b/lib/core/service/talsec_config.dart @@ -0,0 +1,15 @@ +import 'package:freerasp/freerasp.dart'; + +final talsecConfig = TalsecConfig( + androidConfig: AndroidConfig( + packageName: 'com.hmg.hmgDr', + signingCertHashes: ['uNLWc6Ces/bVOgSs5vxQtlHdNtDW8hoBxe4FypG697Y=', 'MP0tIs2hPii94DAsiU9Jy9oZJfsEQy0a0PrG0/qVQfo='], // Must be the release cert hash + supportedStores: ['com.android.vending'], // Google Play Store + ), + iosConfig: IOSConfig( + bundleIds: ['com.hmg.hmgDr'], // iOS Bundle ID + teamId: '3A359E86ZF', // Found in Apple Developer portal + ), + watcherMail: '', // Required to receive security alerts + isProd: true, // Enforces strict checks for release builds +); \ No newline at end of file diff --git a/lib/locator.dart b/lib/locator.dart index 36441baf..39aba533 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -3,6 +3,7 @@ import 'package:doctor_app_flutter/core/service/home/scan_qr_service.dart'; import 'package:doctor_app_flutter/core/service/patient/profile/discharge_summary_servive.dart'; import 'package:doctor_app_flutter/core/service/patient_medical_file/ER_signin/ER_signin_service.dart'; import 'package:doctor_app_flutter/core/service/pending_order_service.dart'; +import 'package:doctor_app_flutter/core/service/security_service.dart'; import 'package:doctor_app_flutter/core/viewModel/dashboard_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/hospitals_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/medical_file_view_model.dart'; @@ -155,4 +156,5 @@ void setupLocator() { locator.registerFactory(() => InterventionMedicationViewModel()); locator.registerFactory(() => ERSignInViewModel()); locator.registerFactory(() => PharmacyInterventionViewModel()); + locator.registerFactory(() => SecurityServiceImpl()); } diff --git a/lib/main.dart b/lib/main.dart index 026ea959..20577199 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,14 +11,19 @@ import 'package:doctor_app_flutter/core/viewModel/livecare_view_model.dart'; import 'package:doctor_app_flutter/core/viewModel/project_view_model.dart'; import 'package:doctor_app_flutter/locator.dart'; import 'package:doctor_app_flutter/routes.dart'; +import 'package:doctor_app_flutter/unsafe_device.dart'; import 'package:doctor_app_flutter/utils/translations_delegate_base_utils.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; - import 'package:timezone/data/latest_all.dart' as tz; +import 'package:timezone/data/latest_all.dart' as tz; + +import 'core/service/security_service.dart'; + void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); @@ -26,6 +31,24 @@ void main() async { setupLocator(); await clearPrefsOnFirstLaunch(); tz.initializeTimeZones(); + + if (!kReleaseMode) { + await locator.get().initialize(); + + // Set up critical threat callback to navigate to unsafe device page + locator.get().setOnCriticalThreatCallback(() { + final navigationService = locator.get(); + final context = navigationService.navigatorKey.currentContext; + if (context != null) { + // Clear entire navigation stack and show unsafe device page + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (_) => const UnsafeDevice()), + (route) => false, // Remove all previous routes + ); + debugPrint('🚨 Navigated to UnsafeDevice page - Critical threat detected'); + } + }); + } runApp(MyApp()); } @@ -43,42 +66,36 @@ class MyApp extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { - return OrientationBuilder(builder: (context, orientation) { - SizeConfig().init(constraints, orientation); - return MultiProvider( - providers: [ - ChangeNotifierProvider(create: (context) => AuthenticationViewModel()), - ChangeNotifierProvider( - create: (context) => ProjectViewModel(), - ), - ChangeNotifierProvider( - create: (context) => LiveCareViewModel(), - ), - StreamProvider.value( - value: RobotProvider().intStream(), - initialData: RobotProvider().setValue({}), - ) - ], - child: Consumer( - builder: (context, projectProvider, child) => SafeArea( - top: false, - bottom: Platform.isAndroid ? true : false, - child: MaterialApp( - showSemanticsDebugger: false, - title: 'Doctors App', - locale: projectProvider.appLocal, - localizationsDelegates: [ - TranslationBaseDelegate(), - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - DefaultCupertinoLocalizations.delegate - ], - supportedLocales: [ - const Locale('ar', ''), // Arabic - const Locale('en', ''), // English - ], - theme: ThemeData( + return OrientationBuilder( + builder: (context, orientation) { + SizeConfig().init(constraints, orientation); + return MultiProvider( + providers: [ + ChangeNotifierProvider(create: (context) => AuthenticationViewModel()), + ChangeNotifierProvider(create: (context) => ProjectViewModel()), + ChangeNotifierProvider(create: (context) => LiveCareViewModel()), + StreamProvider.value(value: RobotProvider().intStream(), initialData: RobotProvider().setValue({})), + ], + child: Consumer( + builder: (context, projectProvider, child) => SafeArea( + top: false, + bottom: Platform.isAndroid ? true : false, + child: MaterialApp( + showSemanticsDebugger: false, + title: 'Doctors App', + locale: projectProvider.appLocal, + localizationsDelegates: [ + TranslationBaseDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + DefaultCupertinoLocalizations.delegate, + ], + supportedLocales: [ + const Locale('ar', ''), // Arabic + const Locale('en', ''), // English + ], + theme: ThemeData( primarySwatch: Colors.grey, primaryColor: Colors.grey, //buttonColor: HexColor('#D02127'), @@ -86,19 +103,19 @@ class MyApp extends StatelessWidget { dividerColor: Colors.grey[350], // backgroundColor: Color.fromRGBO(255, 255, 255, 1), - useMaterial3: false), - navigatorKey: locator().navigatorKey, - navigatorObservers: [ - locator().getAnalyticsObserver(), - ], - initialRoute: INIT_ROUTE, - routes: routes, - debugShowCheckedModeBanner: false, + useMaterial3: false, + ), + navigatorKey: locator().navigatorKey, + navigatorObservers: [locator().getAnalyticsObserver()], + initialRoute: INIT_ROUTE, + routes: routes, + debugShowCheckedModeBanner: false, + ), ), ), - ), - ); - }); + ); + }, + ); }, ); } diff --git a/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart b/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart index c2e1c274..a1a20021 100644 --- a/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart +++ b/lib/screens/doctor/doctor_replay/doctor_repaly_chat.dart @@ -100,7 +100,7 @@ class _DoctorReplayChatState extends State { onTap: () { Navigator.pop(context); }, - child: Icon(FontAwesomeIcons.times, + child: Icon(FontAwesomeIcons.times.data, size: 30, color: Color(0xFF2B353E))) ], @@ -522,7 +522,7 @@ class _DoctorReplayChatState extends State { .typeHereToReply, fontSize: 13.5, suffixIcon: - FontAwesomeIcons.arrowRight, + FontAwesomeIcons.arrowRight.data, suffixIconColor: AppGlobal.appGreenColor, onSuffixTap: () async { diff --git a/lib/screens/patients/In_patient/in_patient_list_page.dart b/lib/screens/patients/In_patient/in_patient_list_page.dart index c5004a9e..961d9f5a 100644 --- a/lib/screens/patients/In_patient/in_patient_list_page.dart +++ b/lib/screens/patients/In_patient/in_patient_list_page.dart @@ -109,7 +109,7 @@ class _InPatientListPageState extends State { widget.selectedClinicName ?? TranslationBase.of(context).clinicSelect, fontSize: 15, ), - Container(margin: EdgeInsets.only(bottom: 10), child: Icon(FontAwesomeIcons.sortDown)) + Container(margin: EdgeInsets.only(bottom: 10), child: Icon(FontAwesomeIcons.sortDown.data)) ], )), ], @@ -126,9 +126,9 @@ class _InPatientListPageState extends State { marginTop: widget.isMyInPatient ? 15 : 5, positionedChild: IconButton( icon: Icon( - isSortDes ? FontAwesomeIcons.sortAmountDown : FontAwesomeIcons.sortAmountUp, - color: Colors.black, - ), + isSortDes ? FontAwesomeIcons.sortAmountDown.data : FontAwesomeIcons.sortAmountUp.data, + color: Colors.black, + ), iconSize: 20, // padding: EdgeInsets.only(bottom: 30), onPressed: () { diff --git a/lib/screens/patients/ReferralDischargedPatientPage.dart b/lib/screens/patients/ReferralDischargedPatientPage.dart index 0ee33ee2..7f51e526 100644 --- a/lib/screens/patients/ReferralDischargedPatientPage.dart +++ b/lib/screens/patients/ReferralDischargedPatientPage.dart @@ -107,8 +107,8 @@ class _ReferralDischargedPatientPageState clinicDescription: model .myDischargeReferralPatient[index] .referringClinicDescription!, - infoIcon: Icon(FontAwesomeIcons.arrowRight, - size: 25, color: Colors.black), + infoIcon: Icon(FontAwesomeIcons.arrowRight.data, + size: 25, color: Colors.black), ), )), ), diff --git a/lib/screens/patients/out_patient/out_patient_screen.dart b/lib/screens/patients/out_patient/out_patient_screen.dart index be2333d3..bec9058b 100644 --- a/lib/screens/patients/out_patient/out_patient_screen.dart +++ b/lib/screens/patients/out_patient/out_patient_screen.dart @@ -167,7 +167,7 @@ class _OutPatientsScreenState extends State { marginTop: 5, suffixIcon: IconButton( icon: Icon( - _activeLocation != 0 ? DoctorApp.filter_1 : FontAwesomeIcons.slidersH, + _activeLocation != 0 ? DoctorApp.filter_1 : FontAwesomeIcons.slidersH.data, color: Colors.black, ), iconSize: 20, @@ -187,7 +187,7 @@ class _OutPatientsScreenState extends State { ), positionedChild: IconButton( icon: Icon( - isSortDes ? FontAwesomeIcons.sortAmountDown : FontAwesomeIcons.sortAmountUp, + isSortDes ? FontAwesomeIcons.sortAmountDown.data : FontAwesomeIcons.sortAmountUp.data, color: Colors.black, ), iconSize: 20, diff --git a/lib/screens/patients/profile/notes/note/progress_note_screen.dart b/lib/screens/patients/profile/notes/note/progress_note_screen.dart index a7cd574b..f0a942ab 100644 --- a/lib/screens/patients/profile/notes/note/progress_note_screen.dart +++ b/lib/screens/patients/profile/notes/note/progress_note_screen.dart @@ -237,7 +237,7 @@ class _ProgressNoteState extends State { child: Row( children: [ Icon( - FontAwesomeIcons.check, + FontAwesomeIcons.check.data, size: 12, color: Colors.white, ), @@ -289,13 +289,13 @@ class _ProgressNoteState extends State { ), // color:Colors.red[600], - child: Row( - children: [ - Icon( - FontAwesomeIcons.trash, - size: 12, - color: Colors.white, - ), + child: Row( + children: [ + Icon( + FontAwesomeIcons.trash.data, + size: 12, + color: Colors.white, + ), SizedBox( width: 2, ), diff --git a/lib/screens/patients/profile/referral/refer_details/referred-patient-screen.dart b/lib/screens/patients/profile/referral/refer_details/referred-patient-screen.dart index caeadca6..50fb93e2 100644 --- a/lib/screens/patients/profile/referral/refer_details/referred-patient-screen.dart +++ b/lib/screens/patients/profile/referral/refer_details/referred-patient-screen.dart @@ -113,7 +113,7 @@ class _ReferredPatientScreenState extends State { doctorAvatar: model.getReferredPatientItem(index).doctorImageURL!, referralDoctorName: "${TranslationBase.of(context).dr} ${model.getReferredPatientItem(index).referralDoctorName}", clinicDescription: model.getReferredPatientItem(index).referralClinicDescription!, - infoIcon: Icon(FontAwesomeIcons.arrowRight, size: 25, color: Colors.black), + infoIcon: Icon(FontAwesomeIcons.arrowRight.data, size: 25, color: Colors.black), ), ); }, diff --git a/lib/screens/patients/profile/referral/referral_details/my-referral-inpatient-screen.dart b/lib/screens/patients/profile/referral/referral_details/my-referral-inpatient-screen.dart index e04ded24..a3505a0d 100644 --- a/lib/screens/patients/profile/referral/referral_details/my-referral-inpatient-screen.dart +++ b/lib/screens/patients/profile/referral/referral_details/my-referral-inpatient-screen.dart @@ -105,7 +105,7 @@ class _MyReferralInPatientScreenState extends State { doctorAvatar: model.myReferralPatients[index].doctorImageURL!, referralDoctorName: model.myReferralPatients[index].referringDoctorName!, clinicDescription: model.myReferralPatients[index].referringClinicDescription!, - infoIcon: Icon(FontAwesomeIcons.arrowRight, size: 25, color: Colors.black), + infoIcon: Icon(FontAwesomeIcons.arrowRight.data, size: 25, color: Colors.black), ), ); }) diff --git a/lib/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart b/lib/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart index 6b6e75d4..ca32972c 100644 --- a/lib/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart +++ b/lib/screens/patients/profile/soap_update/shared_soap_widgets/expandable_SOAP_widget.dart @@ -51,7 +51,7 @@ class ExpandableSOAPWidget extends StatelessWidget { ), if (isRequired) Icon( - FontAwesomeIcons.asterisk, + FontAwesomeIcons.asterisk.data, size: SizeConfig.getTextMultiplierBasedOnWidth() * 2.5, ) ], diff --git a/lib/screens/patients/profile/soap_update/shared_soap_widgets/remove_button.dart b/lib/screens/patients/profile/soap_update/shared_soap_widgets/remove_button.dart index c970f62a..370a008c 100644 --- a/lib/screens/patients/profile/soap_update/shared_soap_widgets/remove_button.dart +++ b/lib/screens/patients/profile/soap_update/shared_soap_widgets/remove_button.dart @@ -25,11 +25,11 @@ class RemoveButton extends StatelessWidget { letterSpacing: -0.48, ), ), - Icon( - FontAwesomeIcons.times, - color: HexColor("#D02127"), - size: SizeConfig.getTextMultiplierBasedOnWidth() * 4, - ), + Icon( + FontAwesomeIcons.times.data, + color: HexColor("#D02127"), + size: SizeConfig.getTextMultiplierBasedOnWidth() * 4, + ), ], ), onTap: onTap, diff --git a/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart b/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart index 5c9e103e..656e9549 100644 --- a/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart +++ b/lib/screens/patients/profile/soap_update/shared_soap_widgets/steper/steps_widget.dart @@ -80,7 +80,7 @@ class StepsWidget extends StatelessWidget { ), child: Center( child: Icon( - FontAwesomeIcons.check, + FontAwesomeIcons.check.data, size: 20, color: Colors.white, )), @@ -128,7 +128,7 @@ class StepsWidget extends StatelessWidget { ), child: Center( child: Icon( - FontAwesomeIcons.check, + FontAwesomeIcons.check.data, size: 20, color: Colors.white, )), @@ -179,22 +179,22 @@ class StepsWidget extends StatelessWidget { ? AppGlobal.appGreenColor : Color(0xFFCCCCCC), ), - child: Center( - child: Icon( - FontAwesomeIcons.check, - size: 20, - color: Colors.white, - )), - ), - SizedBox( - height: 5, - ), - Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - StepDetailsWidget( - stepLabel: "Assessment", - ), + child: Center( + child: Icon( + FontAwesomeIcons.check.data, + size: 20, + color: Colors.white, + )), + ), + SizedBox( + height: 5, + ), + Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + StepDetailsWidget( + stepLabel: "Assessment", + ), StatusLabel( selectedStepId: index, stepId: 2, @@ -230,7 +230,7 @@ class StepsWidget extends StatelessWidget { ), child: Center( child: Icon( - FontAwesomeIcons.check, + FontAwesomeIcons.check.data, size: 20, color: Colors.white, )), @@ -302,7 +302,7 @@ class StepsWidget extends StatelessWidget { ), child: Center( child: Icon( - FontAwesomeIcons.check, + FontAwesomeIcons.check.data, size: 20, color: Colors.white, )), @@ -349,7 +349,7 @@ class StepsWidget extends StatelessWidget { ), child: Center( child: Icon( - FontAwesomeIcons.check, + FontAwesomeIcons.check.data, size: 20, color: Colors.white, )), @@ -395,23 +395,23 @@ class StepsWidget extends StatelessWidget { ? Color(0xFFCC9B14) : Color(0xFFCCCCCC), ), - child: Center( - child: Icon( - FontAwesomeIcons.check, - size: 20, - color: Colors.white, - )), - ), - SizedBox( - height: 5, - ), - Padding( - padding: const EdgeInsets.only(right: 2), - child: Column( - children: [ - StepDetailsWidget( - stepLabel: "تقدير", - ), + child: Center( + child: Icon( + FontAwesomeIcons.check.data, + size: 20, + color: Colors.white, + )), + ), + SizedBox( + height: 5, + ), + Padding( + padding: const EdgeInsets.only(right: 2), + child: Column( + children: [ + StepDetailsWidget( + stepLabel: "تقدير", + ), StatusLabel( selectedStepId: index, stepId: 2, @@ -450,7 +450,7 @@ class StepsWidget extends StatelessWidget { ), child: Center( child: Icon( - FontAwesomeIcons.check, + FontAwesomeIcons.check.data, size: 20, color: Colors.white, )), diff --git a/lib/screens/splash/splash_screen.dart b/lib/screens/splash/splash_screen.dart index 6681d954..72a6a214 100644 --- a/lib/screens/splash/splash_screen.dart +++ b/lib/screens/splash/splash_screen.dart @@ -8,8 +8,13 @@ import 'package:doctor_app_flutter/screens/auth/login_screen.dart'; import 'package:doctor_app_flutter/screens/auth/verification_methods_screen.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:safe_device/safe_device.dart'; + +import '../../core/service/NavigationService.dart'; +import '../../unsafe_device.dart' show UnsafeDevice; class SplashScreen extends StatefulWidget { @override _SplashScreenState createState() => _SplashScreenState(); @@ -18,17 +23,44 @@ class SplashScreen extends StatefulWidget { class _SplashScreenState extends State { final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance; late AuthenticationViewModel _authViewModel; + bool isJailBroken = false; + bool isRealDevice = true; + bool isDevelopmentModeEnable = false; @override void initState() { super.initState(); AppGlobal.CONTEX = context; + if (!kReleaseMode) { + checkDeviceSafety(); + } + Timer(Duration(seconds: 2, milliseconds: 500), () async { + if (isJailBroken || !isRealDevice || !isSafeDevice) { + // Critical threat detected - navigate to unsafe device page + Navigator.of(locator.get().navigatorKey.currentContext!).pushAndRemoveUntil( + MaterialPageRoute(builder: (_) => const UnsafeDevice()), + (route) => false, // Remove all previous routes + ); + }else { + _initializeApp(); + } + }); - - _initializeApp(); - - - + } + void checkDeviceSafety() { + try { + SafeDevice.isJailBroken.then((bool value) { + isJailBroken = value; + }); + SafeDevice.isJailBrokenCustom.then((bool value) { + isJailBroken = value; + }); + SafeDevice.isRealDevice.then((value) { + isRealDevice = value; + }); + } catch (error) { + print(error); + } } Future _initializeApp() async { diff --git a/lib/unsafe_device.dart b/lib/unsafe_device.dart new file mode 100644 index 00000000..72606390 --- /dev/null +++ b/lib/unsafe_device.dart @@ -0,0 +1,117 @@ +import 'package:doctor_app_flutter/core/service/security_service.dart'; +import 'package:flutter/material.dart'; +import 'package:freerasp/freerasp.dart'; +import 'package:http/http.dart' as getIt; + +import 'locator.dart'; + +class UnsafeDevice extends StatefulWidget { + const UnsafeDevice({super.key}); + + @override + State createState() => _UnsafeDeviceState(); +} + +class _UnsafeDeviceState extends State { + @override + void initState() { + Talsec.instance.detachListener(); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + body: SafeArea( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 24), + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Logo + Center( + child: Image.asset('assets/images/dr_app_logo.png'), + ), + SizedBox(height: 32), + // Warning Icon + Icon( + Icons.security, + size: 80, + color: Color(0xFFED1C2B), + ), + SizedBox(height: 24), + // Title + Text( + 'Unsafe Device Detected', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Color(0xFFED1C2B), + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 16), + + // Description + Text( + 'For your security, this app cannot run on devices with security vulnerabilities. is ssss', + style: TextStyle( + fontSize: 16, + color: Colors.black87, + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 24), + if (locator.get().detectedThreats.isNotEmpty) ...[ + Text( + 'Detected Issues:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + SizedBox(height: 8), + Container( + padding: EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.red.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: Colors.red.withOpacity(0.3)), + ), + child: Column( + children: locator + .get() + .detectedThreats + .where((t) => t.severity == ThreatSeverity.critical) + .take(5) // Show max 5 threats + .map((threat) => Padding( + padding: EdgeInsets.symmetric(vertical: 4), + child: Row( + children: [ + Icon(Icons.error_outline, size: 16, color: Colors.red), + SizedBox(width: 8), + Expanded( + child: Text( + threat.threatType, + style: TextStyle(fontSize: 12), + ), + ), + ], + ), + )) + .toList(), + ), + ), + SizedBox(height: 24), + ], + ], + ), + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index cb832c0c..ff2fdad7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -121,14 +121,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.1" - build_modules: - dependency: transitive - description: - name: build_modules - sha256: "0126ba5111c4b8f5b1f557beb23eb0bd9266f9114199ff42d9270c29c997b1be" - url: "https://pub.dev" - source: hosted - version: "5.0.18" build_resolvers: dependency: transitive description: @@ -157,10 +149,10 @@ packages: dependency: "direct dev" description: name: build_web_compilers - sha256: e93b5d5af529269f52b691f7542d859fba82982cadec23b19680c15c70f65378 + sha256: c8be4b48f09289d145c7eaa3240f1e7776c529ea1cecddf483218edd3129de3f url: "https://pub.dev" source: hosted - version: "4.3.0" + version: "4.8.0" built_collection: dependency: transitive description: @@ -205,10 +197,10 @@ packages: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" charts_common: dependency: transitive description: @@ -373,10 +365,10 @@ packages: dependency: "direct main" description: name: eva_icons_flutter - sha256: "6d48a10b93590ab83eb092bee5adacdeb14f3d83f527a4b9e4092c363d56e2a8" + sha256: d87ed92f8ec1cd4b6a3100c34a644e201758900a3bc64f4bf3e0f39ec297093c url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.0" events_emitter: dependency: transitive description: @@ -413,10 +405,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_picker: dependency: "direct main" description: @@ -769,10 +761,18 @@ packages: dependency: "direct main" description: name: font_awesome_flutter - sha256: "275ff26905134bcb59417cf60ad979136f1f8257f2f449914b2c3e05bbb4cd6f" + sha256: "09dcde8ab90ffae1a7d65ff2ef96fc62a17ad9d0ce7c127b317ded676b0d5935" + url: "https://pub.dev" + source: hosted + version: "11.0.0" + freerasp: + dependency: "direct main" + description: + name: freerasp + sha256: afba9e2ec1b578450701345230e87fda54e95c2f448154fbca55cf993f1ab2b3 url: "https://pub.dev" source: hosted - version: "10.7.0" + version: "8.2.1" frontend_server_client: dependency: transitive description: @@ -1057,26 +1057,26 @@ packages: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" meta: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" mime: dependency: transitive description: @@ -1373,14 +1373,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + safe_device: + dependency: "direct main" + description: + name: safe_device + sha256: ad1b32a564484c710f6d52b5a526838c8a7d999c8ab2e14890ff55c06a018248 + url: "https://pub.dev" + source: hosted + version: "1.4.1" scratch_space: dependency: transitive description: name: scratch_space - sha256: "8510fbff458d733a58fc427057d1ac86303b376d609d6e1bc43f240aad9aa445" + sha256: "55f141cf286eca871f739518b689af61cb994d671f3fd8efabd63aba7578c309" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.2.2" shared_preferences: dependency: "direct main" description: @@ -1598,10 +1606,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.11" timezone: dependency: "direct main" description: @@ -1819,5 +1827,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.8.0-0 <3.11.0-z" + dart: ">=3.10.0-0 <3.13.0-z" flutter: ">=3.29.0" diff --git a/pubspec.yaml b/pubspec.yaml index f1275715..e4a705ba 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -52,8 +52,8 @@ dependencies: #flutter_swiper: ^1.1.6 flutter_swiper_view: ^1.1.8 #Icons - eva_icons_flutter: ^3.1.0 - font_awesome_flutter: ^10.6.0 + eva_icons_flutter: ^4.0.0 + font_awesome_flutter: ^11.0.0 dropdown_search: ^5.0.6 flutter_staggered_grid_view: ^0.7.0 @@ -141,6 +141,8 @@ dependencies: two_dimensional_scrollables: ^0.3.3 timezone: ^0.10.1 logger: ^2.6.1 + freerasp: ^8.2.1 + safe_device: ^1.4.1 dependency_overrides: flutter_localizations: