freerasp-react-native 3.9.2 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -2
- package/android/build.gradle +4 -1
- package/android/src/main/java/com/freeraspreactnative/FreeraspReactNativeModule.kt +49 -4
- package/android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt +5 -1
- package/android/src/main/java/com/freeraspreactnative/Threat.kt +3 -1
- package/android/src/main/java/com/freeraspreactnative/models/RNSuspiciousAppInfo.kt +25 -0
- package/android/src/main/java/com/freeraspreactnative/utils/Extensions.kt +116 -0
- package/android/src/main/java/com/freeraspreactnative/utils/Utils.kt +82 -0
- package/example/assets/arrow-down.png +0 -0
- package/example/assets/arrow-up.png +0 -0
- package/example/ios/FreeraspReactNativeExample.xcodeproj/project.pbxproj +45 -45
- package/example/src/App.tsx +57 -2
- package/example/src/DemoApp.tsx +16 -2
- package/example/src/MalwareItem.tsx +158 -0
- package/example/src/MalwareModal.tsx +126 -0
- package/example/src/checks.ts +1 -0
- package/example/src/styles.ts +1 -0
- package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeDirectory +0 -0
- package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeRequirements +0 -0
- package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeRequirements-1 +0 -0
- package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeResources +60 -60
- package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeSignature +0 -0
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/CurlWrapper.h +1 -1
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/TalsecRuntime-Swift.h +1 -1
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/curl.h +7 -7
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/multi.h +4 -4
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/options.h +1 -1
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/urlapi.h +1 -1
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Info.plist +0 -0
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Modules/TalsecRuntime.swiftmodule/arm64-apple-ios.abi.json +135 -135
- package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/TalsecRuntime +0 -0
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/CurlWrapper.h +1 -1
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/TalsecRuntime-Swift.h +2 -2
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/curl.h +7 -7
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/multi.h +4 -4
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/options.h +1 -1
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/urlapi.h +1 -1
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Info.plist +0 -0
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Modules/TalsecRuntime.swiftmodule/arm64-apple-ios-simulator.abi.json +135 -135
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Modules/TalsecRuntime.swiftmodule/x86_64-apple-ios-simulator.abi.json +135 -135
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/TalsecRuntime +0 -0
- package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/_CodeSignature/CodeResources +21 -21
- package/lib/commonjs/index.js +63 -19
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/{definitions.js → threat.js} +3 -2
- package/lib/commonjs/threat.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/utils.js +2 -2
- package/lib/commonjs/utils.js.map +1 -1
- package/lib/module/index.js +30 -5
- package/lib/module/index.js.map +1 -1
- package/lib/module/{definitions.js → threat.js} +3 -2
- package/lib/module/threat.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils.js +1 -1
- package/lib/module/utils.js.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/threat.d.ts +20 -0
- package/lib/typescript/src/threat.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +50 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +3 -24
- package/src/index.tsx +35 -8
- package/src/{definitions.ts → threat.ts} +2 -30
- package/src/types.ts +55 -0
- package/src/utils.ts +1 -1
- package/android/src/main/java/com/freeraspreactnative/Utils.kt +0 -40
- package/lib/commonjs/definitions.js.map +0 -1
- package/lib/module/definitions.js.map +0 -1
- package/lib/typescript/src/definitions.d.ts +0 -47
- package/lib/typescript/src/definitions.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,54 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.10.0] - 2024-11-15
|
|
9
|
+
|
|
10
|
+
- Android SDK version: 12.0.0
|
|
11
|
+
- iOS SDK version: 6.6.3
|
|
12
|
+
|
|
13
|
+
### React Native
|
|
14
|
+
|
|
15
|
+
#### Added
|
|
16
|
+
|
|
17
|
+
- Added configuration fields for malware detection
|
|
18
|
+
|
|
19
|
+
### Android
|
|
20
|
+
|
|
21
|
+
#### Added
|
|
22
|
+
|
|
23
|
+
- New feature: **malware detection** as a new callback for enhanced app security
|
|
24
|
+
|
|
25
|
+
#### Fixed
|
|
26
|
+
|
|
27
|
+
- Refactoring Magisk checks in the root detection
|
|
28
|
+
|
|
29
|
+
### iOS
|
|
30
|
+
|
|
31
|
+
#### Added
|
|
32
|
+
|
|
33
|
+
- Enhanced security with **[Serotonin Jailbreak](https://github.com/SerotoninApp/Serotonin) Detection** to identify compromised devices.
|
|
34
|
+
|
|
35
|
+
#### Changed
|
|
36
|
+
|
|
37
|
+
- Updated SDK code signing; it will now be signed with:
|
|
38
|
+
- Team ID: PBDDS45LQS
|
|
39
|
+
- Team Name: Lynx SFT s.r.o.
|
|
40
|
+
|
|
41
|
+
## [3.9.3] - 2024-10-28
|
|
42
|
+
- Android SDK version: 11.1.3
|
|
43
|
+
- iOS SDK version: 6.6.1
|
|
44
|
+
|
|
45
|
+
### iOS
|
|
46
|
+
|
|
47
|
+
#### Changed
|
|
48
|
+
- Renewed the signing certificate
|
|
49
|
+
|
|
8
50
|
## [3.9.2] - 2024-10-18
|
|
51
|
+
- Android SDK version: 11.1.3
|
|
52
|
+
- iOS SDK version: 6.6.0
|
|
53
|
+
|
|
54
|
+
- Android SDK version: 11.1.3
|
|
55
|
+
- iOS SDK version: 6.6.0
|
|
9
56
|
|
|
10
57
|
### Android
|
|
11
58
|
|
|
@@ -40,7 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
40
87
|
|
|
41
88
|
### Android
|
|
42
89
|
|
|
43
|
-
#### Added
|
|
90
|
+
#### Added
|
|
44
91
|
|
|
45
92
|
- Added the auditing of the internal execution for the future check optimization and overall security improvements.
|
|
46
93
|
|
|
@@ -58,7 +105,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
58
105
|
|
|
59
106
|
### iOS
|
|
60
107
|
|
|
61
|
-
#### Added
|
|
108
|
+
#### Added
|
|
62
109
|
|
|
63
110
|
- [Dopamine](https://github.com/opa334/Dopamine) jailbreak detection.
|
|
64
111
|
|
package/android/build.gradle
CHANGED
|
@@ -11,6 +11,7 @@ buildscript {
|
|
|
11
11
|
classpath "com.android.tools.build:gradle:7.2.1"
|
|
12
12
|
// noinspection DifferentKotlinGradleVersion
|
|
13
13
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
14
|
+
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
|
14
15
|
}
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -20,6 +21,7 @@ def isNewArchitectureEnabled() {
|
|
|
20
21
|
|
|
21
22
|
apply plugin: "com.android.library"
|
|
22
23
|
apply plugin: "kotlin-android"
|
|
24
|
+
apply plugin: 'kotlinx-serialization'
|
|
23
25
|
|
|
24
26
|
if (isNewArchitectureEnabled()) {
|
|
25
27
|
apply plugin: "com.facebook.react"
|
|
@@ -87,7 +89,8 @@ dependencies {
|
|
|
87
89
|
//noinspection GradleDynamicVersion
|
|
88
90
|
implementation "com.facebook.react:react-native:$react_native_version"
|
|
89
91
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
90
|
-
implementation "
|
|
92
|
+
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
|
|
93
|
+
implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:12.0.0"
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
if (isNewArchitectureEnabled()) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.freeraspreactnative
|
|
2
2
|
|
|
3
|
+
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
|
|
3
4
|
import com.aheaditec.talsec_security.security.api.Talsec
|
|
4
5
|
import com.aheaditec.talsec_security.security.api.TalsecConfig
|
|
5
6
|
import com.aheaditec.talsec_security.security.api.ThreatListener
|
|
@@ -12,8 +13,14 @@ import com.facebook.react.bridge.ReadableMap
|
|
|
12
13
|
import com.facebook.react.bridge.UiThreadUtil.runOnUiThread
|
|
13
14
|
import com.facebook.react.bridge.WritableArray
|
|
14
15
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
import com.freeraspreactnative.utils.getArraySafe
|
|
17
|
+
import com.freeraspreactnative.utils.getBooleanSafe
|
|
18
|
+
import com.freeraspreactnative.utils.getMapThrowing
|
|
19
|
+
import com.freeraspreactnative.utils.getNestedArraySafe
|
|
20
|
+
import com.freeraspreactnative.utils.getStringThrowing
|
|
21
|
+
import com.freeraspreactnative.utils.toEncodedWritableArray
|
|
22
|
+
|
|
23
|
+
class FreeraspReactNativeModule(private val reactContext: ReactApplicationContext) :
|
|
17
24
|
ReactContextBaseJavaModule(reactContext) {
|
|
18
25
|
|
|
19
26
|
private val listener = ThreatListener(FreeraspThreatHandler, FreeraspThreatHandler)
|
|
@@ -42,8 +49,7 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) :
|
|
|
42
49
|
|
|
43
50
|
promise.resolve("freeRASP started")
|
|
44
51
|
|
|
45
|
-
}
|
|
46
|
-
catch (e: Exception) {
|
|
52
|
+
} catch (e: Exception) {
|
|
47
53
|
promise.reject("TalsecInitializationError", e.message, e)
|
|
48
54
|
}
|
|
49
55
|
}
|
|
@@ -65,6 +71,7 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) :
|
|
|
65
71
|
val channelData: WritableArray = Arguments.createArray()
|
|
66
72
|
channelData.pushString(THREAT_CHANNEL_NAME)
|
|
67
73
|
channelData.pushString(THREAT_CHANNEL_KEY)
|
|
74
|
+
channelData.pushString(MALWARE_CHANNEL_KEY)
|
|
68
75
|
promise.resolve(channelData)
|
|
69
76
|
}
|
|
70
77
|
|
|
@@ -87,6 +94,15 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) :
|
|
|
87
94
|
// Remove upstream listeners, stop unnecessary background tasks
|
|
88
95
|
}
|
|
89
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Method to add apps to Malware whitelist, so they don't get flagged as malware
|
|
99
|
+
*/
|
|
100
|
+
@ReactMethod
|
|
101
|
+
fun addToWhitelist(packageName: String, promise: Promise) {
|
|
102
|
+
Talsec.addToWhitelist(reactContext, packageName)
|
|
103
|
+
promise.resolve(true)
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
private fun buildTalsecConfig(config: ReadableMap): TalsecConfig {
|
|
91
107
|
val androidConfig = config.getMapThrowing("androidConfig")
|
|
92
108
|
val packageName = androidConfig.getStringThrowing("packageName")
|
|
@@ -97,6 +113,14 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) :
|
|
|
97
113
|
.supportedAlternativeStores(androidConfig.getArraySafe("supportedAlternativeStores"))
|
|
98
114
|
.prod(config.getBooleanSafe("isProd"))
|
|
99
115
|
|
|
116
|
+
if (androidConfig.hasKey("malwareConfig")) {
|
|
117
|
+
val malwareConfig = androidConfig.getMapThrowing("malwareConfig")
|
|
118
|
+
talsecBuilder.whitelistedInstallationSources(malwareConfig.getArraySafe("whitelistedInstallationSources"))
|
|
119
|
+
talsecBuilder.blacklistedHashes(malwareConfig.getArraySafe("blacklistedHashes"))
|
|
120
|
+
talsecBuilder.blacklistedPackageNames(malwareConfig.getArraySafe("blacklistedPackageNames"))
|
|
121
|
+
talsecBuilder.suspiciousPermissions(malwareConfig.getNestedArraySafe("suspiciousPermissions"))
|
|
122
|
+
}
|
|
123
|
+
|
|
100
124
|
return talsecBuilder.build()
|
|
101
125
|
}
|
|
102
126
|
|
|
@@ -106,6 +130,8 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) :
|
|
|
106
130
|
.toString() // name of the channel over which threat callbacks are sent
|
|
107
131
|
val THREAT_CHANNEL_KEY = (10000..999999999).random()
|
|
108
132
|
.toString() // key of the argument map under which threats are expected
|
|
133
|
+
val MALWARE_CHANNEL_KEY = (10000..999999999).random()
|
|
134
|
+
.toString() // key of the argument map under which malware data is expected
|
|
109
135
|
private lateinit var appReactContext: ReactApplicationContext
|
|
110
136
|
private fun notifyListeners(threat: Threat) {
|
|
111
137
|
val params = Arguments.createMap()
|
|
@@ -114,11 +140,30 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) :
|
|
|
114
140
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
115
141
|
.emit(THREAT_CHANNEL_NAME, params)
|
|
116
142
|
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Sends malware detected event to React Native
|
|
146
|
+
*/
|
|
147
|
+
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)
|
|
157
|
+
}
|
|
117
158
|
}
|
|
118
159
|
|
|
119
160
|
internal object ThreatListener : FreeraspThreatHandler.TalsecReactNative {
|
|
120
161
|
override fun threatDetected(threatType: Threat) {
|
|
121
162
|
notifyListeners(threatType)
|
|
122
163
|
}
|
|
164
|
+
|
|
165
|
+
override fun malwareDetected(suspiciousApps: MutableList<SuspiciousAppInfo>) {
|
|
166
|
+
notifyMalware(suspiciousApps)
|
|
167
|
+
}
|
|
123
168
|
}
|
|
124
169
|
}
|
|
@@ -39,7 +39,9 @@ internal object FreeraspThreatHandler : ThreatListener.ThreatDetected, ThreatLis
|
|
|
39
39
|
listener?.threatDetected(Threat.ObfuscationIssues)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
override fun onMalwareDetected(
|
|
42
|
+
override fun onMalwareDetected(suspiciousAppInfos: MutableList<SuspiciousAppInfo>?) {
|
|
43
|
+
listener?.malwareDetected(suspiciousAppInfos ?: mutableListOf())
|
|
44
|
+
}
|
|
43
45
|
|
|
44
46
|
override fun onUnlockedDeviceDetected() {
|
|
45
47
|
listener?.threatDetected(Threat.Passcode)
|
|
@@ -59,5 +61,7 @@ internal object FreeraspThreatHandler : ThreatListener.ThreatDetected, ThreatLis
|
|
|
59
61
|
|
|
60
62
|
internal interface TalsecReactNative {
|
|
61
63
|
fun threatDetected(threatType: Threat)
|
|
64
|
+
|
|
65
|
+
fun malwareDetected(suspiciousApps: MutableList<SuspiciousAppInfo>)
|
|
62
66
|
}
|
|
63
67
|
}
|
|
@@ -23,6 +23,7 @@ internal sealed class Threat(val value: Int) {
|
|
|
23
23
|
object ObfuscationIssues : Threat((10000..999999999).random())
|
|
24
24
|
object SystemVPN : Threat((10000..999999999).random())
|
|
25
25
|
object DevMode : Threat((10000..999999999).random())
|
|
26
|
+
object Malware : Threat((10000..999999999).random())
|
|
26
27
|
|
|
27
28
|
companion object {
|
|
28
29
|
internal fun getThreatValues(): WritableArray {
|
|
@@ -39,7 +40,8 @@ internal sealed class Threat(val value: Int) {
|
|
|
39
40
|
DeviceBinding.value,
|
|
40
41
|
UnofficialStore.value,
|
|
41
42
|
ObfuscationIssues.value,
|
|
42
|
-
DevMode.value
|
|
43
|
+
DevMode.value,
|
|
44
|
+
Malware.value
|
|
43
45
|
)
|
|
44
46
|
)
|
|
45
47
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
package com.freeraspreactnative.models
|
|
2
|
+
|
|
3
|
+
import kotlinx.serialization.Serializable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Simplified, serializable wrapper for Talsec's SuspiciousAppInfo
|
|
8
|
+
*/
|
|
9
|
+
@Serializable
|
|
10
|
+
data class RNSuspiciousAppInfo(
|
|
11
|
+
val packageInfo: RNPackageInfo,
|
|
12
|
+
val reason: String,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Simplified, serializable wrapper for Android's PackageInfo
|
|
17
|
+
*/
|
|
18
|
+
@Serializable
|
|
19
|
+
data class RNPackageInfo(
|
|
20
|
+
val packageName: String,
|
|
21
|
+
val appName: String?,
|
|
22
|
+
val version: String?,
|
|
23
|
+
val appIcon: String?,
|
|
24
|
+
val installerStore: String?
|
|
25
|
+
)
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
package com.freeraspreactnative.utils
|
|
2
|
+
|
|
3
|
+
import android.content.pm.PackageInfo
|
|
4
|
+
import android.util.Base64
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
|
|
7
|
+
import com.facebook.react.bridge.Arguments
|
|
8
|
+
import com.facebook.react.bridge.ReactContext
|
|
9
|
+
import com.facebook.react.bridge.ReadableArray
|
|
10
|
+
import com.facebook.react.bridge.ReadableMap
|
|
11
|
+
import com.facebook.react.bridge.WritableArray
|
|
12
|
+
import com.freeraspreactnative.exceptions.TalsecException
|
|
13
|
+
import com.freeraspreactnative.models.RNPackageInfo
|
|
14
|
+
import com.freeraspreactnative.models.RNSuspiciousAppInfo
|
|
15
|
+
import kotlinx.serialization.encodeToString
|
|
16
|
+
import kotlinx.serialization.json.Json
|
|
17
|
+
import org.json.JSONException
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
internal fun ReadableMap.getMapThrowing(key: String): ReadableMap {
|
|
21
|
+
return this.getMap(key) ?: throw TalsecException("Key missing in configuration: $key")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
internal fun ReadableMap.getStringThrowing(key: String): String {
|
|
25
|
+
return this.getString(key) ?: throw TalsecException("Key missing in configuration: $key")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
internal fun ReadableMap.getBooleanSafe(key: String, defaultValue: Boolean = true): Boolean {
|
|
29
|
+
if (this.hasKey(key)) {
|
|
30
|
+
return this.getBoolean(key)
|
|
31
|
+
}
|
|
32
|
+
return defaultValue
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private inline fun <reified T> ReadableArray.toPrimitiveArray(): Array<T> {
|
|
36
|
+
val output = mutableListOf<T>()
|
|
37
|
+
|
|
38
|
+
for (i in 0 until this.size()) {
|
|
39
|
+
val element: T? = when (T::class) {
|
|
40
|
+
String::class -> this.getString(i) as T?
|
|
41
|
+
Int::class -> this.getInt(i) as T?
|
|
42
|
+
Double::class -> this.getDouble(i) as T?
|
|
43
|
+
Boolean::class -> this.getBoolean(i) as T?
|
|
44
|
+
else -> throw JSONException("Cannot parse JSON array - unsupported type")
|
|
45
|
+
}
|
|
46
|
+
element?.let(output::add)
|
|
47
|
+
}
|
|
48
|
+
return output.toTypedArray()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
internal fun ReadableMap.getArraySafe(key: String): Array<String> {
|
|
52
|
+
if (this.hasKey(key)) {
|
|
53
|
+
val inputArray = this.getArray(key)!!
|
|
54
|
+
return inputArray.toPrimitiveArray()
|
|
55
|
+
}
|
|
56
|
+
return arrayOf()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
internal fun ReadableMap.getNestedArraySafe(key: String): Array<Array<String>> {
|
|
60
|
+
val outArray = mutableListOf<Array<String>>()
|
|
61
|
+
if (this.hasKey(key)) {
|
|
62
|
+
val inputArray = this.getArray(key)!!
|
|
63
|
+
for (i in 0 until inputArray.size()) {
|
|
64
|
+
outArray.add(inputArray.getArray(i).toPrimitiveArray())
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return outArray.toTypedArray()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Converts the Talsec's SuspiciousAppInfo to React Native equivalent
|
|
73
|
+
*/
|
|
74
|
+
internal fun SuspiciousAppInfo.toRNSuspiciousAppInfo(context: ReactContext): RNSuspiciousAppInfo {
|
|
75
|
+
return RNSuspiciousAppInfo(
|
|
76
|
+
packageInfo = this.packageInfo.toRNPackageInfo(context),
|
|
77
|
+
reason = this.reason,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Converts the Android's PackageInfo to React Native equivalent
|
|
83
|
+
*/
|
|
84
|
+
internal fun PackageInfo.toRNPackageInfo(context: ReactContext): RNPackageInfo {
|
|
85
|
+
return RNPackageInfo(
|
|
86
|
+
packageName = this.packageName,
|
|
87
|
+
appName = Utils.getAppName(context, this.applicationInfo),
|
|
88
|
+
version = this.versionName,
|
|
89
|
+
appIcon = Utils.getAppIconAsBase64String(context, this.packageName),
|
|
90
|
+
installerStore = Utils.getInstallationSource(context, this.packageName)
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Convert the Talsec's SuspiciousAppInfo to base64-encoded json array,
|
|
96
|
+
* which can be then sent to React Native
|
|
97
|
+
*/
|
|
98
|
+
internal fun MutableList<SuspiciousAppInfo>.toEncodedWritableArray(context: ReactContext): WritableArray {
|
|
99
|
+
val output = Arguments.createArray()
|
|
100
|
+
this.forEach { suspiciousAppInfo ->
|
|
101
|
+
val rnSuspiciousAppInfo = suspiciousAppInfo.toRNSuspiciousAppInfo(context)
|
|
102
|
+
try {
|
|
103
|
+
val encodedAppInfo =
|
|
104
|
+
Base64.encodeToString(
|
|
105
|
+
Json.encodeToString(rnSuspiciousAppInfo).toByteArray(),
|
|
106
|
+
Base64.DEFAULT
|
|
107
|
+
)
|
|
108
|
+
output.pushString(encodedAppInfo)
|
|
109
|
+
} catch (e: Exception) {
|
|
110
|
+
Log.e("Talsec", "Could not serialize suspicious app data: ${e.message}")
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
return output
|
|
115
|
+
}
|
|
116
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
package com.freeraspreactnative.utils
|
|
2
|
+
|
|
3
|
+
import android.content.pm.ApplicationInfo
|
|
4
|
+
import android.graphics.Bitmap
|
|
5
|
+
import android.graphics.Canvas
|
|
6
|
+
import android.graphics.drawable.BitmapDrawable
|
|
7
|
+
import android.os.Build
|
|
8
|
+
import android.util.Base64
|
|
9
|
+
import android.util.Log
|
|
10
|
+
import com.facebook.react.bridge.ReactContext
|
|
11
|
+
import java.io.ByteArrayOutputStream
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
internal object Utils {
|
|
15
|
+
|
|
16
|
+
private fun compressBitmap(bitmap: Bitmap): String {
|
|
17
|
+
val byteArrayOutputStream = ByteArrayOutputStream()
|
|
18
|
+
bitmap.compress(Bitmap.CompressFormat.PNG, 10, byteArrayOutputStream)
|
|
19
|
+
val byteArray = byteArrayOutputStream.toByteArray()
|
|
20
|
+
return Base64.encodeToString(byteArray, Base64.NO_WRAP)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves human-readable application name
|
|
25
|
+
*/
|
|
26
|
+
internal fun getAppName(context: ReactContext, applicationInfo: ApplicationInfo?): String? {
|
|
27
|
+
return applicationInfo?.let { context.packageManager.getApplicationLabel(it) as String }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Retrieves app icon for the given package name as Drawable, transforms it to Bitmap,
|
|
32
|
+
* compresses to PNG and finally encodes the data to Base64
|
|
33
|
+
* @param context React Native context
|
|
34
|
+
* @param packageName package name for which icon should be retrieved
|
|
35
|
+
* @return Base-64 encoded string
|
|
36
|
+
*/
|
|
37
|
+
internal fun getAppIconAsBase64String(context: ReactContext, packageName: String): String? {
|
|
38
|
+
try {
|
|
39
|
+
val drawable = context.packageManager.getApplicationIcon(packageName)
|
|
40
|
+
|
|
41
|
+
if (drawable is BitmapDrawable && drawable.bitmap != null) {
|
|
42
|
+
return compressBitmap(drawable.bitmap)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (drawable.intrinsicWidth > 0 && drawable.intrinsicHeight > 0) {
|
|
46
|
+
val bitmap = Bitmap.createBitmap(
|
|
47
|
+
drawable.intrinsicWidth,
|
|
48
|
+
drawable.intrinsicHeight,
|
|
49
|
+
Bitmap.Config.ARGB_8888
|
|
50
|
+
)
|
|
51
|
+
val canvas = Canvas(bitmap)
|
|
52
|
+
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
|
53
|
+
drawable.draw(canvas)
|
|
54
|
+
return compressBitmap(bitmap)
|
|
55
|
+
}
|
|
56
|
+
return null
|
|
57
|
+
} catch (e: Exception) {
|
|
58
|
+
Log.e("Talsec", "Could not retrieve app icon for ${packageName}: ${e.message}")
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Retrieves installation source for the given package name
|
|
65
|
+
* @param context React Native context
|
|
66
|
+
* @param packageName package name for which installation source should be retrieved
|
|
67
|
+
* @return Installation source package name
|
|
68
|
+
*/
|
|
69
|
+
@Suppress("DEPRECATION")
|
|
70
|
+
internal fun getInstallationSource(context: ReactContext, packageName: String): String? {
|
|
71
|
+
return try {
|
|
72
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
73
|
+
context.packageManager.getInstallSourceInfo(packageName).installingPackageName
|
|
74
|
+
} else {
|
|
75
|
+
context.packageManager.getInstallerPackageName(packageName)
|
|
76
|
+
}
|
|
77
|
+
} catch (e: Exception) {
|
|
78
|
+
Log.e("Talsec", "Could not retrieve app installation source for ${packageName}: ${e.message}")
|
|
79
|
+
null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
Binary file
|
|
Binary file
|