Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,56 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.3.2] - 2025-01-03
## [4.4.0] - 2026-02-06

- Android SDK version: 18.0.1
- iOS SDK version: 6.13.0

### React Native

#### Added

- Added cache for freeRASP callbacks when listener is not registered with the app
- Added API for `automation` callback into `ThreatEventActions` (Android only)

#### Fixed

- Prevent multiple registration of the freeRASP listeners on the native side

#### Changed

- Updated compile and target SDK versions to 36 on Android
- Higher compileSdk from [rootProject, plugin] is now used in build.gradle on Android

### Android

#### Added

- Added support for `KernelSU` to the existing root detection capabilities
- Added support for `HMA` to the existing root detection capabilities
- Added new malware detection capabilities
- Added `onAutomationDetected()` callback to `ThreatDetected` interface
- We are introducing a new capability, detecting whether the device is being automated using tools like Appium
- Added value restrictions to `externalId`
- Method `storeExternalId()` now returns `ExternalIdResult`, which indicates `Success` or `Error` when `externalId` violates restrictions

#### Fixed

- Fixed exception handling for the KeyStore `getEntry` operation
- Fixed issue in `ScreenProtector` concerning the `onScreenRecordingDetected` invocations
- Merged internal shared libraries into a single one, reducing the final APK size
- Fixed bug related to key storing in keystore type detection (hw-backed keystore check)
- Fixed manifest queries merge

#### Changed

- Removed unused library `tmlib`
- Refactoring of signature verification code
- Updated compile and target API to 36
- Improved root detection capabilities
- Detection of wireless ADB added to ADB detections

## [4.3.2] - 2026-01-03

- Android SDK version: 17.0.1
- iOS SDK version: 6.13.0
Expand Down
10 changes: 8 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,14 @@ def getDefault(name) {
return project.properties["FreeraspReactNative_" + name]
}

def getMaxVersion(name) {
def rootVersion = rootProject.ext.has(name) ? rootProject.ext.get(name).toInteger() : 0
def pluginVersion = getIntegerDefault(name)
return Math.max(rootVersion, pluginVersion)
}

android {
compileSdkVersion getIntegerDefault("compileSdkVersion")
compileSdk getMaxVersion("compileSdk")

defaultConfig {
minSdkVersion getIntegerDefault("minSdkVersion")
Expand Down Expand Up @@ -99,7 +105,7 @@ dependencies {
implementation "com.facebook.react:react-native:$react_native_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:17.0.1"
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:18.0.1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have 18.0.2, could you please use that version?

}

if (isNewArchitectureEnabled()) {
Expand Down
4 changes: 2 additions & 2 deletions android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FreeraspReactNative_kotlinVersion=2.1.0
FreeraspReactNative_minSdkVersion=23
FreeraspReactNative_targetSdkVersion=35
FreeraspReactNative_compileSdkVersion=35
FreeraspReactNative_targetSdkVersion=36
FreeraspReactNative_compileSdk=36
FreeraspReactNative_ndkversion=21.4.7075529
FreeraspReactNative_reactNativeVersion=+
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
import com.freeraspreactnative.events.BaseRaspEvent
import com.freeraspreactnative.events.RaspExecutionStateEvent
import com.freeraspreactnative.events.ThreatEvent
import com.freeraspreactnative.interfaces.WrapperExecutionStateListener
import com.freeraspreactnative.interfaces.WrapperThreatListener
import com.freeraspreactnative.utils.Utils
import com.freeraspreactnative.utils.getArraySafe
import com.freeraspreactnative.utils.getBooleanSafe
Expand All @@ -33,7 +35,12 @@ import com.freeraspreactnative.utils.toEncodedWritableArray
class FreeraspReactNativeModule(private val reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {

private val listener = ThreatListener(FreeraspThreatHandler, FreeraspThreatHandler, FreeraspThreatHandler)
private val listener = ThreatListener(
WrapperThreatHandler.threatDetected,
WrapperThreatHandler.deviceState,
WrapperThreatHandler.raspExecutionState
)

private val lifecycleListener = object : LifecycleEventListener {
override fun onHostResume() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
Expand Down Expand Up @@ -69,7 +76,6 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex

try {
val config = buildTalsecConfig(options)
FreeraspThreatHandler.listener = ThreatListener
listener.registerListener(reactContext)
runOnUiThread {
Talsec.start(reactContext, config, TalsecMode.BACKGROUND)
Expand Down Expand Up @@ -147,13 +153,30 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
}

@ReactMethod
fun addListener(@Suppress("UNUSED_PARAMETER") eventName: String) {
// Set up any upstream listeners or background tasks as necessary
fun addListener(eventName: String) {
if (eventName == ThreatEvent.CHANNEL_NAME) {
WrapperThreatHandler.threatDispatcher.listener = WrapperListener
}
if (eventName == RaspExecutionStateEvent.CHANNEL_NAME) {
WrapperThreatHandler.executionStateDispatcher.listener = WrapperListener
}
}

@ReactMethod
fun removeListeners(@Suppress("UNUSED_PARAMETER") count: Int) {
// Remove upstream listeners, stop unnecessary background tasks
// built-in RN method, however it does not suit us as it just tells
// number of un-registered listeners, so we use `removeListenerForEvent`
}

@ReactMethod
fun removeListenerForEvent(eventName: String, promise: Promise) {
if (eventName == ThreatEvent.CHANNEL_NAME) {
WrapperThreatHandler.threatDispatcher.listener = null
}
if (eventName == RaspExecutionStateEvent.CHANNEL_NAME) {
WrapperThreatHandler.executionStateDispatcher.listener = null
}
promise.resolve("Listener unregistered")
}

/**
Expand Down Expand Up @@ -218,17 +241,17 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex

@ReactMethod
fun storeExternalId(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Talsec.storeExternalId method now enforces value restrictions (regex) and returns an ExternalIdResult instead of void. Your current implementation ignores this return value and always resolves the promise with "OK". This means if an invalid externalId is passed, the native side will reject it, but the React Native app will incorrectly think it was saved successfully.

externalId: String, promise: Promise
externalId: String, promise: Promise
) {
try {
Talsec.storeExternalId(reactContext, externalId)
promise.resolve("OK - Store external ID")
} catch (e: Exception) {
promise.reject(
"NativePluginError",
"Error during storeExternalId operation in Talsec Native Plugin"
)
}
try {
Talsec.storeExternalId(reactContext, externalId)
promise.resolve("OK - Store external ID")
} catch (e: Exception) {
promise.reject(
"NativePluginError",
"Error during storeExternalId operation in Talsec Native Plugin"
)
}
}

private fun buildTalsecConfig(config: ReadableMap): TalsecConfig {
Expand Down Expand Up @@ -294,7 +317,7 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
}
}

internal object ThreatListener : FreeraspThreatHandler.TalsecReactNative {
internal object WrapperListener : WrapperThreatListener, WrapperExecutionStateListener {
override fun threatDetected(threatEventType: ThreatEvent) {
notifyEvent(threatEventType)
}
Expand Down
103 changes: 0 additions & 103 deletions android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt

This file was deleted.

Loading
Loading