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.
Files changed (74) hide show
  1. package/CHANGELOG.md +49 -2
  2. package/android/build.gradle +4 -1
  3. package/android/src/main/java/com/freeraspreactnative/FreeraspReactNativeModule.kt +49 -4
  4. package/android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt +5 -1
  5. package/android/src/main/java/com/freeraspreactnative/Threat.kt +3 -1
  6. package/android/src/main/java/com/freeraspreactnative/models/RNSuspiciousAppInfo.kt +25 -0
  7. package/android/src/main/java/com/freeraspreactnative/utils/Extensions.kt +116 -0
  8. package/android/src/main/java/com/freeraspreactnative/utils/Utils.kt +82 -0
  9. package/example/assets/arrow-down.png +0 -0
  10. package/example/assets/arrow-up.png +0 -0
  11. package/example/ios/FreeraspReactNativeExample.xcodeproj/project.pbxproj +45 -45
  12. package/example/src/App.tsx +57 -2
  13. package/example/src/DemoApp.tsx +16 -2
  14. package/example/src/MalwareItem.tsx +158 -0
  15. package/example/src/MalwareModal.tsx +126 -0
  16. package/example/src/checks.ts +1 -0
  17. package/example/src/styles.ts +1 -0
  18. package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeDirectory +0 -0
  19. package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeRequirements +0 -0
  20. package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeRequirements-1 +0 -0
  21. package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeResources +60 -60
  22. package/ios/TalsecRuntime.xcframework/_CodeSignature/CodeSignature +0 -0
  23. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/CurlWrapper.h +1 -1
  24. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/TalsecRuntime-Swift.h +1 -1
  25. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/curl.h +7 -7
  26. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/multi.h +4 -4
  27. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/options.h +1 -1
  28. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Headers/urlapi.h +1 -1
  29. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Info.plist +0 -0
  30. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/Modules/TalsecRuntime.swiftmodule/arm64-apple-ios.abi.json +135 -135
  31. package/ios/TalsecRuntime.xcframework/ios-arm64/TalsecRuntime.framework/TalsecRuntime +0 -0
  32. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/CurlWrapper.h +1 -1
  33. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/TalsecRuntime-Swift.h +2 -2
  34. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/curl.h +7 -7
  35. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/multi.h +4 -4
  36. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/options.h +1 -1
  37. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Headers/urlapi.h +1 -1
  38. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Info.plist +0 -0
  39. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Modules/TalsecRuntime.swiftmodule/arm64-apple-ios-simulator.abi.json +135 -135
  40. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/Modules/TalsecRuntime.swiftmodule/x86_64-apple-ios-simulator.abi.json +135 -135
  41. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/TalsecRuntime +0 -0
  42. package/ios/TalsecRuntime.xcframework/ios-arm64_x86_64-simulator/TalsecRuntime.framework/_CodeSignature/CodeResources +21 -21
  43. package/lib/commonjs/index.js +63 -19
  44. package/lib/commonjs/index.js.map +1 -1
  45. package/lib/commonjs/{definitions.js → threat.js} +3 -2
  46. package/lib/commonjs/threat.js.map +1 -0
  47. package/lib/commonjs/types.js +2 -0
  48. package/lib/commonjs/types.js.map +1 -0
  49. package/lib/commonjs/utils.js +2 -2
  50. package/lib/commonjs/utils.js.map +1 -1
  51. package/lib/module/index.js +30 -5
  52. package/lib/module/index.js.map +1 -1
  53. package/lib/module/{definitions.js → threat.js} +3 -2
  54. package/lib/module/threat.js.map +1 -0
  55. package/lib/module/types.js +2 -0
  56. package/lib/module/types.js.map +1 -0
  57. package/lib/module/utils.js +1 -1
  58. package/lib/module/utils.js.map +1 -1
  59. package/lib/typescript/src/index.d.ts +3 -1
  60. package/lib/typescript/src/index.d.ts.map +1 -1
  61. package/lib/typescript/src/threat.d.ts +20 -0
  62. package/lib/typescript/src/threat.d.ts.map +1 -0
  63. package/lib/typescript/src/types.d.ts +50 -0
  64. package/lib/typescript/src/types.d.ts.map +1 -0
  65. package/package.json +3 -24
  66. package/src/index.tsx +35 -8
  67. package/src/{definitions.ts → threat.ts} +2 -30
  68. package/src/types.ts +55 -0
  69. package/src/utils.ts +1 -1
  70. package/android/src/main/java/com/freeraspreactnative/Utils.kt +0 -40
  71. package/lib/commonjs/definitions.js.map +0 -1
  72. package/lib/module/definitions.js.map +0 -1
  73. package/lib/typescript/src/definitions.d.ts +0 -47
  74. 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
 
@@ -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 "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:11.1.3"
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
- class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) :
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(p0: MutableList<SuspiciousAppInfo>?) {}
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