Skip to content

Commit 24f24a3

Browse files
authored
release: freeRASP 4.3.0 (#125)
* add implementation * feat: refactor ios * feat: add permissions, killOnBypass * fix: resolve potential collision with threat identifiers * fix: update identifiers on ios * chore: bump android to 17.0.1 * chore: remove unused file * chore: fix ios podspec * fix: random generator * fix: identifier generator change
1 parent d75a3d7 commit 24f24a3

File tree

88 files changed

+4715
-1994
lines changed

Some content is hidden

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

88 files changed

+4715
-1994
lines changed

CHANGELOG.md

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,60 @@ 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+
## [4.3.0] - 2025-10-31
9+
10+
- Android SDK version: 17.0.1
11+
- iOS SDK version: 6.13.0
12+
13+
### React Native
14+
15+
#### Added
16+
17+
- 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))
18+
- Added API for `timeSpoofing` callback into `ThreatEventActions` (Android only)
19+
- Added API for `unsecureWifi` callback into `ThreatEventActions` (Android only)
20+
- Added API for `allChecksFinished` callback into new `RaspExecutionStateEventActions` object
21+
- Added matched permissions to `SuspiciousAppInfo` object when malware detection reason is `suspiciousPermission`
22+
23+
#### Fixed
24+
25+
- Resolved potential collision in threat identifiers
26+
27+
### Android
28+
29+
#### Added
30+
31+
- Added `killOnBypass` method to the `TalsecConfig.Builder` that configures if the app should be terminated when the threat callbacks are suppressed/hooked by an attacker [Issue 65](https://github.com/talsec/Free-RASP-Android/issues/65)
32+
- We are introducing a new capability, detecting whether the device time has been tampered with (`timeSpoofing`)
33+
- We are introducing a new capability, detecting whether the location is being spoofed on the device (`locationSpoofing`)
34+
- We are introducing a new capability, detection of unsecure WiFi (`unecureWifi`)
35+
- Removed deprecated functionality `Pbkdf2Native` and both related native libraries (`libpbkdf2_native.so` and `libpolarssl.so`)
36+
- Added new `RaspExecutionState` which contains `onAllChecksFinished()` method, which is triggered after all checks are completed.
37+
- Added matched permissions to `SuspiciousAppInfo` object when malware detection reason is `suspiciousPermission`
38+
- New option to start Talsec, `Talsec.start()` takes new parameter `TalsecMode` that determines the dispatcher thread of initialization and sync checks (uses background thread by default)
39+
- Capability to check if another app has an option `REQUEST_INSTALL_PACKAGES` enabled in the system settings to malware detection
40+
41+
#### Fixed
42+
43+
- ANR issue caused by `registerScreenCaptureCallback()` method on the main thread
44+
- `NullPointerException` when checking key alias in Keystore on Android 7
45+
- `JaCoCo` issue causing `MethodTooLargeException` during instrumentation
46+
- `DeadApplicationException` when calling `Settings.Global.getInt` or `Settings.Secure.getInt` on invalid context
47+
- `AndroidKeyStore` crashes causing `java.util.concurrent.TimeoutException` when calling `finalize()` method on `Cipher` (GC issues)
48+
- Fixed issue with late initializers and `TalsecMode` coroutines scopes
49+
50+
#### Changed
51+
52+
- Shortened the value of threat detection interval
53+
- Refactoring of internal architecture of SDK that newly uses Coroutines to manage threading
54+
- Update of internal dependencies and security libraries
55+
56+
### iOS
57+
58+
#### Changed
59+
60+
- Updated internal dependencies
61+
862
## [4.2.4] - 2025-09-17
963

1064
- iOS SDK version: 6.12.1
@@ -112,7 +166,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
112166
- Added interface for screenshot / screen recording blocking on iOS
113167
- Added interface for external ID storage
114168

115-
### Android
169+
### Android
116170

117171
#### Added
118172

@@ -148,7 +202,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
148202
- Android SDK requires `kotlinVersion` >= `2.0.0`
149203
- Set Java verison to 17
150204

151-
### Android
205+
### Android
152206

153207
#### Changed
154208

@@ -200,7 +254,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
200254

201255
- Raised Android compileSDK level to 35
202256

203-
#### Fixed
257+
#### Fixed
204258

205259
- Compatibility issues with RN New Architecture
206260
- Added proguard rules for malware data serialization in release mode on Android
@@ -278,7 +332,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
278332

279333
#### Added
280334

281-
- Added configuration fields for malware detection
335+
- Added configuration fields for malware detection
282336

283337
### Android
284338

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ dependencies {
9999
implementation "com.facebook.react:react-native:$react_native_version"
100100
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
101101
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
102-
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:16.0.4"
102+
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:17.0.1"
103103
}
104104

105105
if (isNewArchitectureEnabled()) {

android/src/main/java/com/freeraspreactnative/FreeraspReactNativeModule.kt

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import android.os.Looper
77
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
88
import com.aheaditec.talsec_security.security.api.Talsec
99
import com.aheaditec.talsec_security.security.api.TalsecConfig
10+
import com.aheaditec.talsec_security.security.api.TalsecMode
1011
import com.aheaditec.talsec_security.security.api.ThreatListener
1112
import com.facebook.react.bridge.Arguments
1213
import com.facebook.react.bridge.LifecycleEventListener
@@ -18,6 +19,9 @@ import com.facebook.react.bridge.ReadableMap
1819
import com.facebook.react.bridge.UiThreadUtil.runOnUiThread
1920
import com.facebook.react.bridge.WritableArray
2021
import com.facebook.react.modules.core.DeviceEventManagerModule
22+
import com.freeraspreactnative.events.BaseRaspEvent
23+
import com.freeraspreactnative.events.RaspExecutionStateEvent
24+
import com.freeraspreactnative.events.ThreatEvent
2125
import com.freeraspreactnative.utils.Utils
2226
import com.freeraspreactnative.utils.getArraySafe
2327
import com.freeraspreactnative.utils.getBooleanSafe
@@ -29,7 +33,7 @@ import com.freeraspreactnative.utils.toEncodedWritableArray
2933
class FreeraspReactNativeModule(private val reactContext: ReactApplicationContext) :
3034
ReactContextBaseJavaModule(reactContext) {
3135

32-
private val listener = ThreatListener(FreeraspThreatHandler, FreeraspThreatHandler)
36+
private val listener = ThreatListener(FreeraspThreatHandler, FreeraspThreatHandler, FreeraspThreatHandler)
3337
private val lifecycleListener = object : LifecycleEventListener {
3438
override fun onHostResume() {
3539
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
@@ -67,7 +71,7 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
6771
FreeraspThreatHandler.listener = ThreatListener
6872
listener.registerListener(reactContext)
6973
runOnUiThread {
70-
Talsec.start(reactContext, config)
74+
Talsec.start(reactContext, config, TalsecMode.BACKGROUND)
7175
mainHandler.post {
7276
talsecStarted = true
7377
// This code must be called only AFTER Talsec.start
@@ -90,19 +94,39 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
9094
*/
9195
@ReactMethod
9296
fun getThreatIdentifiers(promise: Promise) {
93-
promise.resolve(Threat.getThreatValues())
97+
promise.resolve(ThreatEvent.ALL_EVENTS)
9498
}
9599

96100
/**
97-
* Method to setup the message passing between native and React Native
101+
* Method to get the random identifiers of callbacks
102+
*/
103+
@ReactMethod
104+
fun getRaspExecutionStateIdentifiers(promise: Promise) {
105+
promise.resolve(RaspExecutionStateEvent.ALL_EVENTS)
106+
}
107+
108+
/**
109+
* Method to setup the threat message passing between native and React Native
98110
* @return list of [THREAT_CHANNEL_NAME, THREAT_CHANNEL_KEY]
99111
*/
100112
@ReactMethod
101113
fun getThreatChannelData(promise: Promise) {
102114
val channelData: WritableArray = Arguments.createArray()
103-
channelData.pushString(THREAT_CHANNEL_NAME)
104-
channelData.pushString(THREAT_CHANNEL_KEY)
105-
channelData.pushString(MALWARE_CHANNEL_KEY)
115+
channelData.pushString(ThreatEvent.CHANNEL_NAME)
116+
channelData.pushString(ThreatEvent.CHANNEL_KEY)
117+
channelData.pushString(ThreatEvent.MALWARE_CHANNEL_KEY)
118+
promise.resolve(channelData)
119+
}
120+
121+
/**
122+
* Method to setup the execution state message passing between native and React Native
123+
* @return list of [THREAT_CHANNEL_NAME, THREAT_CHANNEL_KEY]
124+
*/
125+
@ReactMethod
126+
fun getRaspExecutionStateChannelData(promise: Promise) {
127+
val channelData: WritableArray = Arguments.createArray()
128+
channelData.pushString(RaspExecutionStateEvent.CHANNEL_NAME)
129+
channelData.pushString(RaspExecutionStateEvent.CHANNEL_KEY)
106130
promise.resolve(channelData)
107131
}
108132

@@ -207,8 +231,9 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
207231

208232
val talsecBuilder = TalsecConfig.Builder(packageName, certificateHashes)
209233
.watcherMail(config.getString("watcherMail"))
210-
.supportedAlternativeStores(androidConfig.getArraySafe("supportedAlternativeStores"))
211234
.prod(config.getBooleanSafe("isProd"))
235+
.killOnBypass(config.getBooleanSafe("killOnBypass", false))
236+
.supportedAlternativeStores(androidConfig.getArraySafe("supportedAlternativeStores"))
212237

213238
if (androidConfig.hasKey("malwareConfig")) {
214239
val malwareConfig = androidConfig.getMapThrowing("malwareConfig")
@@ -223,12 +248,6 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
223248

224249
companion object {
225250
const val NAME = "FreeraspReactNative"
226-
private val THREAT_CHANNEL_NAME = (10000..999999999).random()
227-
.toString() // name of the channel over which threat callbacks are sent
228-
private val THREAT_CHANNEL_KEY = (10000..999999999).random()
229-
.toString() // key of the argument map under which threats are expected
230-
private val MALWARE_CHANNEL_KEY = (10000..999999999).random()
231-
.toString() // key of the argument map under which malware data is expected
232251

233252
private val backgroundHandlerThread = HandlerThread("BackgroundThread").apply { start() }
234253
private val backgroundHandler = Handler(backgroundHandlerThread.looper)
@@ -238,11 +257,11 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
238257

239258
internal var talsecStarted = false
240259

241-
private fun notifyListeners(threat: Threat) {
260+
private fun notifyEvent(event: BaseRaspEvent) {
242261
val params = Arguments.createMap()
243-
params.putInt(THREAT_CHANNEL_KEY, threat.value)
262+
params.putInt(event.channelKey, event.value)
244263
appReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
245-
.emit(THREAT_CHANNEL_NAME, params)
264+
.emit(event.channelName, params)
246265
}
247266

248267
/**
@@ -256,25 +275,29 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
256275

257276
mainHandler.post {
258277
val params = Arguments.createMap()
259-
params.putInt(THREAT_CHANNEL_KEY, Threat.Malware.value)
278+
params.putInt(ThreatEvent.CHANNEL_KEY, ThreatEvent.Malware.value)
260279
params.putArray(
261-
MALWARE_CHANNEL_KEY, encodedSuspiciousApps
280+
ThreatEvent.MALWARE_CHANNEL_KEY, encodedSuspiciousApps
262281
)
263282

264283
appReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
265-
.emit(THREAT_CHANNEL_NAME, params)
284+
.emit(ThreatEvent.CHANNEL_NAME, params)
266285
}
267286
}
268287
}
269288
}
270289

271290
internal object ThreatListener : FreeraspThreatHandler.TalsecReactNative {
272-
override fun threatDetected(threatType: Threat) {
273-
notifyListeners(threatType)
291+
override fun threatDetected(threatEventType: ThreatEvent) {
292+
notifyEvent(threatEventType)
274293
}
275294

276295
override fun malwareDetected(suspiciousApps: MutableList<SuspiciousAppInfo>) {
277296
notifyMalware(suspiciousApps)
278297
}
298+
299+
override fun raspExecutionStateChanged(event: RaspExecutionStateEvent) {
300+
notifyEvent(event)
301+
}
279302
}
280303
}

android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,102 @@ package com.freeraspreactnative
22

33
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
44
import com.aheaditec.talsec_security.security.api.ThreatListener
5+
import com.freeraspreactnative.events.RaspExecutionStateEvent
6+
import com.freeraspreactnative.events.ThreatEvent
57

6-
internal object FreeraspThreatHandler : ThreatListener.ThreatDetected, ThreatListener.DeviceState {
8+
internal object FreeraspThreatHandler : ThreatListener.ThreatDetected, ThreatListener.DeviceState, ThreatListener.RaspExecutionState() {
79

810
internal var listener: TalsecReactNative? = null
911

1012
override fun onRootDetected() {
11-
listener?.threatDetected(Threat.PrivilegedAccess)
13+
listener?.threatDetected(ThreatEvent.PrivilegedAccess)
1214
}
1315

1416
override fun onDebuggerDetected() {
15-
listener?.threatDetected(Threat.Debug)
17+
listener?.threatDetected(ThreatEvent.Debug)
1618
}
1719

1820
override fun onEmulatorDetected() {
19-
listener?.threatDetected(Threat.Simulator)
21+
listener?.threatDetected(ThreatEvent.Simulator)
2022
}
2123

2224
override fun onTamperDetected() {
23-
listener?.threatDetected(Threat.AppIntegrity)
25+
listener?.threatDetected(ThreatEvent.AppIntegrity)
2426
}
2527

2628
override fun onUntrustedInstallationSourceDetected() {
27-
listener?.threatDetected(Threat.UnofficialStore)
29+
listener?.threatDetected(ThreatEvent.UnofficialStore)
2830
}
2931

3032
override fun onHookDetected() {
31-
listener?.threatDetected(Threat.Hooks)
33+
listener?.threatDetected(ThreatEvent.Hooks)
3234
}
3335

3436
override fun onDeviceBindingDetected() {
35-
listener?.threatDetected(Threat.DeviceBinding)
37+
listener?.threatDetected(ThreatEvent.DeviceBinding)
3638
}
3739

3840
override fun onObfuscationIssuesDetected() {
39-
listener?.threatDetected(Threat.ObfuscationIssues)
41+
listener?.threatDetected(ThreatEvent.ObfuscationIssues)
4042
}
4143

42-
override fun onMalwareDetected(suspiciousAppInfos: MutableList<SuspiciousAppInfo>?) {
44+
override fun onMalwareDetected(suspiciousAppInfos: MutableList<SuspiciousAppInfo>) {
4345
listener?.malwareDetected(suspiciousAppInfos ?: mutableListOf())
4446
}
4547

4648
override fun onUnlockedDeviceDetected() {
47-
listener?.threatDetected(Threat.Passcode)
49+
listener?.threatDetected(ThreatEvent.Passcode)
4850
}
4951

5052
override fun onHardwareBackedKeystoreNotAvailableDetected() {
51-
listener?.threatDetected(Threat.SecureHardwareNotAvailable)
53+
listener?.threatDetected(ThreatEvent.SecureHardwareNotAvailable)
5254
}
5355

5456
override fun onDeveloperModeDetected() {
55-
listener?.threatDetected(Threat.DevMode)
57+
listener?.threatDetected(ThreatEvent.DevMode)
5658
}
5759

5860
override fun onADBEnabledDetected() {
59-
listener?.threatDetected(Threat.ADBEnabled)
61+
listener?.threatDetected(ThreatEvent.ADBEnabled)
6062
}
6163

6264
override fun onSystemVPNDetected() {
63-
listener?.threatDetected(Threat.SystemVPN)
65+
listener?.threatDetected(ThreatEvent.SystemVPN)
6466
}
6567

6668
override fun onScreenshotDetected() {
67-
listener?.threatDetected(Threat.Screenshot)
69+
listener?.threatDetected(ThreatEvent.Screenshot)
6870
}
6971

7072
override fun onScreenRecordingDetected() {
71-
listener?.threatDetected(Threat.ScreenRecording)
73+
listener?.threatDetected(ThreatEvent.ScreenRecording)
7274
}
7375

7476
override fun onMultiInstanceDetected() {
75-
listener?.threatDetected(Threat.MultiInstance)
77+
listener?.threatDetected(ThreatEvent.MultiInstance)
78+
}
79+
80+
override fun onUnsecureWifiDetected() {
81+
listener?.threatDetected(ThreatEvent.UnsecureWifi)
82+
}
83+
84+
override fun onTimeSpoofingDetected() {
85+
listener?.threatDetected(ThreatEvent.TimeSpoofing)
86+
}
87+
88+
override fun onLocationSpoofingDetected() {
89+
listener?.threatDetected(ThreatEvent.LocationSpoofing)
90+
}
91+
92+
override fun onAllChecksFinished() {
93+
listener?.raspExecutionStateChanged(RaspExecutionStateEvent.AllChecksFinished)
7694
}
7795

7896
internal interface TalsecReactNative {
79-
fun threatDetected(threatType: Threat)
97+
fun threatDetected(threatEventType: ThreatEvent)
8098

8199
fun malwareDetected(suspiciousApps: MutableList<SuspiciousAppInfo>)
100+
101+
fun raspExecutionStateChanged(event: RaspExecutionStateEvent)
82102
}
83103
}

0 commit comments

Comments
 (0)