diff --git a/FreeRASPDemoApp/app/build.gradle b/FreeRASPDemoApp/app/build.gradle index 57d76df..fcaac34 100644 --- a/FreeRASPDemoApp/app/build.gradle +++ b/FreeRASPDemoApp/app/build.gradle @@ -7,8 +7,8 @@ android { defaultConfig { applicationId "com.aheaditec.talsec.demoapp" minSdk 23 - compileSdk 34 - targetSdk 34 + compileSdk 35 + targetSdk 35 versionCode 1 versionName "1.0" @@ -30,11 +30,13 @@ android { kotlinOptions { jvmTarget = '1.8' } + + namespace "com.aheaditec.talsec.demoapp" } dependencies { // freeRASP SDK - implementation 'com.aheaditec.talsec.security:TalsecSecurity-Community:13.2.0' + implementation 'com.aheaditec.talsec.security:TalsecSecurity-Community:14.0.1' implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.12.0' diff --git a/FreeRASPDemoApp/app/src/main/AndroidManifest.xml b/FreeRASPDemoApp/app/src/main/AndroidManifest.xml index 8f0fe94..2757800 100644 --- a/FreeRASPDemoApp/app/src/main/AndroidManifest.xml +++ b/FreeRASPDemoApp/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + = Consumer { state -> + if (state == SCREEN_RECORDING_STATE_VISIBLE) { + Talsec.onScreenRecordingDetected() + } + } + override fun onCreate() { super.onCreate() @@ -26,6 +39,64 @@ class TalsecApplication : Application(), ThreatListener.ThreatDetected { ThreatListener(this, deviceStateListener).registerListener(this) Talsec.start(this, config) + + registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { + override fun onActivityCreated(activity: Activity, bundle: Bundle?) { + + // Set to 'true' to block screen capture + Talsec.blockScreenCapture(activity, false) + } + + override fun onActivityStarted(activity: Activity) { + unregisterCallbacks() + currentActivity = activity + registerCallbacks(activity) + } + + override fun onActivityResumed(activity: Activity) {} + override fun onActivityPaused(activity: Activity) {} + + override fun onActivityStopped(activity: Activity) { + if (activity == currentActivity) { + unregisterCallbacks() + currentActivity = null + } + } + + override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {} + override fun onActivityDestroyed(activity: Activity) {} + }) + } + + private fun registerCallbacks(activity: Activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + screenCaptureCallback = Activity.ScreenCaptureCallback { + Talsec.onScreenshotDetected() + } + activity.registerScreenCaptureCallback( + baseContext.mainExecutor, screenCaptureCallback!! + ) + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + val initialState = activity.windowManager.addScreenRecordingCallback( + mainExecutor, screenRecordCallback + ) + screenRecordCallback.accept(initialState) + } + } + + private fun unregisterCallbacks() { + currentActivity?.let { activity -> + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && screenCaptureCallback != null) { + activity.unregisterScreenCaptureCallback(screenCaptureCallback!!) + screenCaptureCallback = null + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { + activity.windowManager.removeScreenRecordingCallback(screenRecordCallback) + } + } } override fun onRootDetected() { @@ -77,6 +148,14 @@ class TalsecApplication : Application(), ThreatListener.ThreatDetected { println("onMalwareDetected") } + override fun onScreenshotDetected() { + println("onScreenshotDetected") + } + + override fun onScreenRecordingDetected() { + println("onScreenRecordingDetected") + } + // This is optional. Use only if you are interested in device state information like device lock and HW backed keystore state private val deviceStateListener = object : ThreatListener.DeviceState { override fun onUnlockedDeviceDetected() { diff --git a/FreeRASPDemoApp/app/src/main/java/com/aheaditec/talsec/demoapp/Utils.kt b/FreeRASPDemoApp/app/src/main/java/com/aheaditec/talsec/demoapp/Utils.kt index bb58d04..456f034 100644 --- a/FreeRASPDemoApp/app/src/main/java/com/aheaditec/talsec/demoapp/Utils.kt +++ b/FreeRASPDemoApp/app/src/main/java/com/aheaditec/talsec/demoapp/Utils.kt @@ -30,15 +30,15 @@ object Utils { private fun getApkSigningCertificate(packageInfo: PackageInfo): List { val signingHashes = mutableListOf() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - packageInfo.signingInfo.apply { + packageInfo.signingInfo?.apply { if (hasMultipleSigners()) { - apkContentsSigners.forEach { + apkContentsSigners?.forEach { signingHashes.add( hashCertificate(it) ) } } else { - signingCertificateHistory.forEach { + signingCertificateHistory?.forEach { signingHashes.add( hashCertificate(it) ) @@ -46,7 +46,7 @@ object Utils { } } } else { - packageInfo.signatures.forEach { + packageInfo.signatures?.forEach { signingHashes.add( hashCertificate(it) ) diff --git a/FreeRASPDemoApp/build.gradle b/FreeRASPDemoApp/build.gradle index 796a094..e504a64 100644 --- a/FreeRASPDemoApp/build.gradle +++ b/FreeRASPDemoApp/build.gradle @@ -1,12 +1,12 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.7.10" + ext.kotlin_version = "2.0.0" repositories { google() mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:7.1.3" + classpath "com.android.tools.build:gradle:8.7.3" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/FreeRASPDemoApp/gradle/wrapper/gradle-wrapper.properties b/FreeRASPDemoApp/gradle/wrapper/gradle-wrapper.properties index ffed3a2..19cfad9 100644 --- a/FreeRASPDemoApp/gradle/wrapper/gradle-wrapper.properties +++ b/FreeRASPDemoApp/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists