11package com.freeraspreactnative
22
3+ import android.os.Handler
4+ import android.os.HandlerThread
5+ import android.os.Looper
36import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
47import com.aheaditec.talsec_security.security.api.Talsec
58import com.aheaditec.talsec_security.security.api.TalsecConfig
69import com.aheaditec.talsec_security.security.api.ThreatListener
710import com.facebook.react.bridge.Arguments
11+ import com.facebook.react.bridge.LifecycleEventListener
812import com.facebook.react.bridge.Promise
913import com.facebook.react.bridge.ReactApplicationContext
1014import com.facebook.react.bridge.ReactContextBaseJavaModule
@@ -13,6 +17,7 @@ import com.facebook.react.bridge.ReadableMap
1317import com.facebook.react.bridge.UiThreadUtil.runOnUiThread
1418import com.facebook.react.bridge.WritableArray
1519import com.facebook.react.modules.core.DeviceEventManagerModule
20+ import com.freeraspreactnative.utils.Utils
1621import com.freeraspreactnative.utils.getArraySafe
1722import com.freeraspreactnative.utils.getBooleanSafe
1823import com.freeraspreactnative.utils.getMapThrowing
@@ -24,13 +29,27 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
2429 ReactContextBaseJavaModule (reactContext) {
2530
2631 private val listener = ThreatListener (FreeraspThreatHandler , FreeraspThreatHandler )
32+ private val lifecycleListener = object : LifecycleEventListener {
33+ override fun onHostResume () {
34+ // do nothing
35+ }
36+
37+ override fun onHostPause () {
38+ // do nothing
39+ }
40+
41+ override fun onHostDestroy () {
42+ backgroundHandlerThread.quitSafely()
43+ }
44+ }
2745
2846 override fun getName (): String {
2947 return NAME
3048 }
3149
3250 init {
3351 appReactContext = reactContext
52+ reactContext.addLifecycleEventListener(lifecycleListener)
3453 }
3554
3655 @ReactMethod
@@ -103,6 +122,20 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
103122 promise.resolve(true )
104123 }
105124
125+ /* *
126+ * Method retrieves app icon for the given parameter
127+ * @param packageName package name of the app we want to retrieve icon for
128+ * @return PNG with app icon encoded as a base64 string
129+ */
130+ @ReactMethod
131+ fun getAppIcon (packageName : String , promise : Promise ) {
132+ // Perform the app icon encoding on a background thread
133+ backgroundHandler.post {
134+ val encodedData = Utils .getAppIconAsBase64String(reactContext, packageName)
135+ mainHandler.post { promise.resolve(encodedData) }
136+ }
137+ }
138+
106139 private fun buildTalsecConfig (config : ReadableMap ): TalsecConfig {
107140 val androidConfig = config.getMapThrowing(" androidConfig" )
108141 val packageName = androidConfig.getStringThrowing(" packageName" )
@@ -126,13 +159,19 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
126159
127160 companion object {
128161 const val NAME = " FreeraspReactNative"
129- val THREAT_CHANNEL_NAME = (10000 .. 999999999 ).random()
162+ private val THREAT_CHANNEL_NAME = (10000 .. 999999999 ).random()
130163 .toString() // name of the channel over which threat callbacks are sent
131- val THREAT_CHANNEL_KEY = (10000 .. 999999999 ).random()
164+ private val THREAT_CHANNEL_KEY = (10000 .. 999999999 ).random()
132165 .toString() // key of the argument map under which threats are expected
133- val MALWARE_CHANNEL_KEY = (10000 .. 999999999 ).random()
166+ private val MALWARE_CHANNEL_KEY = (10000 .. 999999999 ).random()
134167 .toString() // key of the argument map under which malware data is expected
168+
169+ private val backgroundHandlerThread = HandlerThread (" BackgroundThread" ).apply { start() }
170+ private val backgroundHandler = Handler (backgroundHandlerThread.looper)
171+ private val mainHandler = Handler (Looper .getMainLooper())
172+
135173 private lateinit var appReactContext: ReactApplicationContext
174+
136175 private fun notifyListeners (threat : Threat ) {
137176 val params = Arguments .createMap()
138177 params.putInt(THREAT_CHANNEL_KEY , threat.value)
@@ -145,15 +184,23 @@ class FreeraspReactNativeModule(private val reactContext: ReactApplicationContex
145184 * Sends malware detected event to React Native
146185 */
147186 private fun notifyMalware (suspiciousApps : MutableList <SuspiciousAppInfo >) {
148- val params = Arguments .createMap()
149- params.putInt(THREAT_CHANNEL_KEY , Threat .Malware .value)
150- params.putArray(
151- MALWARE_CHANNEL_KEY , suspiciousApps.toEncodedWritableArray(appReactContext)
152- )
153-
154- appReactContext
155- .getJSModule(DeviceEventManagerModule .RCTDeviceEventEmitter ::class .java)
156- .emit(THREAT_CHANNEL_NAME , params)
187+ // Perform the malware encoding on a background thread
188+ backgroundHandler.post {
189+
190+ val encodedSuspiciousApps = suspiciousApps.toEncodedWritableArray(appReactContext)
191+
192+ mainHandler.post {
193+ val params = Arguments .createMap()
194+ params.putInt(THREAT_CHANNEL_KEY , Threat .Malware .value)
195+ params.putArray(
196+ MALWARE_CHANNEL_KEY , encodedSuspiciousApps
197+ )
198+
199+ appReactContext
200+ .getJSModule(DeviceEventManagerModule .RCTDeviceEventEmitter ::class .java)
201+ .emit(THREAT_CHANNEL_NAME , params)
202+ }
203+ }
157204 }
158205 }
159206
0 commit comments