Skip to content

Commit bb151df

Browse files
authored
freeRASP: 7.3.0 (#182)
* feat!: add new detection callbacks * feat!: add new termination option * chore: update tests * chore: raise SDK version * chore: raise version * feat: add new kill option * refactor(demo): fix `minSdkVersion` * refactor(demo): add new checks and run check control * chore: update iOS SDK * refactor: add pigeon api * refactor: implement new callback * chore: add dependency * chore: update demo app * chore: update build script * chore: update tests * chore: update analysis_options * chore: update docs * style: formatting * chore: update CHANGELOG * ci: raise flutter sdk version * fix: downgrade `very_good_analysis` * fix: downgrade `pigeon` * style: formatting * style: formatting * fix: raise minSdkVersion * fix: argument handling * fix: argument handling * fix: remove unnecessary log * fix: rename variable * refactor: organise files * refactor: update generation path * refactor: update * fix: add docs * chore: update CHANGELOG * fix: change default value of `killOnBypass` * docs: update * chore: fix versions
1 parent 68abd61 commit bb151df

File tree

89 files changed

+4483
-1686
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+4483
-1686
lines changed

.github/workflows/flutter-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ on:
1717
workflow_dispatch:
1818

1919
env:
20-
FLUTTER_VERSION: 3.19.0
20+
FLUTTER_VERSION: 3.24.0
2121
PANA_VERSION: 0.22.8
2222

2323
jobs:

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [7.3.0] - 2025-10-20
9+
- Android SDK version: 17.0.0
10+
- iOS SDK version: 6.13.0
11+
12+
### Flutter
13+
14+
#### Added
15+
- Added `killOnBypass` to `TalsecConfig` that configures if the app should be terminated when the threat callbacks are suppressed/hooked by an attacker (Android only) ([Issue 65](https://github.com/talsec/Free-RASP-Android/issues/65))
16+
- Added `onTimeSpoofing` callback to `ThreatCallback` for handling `Threat.timeSpoofing` threat (Android only)
17+
- We are introducing a new capability, detecting whether the device time has been tampered with
18+
- Added `onLocationSpoofing` callback to `ThreatCallback` for handling `Threat.locationSpoofing` threat (Android only)
19+
- We are introducing a new capability, detecting whether the location is being spoofed on the device.
20+
- Added `onUnsecureWifi` callback to `ThreatCallback` for handling `Threat.unsecureWifi` threat (Android only)
21+
- We are introducing a new capability, detecting whether the device is connected to an unsecured Wi-Fi network.
22+
- Added `onAllChecksDone` callback to new `RaspExecutionStateCallback`
23+
- We are introducing a new callback that notifies when all security checks have been completed.
24+
25+
### Android
26+
27+
#### Removed
28+
- Removed deprecated functionality `Pbkdf2Native` and both related native libraries (`libpbkdf2_native.so` and `libpolarssl.so`)
29+
30+
#### Changed
31+
- Updated internal dependencies
32+
33+
### iOS
34+
35+
#### Changed
36+
- Updated internal dependencies
37+
838
## [7.2.2] - 2025-10-09
939
- iOS SDK version: 6.12.1
1040
- Android SDK version: 16.0.1

analysis_options.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
include: package:very_good_analysis/analysis_options.yaml
22

33
analyzer:
4+
errors:
5+
document_ignores: false
46
exclude:
57
- '**/*.g.dart'

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version '1.0-SNAPSHOT'
33

44
buildscript {
55
ext.kotlin_version = '2.1.0'
6-
ext.talsec_version = '16.0.1'
6+
ext.talsec_version = '17.0.0'
77
repositories {
88
google()
99
mavenCentral()

android/src/main/kotlin/com/aheaditec/freerasp/Threat.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,10 @@ internal sealed class Threat(val value: Int) {
3939
object ScreenRecording : Threat(64690214)
4040

4141
object MultiInstance : Threat(859307284)
42+
43+
object UnsecureWiFi : Threat(363588890)
44+
45+
object TimeSpoofing : Threat(189105221)
46+
47+
object LocationSpoofing : Threat(653273273)
4248
}

android/src/main/kotlin/com/aheaditec/freerasp/Utils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ internal object Utils {
3131

3232
val watcherMail = json.getString("watcherMail")
3333
val isProd = json.getBoolean("isProd")
34+
val killOnBypass = json.optBoolean("killOnBypass")
3435
val androidConfig = json.getJSONObject("androidConfig")
3536
val packageName = androidConfig.getString("packageName")
3637
val certificateHashes = androidConfig.extractArray<String>("signingCertHashes")
@@ -41,6 +42,7 @@ internal object Utils {
4142
.watcherMail(watcherMail)
4243
.supportedAlternativeStores(alternativeStores)
4344
.prod(isProd)
45+
.killOnBypass(killOnBypass)
4446
.blacklistedPackageNames(malwareConfig.blacklistedPackageNames)
4547
.blacklistedHashes(malwareConfig.blacklistedHashes)
4648
.suspiciousPermissions(malwareConfig.suspiciousPermissions)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Autogenerated from Pigeon (v22.7.4), do not edit directly.
2+
// See also: https://pub.dev/packages/pigeon
3+
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
4+
5+
package com.aheaditec.freerasp.generated
6+
7+
import android.util.Log
8+
import io.flutter.plugin.common.BasicMessageChannel
9+
import io.flutter.plugin.common.BinaryMessenger
10+
import io.flutter.plugin.common.EventChannel
11+
import io.flutter.plugin.common.MessageCodec
12+
import io.flutter.plugin.common.StandardMethodCodec
13+
import io.flutter.plugin.common.StandardMessageCodec
14+
import java.io.ByteArrayOutputStream
15+
import java.nio.ByteBuffer
16+
17+
private fun createConnectionError(channelName: String): FlutterError {
18+
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "")}
19+
private open class RaspExecutionStatePigeonCodec : StandardMessageCodec() {
20+
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
21+
return super.readValueOfType(type, buffer)
22+
}
23+
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
24+
super.writeValue(stream, value)
25+
}
26+
}
27+
28+
/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */
29+
class RaspExecutionState(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") {
30+
companion object {
31+
/** The codec used by RaspExecutionState. */
32+
val codec: MessageCodec<Any?> by lazy {
33+
RaspExecutionStatePigeonCodec()
34+
}
35+
}
36+
fun onAllChecksFinished(callback: (Result<Unit>) -> Unit)
37+
{
38+
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
39+
val channelName = "dev.flutter.pigeon.freerasp.RaspExecutionState.onAllChecksFinished$separatedMessageChannelSuffix"
40+
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
41+
channel.send(null) {
42+
if (it is List<*>) {
43+
if (it.size > 1) {
44+
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
45+
} else {
46+
callback(Result.success(Unit))
47+
}
48+
} else {
49+
callback(Result.failure(createConnectionError(channelName)))
50+
}
51+
}
52+
}
53+
}

android/src/main/kotlin/com/aheaditec/freerasp/generated/TalsecPigeonApi.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
// Autogenerated from Pigeon (v22.4.0), do not edit directly.
1+
// Autogenerated from Pigeon (v22.7.4), do not edit directly.
22
// See also: https://pub.dev/packages/pigeon
33
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")
44

55
package com.aheaditec.freerasp.generated
66

7+
import android.util.Log
78
import io.flutter.plugin.common.BasicMessageChannel
89
import io.flutter.plugin.common.BinaryMessenger
10+
import io.flutter.plugin.common.EventChannel
911
import io.flutter.plugin.common.MessageCodec
12+
import io.flutter.plugin.common.StandardMethodCodec
1013
import io.flutter.plugin.common.StandardMessageCodec
1114
import java.io.ByteArrayOutputStream
1215
import java.nio.ByteBuffer

android/src/main/kotlin/com/aheaditec/freerasp/handlers/MethodCallHandler.kt

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import android.os.Looper
88
import androidx.lifecycle.Lifecycle
99
import androidx.lifecycle.LifecycleEventObserver
1010
import androidx.lifecycle.LifecycleOwner
11-
import com.aheaditec.freerasp.runResultCatching
1211
import com.aheaditec.freerasp.Utils
12+
import com.aheaditec.freerasp.generated.RaspExecutionState
13+
import com.aheaditec.freerasp.runResultCatching
1314
import com.aheaditec.freerasp.generated.TalsecPigeonApi
1415
import com.aheaditec.freerasp.toPigeon
1516
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
@@ -26,7 +27,8 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler
2627
internal class MethodCallHandler : MethodCallHandler, LifecycleEventObserver {
2728
private var context: Context? = null
2829
private var methodChannel: MethodChannel? = null
29-
private var pigeonApi: TalsecPigeonApi? = null
30+
private var talsecPigeon: TalsecPigeonApi? = null
31+
private var raspExecutionPigeon : RaspExecutionState? = null
3032
private val backgroundHandlerThread = HandlerThread("BackgroundThread").apply { start() }
3133
private val backgroundHandler = Handler(backgroundHandlerThread.looper)
3234
private val mainHandler = Handler(Looper.getMainLooper())
@@ -41,7 +43,7 @@ internal class MethodCallHandler : MethodCallHandler, LifecycleEventObserver {
4143
override fun onMalwareDetected(packageInfo: List<SuspiciousAppInfo>) {
4244
context?.let { context ->
4345
val pigeonPackageInfo = packageInfo.map { it.toPigeon(context) }
44-
pigeonApi?.onMalwareDetected(pigeonPackageInfo) { result ->
46+
talsecPigeon?.onMalwareDetected(pigeonPackageInfo) { result ->
4547
// Parse the result (which is Unit so we can ignore it) or throw an exception
4648
// Exceptions are translated to Flutter errors automatically
4749
result.getOrElse {
@@ -51,10 +53,22 @@ internal class MethodCallHandler : MethodCallHandler, LifecycleEventObserver {
5153
}
5254
}
5355
}
56+
57+
override fun onAllChecksFinished() {
58+
raspExecutionPigeon?.onAllChecksFinished { result ->
59+
// Parse the result (which is Unit so we can ignore it) or throw an exception
60+
// Exceptions are translated to Flutter errors automatically
61+
result.getOrElse {
62+
Log.e("MethodCallHandlerSink", "Result ended with failure")
63+
throw it
64+
}
65+
}
66+
}
5467
}
5568

5669
internal interface MethodSink {
5770
fun onMalwareDetected(packageInfo: List<SuspiciousAppInfo>)
71+
fun onAllChecksFinished()
5872
}
5973

6074
/**
@@ -76,7 +90,8 @@ internal class MethodCallHandler : MethodCallHandler, LifecycleEventObserver {
7690
}
7791

7892
this.context = context
79-
this.pigeonApi = TalsecPigeonApi(messenger)
93+
this.talsecPigeon = TalsecPigeonApi(messenger)
94+
this.raspExecutionPigeon = RaspExecutionState(messenger)
8095

8196
TalsecThreatHandler.attachMethodSink(sink)
8297
}
@@ -89,7 +104,8 @@ internal class MethodCallHandler : MethodCallHandler, LifecycleEventObserver {
89104
methodChannel = null
90105

91106
this.context = null
92-
this.pigeonApi = null
107+
this.talsecPigeon = null
108+
this.raspExecutionPigeon = null
93109

94110
TalsecThreatHandler.detachMethodSink()
95111
}
@@ -184,9 +200,13 @@ internal class MethodCallHandler : MethodCallHandler, LifecycleEventObserver {
184200
*/
185201
private fun blockScreenCapture(call: MethodCall, result: MethodChannel.Result) {
186202
runResultCatching(result) {
187-
val enable = call.argument<Boolean>("enable") ?: false
188-
Talsec.blockScreenCapture(activity, enable)
189-
result.success(null)
203+
val enable = call.argument<Boolean>("enable") ?: throw NullPointerException("Enable flag cannot be null.")
204+
activity?.let {
205+
Talsec.blockScreenCapture(it, enable)
206+
result.success(null)
207+
return@runResultCatching
208+
}
209+
throw IllegalStateException("Unable to block screen capture - context is null")
190210
}
191211
}
192212

@@ -209,9 +229,13 @@ internal class MethodCallHandler : MethodCallHandler, LifecycleEventObserver {
209229
*/
210230
private fun storeExternalId(call: MethodCall, result: MethodChannel.Result) {
211231
runResultCatching(result) {
212-
val data = call.argument<String>("data")
213-
Talsec.storeExternalId(context, data)
214-
result.success(null)
232+
context?.let {
233+
val data = call.argument<String>("data") ?: throw NullPointerException("External ID data cannot be null.")
234+
Talsec.storeExternalId(it, data)
235+
result.success(null)
236+
return@runResultCatching
237+
}
238+
throw IllegalStateException("Unable to store external ID - context is null")
215239
}
216240
}
217241
}

android/src/main/kotlin/com/aheaditec/freerasp/handlers/PluginThreatHandler.kt

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.aheaditec.freerasp.Threat
55
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
66
import com.aheaditec.talsec_security.security.api.ThreatListener
77
import com.aheaditec.talsec_security.security.api.ThreatListener.DeviceState
8+
import com.aheaditec.talsec_security.security.api.ThreatListener.RaspExecutionState
89
import com.aheaditec.talsec_security.security.api.ThreatListener.ThreatDetected
910

1011
/**
@@ -13,12 +14,13 @@ import com.aheaditec.talsec_security.security.api.ThreatListener.ThreatDetected
1314
* The object provides methods to register a listener for threat notifications and notifies the
1415
* listener when a security threat is detected.
1516
*/
16-
internal object PluginThreatHandler : ThreatDetected, DeviceState {
17+
internal object PluginThreatHandler : ThreatDetected, DeviceState, RaspExecutionState() {
1718
internal val detectedThreats = mutableSetOf<Threat>()
1819
internal val detectedMalware = mutableListOf<SuspiciousAppInfo>()
20+
internal var shouldNotifyAllChecksFinished = false
1921

2022
internal var listener: TalsecFlutter? = null
21-
private val internalListener = ThreatListener(this, this)
23+
private val internalListener = ThreatListener(this, this, this)
2224

2325
internal fun registerListener(context: Context) {
2426
internalListener.registerListener(context)
@@ -28,6 +30,10 @@ internal object PluginThreatHandler : ThreatDetected, DeviceState {
2830
internalListener.unregisterListener(context)
2931
}
3032

33+
override fun onAllChecksFinished() {
34+
notifyAllChecksFinished()
35+
}
36+
3137
override fun onRootDetected() {
3238
notify(Threat.PrivilegedAccess)
3339
}
@@ -96,6 +102,18 @@ internal object PluginThreatHandler : ThreatDetected, DeviceState {
96102
notify(Threat.MultiInstance)
97103
}
98104

105+
override fun onUnsecureWifiDetected() {
106+
notify(Threat.UnsecureWiFi)
107+
}
108+
109+
override fun onTimeSpoofingDetected() {
110+
notify(Threat.TimeSpoofing)
111+
}
112+
113+
override fun onLocationSpoofingDetected() {
114+
notify(Threat.LocationSpoofing)
115+
}
116+
99117
private fun notify(threat: Threat) {
100118
listener?.threatDetected(threat) ?: detectedThreats.add(threat)
101119
}
@@ -104,9 +122,15 @@ internal object PluginThreatHandler : ThreatDetected, DeviceState {
104122
listener?.malwareDetected(suspiciousApps) ?: detectedMalware.addAll(suspiciousApps)
105123
}
106124

125+
private fun notifyAllChecksFinished() {
126+
listener?.allChecksFinished() ?: run { shouldNotifyAllChecksFinished = true }
127+
}
128+
107129
internal interface TalsecFlutter {
108130
fun threatDetected(threatType: Threat)
109131

110132
fun malwareDetected(suspiciousApps: List<SuspiciousAppInfo>)
133+
134+
fun allChecksFinished()
111135
}
112136
}

0 commit comments

Comments
 (0)