Skip to content

Commit 8009b2a

Browse files
authored
release: freeRASP 2.5.0 (#45)
* feat: add code * chore: generate js sources * feat: update ios sdk * chore: update gitignore * feat: add register listener method * update listener rasp registration * update ios * update start * update dist * update code * update dist * fix ios code * fix android * fix: lint * fix: bugs
1 parent 581fadc commit 8009b2a

71 files changed

Lines changed: 1652 additions & 624 deletions

File tree

Some content is hidden

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

CHANGELOG.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,55 @@ 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+
## [2.5.0] - 2026-03-03
9+
10+
- Android SDK version: 18.0.4
11+
- iOS SDK version: 6.14.1
12+
13+
### Capacitor
14+
15+
#### Changed
16+
17+
- Refactor the Android plugin to separate the logic for managing listener states
18+
19+
### Android
20+
21+
#### Added
22+
23+
- Added support for `KernelSU` to the existing root detection capabilities
24+
- Added support for `HMA` to the existing root detection capabilities
25+
- Added new malware detection capabilities
26+
- Added `onAutomationDetected()` callback to `ThreatDetected` interface
27+
- We are introducing a new capability, detecting whether the device is being automated using tools like Appium
28+
- Added value restrictions to `externalId`
29+
- Method `storeExternalId()` now returns `ExternalIdResult`, which indicates `Success` or `Error` when `externalId` violates restrictions
30+
31+
#### Fixed
32+
33+
- Fixed exception handling for the KeyStore `getEntry` operation
34+
- Fixed issue in `ScreenProtector` concerning the `onScreenRecordingDetected` invocations
35+
- Merged internal shared libraries into a single one, reducing the final APK size
36+
- Fixed bug related to key storing in keystore type detection (hw-backed keystore check)
37+
- Fixed manifest queries merge
38+
39+
#### Changed
40+
41+
- Removed unused library `tmlib`
42+
- Refactoring of signature verification code
43+
- Updated compile and target API to 36
44+
- Improved root detection capabilities
45+
- Detection of wireless ADB added to ADB detections
46+
47+
### iOS
48+
49+
#### Added
50+
51+
- Added time spoofing detection, detecting an inaccurate device clock. It is a new threat `timeSpoofing`.
52+
53+
#### Changed
54+
55+
- Improved jailbreak detection methods.
56+
857
## [2.4.1] - 2026-02-13
958

1059
- Android SDK version: 18.0.2

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,5 @@ dependencies {
7676
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
7777
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
7878

79-
implementation 'com.aheaditec.talsec.security:TalsecSecurity-Community-Capacitor:18.0.2'
79+
implementation 'com.aheaditec.talsec.security:TalsecSecurity-Community-Capacitor:18.0.4'
8080
}

android/src/main/java/com/aheaditec/freerasp/FreeraspPlugin.kt

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,30 @@ typealias CapacitorCallback = (String, JSObject) -> Unit
2929
@CapacitorPlugin(name = "Freerasp")
3030
class FreeraspPlugin : Plugin() {
3131

32-
private var registered = true
33-
3432
override fun load() {
3533
initializeEventKeys()
34+
val pluginCallback: CapacitorCallback = { eventName, data ->
35+
notifyListeners(eventName, data, true)
36+
}
37+
PluginThreatHandler.initializeDispatchers(PluginListener(context, pluginCallback))
3638
super.load()
3739
}
3840

3941
@PluginMethod
4042
fun talsecStart(call: PluginCall) {
43+
if (talsecStarted) {
44+
call.resolve(JSObject().put("started", true))
45+
return
46+
}
47+
4148
val config = call.getObject("config")
4249
if (config == null) {
4350
call.reject("Missing config parameter in freeRASP Native Plugin")
4451
return
4552
}
4653
try {
4754
val talsecConfig = buildTalsecConfigThrowing(config)
48-
49-
val pluginCallback: CapacitorCallback = { eventName, data ->
50-
notifyListeners(eventName, data, true)
51-
}
52-
53-
PluginThreatHandler.threatDispatcher.listener = PluginListener(context, pluginCallback)
54-
PluginThreatHandler.executionStateDispatcher.listener = PluginListener(context, pluginCallback)
55-
PluginThreatHandler.registerListener(context)
55+
PluginThreatHandler.registerSDKListener(context)
5656

5757
bridge.activity.runOnUiThread {
5858
Talsec.start(context, talsecConfig)
@@ -75,35 +75,49 @@ class FreeraspPlugin : Plugin() {
7575
}
7676
}
7777

78-
override fun handleOnStart() {
79-
super.handleOnStart()
80-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
81-
ScreenProtector.register(activity)
78+
@PluginMethod(returnType = PluginMethod.RETURN_NONE)
79+
override fun addListener(call: PluginCall) {
80+
val eventName = call.getString("eventName")
81+
if (eventName == ThreatEvent.CHANNEL_NAME) {
82+
PluginThreatHandler.threatDispatcher.registerListener()
83+
}
84+
if (eventName == RaspExecutionStateEvent.CHANNEL_NAME) {
85+
PluginThreatHandler.executionStateDispatcher.registerListener()
86+
}
87+
super.addListener(call)
88+
}
89+
90+
@PluginMethod(returnType = PluginMethod.RETURN_NONE)
91+
fun removeListenerForEvent(call: PluginCall) {
92+
val eventName = call.getString("eventName")
93+
if (eventName == ThreatEvent.CHANNEL_NAME) {
94+
PluginThreatHandler.threatDispatcher.unregisterListener()
95+
}
96+
if (eventName == RaspExecutionStateEvent.CHANNEL_NAME) {
97+
PluginThreatHandler.executionStateDispatcher.unregisterListener()
8298
}
8399
}
84100

85101
override fun handleOnPause() {
86102
super.handleOnPause()
103+
PluginThreatHandler.threatDispatcher.onPause()
104+
PluginThreatHandler.executionStateDispatcher.onPause()
105+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
106+
ScreenProtector.unregister(activity)
107+
}
87108
if (activity.isFinishing) {
88-
PluginThreatHandler.unregisterListener(context)
89-
registered = false
90-
PluginThreatHandler.threatDispatcher.listener = null
91-
PluginThreatHandler.executionStateDispatcher.listener = null
109+
PluginThreatHandler.threatDispatcher.unregisterListener()
110+
PluginThreatHandler.executionStateDispatcher.unregisterListener()
111+
PluginThreatHandler.unregisterSDKListener(context)
92112
}
93113
}
94114

95115
override fun handleOnResume() {
96116
super.handleOnResume()
97-
if (!registered) {
98-
registered = true
99-
PluginThreatHandler.registerListener(context)
100-
}
101-
}
102-
103-
override fun handleOnStop() {
104-
super.handleOnStop()
117+
PluginThreatHandler.threatDispatcher.onResume()
118+
PluginThreatHandler.executionStateDispatcher.onResume()
105119
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
106-
ScreenProtector.unregister(activity)
120+
ScreenProtector.register(activity)
107121
}
108122
}
109123

@@ -317,16 +331,33 @@ class FreeraspPlugin : Plugin() {
317331
private val mainHandler = Handler(Looper.getMainLooper())
318332

319333
internal var talsecStarted = false
334+
}
320335

321-
internal fun notifyEvent(
336+
internal class PluginListener(
337+
private val context: Context,
338+
private val pluginCallback: CapacitorCallback
339+
) : PluginThreatListener, PluginExecutionStateListener {
340+
override fun threatDetected(threatEventType: ThreatEvent) {
341+
notifyEvent(threatEventType, pluginCallback)
342+
}
343+
344+
override fun malwareDetected(suspiciousApps: MutableList<SuspiciousAppInfo>) {
345+
notifyMalware(suspiciousApps, context, pluginCallback)
346+
}
347+
348+
override fun raspExecutionStateChanged(event: RaspExecutionStateEvent) {
349+
notifyEvent(event, pluginCallback)
350+
}
351+
352+
private fun notifyEvent(
322353
event: BaseRaspEvent,
323354
notifyListenersCallback: CapacitorCallback
324355
) {
325356
val params = JSObject().put(event.channelKey, event.value)
326357
notifyListenersCallback(event.channelName, params)
327358
}
328359

329-
internal fun notifyMalware(
360+
private fun notifyMalware(
330361
suspiciousApps: MutableList<SuspiciousAppInfo>,
331362
context: Context,
332363
notifyListenersCallback: CapacitorCallback
@@ -345,21 +376,4 @@ class FreeraspPlugin : Plugin() {
345376
}
346377
}
347378
}
348-
349-
internal class PluginListener(
350-
private val context: Context,
351-
private val pluginCallback: CapacitorCallback
352-
) : PluginThreatListener, PluginExecutionStateListener {
353-
override fun threatDetected(threatEventType: ThreatEvent) {
354-
notifyEvent(threatEventType, pluginCallback)
355-
}
356-
357-
override fun malwareDetected(suspiciousApps: MutableList<SuspiciousAppInfo>) {
358-
notifyMalware(suspiciousApps, context, pluginCallback)
359-
}
360-
361-
override fun raspExecutionStateChanged(event: RaspExecutionStateEvent) {
362-
notifyEvent(event, pluginCallback)
363-
}
364-
}
365379
}

android/src/main/java/com/aheaditec/freerasp/PluginThreatHandler.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ import com.aheaditec.freerasp.events.ThreatEvent
1010

1111
internal object PluginThreatHandler {
1212

13-
internal val threatDispatcher = ThreatDispatcher()
14-
internal val executionStateDispatcher = ExecutionStateDispatcher()
13+
internal lateinit var threatDispatcher: ThreatDispatcher
14+
internal lateinit var executionStateDispatcher: ExecutionStateDispatcher
15+
16+
fun initializeDispatchers(listener: FreeraspPlugin.PluginListener) {
17+
threatDispatcher = ThreatDispatcher(listener)
18+
executionStateDispatcher = ExecutionStateDispatcher(listener)
19+
}
1520

1621
private val threatDetected = object : ThreatListener.ThreatDetected() {
1722

@@ -111,11 +116,11 @@ internal object PluginThreatHandler {
111116

112117
private val internalListener = ThreatListener(threatDetected, deviceState, raspExecutionState)
113118

114-
internal fun registerListener(context: Context) {
119+
internal fun registerSDKListener(context: Context) {
115120
internalListener.registerListener(context)
116121
}
117122

118-
internal fun unregisterListener(context: Context) {
123+
internal fun unregisterSDKListener(context: Context) {
119124
internalListener.unregisterListener(context)
120125
}
121126
}

android/src/main/java/com/aheaditec/freerasp/dispatchers/ExecutionStateDispatcher.kt

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,53 @@ package com.aheaditec.freerasp.dispatchers
33
import com.aheaditec.freerasp.events.RaspExecutionStateEvent
44
import com.aheaditec.freerasp.interfaces.PluginExecutionStateListener
55

6-
internal class ExecutionStateDispatcher {
6+
internal class ExecutionStateDispatcher(private val listener: PluginExecutionStateListener) {
77
private val cache = mutableSetOf<RaspExecutionStateEvent>()
88

9-
var listener: PluginExecutionStateListener? = null
10-
set(value) {
11-
field = value
12-
if (value != null) {
13-
flushCache(value)
14-
}
9+
private var isAppInForeground = false
10+
private var isListenerRegistered = false
11+
12+
fun registerListener() {
13+
isListenerRegistered = true
14+
isAppInForeground = true
15+
flushCache()
16+
}
17+
18+
fun unregisterListener() {
19+
isListenerRegistered = false
20+
isAppInForeground = false
21+
}
22+
23+
fun onResume() {
24+
isAppInForeground = true
25+
if (isListenerRegistered) {
26+
flushCache()
1527
}
28+
}
29+
30+
fun onPause() {
31+
isAppInForeground = false
32+
}
1633

1734
fun dispatch(event: RaspExecutionStateEvent) {
18-
val checkedListener = synchronized(cache) {
19-
val currentListener = listener
20-
if (currentListener != null) {
21-
currentListener
22-
} else {
35+
if (isAppInForeground && isListenerRegistered) {
36+
listener.raspExecutionStateChanged(event)
37+
} else {
38+
synchronized(cache) {
2339
cache.add(event)
24-
null
2540
}
2641
}
27-
checkedListener?.raspExecutionStateChanged(event)
2842
}
2943

30-
private fun flushCache(registeredListener: PluginExecutionStateListener) {
44+
private fun flushCache() {
45+
if (!isListenerRegistered || !isAppInForeground) {
46+
return
47+
}
3148
val events = synchronized(cache) {
3249
val snapshot = cache.toSet()
3350
cache.clear()
3451
snapshot
3552
}
36-
events.forEach { registeredListener.raspExecutionStateChanged(it) }
53+
events.forEach { listener.raspExecutionStateChanged(it) }
3754
}
3855
}

0 commit comments

Comments
 (0)