Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make malware async #25

Merged
merged 6 commits into from
Dec 16, 2024
Merged
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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,24 @@ 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).

## [1.8.0] - 2024-12-06

- iOS SDK version: 6.6.3
- Android SDK version: 13.0.0

### Capacitor

#### Changed

- App icons for detected malware are not fetched automatically anymore, which reduces computation required to retrieve malware data. From now on, app icons have to be retrieved using the `getAppIcon` method
- Parsing of malware data is now async

### Android

#### Changed

- Malware data is now parsed on background thread to improve responsiveness

## [1.7.0] - 2024-11-19

### Capacitor
Expand Down
55 changes: 51 additions & 4 deletions android/src/main/java/com/aheaditec/freerasp/FreeraspPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.aheaditec.freerasp

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import com.aheaditec.freerasp.utils.Utils
import com.aheaditec.freerasp.utils.getArraySafe
import com.aheaditec.freerasp.utils.getNestedArraySafe
import com.aheaditec.freerasp.utils.toEncodedJSArray
Expand Down Expand Up @@ -37,7 +41,11 @@ class FreeraspPlugin : Plugin() {
}
call.resolve(JSObject().put("started", true))
} catch (e: Exception) {
call.reject("Error during Talsec Native plugin initialization - ${e.message}", "TalsecInitializationError", e)
call.reject(
"Error during Talsec Native plugin initialization - ${e.message}",
"TalsecInitializationError",
e
)
}
}

Expand All @@ -57,6 +65,11 @@ class FreeraspPlugin : Plugin() {
}
}

override fun handleOnDestroy() {
super.handleOnDestroy()
backgroundHandlerThread.quitSafely()
}

/**
* Method to get the random identifiers of callbacks
*/
Expand Down Expand Up @@ -107,13 +120,44 @@ class FreeraspPlugin : Plugin() {
call.resolve(JSObject().put("result", true))
}

/**
* Method retrieves app icon for the given parameter
* @param packageName package name of the app we want to retrieve icon for
* @return PNG with app icon encoded as a base64 string
*/
@PluginMethod
fun getAppIcon(call: PluginCall) {
val packageName = call.getString("packageName")
if (packageName.isNullOrEmpty()) {
call.reject(
"Package name argument is missing or empty in the call",
"MissingArgumentError"
)
return
}
// Perform the app icon encoding on a background thread
backgroundHandler.post {
val encodedData = Utils.getAppIconAsBase64String(context, packageName)
mainHandler.post { call.resolve(JSObject().put("result", encodedData)) }
}
}

internal fun notifyListeners(threat: Threat) {
notifyListeners(THREAT_CHANNEL_NAME, JSObject().put(THREAT_CHANNEL_KEY, threat.value), true)
}

internal fun notifyMalware(suspiciousApps: MutableList<SuspiciousAppInfo>) {
notifyListeners(THREAT_CHANNEL_NAME, JSObject().put(THREAT_CHANNEL_KEY, Threat.Malware.value).put(
MALWARE_CHANNEL_KEY, suspiciousApps.toEncodedJSArray(context)), true)
// Perform the malware encoding on a background thread
backgroundHandler.post {

val encodedSuspiciousApps = suspiciousApps.toEncodedJSArray(context)
mainHandler.post {
val params = JSObject()
.put(THREAT_CHANNEL_KEY, Threat.Malware.value)
.put(MALWARE_CHANNEL_KEY, encodedSuspiciousApps)
notifyListeners(THREAT_CHANNEL_NAME, params, true)
}
}
}

private fun buildTalsecConfigThrowing(configJson: JSObject): TalsecConfig {
Expand All @@ -140,7 +184,10 @@ class FreeraspPlugin : Plugin() {
.toString() // name of the channel over which threat callbacks are sent
private val THREAT_CHANNEL_KEY = (10000..999999999).random()
.toString() // key of the argument map under which threats are expected
val MALWARE_CHANNEL_KEY = (10000..999999999).random()
private val MALWARE_CHANNEL_KEY = (10000..999999999).random()
.toString() // key of the argument map under which malware data is expected
private val backgroundHandlerThread = HandlerThread("BackgroundThread").apply { start() }
private val backgroundHandler = Handler(backgroundHandlerThread.looper)
private val mainHandler = Handler(Looper.getMainLooper())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ internal fun PackageInfo.toCapPackageInfo(context: Context): CapPackageInfo {
packageName = this.packageName,
appName = Utils.getAppName(context, this.applicationInfo),
version = this.versionName,
appIcon = Utils.getAppIconAsBase64String(context, this.packageName),
appIcon = null, // this requires heavier computations, so appIcon has to be retrieved separately
installerStore = Utils.getInstallationSource(context, this.packageName)
)
}
Expand Down
5 changes: 4 additions & 1 deletion android/src/main/java/com/aheaditec/freerasp/utils/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ internal object Utils {
context.packageManager.getInstallerPackageName(packageName)
}
} catch (e: Exception) {
Log.e("Talsec", "Could not retrieve app installation source for ${packageName}: ${e.message}")
Log.e(
"Talsec",
"Could not retrieve app installation source for ${packageName}: ${e.message}"
)
null
}
}
Expand Down
5 changes: 5 additions & 0 deletions dist/esm/definitions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ export interface FreeraspPlugin {
}): Promise<{
result: boolean;
}>;
getAppIcon(options: {
packageName: string;
}): Promise<{
result: string;
}>;
}
export type FreeraspConfig = {
androidConfig?: AndroidConfig;
Expand Down
2 changes: 1 addition & 1 deletion dist/esm/definitions.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion dist/esm/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ declare const setThreatListeners: <T extends NativeEventEmitterActions>(callback
declare const removeThreatListeners: () => void;
declare const startFreeRASP: <T extends NativeEventEmitterActions>(config: FreeraspConfig, reactions: T & Record<Exclude<keyof T, keyof NativeEventEmitterActions>, []>) => Promise<boolean>;
declare const addToWhitelist: (packageName: string) => Promise<boolean>;
declare const getAppIcon: (packageName: string) => Promise<string>;
export * from './definitions';
export { Freerasp, startFreeRASP, setThreatListeners, removeThreatListeners, addToWhitelist, };
export { Freerasp, startFreeRASP, setThreatListeners, removeThreatListeners, addToWhitelist, getAppIcon, };
25 changes: 20 additions & 5 deletions dist/esm/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading