Skip to content

Commit adf5475

Browse files
committed
update the android sdk, implement ios cache + align api
1 parent a9ba177 commit adf5475

File tree

12 files changed

+201
-25
lines changed

12 files changed

+201
-25
lines changed

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ dependencies {
105105
implementation "com.facebook.react:react-native:$react_native_version"
106106
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
107107
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
108-
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:18.0.1"
108+
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:18.0.2"
109109
}
110110

111111
if (isNewArchitectureEnabled()) {

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.os.Build
44
import android.os.Handler
55
import android.os.HandlerThread
66
import android.os.Looper
7+
import com.aheaditec.talsec_security.security.api.ExternalIdResult
78
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
89
import com.aheaditec.talsec_security.security.api.Talsec
910
import com.aheaditec.talsec_security.security.api.TalsecConfig
@@ -244,8 +245,32 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
244245
externalId: String, promise: Promise
245246
) {
246247
try {
247-
Talsec.storeExternalId(reactContext, externalId)
248-
promise.resolve("OK - Store external ID")
248+
when (val result = Talsec.storeExternalId(reactContext, externalId)) {
249+
is ExternalIdResult.Error -> {
250+
promise.reject(
251+
"ExternalIdError",
252+
"Setting up External ID failed - ${result.errorMsg}"
253+
)
254+
}
255+
256+
is ExternalIdResult.Success -> {
257+
promise.resolve("OK - Store external ID")
258+
return
259+
}
260+
}
261+
} catch (e: Exception) {
262+
promise.reject(
263+
"NativePluginError",
264+
"Error during storeExternalId operation in Talsec Native Plugin"
265+
)
266+
}
267+
}
268+
269+
@ReactMethod
270+
fun removeExternalId(promise: Promise) {
271+
try {
272+
Talsec.removeExternalId(reactContext)
273+
promise.resolve("OK - External ID removed")
249274
} catch (e: Exception) {
250275
promise.reject(
251276
"NativePluginError",

android/src/main/java/com/freeraspreactnative/dispatchers/ExecutionStateDispatcher.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ internal class ExecutionStateDispatcher {
2727
}
2828

2929
private fun flushCache(registeredListener: WrapperExecutionStateListener) {
30-
synchronized(cache) {
31-
cache.forEach { registeredListener.raspExecutionStateChanged(it) }
30+
val events = synchronized(cache) {
31+
val snapshot = cache.toSet()
3232
cache.clear()
33+
snapshot
3334
}
35+
events.forEach { registeredListener.raspExecutionStateChanged(it) }
3436
}
3537
}
3638

android/src/main/java/com/freeraspreactnative/dispatchers/ThreatDispatcher.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,20 @@ internal class ThreatDispatcher {
4141
}
4242

4343
private fun flushCache(registeredListener: WrapperThreatListener) {
44-
synchronized(threatCache) {
45-
threatCache.forEach { registeredListener.threatDetected(it) }
44+
val threats = synchronized(threatCache) {
45+
val snapshot = threatCache.toSet()
4646
threatCache.clear()
47+
snapshot
4748
}
48-
synchronized(malwareCache) {
49-
if (malwareCache.isNotEmpty()) {
50-
registeredListener.malwareDetected(malwareCache.toMutableList())
51-
malwareCache.clear()
52-
}
49+
threats.forEach { registeredListener.threatDetected(it) }
50+
51+
val malware = synchronized(malwareCache) {
52+
val snapshot = malwareCache.toMutableList()
53+
malwareCache.clear()
54+
snapshot
55+
}
56+
if (malware.isNotEmpty()) {
57+
registeredListener.malwareDetected(malware)
5358
}
5459
}
5560
}

example/src/DemoApp.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
blockScreenCapture,
2222
type SuspiciousAppInfo,
2323
storeExternalId,
24+
removeExternalId,
2425
} from 'freerasp-react-native';
2526
import {
2627
ALERT_TYPE,
@@ -84,6 +85,24 @@ export const DemoApp: React.FC<{
8485
}
8586
};
8687

88+
const handleModalRemove = async () => {
89+
setModalVisible(false);
90+
try {
91+
await removeExternalId();
92+
Toast.show({
93+
type: ALERT_TYPE.SUCCESS,
94+
title: 'Success',
95+
textBody: 'External ID removed',
96+
});
97+
} catch (error: any) {
98+
Toast.show({
99+
type: ALERT_TYPE.WARNING,
100+
title: 'Warning',
101+
textBody: 'External ID not removed',
102+
});
103+
}
104+
};
105+
87106
const handleModalDismiss = () => {
88107
setModalVisible(false);
89108
};
@@ -140,6 +159,11 @@ export const DemoApp: React.FC<{
140159
onPress={handleModalSend}>
141160
<Text style={styles.modalText}>Send</Text>
142161
</TouchableOpacity>
162+
<TouchableOpacity
163+
style={styles.removeButton}
164+
onPress={handleModalRemove}>
165+
<Text style={styles.modalText}>Remove</Text>
166+
</TouchableOpacity>
143167
<TouchableOpacity
144168
style={styles.dismissButton}
145169
onPress={handleModalDismiss}>
@@ -346,6 +370,14 @@ const styles = StyleSheet.create({
346370
marginRight: 10,
347371
alignItems: 'center',
348372
},
373+
removeButton: {
374+
backgroundColor: '#FF9800',
375+
padding: 10,
376+
borderRadius: 5,
377+
flex: 1,
378+
marginRight: 10,
379+
alignItems: 'center',
380+
},
349381
dismissButton: {
350382
backgroundColor: '#f44336',
351383
padding: 10,

freerasp-react-native.podspec

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ Pod::Spec.new do |s|
1414
s.platforms = { :ios => "11.0" }
1515
s.source = { :git => "https://github.com/talsec/freerasp-react-native.git", :tag => "#{s.version}" }
1616

17-
s.source_files = 'ios/models/*.{h,m,mm,swift}', 'ios/utils/*.{h,m,mm,swift}', 'ios/*.{h,m,mm,swift}', 'ios/TalsecRuntime.xcframework'
17+
s.source_files = 'ios/models/*.{h,m,mm,swift}',
18+
'ios/utils/*.{h,m,mm,swift}',
19+
'ios/dispatchers/*.{h,m,mm,swift}',
20+
'ios/*.{h,m,mm,swift}',
21+
'ios/TalsecRuntime.xcframework'
1822
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework TalsecRuntime' }
1923
s.ios.vendored_frameworks = "ios/TalsecRuntime.xcframework"
2024

ios/FreeraspReactNative.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ @interface RCT_EXTERN_MODULE(FreeraspReactNative, RCTEventEmitter)
1515
withRejecter:(RCTPromiseRejectBlock)reject)
1616
RCT_EXTERN_METHOD(getRaspExecutionStateIdentifiers:(RCTPromiseResolveBlock)resolve
1717
withRejecter:(RCTPromiseRejectBlock)reject)
18+
RCT_EXTERN_METHOD(removeListenerForEvent:(NSString *)eventName
19+
withResolver:(RCTPromiseResolveBlock)resolve
20+
withRejecter:(RCTPromiseRejectBlock)reject)
1821
RCT_EXTERN_METHOD(blockScreenCapture:(BOOL)enable
1922
withResolver:(RCTPromiseResolveBlock)resolve
2023
withRejecter:(RCTPromiseRejectBlock)reject)
@@ -23,6 +26,8 @@ @interface RCT_EXTERN_MODULE(FreeraspReactNative, RCTEventEmitter)
2326
RCT_EXTERN_METHOD(storeExternalId:(NSString *)externalId
2427
withResolver:(RCTPromiseResolveBlock)resolve
2528
withRejecter:(RCTPromiseRejectBlock)reject)
29+
RCT_EXTERN_METHOD(removeExternalId:(RCTPromiseResolveBlock)resolve
30+
withRejecter:(RCTPromiseRejectBlock)reject)
2631
RCT_EXTERN_METHOD(onInvalidCallback)
2732

2833
+ (BOOL)requiresMainQueueSetup

ios/FreeraspReactNative.swift

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,30 @@ class FreeraspReactNative: RCTEventEmitter {
1111
FreeraspReactNative.shared = self
1212
}
1313

14+
@objc(addListener:)
15+
override func addListener(_ eventName: String!) {
16+
super.addListener(eventName)
17+
if eventName == EventIdentifiers.threatChannelName {
18+
ThreatDispatcher.shared.listener = { [weak self] threat in
19+
self?.dispatchThreatEvent(threat: threat)
20+
}
21+
} else if eventName == EventIdentifiers.raspExecutionStateChannelName {
22+
ExecutionStateDispatcher.shared.listener = { [weak self] event in
23+
self?.dispatchRaspExecutionStateEvent(event: event)
24+
}
25+
}
26+
}
27+
28+
@objc(removeListenerForEvent:withResolver:withRejecter:)
29+
func removeListenerForEvent(eventName: String, resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
30+
if eventName == EventIdentifiers.threatChannelName {
31+
ThreatDispatcher.shared.listener = nil
32+
} else if eventName == EventIdentifiers.raspExecutionStateChannelName {
33+
ExecutionStateDispatcher.shared.listener = nil
34+
}
35+
resolve("Listener unregistered")
36+
}
37+
1438
@objc(talsecStart:withResolver:withRejecter:)
1539
func talsecStart(options: NSDictionary, resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
1640
do {
@@ -72,12 +96,18 @@ class FreeraspReactNative: RCTEventEmitter {
7296
resolve("OK - Store external ID")
7397
}
7498

99+
@objc(removeExternalId:withRejecter:)
100+
private func removeExternalId(resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
101+
UserDefaults.standard.removeObject(forKey: "app.talsec.externalid")
102+
resolve("OK - External ID removed")
103+
}
104+
75105
/**
76106
* Method to setup the message passing between native and React Native
77107
*/
78108
@objc(getThreatChannelData:withRejecter:)
79109
private func getThreatChannelData(resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) -> Void {
80-
resolve([EventIdentifiers.threatChannelName, EventIdentifiers.threatChannelKey])
110+
resolve([EventIdentifiers.threatChannelName, EventIdentifiers.threatChannelKey, "0"])
81111
}
82112

83113
/**
@@ -88,16 +118,16 @@ class FreeraspReactNative: RCTEventEmitter {
88118
resolve([EventIdentifiers.raspExecutionStateChannelName, EventIdentifiers.raspExecutionStateChannelKey])
89119
}
90120

91-
func dispatchEvent(securityThreat: SecurityThreat) -> Void {
121+
func dispatchThreatEvent(threat: SecurityThreat) {
92122
FreeraspReactNative.shared!.sendEvent(withName: EventIdentifiers.threatChannelName, body: [
93-
EventIdentifiers.threatChannelKey: securityThreat.callbackIdentifier,
123+
EventIdentifiers.threatChannelKey: threat.callbackIdentifier
94124
])
95125
}
96126

97-
func dispatchRaspExecutionStateEvent(event: RaspExecutionStates) -> Void {
98-
FreeraspReactNative.shared!.sendEvent(withName: EventIdentifiers.raspExecutionStateChannelName, body: [
99-
EventIdentifiers.raspExecutionStateChannelKey: event.callbackIdentifier,
100-
])
127+
func dispatchRaspExecutionStateEvent(event: RaspExecutionStates) {
128+
FreeraspReactNative.shared!.sendEvent(withName: EventIdentifiers.raspExecutionStateChannelName, body: [
129+
EventIdentifiers.raspExecutionStateChannelKey: event.callbackIdentifier,
130+
])
101131
}
102132

103133
/**
@@ -139,12 +169,11 @@ extension SecurityThreatCenter: @retroactive SecurityThreatHandler, @retroactive
139169
if (securityThreat.rawValue == "passcodeChange") {
140170
return
141171
}
142-
FreeraspReactNative.shared!.dispatchEvent(securityThreat: securityThreat)
172+
ThreatDispatcher.shared.dispatch(threat: securityThreat)
143173
}
144174

145175
public func onAllChecksFinished() {
146-
147-
FreeraspReactNative.shared!.dispatchRaspExecutionStateEvent(event: RaspExecutionStates.allChecksFinished)
176+
ExecutionStateDispatcher.shared.dispatch(event: RaspExecutionStates.allChecksFinished)
148177
}
149178
}
150179

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import Foundation
2+
3+
class ExecutionStateDispatcher {
4+
static let shared = ExecutionStateDispatcher()
5+
private var cache: Set<RaspExecutionStates> = []
6+
private let lock = NSLock()
7+
8+
var listener: ((RaspExecutionStates) -> Void)? {
9+
didSet {
10+
if listener != nil {
11+
flushCache()
12+
}
13+
}
14+
}
15+
16+
func dispatch(event: RaspExecutionStates) {
17+
lock.lock()
18+
defer { lock.unlock() }
19+
20+
if let listener = listener {
21+
listener(event)
22+
} else {
23+
cache.insert(event)
24+
}
25+
}
26+
27+
private func flushCache() {
28+
lock.lock()
29+
let events = cache
30+
cache.removeAll()
31+
lock.unlock()
32+
33+
events.forEach { listener?($0) }
34+
}
35+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Foundation
2+
import TalsecRuntime
3+
4+
class ThreatDispatcher {
5+
static let shared = ThreatDispatcher()
6+
private var threatCache: Set<SecurityThreat> = []
7+
private let lock = NSLock()
8+
9+
var listener: ((SecurityThreat) -> Void)? {
10+
didSet {
11+
if listener != nil {
12+
flushCache()
13+
}
14+
}
15+
}
16+
17+
func dispatch(threat: SecurityThreat) {
18+
lock.lock()
19+
defer { lock.unlock() }
20+
21+
if let listener = listener {
22+
listener(threat)
23+
} else {
24+
threatCache.insert(threat)
25+
}
26+
}
27+
28+
private func flushCache() {
29+
lock.lock()
30+
let threats = threatCache
31+
threatCache.removeAll()
32+
lock.unlock()
33+
34+
threats.forEach { listener?($0) }
35+
}
36+
}

0 commit comments

Comments
 (0)