react-native-device-defense 1.0.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 (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -0
  3. package/android/build.gradle +90 -0
  4. package/android/proguard-rules.pro +28 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/cpp/CMakeLists.txt +45 -0
  7. package/android/src/main/cpp/device-security.cpp +314 -0
  8. package/android/src/main/java/vn/osp/security/DebugDetection.kt +131 -0
  9. package/android/src/main/java/vn/osp/security/DeviceSecurityModule.kt +277 -0
  10. package/android/src/main/java/vn/osp/security/DeviceSecurityPackage.kt +58 -0
  11. package/android/src/main/java/vn/osp/security/EmulatorDetection.kt +204 -0
  12. package/android/src/main/java/vn/osp/security/HookDetection.kt +270 -0
  13. package/android/src/main/java/vn/osp/security/NativeSecurityCheck.kt +66 -0
  14. package/android/src/main/java/vn/osp/security/RootDetection.kt +349 -0
  15. package/lib/commonjs/NativeDeviceSecurity.js +9 -0
  16. package/lib/commonjs/NativeDeviceSecurity.js.map +1 -0
  17. package/lib/commonjs/api.js +213 -0
  18. package/lib/commonjs/api.js.map +1 -0
  19. package/lib/commonjs/components/SecurityBlockedScreen.js +177 -0
  20. package/lib/commonjs/components/SecurityBlockedScreen.js.map +1 -0
  21. package/lib/commonjs/components/index.js +13 -0
  22. package/lib/commonjs/components/index.js.map +1 -0
  23. package/lib/commonjs/hooks/index.js +13 -0
  24. package/lib/commonjs/hooks/index.js.map +1 -0
  25. package/lib/commonjs/hooks/useDeviceSecurity.js +81 -0
  26. package/lib/commonjs/hooks/useDeviceSecurity.js.map +1 -0
  27. package/lib/commonjs/index.js +48 -0
  28. package/lib/commonjs/index.js.map +1 -0
  29. package/lib/commonjs/types.js +2 -0
  30. package/lib/commonjs/types.js.map +1 -0
  31. package/lib/module/NativeDeviceSecurity.js +3 -0
  32. package/lib/module/NativeDeviceSecurity.js.map +1 -0
  33. package/lib/module/api.js +206 -0
  34. package/lib/module/api.js.map +1 -0
  35. package/lib/module/components/SecurityBlockedScreen.js +169 -0
  36. package/lib/module/components/SecurityBlockedScreen.js.map +1 -0
  37. package/lib/module/components/index.js +2 -0
  38. package/lib/module/components/index.js.map +1 -0
  39. package/lib/module/hooks/index.js +2 -0
  40. package/lib/module/hooks/index.js.map +1 -0
  41. package/lib/module/hooks/useDeviceSecurity.js +73 -0
  42. package/lib/module/hooks/useDeviceSecurity.js.map +1 -0
  43. package/lib/module/index.js +21 -0
  44. package/lib/module/index.js.map +1 -0
  45. package/lib/module/types.js +2 -0
  46. package/lib/module/types.js.map +1 -0
  47. package/lib/typescript/NativeDeviceSecurity.d.ts +16 -0
  48. package/lib/typescript/NativeDeviceSecurity.d.ts.map +1 -0
  49. package/lib/typescript/api.d.ts +55 -0
  50. package/lib/typescript/api.d.ts.map +1 -0
  51. package/lib/typescript/components/SecurityBlockedScreen.d.ts +23 -0
  52. package/lib/typescript/components/SecurityBlockedScreen.d.ts.map +1 -0
  53. package/lib/typescript/components/index.d.ts +2 -0
  54. package/lib/typescript/components/index.d.ts.map +1 -0
  55. package/lib/typescript/hooks/index.d.ts +3 -0
  56. package/lib/typescript/hooks/index.d.ts.map +1 -0
  57. package/lib/typescript/hooks/useDeviceSecurity.d.ts +7 -0
  58. package/lib/typescript/hooks/useDeviceSecurity.d.ts.map +1 -0
  59. package/lib/typescript/index.d.ts +12 -0
  60. package/lib/typescript/index.d.ts.map +1 -0
  61. package/lib/typescript/types.d.ts +81 -0
  62. package/lib/typescript/types.d.ts.map +1 -0
  63. package/package.json +72 -0
  64. package/react-native-device-security.podspec +18 -0
  65. package/src/NativeDeviceSecurity.ts +33 -0
  66. package/src/api.ts +225 -0
  67. package/src/components/SecurityBlockedScreen.tsx +204 -0
  68. package/src/components/index.ts +1 -0
  69. package/src/hooks/index.ts +5 -0
  70. package/src/hooks/useDeviceSecurity.ts +91 -0
  71. package/src/index.ts +27 -0
  72. package/src/types.ts +95 -0
@@ -0,0 +1,270 @@
1
+ package vn.osp.security
2
+
3
+ import android.content.Context
4
+ import android.content.pm.PackageManager
5
+ import java.io.BufferedReader
6
+ import java.io.File
7
+ import java.io.InputStreamReader
8
+
9
+ /**
10
+ * Detection for hooking frameworks (Frida, Xposed, Magisk, etc.)
11
+ */
12
+ class HookDetection(private val context: Context) {
13
+
14
+ /**
15
+ * Check if Frida framework is present
16
+ */
17
+ fun hasFrida(): Boolean {
18
+ return checkFridaPorts() ||
19
+ checkFridaLibraries() ||
20
+ checkFridaProcesses() ||
21
+ checkFridaFiles()
22
+ }
23
+
24
+ /**
25
+ * Check if Xposed framework is present
26
+ */
27
+ fun hasXposed(): Boolean {
28
+ return checkXposedApp() ||
29
+ checkXposedInClassLoader() ||
30
+ checkXposedFiles()
31
+ }
32
+
33
+ /**
34
+ * Check if Magisk is present
35
+ */
36
+ fun hasMagisk(): Boolean {
37
+ return checkMagiskApp() ||
38
+ checkMagiskFiles() ||
39
+ checkMagiskModules()
40
+ }
41
+
42
+ /**
43
+ * Check for Frida ports (default: 27042, 27043)
44
+ */
45
+ private fun checkFridaPorts(): Boolean {
46
+ val fridaPorts = listOf(27042, 27043, 27044, 27045)
47
+
48
+ // Read /proc/net/tcp to check for open ports
49
+ try {
50
+ val bufferedReader = BufferedReader(InputStreamReader(
51
+ File("/proc/net/tcp").inputStream()
52
+ ))
53
+
54
+ bufferedReader.use { reader ->
55
+ var line: String?
56
+ while (reader.readLine().also { line = it } != null) {
57
+ // Format: sl local_address rem_address st ...
58
+ // Skip header
59
+ if (line?.startsWith(" sl") == true) continue
60
+
61
+ val parts = line?.trim()?.split("\\s+".toRegex()) ?: continue
62
+ if (parts.size >= 2) {
63
+ try {
64
+ // local_address format: hex_ip:hex_port
65
+ val localAddress = parts[1]
66
+ val addressParts = localAddress.split(":")
67
+ if (addressParts.size == 2) {
68
+ val portHex = addressParts[1]
69
+ val port = portHex.toInt(16)
70
+ if (port in fridaPorts) {
71
+ return true
72
+ }
73
+ }
74
+ } catch (e: Exception) {
75
+ // Ignore parsing errors
76
+ }
77
+ }
78
+ }
79
+ }
80
+ } catch (e: Exception) {
81
+ // Ignore errors
82
+ }
83
+
84
+ return false
85
+ }
86
+
87
+ /**
88
+ * Check for Frida libraries in memory
89
+ */
90
+ private fun checkFridaLibraries(): Boolean {
91
+ // Check /proc/self/maps for Frida libraries
92
+ try {
93
+ val bufferedReader = BufferedReader(InputStreamReader(
94
+ File("/proc/self/maps").inputStream()
95
+ ))
96
+
97
+ bufferedReader.use { reader ->
98
+ var line: String?
99
+ while (reader.readLine().also { line = it } != null) {
100
+ if (line?.contains("frida") == true ||
101
+ line?.contains("frida-agent") == true ||
102
+ line?.contains("libfrida") == true) {
103
+ return true
104
+ }
105
+ }
106
+ }
107
+ } catch (e: Exception) {
108
+ // Ignore errors
109
+ }
110
+
111
+ return false
112
+ }
113
+
114
+ /**
115
+ * Check for Frida processes
116
+ */
117
+ private fun checkFridaProcesses(): Boolean {
118
+ try {
119
+ val process = Runtime.getRuntime().exec("ps")
120
+ val reader = BufferedReader(InputStreamReader(process.inputStream))
121
+
122
+ reader.use {
123
+ var line: String?
124
+ while (it.readLine().also { line = it } != null) {
125
+ if (line?.contains("frida") == true ||
126
+ line?.contains("frida-server") == true) {
127
+ return true
128
+ }
129
+ }
130
+ }
131
+ } catch (e: Exception) {
132
+ // Ignore errors
133
+ }
134
+
135
+ return false
136
+ }
137
+
138
+ /**
139
+ * Check for Frida-related files
140
+ */
141
+ private fun checkFridaFiles(): Boolean {
142
+ val fridaPaths = listOf(
143
+ "/data/local/tmp/frida",
144
+ "/data/local/tmp/frida-server",
145
+ "/data/local/tmp/frida-agent.so",
146
+ "/data/local/tmp/frida-agent-*.so",
147
+ "/system/lib/libfrida.so",
148
+ "/system/lib64/libfrida.so"
149
+ )
150
+
151
+ return fridaPaths.any { path ->
152
+ try {
153
+ // Handle wildcards
154
+ if (path.contains("*")) {
155
+ val dir = File(path.substringBeforeLast("/"))
156
+ val prefix = path.substringAfterLast("/").replace("*", "")
157
+ dir.list()?.any { it.startsWith(prefix) } == true
158
+ } else {
159
+ File(path).exists()
160
+ }
161
+ } catch (e: Exception) {
162
+ false
163
+ }
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Check if Xposed installer app is present
169
+ */
170
+ private fun checkXposedApp(): Boolean {
171
+ val xposedPackages = listOf(
172
+ "de.robv.android.xposed.installer",
173
+ "de.robv.android.xposed.installer",
174
+ "org.meowcat.edxposed.manager",
175
+ "io.github.huskydg.xposed",
176
+ "com.solohsu.android.edxp.manager"
177
+ )
178
+
179
+ return xposedPackages.any { isPackageInstalled(it) }
180
+ }
181
+
182
+ /**
183
+ * Check for Xposed in class loader
184
+ */
185
+ private fun checkXposedInClassLoader(): Boolean {
186
+ return try {
187
+ // Check for XposedBridge class
188
+ Class.forName("de.robv.android.xposed.XposedBridge")
189
+ true
190
+ } catch (e: ClassNotFoundException) {
191
+ false
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Check for Xposed-related files
197
+ */
198
+ private fun checkXposedFiles(): Boolean {
199
+ val xposedPaths = listOf(
200
+ "/system/framework/XposedBridge.jar",
201
+ "/system/bin/app_process32_xposed",
202
+ "/system/bin/app_process64_xposed",
203
+ "/system/xposed.prop",
204
+ "/cache/XposedBridge.jar"
205
+ )
206
+
207
+ return xposedPaths.any { File(it).exists() }
208
+ }
209
+
210
+ /**
211
+ * Check if Magisk app is present
212
+ */
213
+ private fun checkMagiskApp(): Boolean {
214
+ val magiskPackages = listOf(
215
+ "com.topjohnwu.magisk",
216
+ "com.topjohnwu.magisk.ui"
217
+ )
218
+
219
+ return magiskPackages.any { isPackageInstalled(it) }
220
+ }
221
+
222
+ /**
223
+ * Check for Magisk-related files
224
+ */
225
+ private fun checkMagiskFiles(): Boolean {
226
+ val magiskPaths = listOf(
227
+ "/sbin/.magisk",
228
+ "/sbin/.core/mirror",
229
+ "/sbin/.core/img",
230
+ "/sbin/.core/db-0/magisk.db",
231
+ "/cache/magisk.log",
232
+ "/dev/com.topjohnwu.magisk",
233
+ "/data/adb/magisk",
234
+ "/data/adb/magisk.img",
235
+ "/data/adb/magisk.db",
236
+ "/data/adb/magisk_simple",
237
+ "/system/addon.d/99-magisk.sh"
238
+ )
239
+
240
+ return magiskPaths.any { File(it).exists() }
241
+ }
242
+
243
+ /**
244
+ * Check for Magisk modules
245
+ */
246
+ private fun checkMagiskModules(): Boolean {
247
+ val magiskModuleDir = "/data/adb/modules"
248
+ val moduleDir = File(magiskModuleDir)
249
+
250
+ if (moduleDir.exists() && moduleDir.isDirectory) {
251
+ // Check if any modules are enabled
252
+ val modules = moduleDir.listFiles()
253
+ return modules?.isNotEmpty() == true
254
+ }
255
+
256
+ return false
257
+ }
258
+
259
+ /**
260
+ * Check if package is installed
261
+ */
262
+ private fun isPackageInstalled(packageName: String): Boolean {
263
+ return try {
264
+ context.packageManager.getPackageInfo(packageName, 0)
265
+ true
266
+ } catch (e: PackageManager.NameNotFoundException) {
267
+ false
268
+ }
269
+ }
270
+ }
@@ -0,0 +1,66 @@
1
+ package vn.osp.security
2
+
3
+ /**
4
+ * Native (JNI) security checks
5
+ * This class provides native methods that are harder to bypass with JavaScript hooks
6
+ */
7
+ object NativeSecurityCheck {
8
+
9
+ init {
10
+ try {
11
+ System.loadLibrary("device-security")
12
+ } catch (e: UnsatisfiedLinkError) {
13
+ // Native library not loaded, fallback to Java/Kotlin checks
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Native root detection
19
+ * Uses C++ code to check for root indicators that are harder to bypass
20
+ * @return true if device is rooted
21
+ */
22
+ external fun isRooted(): Boolean
23
+
24
+ /**
25
+ * Native check for dangerous binaries
26
+ * @return true if dangerous binaries found
27
+ */
28
+ external fun hasDangerousBinaries(): Boolean
29
+
30
+ /**
31
+ * Native check for system properties
32
+ * @return true if suspicious system properties found
33
+ */
34
+ external fun hasSuspiciousSystemProperties(): Boolean
35
+
36
+ /**
37
+ * Native check for hook frameworks
38
+ * @return true if hooking framework detected
39
+ */
40
+ external fun hasHookFramework(): Boolean
41
+
42
+ /**
43
+ * Native check for debugger
44
+ * @return true if debugger detected
45
+ */
46
+ external fun isDebuggerAttached(): Boolean
47
+
48
+ /**
49
+ * Get native security status as JSON string
50
+ * @return JSON string with security status
51
+ */
52
+ external fun getSecurityStatus(): String
53
+
54
+ /**
55
+ * Check if native library is loaded
56
+ */
57
+ fun isNativeLibraryLoaded(): Boolean {
58
+ return try {
59
+ // Try to call a native method
60
+ isRooted()
61
+ true
62
+ } catch (e: UnsatisfiedLinkError) {
63
+ false
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,349 @@
1
+ package vn.osp.security
2
+
3
+ import android.content.Context
4
+ import android.content.pm.PackageManager
5
+ import android.os.Build
6
+ import com.scottyab.rootbeer.RootBeer
7
+ import java.io.BufferedReader
8
+ import java.io.File
9
+ import java.io.InputStreamReader
10
+
11
+ /**
12
+ * Multi-layer root detection using various techniques
13
+ */
14
+ class RootDetection(private val context: Context) {
15
+
16
+ data class RootDetectionResult(
17
+ val isRooted: Boolean,
18
+ val hasRootBeerDetected: Boolean,
19
+ val hasNativeRootDetected: Boolean,
20
+ val hasDangerousBins: Boolean,
21
+ val hasRootApps: Boolean,
22
+ val hasSystemPropsModified: Boolean,
23
+ val details: Map<String, Boolean>
24
+ )
25
+
26
+ /**
27
+ * Perform comprehensive root detection
28
+ */
29
+ fun performDetection(): RootDetectionResult {
30
+ val rootBeer = RootBeer(context)
31
+ val hasRootBeerDetected = rootBeer.isRooted
32
+
33
+ // Native detection (JNI)
34
+ val hasNativeRootDetected = NativeSecurityCheck.isRooted()
35
+
36
+ // Check for dangerous binaries
37
+ val hasDangerousBins = checkDangerousBinaries()
38
+
39
+ // Check for root management apps
40
+ val hasRootApps = checkRootApps()
41
+
42
+ // Check system properties
43
+ val hasSystemPropsModified = checkSystemProperties()
44
+
45
+ val details = mapOf(
46
+ "root_beer" to hasRootBeerDetected,
47
+ "native_detection" to hasNativeRootDetected,
48
+ "dangerous_bins" to hasDangerousBins,
49
+ "root_apps" to hasRootApps,
50
+ "system_props" to hasSystemPropsModified,
51
+ "su_binary" to checkForSuBinary(),
52
+ "busybox_binary" to checkForBusybox(),
53
+ "rw_system" to checkSystemRemounted(),
54
+ "dangerous_props" to checkDangerousSystemProperties()
55
+ )
56
+
57
+ val isRooted = hasRootBeerDetected ||
58
+ hasNativeRootDetected ||
59
+ hasDangerousBins ||
60
+ hasRootApps ||
61
+ hasSystemPropsModified
62
+
63
+ return RootDetectionResult(
64
+ isRooted = isRooted,
65
+ hasRootBeerDetected = hasRootBeerDetected,
66
+ hasNativeRootDetected = hasNativeRootDetected,
67
+ hasDangerousBins = hasDangerousBins,
68
+ hasRootApps = hasRootApps,
69
+ hasSystemPropsModified = hasSystemPropsModified,
70
+ details = details
71
+ )
72
+ }
73
+
74
+ /**
75
+ * Check for dangerous binaries commonly found on rooted devices
76
+ */
77
+ private fun checkDangerousBinaries(): Boolean {
78
+ val dangerousBins = listOf(
79
+ "su",
80
+ "busybox",
81
+ "magisk",
82
+ "supolicy",
83
+ "supol",
84
+ "daemonsu",
85
+ "ksu", // KernelSU
86
+ "apd" // Apex (another root solution)
87
+ )
88
+
89
+ val paths = listOf(
90
+ "/system/app/Superuser.apk",
91
+ "/sbin/su",
92
+ "/system/bin/su",
93
+ "/system/xbin/su",
94
+ "/data/local/xbin/su",
95
+ "/data/local/bin/su",
96
+ "/system/sd/xbin/su",
97
+ "/system/bin/failsafe/su",
98
+ "/data/local/su",
99
+ "/su/bin/su",
100
+ "/magisk/.core/bin/su",
101
+ "/system/usr/we-need-root/su",
102
+ "/system/app/SuperSU",
103
+ "/system/app/SuperSU.apk",
104
+ "/system/app/Superuser",
105
+ "/system/app/Superuser.apk",
106
+ "/data/data/com.noshufou.android.su",
107
+ "/data/data/com.thirdparty.superuser",
108
+ "/data/data/eu.chainfire.supersu",
109
+ "/system/xbin/busybox",
110
+ "/system/bin/busybox",
111
+ "/data/data/com.topjohnwu.magisk",
112
+ "/cache/magisk.log",
113
+ "/dev/com.topjohnwu.magisk",
114
+ "/system/app/MagiskManager"
115
+ )
116
+
117
+ // Check for dangerous binaries in PATH
118
+ val pathEnv = System.getenv("PATH") ?: ""
119
+ val pathDirs = pathEnv.split(":")
120
+
121
+ for (bin in dangerousBins) {
122
+ // Check in common locations
123
+ for (path in paths) {
124
+ if (File(path).exists()) {
125
+ return true
126
+ }
127
+ }
128
+
129
+ // Check in PATH directories
130
+ for (dir in pathDirs) {
131
+ if (File(dir, bin).exists()) {
132
+ return true
133
+ }
134
+ }
135
+ }
136
+
137
+ return false
138
+ }
139
+
140
+ /**
141
+ * Check for su binary specifically
142
+ */
143
+ private fun checkForSuBinary(): Boolean {
144
+ val suPaths = listOf(
145
+ "/system/bin/su",
146
+ "/system/xbin/su",
147
+ "/sbin/su",
148
+ "/data/local/xbin/su",
149
+ "/data/local/bin/su",
150
+ "/system/sd/xbin/su",
151
+ "/system/bin/failsafe/su",
152
+ "/data/local/su",
153
+ "/su/bin/su",
154
+ "/magisk/.core/bin/su"
155
+ )
156
+
157
+ return suPaths.any { File(it).exists() && File(it).canExecute() }
158
+ }
159
+
160
+ /**
161
+ * Check for busybox binary
162
+ */
163
+ private fun checkForBusybox(): Boolean {
164
+ val busyboxPaths = listOf(
165
+ "/system/xbin/busybox",
166
+ "/system/bin/busybox",
167
+ "/sbin/busybox",
168
+ "/data/local/xbin/busybox",
169
+ "/data/local/bin/busybox"
170
+ )
171
+
172
+ return busyboxPaths.any { File(it).exists() }
173
+ }
174
+
175
+ /**
176
+ * Check for root management apps
177
+ */
178
+ private fun checkRootApps(): Boolean {
179
+ val rootApps = listOf(
180
+ "com.noshufou.android.su",
181
+ "com.thirdparty.superuser",
182
+ "eu.chainfire.supersu",
183
+ "com.koushikdutta.superuser",
184
+ "com.topjohnwu.magisk",
185
+ "com.topjohnwu.magisk.ui",
186
+ "com.kingroot.kinguser",
187
+ "com.kingo.root",
188
+ "com.smedialink.oneclickroot",
189
+ "com.zhiqupk.root",
190
+ "com.alephzain.framaroot",
191
+ "com.ramdroid.appquarantine",
192
+ "com.ramdroid.appquarantinepro",
193
+ "com.devadvance.rootcloak",
194
+ "com.devadvance.rootcloakplus",
195
+ "de.robv.android.xposed.installer",
196
+ "com.saurik.substrate",
197
+ "com.zachspong.temprootremovejb",
198
+ "com.amphoras.hidemyroot",
199
+ "com.amphoras.hidemyrootadfree",
200
+ "com.formyhm.hiderootPremium",
201
+ "com.formyhm.hideroot",
202
+ "me.phh.superuser",
203
+ "eu.chainfire.firefdsuid",
204
+ "com.koushikdutta.rommanager",
205
+ "com.koushikdutta.rommanager.license",
206
+ "com.dimonvideo.luckypatcher",
207
+ "com.chelpus.luckypatcher",
208
+ "com.android.vending.billing.InAppBillingService.COIN",
209
+ "com.android.vending.billing.InAppBillingService.LUCK",
210
+ "com.topjohnwu.magisk.ua"
211
+ )
212
+
213
+ return rootApps.any { isPackageInstalled(it) }
214
+ }
215
+
216
+ /**
217
+ * Check if package is installed
218
+ */
219
+ private fun isPackageInstalled(packageName: String): Boolean {
220
+ return try {
221
+ context.packageManager.getPackageInfo(packageName, 0)
222
+ true
223
+ } catch (e: PackageManager.NameNotFoundException) {
224
+ false
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Check system properties for root indicators
230
+ */
231
+ private fun checkSystemProperties(): Boolean {
232
+ return checkDangerousSystemProperties() ||
233
+ checkSystemRemounted() ||
234
+ checkForDangerousBuildProps()
235
+ }
236
+
237
+ /**
238
+ * Check for dangerous system properties
239
+ */
240
+ private fun checkDangerousSystemProperties(): Boolean {
241
+ val dangerousProps = listOf(
242
+ "ro.debuggable",
243
+ "ro.secure",
244
+ "service.adb.root",
245
+ "ro.build.selinux"
246
+ )
247
+
248
+ for (prop in dangerousProps) {
249
+ val value = getSystemProperty(prop)
250
+ when (prop) {
251
+ "ro.debuggable" -> {
252
+ // 1 means debuggable (should be 0 on production)
253
+ if (value == "1") return true
254
+ }
255
+ "ro.secure" -> {
256
+ // 0 means insecure (should be 1 on production)
257
+ if (value == "0") return true
258
+ }
259
+ "service.adb.root" -> {
260
+ // 1 means adb root is enabled
261
+ if (value == "1") return true
262
+ }
263
+ }
264
+ }
265
+
266
+ return false
267
+ }
268
+
269
+ /**
270
+ * Check if system is remounted as RW (indicates root)
271
+ */
272
+ private fun checkSystemRemounted(): Boolean {
273
+ val systemMounts = listOf(
274
+ "/system",
275
+ "/vendor",
276
+ "/product",
277
+ "/system_ext"
278
+ )
279
+
280
+ // Read mount info
281
+ try {
282
+ val bufferedReader = BufferedReader(InputStreamReader(
283
+ File("/proc/mounts").inputStream()
284
+ ))
285
+
286
+ bufferedReader.use { reader ->
287
+ var line: String?
288
+ while (reader.readLine().also { line = it } != null) {
289
+ for (mount in systemMounts) {
290
+ if (line?.contains(mount) == true) {
291
+ // Check if mounted RW (read-write)
292
+ if (line?.contains("rw,") == true ||
293
+ line?.contains(" rw ") == true) {
294
+ return true
295
+ }
296
+ }
297
+ }
298
+ }
299
+ }
300
+ } catch (e: Exception) {
301
+ // Ignore errors
302
+ }
303
+
304
+ return false
305
+ }
306
+
307
+ /**
308
+ * Check for dangerous build.prop modifications
309
+ */
310
+ private fun checkForDangerousBuildProps(): Boolean {
311
+ try {
312
+ val buildProps = listOf(
313
+ "/system/build.prop",
314
+ "/vendor/build.prop",
315
+ "/product/build.prop",
316
+ "/system_ext/build.prop"
317
+ )
318
+
319
+ for (propFile in buildProps) {
320
+ val file = File(propFile)
321
+ if (file.exists()) {
322
+ // Check if file is writable (should not be on production)
323
+ if (file.canWrite()) {
324
+ return true
325
+ }
326
+ }
327
+ }
328
+ } catch (e: Exception) {
329
+ // Ignore errors
330
+ }
331
+
332
+ return false
333
+ }
334
+
335
+ /**
336
+ * Get system property value
337
+ */
338
+ private fun getSystemProperty(prop: String): String? {
339
+ return try {
340
+ val process = Runtime.getRuntime().exec("getprop $prop")
341
+ val reader = BufferedReader(InputStreamReader(process.inputStream))
342
+ val value = reader.readLine()
343
+ reader.close()
344
+ value
345
+ } catch (e: Exception) {
346
+ null
347
+ }
348
+ }
349
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _reactNative = require("react-native");
8
+ var _default = exports.default = _reactNative.TurboModuleRegistry.getEnforcing('DeviceSecurity');
9
+ //# sourceMappingURL=NativeDeviceSecurity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeDeviceSecurity.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAAmD,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GA+BpCC,gCAAmB,CAACC,YAAY,CAAO,gBAAgB,CAAC","ignoreList":[]}