diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..88edb62 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +node_modules/ +lib/ diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..0ac178d --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "root": true, + "extends": [ + "@react-native-community", + "prettier" + ], + "rules": { + "prettier/prettier": [ + "error", + { + "quoteProps": "consistent", + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false + } + ], + "no-alert": "off" + } +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5791d03..06e5e40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: uses: ./.github/actions/setup - name: Lint files - run: yarn lint + run: yarn lint --max-warnings=0 - name: Typecheck files run: | @@ -28,6 +28,9 @@ jobs: run: | yarn expo:typecheck + - name: Format check + run: yarn prettier --check + # no tests yet 😥 # test: # runs-on: ubuntu-latest @@ -91,29 +94,31 @@ jobs: run: | yarn build:android - build-ios: - runs-on: macos-14 - needs: build-library - steps: - - name: Checkout - uses: actions/checkout@v4 +# !! Currently build iOS is not working due to issues with XCode version + # build-ios: + # runs-on: macos-14 + # needs: build-library - - name: Setup Xcode version - uses: maxim-lobanov/setup-xcode@v1.6.0 - with: - xcode-version: '14.3.1' + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + + # - name: Setup Xcode version + # uses: maxim-lobanov/setup-xcode@v1.6.0 + # with: + # xcode-version: '15.4.0' - - name: Setup - uses: ./.github/actions/setup + # - name: Setup + # uses: ./.github/actions/setup - - name: Install cocoapods - run: | - cd example/ios - pod install + # - name: Install cocoapods + # run: | + # cd example/ios + # pod install - - name: Build example for iOS - working-directory: ./example - run: | - yarn build:ios + # - name: Build example for iOS + # working-directory: ./example + # run: | + # yarn build:ios diff --git a/.prettierignore b/.prettierignore index 19fa875..f3ba24c 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ -plugin/build \ No newline at end of file +plugin/build +lib/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b73a5c4..3468e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,39 @@ 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). +## [3.10.0] - 2024-11-15 + +- Android SDK version: 12.0.0 +- iOS SDK version: 6.6.3 + +### React Native + +#### Added + +- Added configuration fields for malware detection + +### Android + +#### Added + +- New feature: **malware detection** as a new callback for enhanced app security + +#### Fixed + +- Refactoring Magisk checks in the root detection + +### iOS + +#### Added + +- Enhanced security with **[Serotonin Jailbreak](https://github.com/SerotoninApp/Serotonin) Detection** to identify compromised devices. + +#### Changed + +- Updated SDK code signing; it will now be signed with: + - Team ID: PBDDS45LQS + - Team Name: Lynx SFT s.r.o. + ## [3.9.3] - 2024-10-28 - Android SDK version: 11.1.3 - iOS SDK version: 6.6.1 @@ -18,6 +51,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Android SDK version: 11.1.3 - iOS SDK version: 6.6.0 +- Android SDK version: 11.1.3 +- iOS SDK version: 6.6.0 + ### Android #### Fixed @@ -51,7 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Android -#### Added +#### Added - Added the auditing of the internal execution for the future check optimization and overall security improvements. @@ -69,7 +105,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### iOS -#### Added +#### Added - [Dopamine](https://github.com/opa334/Dopamine) jailbreak detection. diff --git a/android/build.gradle b/android/build.gradle index 3a6febe..15ad19e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -11,6 +11,7 @@ buildscript { classpath "com.android.tools.build:gradle:7.2.1" // noinspection DifferentKotlinGradleVersion classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" } } @@ -20,6 +21,7 @@ def isNewArchitectureEnabled() { apply plugin: "com.android.library" apply plugin: "kotlin-android" +apply plugin: 'kotlinx-serialization' if (isNewArchitectureEnabled()) { apply plugin: "com.facebook.react" @@ -87,7 +89,8 @@ dependencies { //noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:$react_native_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:11.1.3" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1" + implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-ReactNative:12.0.0" } if (isNewArchitectureEnabled()) { diff --git a/android/src/main/java/com/freeraspreactnative/FreeraspReactNativeModule.kt b/android/src/main/java/com/freeraspreactnative/FreeraspReactNativeModule.kt index f75ed07..e55b205 100644 --- a/android/src/main/java/com/freeraspreactnative/FreeraspReactNativeModule.kt +++ b/android/src/main/java/com/freeraspreactnative/FreeraspReactNativeModule.kt @@ -1,5 +1,6 @@ package com.freeraspreactnative +import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo import com.aheaditec.talsec_security.security.api.Talsec import com.aheaditec.talsec_security.security.api.TalsecConfig import com.aheaditec.talsec_security.security.api.ThreatListener @@ -12,8 +13,14 @@ import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.UiThreadUtil.runOnUiThread import com.facebook.react.bridge.WritableArray import com.facebook.react.modules.core.DeviceEventManagerModule - -class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) : +import com.freeraspreactnative.utils.getArraySafe +import com.freeraspreactnative.utils.getBooleanSafe +import com.freeraspreactnative.utils.getMapThrowing +import com.freeraspreactnative.utils.getNestedArraySafe +import com.freeraspreactnative.utils.getStringThrowing +import com.freeraspreactnative.utils.toEncodedWritableArray + +class FreeraspReactNativeModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { private val listener = ThreatListener(FreeraspThreatHandler, FreeraspThreatHandler) @@ -42,8 +49,7 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) : promise.resolve("freeRASP started") - } - catch (e: Exception) { + } catch (e: Exception) { promise.reject("TalsecInitializationError", e.message, e) } } @@ -65,6 +71,7 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) : val channelData: WritableArray = Arguments.createArray() channelData.pushString(THREAT_CHANNEL_NAME) channelData.pushString(THREAT_CHANNEL_KEY) + channelData.pushString(MALWARE_CHANNEL_KEY) promise.resolve(channelData) } @@ -87,6 +94,15 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) : // Remove upstream listeners, stop unnecessary background tasks } + /** + * Method to add apps to Malware whitelist, so they don't get flagged as malware + */ + @ReactMethod + fun addToWhitelist(packageName: String, promise: Promise) { + Talsec.addToWhitelist(reactContext, packageName) + promise.resolve(true) + } + private fun buildTalsecConfig(config: ReadableMap): TalsecConfig { val androidConfig = config.getMapThrowing("androidConfig") val packageName = androidConfig.getStringThrowing("packageName") @@ -97,6 +113,14 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) : .supportedAlternativeStores(androidConfig.getArraySafe("supportedAlternativeStores")) .prod(config.getBooleanSafe("isProd")) + if (androidConfig.hasKey("malwareConfig")) { + val malwareConfig = androidConfig.getMapThrowing("malwareConfig") + talsecBuilder.whitelistedInstallationSources(malwareConfig.getArraySafe("whitelistedInstallationSources")) + talsecBuilder.blacklistedHashes(malwareConfig.getArraySafe("blacklistedHashes")) + talsecBuilder.blacklistedPackageNames(malwareConfig.getArraySafe("blacklistedPackageNames")) + talsecBuilder.suspiciousPermissions(malwareConfig.getNestedArraySafe("suspiciousPermissions")) + } + return talsecBuilder.build() } @@ -106,6 +130,8 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) : .toString() // name of the channel over which threat callbacks are sent 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() + .toString() // key of the argument map under which malware data is expected private lateinit var appReactContext: ReactApplicationContext private fun notifyListeners(threat: Threat) { val params = Arguments.createMap() @@ -114,11 +140,30 @@ class FreeraspReactNativeModule(val reactContext: ReactApplicationContext) : .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) .emit(THREAT_CHANNEL_NAME, params) } + + /** + * Sends malware detected event to React Native + */ + private fun notifyMalware(suspiciousApps: MutableList) { + val params = Arguments.createMap() + params.putInt(THREAT_CHANNEL_KEY, Threat.Malware.value) + params.putArray( + MALWARE_CHANNEL_KEY, suspiciousApps.toEncodedWritableArray(appReactContext) + ) + + appReactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + .emit(THREAT_CHANNEL_NAME, params) + } } internal object ThreatListener : FreeraspThreatHandler.TalsecReactNative { override fun threatDetected(threatType: Threat) { notifyListeners(threatType) } + + override fun malwareDetected(suspiciousApps: MutableList) { + notifyMalware(suspiciousApps) + } } } diff --git a/android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt b/android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt index 4e58a44..d9facd8 100644 --- a/android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt +++ b/android/src/main/java/com/freeraspreactnative/FreeraspThreatHandler.kt @@ -39,7 +39,9 @@ internal object FreeraspThreatHandler : ThreatListener.ThreatDetected, ThreatLis listener?.threatDetected(Threat.ObfuscationIssues) } - override fun onMalwareDetected(p0: MutableList?) {} + override fun onMalwareDetected(suspiciousAppInfos: MutableList?) { + listener?.malwareDetected(suspiciousAppInfos ?: mutableListOf()) + } override fun onUnlockedDeviceDetected() { listener?.threatDetected(Threat.Passcode) @@ -59,5 +61,7 @@ internal object FreeraspThreatHandler : ThreatListener.ThreatDetected, ThreatLis internal interface TalsecReactNative { fun threatDetected(threatType: Threat) + + fun malwareDetected(suspiciousApps: MutableList) } } diff --git a/android/src/main/java/com/freeraspreactnative/Threat.kt b/android/src/main/java/com/freeraspreactnative/Threat.kt index ef53aab..d6fb7d0 100644 --- a/android/src/main/java/com/freeraspreactnative/Threat.kt +++ b/android/src/main/java/com/freeraspreactnative/Threat.kt @@ -23,6 +23,7 @@ internal sealed class Threat(val value: Int) { object ObfuscationIssues : Threat((10000..999999999).random()) object SystemVPN : Threat((10000..999999999).random()) object DevMode : Threat((10000..999999999).random()) + object Malware : Threat((10000..999999999).random()) companion object { internal fun getThreatValues(): WritableArray { @@ -39,7 +40,8 @@ internal sealed class Threat(val value: Int) { DeviceBinding.value, UnofficialStore.value, ObfuscationIssues.value, - DevMode.value + DevMode.value, + Malware.value ) ) } diff --git a/android/src/main/java/com/freeraspreactnative/Utils.kt b/android/src/main/java/com/freeraspreactnative/Utils.kt deleted file mode 100644 index 380dfd5..0000000 --- a/android/src/main/java/com/freeraspreactnative/Utils.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.freeraspreactnative - -import com.facebook.react.bridge.ReadableArray -import com.facebook.react.bridge.ReadableMap -import com.freeraspreactnative.exceptions.TalsecException - -internal fun ReadableMap.getMapThrowing(key: String): ReadableMap { - return this.getMap(key) ?: throw TalsecException("Key missing in configuration: $key") -} - -internal fun ReadableMap.getStringThrowing(key: String): String { - return this.getString(key) ?: throw TalsecException("Key missing in configuration: $key") -} - -internal fun ReadableMap.getBooleanSafe(key: String, defaultValue: Boolean = true): Boolean { - if (this.hasKey(key)) { - return this.getBoolean(key) - } - return defaultValue -} - -internal fun ReadableArray.toArray(): Array { - val output = mutableListOf() - for (i in 0 until this.size()) { - // in RN versions < 0.63, getString is nullable - @Suppress("UNNECESSARY_SAFE_CALL") - this.getString(i)?.let { - output.add(it) - } - } - return output.toTypedArray() -} - -internal fun ReadableMap.getArraySafe(key: String): Array { - if (this.hasKey(key)) { - val inputArray = this.getArray(key)!! - return inputArray.toArray() - } - return arrayOf() -} diff --git a/android/src/main/java/com/freeraspreactnative/models/RNSuspiciousAppInfo.kt b/android/src/main/java/com/freeraspreactnative/models/RNSuspiciousAppInfo.kt new file mode 100644 index 0000000..14f30d5 --- /dev/null +++ b/android/src/main/java/com/freeraspreactnative/models/RNSuspiciousAppInfo.kt @@ -0,0 +1,25 @@ +package com.freeraspreactnative.models + +import kotlinx.serialization.Serializable + + +/** + * Simplified, serializable wrapper for Talsec's SuspiciousAppInfo + */ +@Serializable +data class RNSuspiciousAppInfo( + val packageInfo: RNPackageInfo, + val reason: String, +) + +/** + * Simplified, serializable wrapper for Android's PackageInfo + */ +@Serializable +data class RNPackageInfo( + val packageName: String, + val appName: String?, + val version: String?, + val appIcon: String?, + val installerStore: String? +) diff --git a/android/src/main/java/com/freeraspreactnative/utils/Extensions.kt b/android/src/main/java/com/freeraspreactnative/utils/Extensions.kt new file mode 100644 index 0000000..85cb803 --- /dev/null +++ b/android/src/main/java/com/freeraspreactnative/utils/Extensions.kt @@ -0,0 +1,116 @@ +package com.freeraspreactnative.utils + +import android.content.pm.PackageInfo +import android.util.Base64 +import android.util.Log +import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.bridge.WritableArray +import com.freeraspreactnative.exceptions.TalsecException +import com.freeraspreactnative.models.RNPackageInfo +import com.freeraspreactnative.models.RNSuspiciousAppInfo +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import org.json.JSONException + + +internal fun ReadableMap.getMapThrowing(key: String): ReadableMap { + return this.getMap(key) ?: throw TalsecException("Key missing in configuration: $key") +} + +internal fun ReadableMap.getStringThrowing(key: String): String { + return this.getString(key) ?: throw TalsecException("Key missing in configuration: $key") +} + +internal fun ReadableMap.getBooleanSafe(key: String, defaultValue: Boolean = true): Boolean { + if (this.hasKey(key)) { + return this.getBoolean(key) + } + return defaultValue +} + +private inline fun ReadableArray.toPrimitiveArray(): Array { + val output = mutableListOf() + + for (i in 0 until this.size()) { + val element: T? = when (T::class) { + String::class -> this.getString(i) as T? + Int::class -> this.getInt(i) as T? + Double::class -> this.getDouble(i) as T? + Boolean::class -> this.getBoolean(i) as T? + else -> throw JSONException("Cannot parse JSON array - unsupported type") + } + element?.let(output::add) + } + return output.toTypedArray() +} + +internal fun ReadableMap.getArraySafe(key: String): Array { + if (this.hasKey(key)) { + val inputArray = this.getArray(key)!! + return inputArray.toPrimitiveArray() + } + return arrayOf() +} + +internal fun ReadableMap.getNestedArraySafe(key: String): Array> { + val outArray = mutableListOf>() + if (this.hasKey(key)) { + val inputArray = this.getArray(key)!! + for (i in 0 until inputArray.size()) { + outArray.add(inputArray.getArray(i).toPrimitiveArray()) + } + } + return outArray.toTypedArray() +} + + +/** + * Converts the Talsec's SuspiciousAppInfo to React Native equivalent + */ +internal fun SuspiciousAppInfo.toRNSuspiciousAppInfo(context: ReactContext): RNSuspiciousAppInfo { + return RNSuspiciousAppInfo( + packageInfo = this.packageInfo.toRNPackageInfo(context), + reason = this.reason, + ) +} + +/** + * Converts the Android's PackageInfo to React Native equivalent + */ +internal fun PackageInfo.toRNPackageInfo(context: ReactContext): RNPackageInfo { + return RNPackageInfo( + packageName = this.packageName, + appName = Utils.getAppName(context, this.applicationInfo), + version = this.versionName, + appIcon = Utils.getAppIconAsBase64String(context, this.packageName), + installerStore = Utils.getInstallationSource(context, this.packageName) + ) +} + +/** + * Convert the Talsec's SuspiciousAppInfo to base64-encoded json array, + * which can be then sent to React Native + */ +internal fun MutableList.toEncodedWritableArray(context: ReactContext): WritableArray { + val output = Arguments.createArray() + this.forEach { suspiciousAppInfo -> + val rnSuspiciousAppInfo = suspiciousAppInfo.toRNSuspiciousAppInfo(context) + try { + val encodedAppInfo = + Base64.encodeToString( + Json.encodeToString(rnSuspiciousAppInfo).toByteArray(), + Base64.DEFAULT + ) + output.pushString(encodedAppInfo) + } catch (e: Exception) { + Log.e("Talsec", "Could not serialize suspicious app data: ${e.message}") + } + + } + return output +} + diff --git a/android/src/main/java/com/freeraspreactnative/utils/Utils.kt b/android/src/main/java/com/freeraspreactnative/utils/Utils.kt new file mode 100644 index 0000000..0bcc513 --- /dev/null +++ b/android/src/main/java/com/freeraspreactnative/utils/Utils.kt @@ -0,0 +1,82 @@ +package com.freeraspreactnative.utils + +import android.content.pm.ApplicationInfo +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.drawable.BitmapDrawable +import android.os.Build +import android.util.Base64 +import android.util.Log +import com.facebook.react.bridge.ReactContext +import java.io.ByteArrayOutputStream + + +internal object Utils { + + private fun compressBitmap(bitmap: Bitmap): String { + val byteArrayOutputStream = ByteArrayOutputStream() + bitmap.compress(Bitmap.CompressFormat.PNG, 10, byteArrayOutputStream) + val byteArray = byteArrayOutputStream.toByteArray() + return Base64.encodeToString(byteArray, Base64.NO_WRAP) + } + + /** + * Retrieves human-readable application name + */ + internal fun getAppName(context: ReactContext, applicationInfo: ApplicationInfo?): String? { + return applicationInfo?.let { context.packageManager.getApplicationLabel(it) as String } + } + + /** + * Retrieves app icon for the given package name as Drawable, transforms it to Bitmap, + * compresses to PNG and finally encodes the data to Base64 + * @param context React Native context + * @param packageName package name for which icon should be retrieved + * @return Base-64 encoded string + */ + internal fun getAppIconAsBase64String(context: ReactContext, packageName: String): String? { + try { + val drawable = context.packageManager.getApplicationIcon(packageName) + + if (drawable is BitmapDrawable && drawable.bitmap != null) { + return compressBitmap(drawable.bitmap) + } + + if (drawable.intrinsicWidth > 0 && drawable.intrinsicHeight > 0) { + val bitmap = Bitmap.createBitmap( + drawable.intrinsicWidth, + drawable.intrinsicHeight, + Bitmap.Config.ARGB_8888 + ) + val canvas = Canvas(bitmap) + drawable.setBounds(0, 0, canvas.width, canvas.height) + drawable.draw(canvas) + return compressBitmap(bitmap) + } + return null + } catch (e: Exception) { + Log.e("Talsec", "Could not retrieve app icon for ${packageName}: ${e.message}") + return null + } + } + + /** + * Retrieves installation source for the given package name + * @param context React Native context + * @param packageName package name for which installation source should be retrieved + * @return Installation source package name + */ + @Suppress("DEPRECATION") + internal fun getInstallationSource(context: ReactContext, packageName: String): String? { + return try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + context.packageManager.getInstallSourceInfo(packageName).installingPackageName + } else { + context.packageManager.getInstallerPackageName(packageName) + } + } catch (e: Exception) { + Log.e("Talsec", "Could not retrieve app installation source for ${packageName}: ${e.message}") + null + } + } +} diff --git a/example/assets/arrow-down.png b/example/assets/arrow-down.png new file mode 100644 index 0000000..b24bb77 Binary files /dev/null and b/example/assets/arrow-down.png differ diff --git a/example/assets/arrow-up.png b/example/assets/arrow-up.png new file mode 100644 index 0000000..cd785b0 Binary files /dev/null and b/example/assets/arrow-up.png differ diff --git a/example/ios/FreeraspReactNativeExample.xcodeproj/project.pbxproj b/example/ios/FreeraspReactNativeExample.xcodeproj/project.pbxproj index 0a81610..50dfb44 100644 --- a/example/ios/FreeraspReactNativeExample.xcodeproj/project.pbxproj +++ b/example/ios/FreeraspReactNativeExample.xcodeproj/project.pbxproj @@ -8,11 +8,11 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* FreeraspReactNativeExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* FreeraspReactNativeExampleTests.m */; }; - 0C80B921A6F3F58F76C31292 /* libPods-FreeraspReactNativeExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-FreeraspReactNativeExample.a */; }; + 030014488BDA0448D18833AA /* libPods-FreeraspReactNativeExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8488310E7CEBAD4453B2B105 /* libPods-FreeraspReactNativeExample.a */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 7699B88040F8A987B510C191 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a */; }; + 4ED36F23A824FA42AAF69DEA /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 09A90BCC7156013BB41680E2 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ @@ -30,19 +30,19 @@ 00E356EE1AD99517003FC87E /* FreeraspReactNativeExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FreeraspReactNativeExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* FreeraspReactNativeExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FreeraspReactNativeExampleTests.m; sourceTree = ""; }; + 038937FFB95426BE2297B416 /* Pods-FreeraspReactNativeExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample.debug.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample/Pods-FreeraspReactNativeExample.debug.xcconfig"; sourceTree = ""; }; + 09A90BCC7156013BB41680E2 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07F961A680F5B00A75B9A /* FreeraspReactNativeExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FreeraspReactNativeExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = FreeraspReactNativeExample/AppDelegate.h; sourceTree = ""; }; 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = FreeraspReactNativeExample/AppDelegate.mm; sourceTree = ""; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = FreeraspReactNativeExample/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = FreeraspReactNativeExample/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = FreeraspReactNativeExample/main.m; sourceTree = ""; }; - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B4392A12AC88292D35C810B /* Pods-FreeraspReactNativeExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample.debug.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample/Pods-FreeraspReactNativeExample.debug.xcconfig"; sourceTree = ""; }; - 5709B34CF0A7D63546082F79 /* Pods-FreeraspReactNativeExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample.release.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample/Pods-FreeraspReactNativeExample.release.xcconfig"; sourceTree = ""; }; - 5B7EB9410499542E8C5724F5 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig"; sourceTree = ""; }; - 5DCACB8F33CDC322A6C60F78 /* libPods-FreeraspReactNativeExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FreeraspReactNativeExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1BFFF7106D93FA70E5F83B56 /* Pods-FreeraspReactNativeExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample.release.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample/Pods-FreeraspReactNativeExample.release.xcconfig"; sourceTree = ""; }; + 2DDE1F099A37D62A4850E520 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig"; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = FreeraspReactNativeExample/LaunchScreen.storyboard; sourceTree = ""; }; - 89C6BE57DB24E9ADA2F236DE /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig"; sourceTree = ""; }; + 8488310E7CEBAD4453B2B105 /* libPods-FreeraspReactNativeExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FreeraspReactNativeExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 85E04B3D386AA8B417F2AAF3 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig"; sourceTree = ""; }; 8C2BD8B529DF06E4000304E9 /* Talsec */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Talsec; path = ../../ios/Talsec; sourceTree = ""; }; 8C2BD8BB29DF0976000304E9 /* TalsecRuntime.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TalsecRuntime.xcframework; path = ../../ios/Talsec/TalsecRuntime.xcframework; sourceTree = ""; }; A41E05172962B9FD00B363A8 /* TalsecRuntime.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TalsecRuntime.xcframework; path = "../../../../React/test2/someTestProject/node_modules/freerasp-react-native/ios/TalsecRuntime.xcframework"; sourceTree = ""; }; @@ -57,7 +57,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7699B88040F8A987B510C191 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a in Frameworks */, + 4ED36F23A824FA42AAF69DEA /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -65,7 +65,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0C80B921A6F3F58F76C31292 /* libPods-FreeraspReactNativeExample.a in Frameworks */, + 030014488BDA0448D18833AA /* libPods-FreeraspReactNativeExample.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -112,8 +112,8 @@ A44E69A2295DA98F000A719C /* TalsecRuntime.xcframework */, A41E05172962B9FD00B363A8 /* TalsecRuntime.xcframework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 5DCACB8F33CDC322A6C60F78 /* libPods-FreeraspReactNativeExample.a */, - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a */, + 8488310E7CEBAD4453B2B105 /* libPods-FreeraspReactNativeExample.a */, + 09A90BCC7156013BB41680E2 /* libPods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.a */, ); name = Frameworks; sourceTree = ""; @@ -152,10 +152,10 @@ BBD78D7AC51CEA395F1C20DB /* Pods */ = { isa = PBXGroup; children = ( - 3B4392A12AC88292D35C810B /* Pods-FreeraspReactNativeExample.debug.xcconfig */, - 5709B34CF0A7D63546082F79 /* Pods-FreeraspReactNativeExample.release.xcconfig */, - 5B7EB9410499542E8C5724F5 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig */, - 89C6BE57DB24E9ADA2F236DE /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig */, + 038937FFB95426BE2297B416 /* Pods-FreeraspReactNativeExample.debug.xcconfig */, + 1BFFF7106D93FA70E5F83B56 /* Pods-FreeraspReactNativeExample.release.xcconfig */, + 85E04B3D386AA8B417F2AAF3 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig */, + 2DDE1F099A37D62A4850E520 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -167,12 +167,12 @@ isa = PBXNativeTarget; buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "FreeraspReactNativeExampleTests" */; buildPhases = ( - A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */, + A4BC7293855B5A05F4C72AC9 /* [CP] Check Pods Manifest.lock */, 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, - C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */, - F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */, + 995743924976FEBF7E02912B /* [CP] Embed Pods Frameworks */, + E336F02480C5189A28C1E46B /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -188,14 +188,14 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "FreeraspReactNativeExample" */; buildPhases = ( - C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, + A46062B41DA6D2651EEB7340 /* [CP] Check Pods Manifest.lock */, FD10A7F022414F080027D42C /* Start Packager */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, - E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + 98A5FD6C0A62A5C5AA93C483 /* [CP] Embed Pods Frameworks */, + BE093CB94A51CDDBD748D259 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -278,7 +278,7 @@ shellPath = /bin/sh; shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; }; - 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { + 98A5FD6C0A62A5C5AA93C483 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -295,29 +295,24 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample/Pods-FreeraspReactNativeExample-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = { + 995743924976FEBF7E02912B /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { + A46062B41DA6D2651EEB7340 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -339,24 +334,29 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = { + A4BC7293855B5A05F4C72AC9 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests/Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { + BE093CB94A51CDDBD748D259 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -373,7 +373,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-FreeraspReactNativeExample/Pods-FreeraspReactNativeExample-resources.sh\"\n"; showEnvVarsInLog = 0; }; - F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = { + E336F02480C5189A28C1E46B /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -442,7 +442,7 @@ /* Begin XCBuildConfiguration section */ 00E356F61AD99517003FC87E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig */; + baseConfigurationReference = 85E04B3D386AA8B417F2AAF3 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -469,7 +469,7 @@ }; 00E356F71AD99517003FC87E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig */; + baseConfigurationReference = 2DDE1F099A37D62A4850E520 /* Pods-FreeraspReactNativeExample-FreeraspReactNativeExampleTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; @@ -493,7 +493,7 @@ }; 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-FreeraspReactNativeExample.debug.xcconfig */; + baseConfigurationReference = 038937FFB95426BE2297B416 /* Pods-FreeraspReactNativeExample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -519,7 +519,7 @@ }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-FreeraspReactNativeExample.release.xcconfig */; + baseConfigurationReference = 1BFFF7106D93FA70E5F83B56 /* Pods-FreeraspReactNativeExample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; diff --git a/example/src/App.tsx b/example/src/App.tsx index 42b2092..a25d0f1 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,21 +1,48 @@ import * as React from 'react'; import { Platform } from 'react-native'; -import { useFreeRasp } from 'freerasp-react-native'; +import { + addToWhitelist, + useFreeRasp, + type SuspiciousAppInfo, +} from 'freerasp-react-native'; import { DemoApp } from './DemoApp'; import { commonChecks, iosChecks, androidChecks } from './checks'; +import { useEffect } from 'react'; const App = () => { const [appChecks, setAppChecks] = React.useState([ ...commonChecks, ...(Platform.OS === 'ios' ? iosChecks : androidChecks), ]); + const [suspiciousApps, setSuspiciousApps] = React.useState< + SuspiciousAppInfo[] + >([]); + + useEffect(() => { + (async () => { + Platform.OS === 'android' && (await addItemsToMalwareWhitelist()); + })(); + }, []); const config = { androidConfig: { packageName: 'com.freeraspreactnativeexample', certificateHashes: ['AKoRuyLMM91E7lX/Zqp3u4jMmd0A7hH/Iqozu0TMVd0='], // supportedAlternativeStores: ['storeOne', 'storeTwo'], + malwareConfig: { + blacklistedHashes: ['FgvSehLMM91E7lX/Zqp3u4jMmd0A7hH/Iqozu0TMVd0u'], + blacklistedPackageNames: ['com.wultra.app.screenlogger'], + suspiciousPermissions: [ + [ + 'android.permission.INTERNET', + 'android.permission.ACCESS_COARSE_LOCATION', + ], + ['android.permission.BLUETOOTH'], + ['android.permission.BATTERY_STATS'], + ], + whitelistedInstallationSources: ['com.apkpure.aegon'], + }, }, iosConfig: { appBundleId: 'com.freeraspreactnativeexample', @@ -144,11 +171,39 @@ const App = () => { ) ); }, + // Android only + malware: (detectedApps: SuspiciousAppInfo[]) => { + setSuspiciousApps(detectedApps); + setAppChecks((currentState) => + currentState.map((threat) => + threat.name === 'Malware' ? { ...threat, status: 'nok' } : threat + ) + ); + }, + }; + + const addItemsToMalwareWhitelist = async () => { + const appsToWhitelist = [ + 'com.talsecreactnativesecuritypluginexample', + 'com.example.myApp', + ]; + await Promise.all( + appsToWhitelist.map(async (app) => { + try { + const whitelistResponse = await addToWhitelist(app); + console.info( + `${app} stored to Malware Whitelist: ${whitelistResponse}` + ); + } catch (error) { + console.info('Malware whitelist failed: ', error); + } + }) + ); }; useFreeRasp(config, actions); - return ; + return ; }; export default App; diff --git a/example/src/DemoApp.tsx b/example/src/DemoApp.tsx index f23a16b..8dd4578 100644 --- a/example/src/DemoApp.tsx +++ b/example/src/DemoApp.tsx @@ -6,8 +6,16 @@ import CloseCircle from '../assets/close-circle-outline.png'; import TalsecLogo from '../assets/talsec-logo.png'; import { Image } from 'react-native'; import { Colors } from './styles'; +import { MalwareModal } from './MalwareModal'; +import type { SuspiciousAppInfo } from 'freerasp-react-native'; -export const DemoApp = (props: any) => { +export const DemoApp: React.FC<{ + checks: { + name: string; + status: string; + }[]; + suspiciousApps: SuspiciousAppInfo[]; +}> = ({ checks, suspiciousApps }) => { return ( <> { > freeRASP checks: - {props.checks.map((check: any, idx: number) => ( + {checks.map((check: any, idx: number) => ( { > {check.name} + {check.name === 'Malware' && ( + + )} {check.status === 'ok' ? ( = ({ app }) => { + const [expanded, setExpanded] = useState(false); + + const appUninstall = async () => { + alert('Implement yourself!'); + }; + + const whitelistApp = async (packageName: string) => { + try { + const whitelistResponse = await addToWhitelist(packageName); + console.info( + `Malware Whitelist response for ${app}: ${whitelistResponse}` + ); + alert('Restart app for whitelist to take effect'); + } catch (error: any) { + console.info('Error while adding app to malware whitelist: ', error); + } + }; + + return ( + + setExpanded(!expanded)}> + + + + + {app.packageInfo.appName} + + + + + + + + + {expanded && ( + <> + + Package name: + {app.packageInfo.packageName} + App name: + + {app.packageInfo.appName ?? 'Not specified'} + + App version: + + {app.packageInfo.version ?? 'Not specified'} + + App Icon: + {app.packageInfo.appIcon ? ( + + ) : ( + Not specified + )} + Installer store: + + {app.packageInfo.installerStore ?? 'Not specified'} + + Detection reason: + {app.reason} + +