react-native-security-pack 1.0.1 → 2.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 (73) hide show
  1. package/README.md +181 -13
  2. package/android/CMakeLists.txt +24 -0
  3. package/android/build.gradle +55 -60
  4. package/android/fix-prefab.gradle +44 -0
  5. package/android/gradle.properties +5 -5
  6. package/android/src/main/cpp/cpp-adapter.cpp +6 -0
  7. package/android/src/main/java/com/leerman/rnsecuritypack/RNSecurityPackPackage.kt +23 -0
  8. package/android/src/main/java/com/margelo/nitro/rnsecuritypack/HybridSecurityPack.kt +85 -0
  9. package/ios/HybridSecurityPack.swift +17 -0
  10. package/jest/mock.js +7 -0
  11. package/lib/commonjs/index.js +24 -17
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/specs/SecurityPack.nitro.js +6 -0
  14. package/lib/commonjs/specs/SecurityPack.nitro.js.map +1 -0
  15. package/lib/module/index.js +25 -18
  16. package/lib/module/index.js.map +1 -1
  17. package/lib/module/specs/SecurityPack.nitro.js +4 -0
  18. package/lib/module/specs/SecurityPack.nitro.js.map +1 -0
  19. package/lib/typescript/commonjs/src/index.d.ts +7 -0
  20. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  21. package/lib/typescript/commonjs/src/specs/SecurityPack.nitro.d.ts +9 -0
  22. package/lib/typescript/commonjs/src/specs/SecurityPack.nitro.d.ts.map +1 -0
  23. package/lib/typescript/module/src/index.d.ts +7 -0
  24. package/lib/typescript/module/src/index.d.ts.map +1 -1
  25. package/lib/typescript/module/src/specs/SecurityPack.nitro.d.ts +9 -0
  26. package/lib/typescript/module/src/specs/SecurityPack.nitro.d.ts.map +1 -0
  27. package/nitro.json +24 -0
  28. package/nitrogen/generated/.gitattributes +1 -0
  29. package/nitrogen/generated/android/RNSecurityPack+autolinking.cmake +81 -0
  30. package/nitrogen/generated/android/RNSecurityPack+autolinking.gradle +27 -0
  31. package/nitrogen/generated/android/RNSecurityPackOnLoad.cpp +54 -0
  32. package/nitrogen/generated/android/RNSecurityPackOnLoad.hpp +34 -0
  33. package/nitrogen/generated/android/c++/JHybridSecurityPackSpec.cpp +92 -0
  34. package/nitrogen/generated/android/c++/JHybridSecurityPackSpec.hpp +64 -0
  35. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rnsecuritypack/HybridSecurityPackSpec.kt +59 -0
  36. package/nitrogen/generated/android/kotlin/com/margelo/nitro/rnsecuritypack/RNSecurityPackOnLoad.kt +35 -0
  37. package/nitrogen/generated/ios/RNSecurityPack+autolinking.rb +62 -0
  38. package/nitrogen/generated/ios/RNSecurityPack-Swift-Cxx-Bridge.cpp +57 -0
  39. package/nitrogen/generated/ios/RNSecurityPack-Swift-Cxx-Bridge.hpp +166 -0
  40. package/nitrogen/generated/ios/RNSecurityPack-Swift-Cxx-Umbrella.hpp +46 -0
  41. package/nitrogen/generated/ios/RNSecurityPackAutolinking.mm +33 -0
  42. package/nitrogen/generated/ios/RNSecurityPackAutolinking.swift +26 -0
  43. package/nitrogen/generated/ios/c++/HybridSecurityPackSpecSwift.cpp +11 -0
  44. package/nitrogen/generated/ios/c++/HybridSecurityPackSpecSwift.hpp +92 -0
  45. package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  46. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  47. package/nitrogen/generated/ios/swift/Func_void_std__vector_std__string_.swift +46 -0
  48. package/nitrogen/generated/ios/swift/HybridSecurityPackSpec.swift +56 -0
  49. package/nitrogen/generated/ios/swift/HybridSecurityPackSpec_cxx.swift +170 -0
  50. package/nitrogen/generated/shared/c++/HybridSecurityPackSpec.cpp +22 -0
  51. package/nitrogen/generated/shared/c++/HybridSecurityPackSpec.hpp +65 -0
  52. package/package.json +36 -42
  53. package/react-native-security-pack.podspec +18 -27
  54. package/react-native.config.js +1 -0
  55. package/src/index.ts +39 -0
  56. package/src/specs/SecurityPack.nitro.ts +7 -0
  57. package/android/src/main/AndroidManifestNew.xml +0 -2
  58. package/android/src/main/java/com/leerman/rnsecuritypack/SecurityPackModule.kt +0 -85
  59. package/android/src/main/java/com/leerman/rnsecuritypack/SecurityPackPackage.kt +0 -35
  60. package/android/src/newarch/SecurityPackSpec.kt +0 -7
  61. package/android/src/oldarch/SecurityPackSpec.kt +0 -12
  62. package/ios/SecurityPack.h +0 -12
  63. package/ios/SecurityPack.mm +0 -25
  64. package/lib/commonjs/NativeSecurityPack.js +0 -9
  65. package/lib/commonjs/NativeSecurityPack.js.map +0 -1
  66. package/lib/module/NativeSecurityPack.js +0 -5
  67. package/lib/module/NativeSecurityPack.js.map +0 -1
  68. package/lib/typescript/commonjs/src/NativeSecurityPack.d.ts +0 -8
  69. package/lib/typescript/commonjs/src/NativeSecurityPack.d.ts.map +0 -1
  70. package/lib/typescript/module/src/NativeSecurityPack.d.ts +0 -8
  71. package/lib/typescript/module/src/NativeSecurityPack.d.ts.map +0 -1
  72. package/src/NativeSecurityPack.ts +0 -9
  73. package/src/index.tsx +0 -43
package/README.md CHANGED
@@ -1,33 +1,201 @@
1
1
  # react-native-security-pack
2
2
 
3
- security
3
+ Библиотека для React Native с проверками безопасности на устройстве:
4
4
 
5
- ## Installation
5
+ - **Android** — определение root и сверка SHA-1 отпечатков подписи APK
6
+ - **iOS** — определение jailbreak (проверка подписи APK не применима)
7
+
8
+ Реализована на [Nitro Modules](https://nitro.margelo.com/) (JSI, New Architecture). Используйте **v1** для Bridge-архитектуры RN.
9
+
10
+ ## Требования
11
+
12
+ | Зависимость | Версия |
13
+ |-------------|--------|
14
+ | React Native | `>= 0.75` |
15
+ | New Architecture | **обязательна** (`newArchEnabled=true`) |
16
+ | [react-native-nitro-modules](https://github.com/mrousavy/nitro) | `>= 0.35` |
17
+ | iOS | `>= 15.1` |
18
+ | Android | `>= 24` (Android 7.0 Nougat) |
19
+
20
+ ## Установка
21
+
22
+ ```sh
23
+ yarn add react-native-security-pack react-native-nitro-modules
24
+ # или
25
+ npm install react-native-security-pack react-native-nitro-modules
26
+ ```
27
+
28
+ ### Android
29
+
30
+ В `android/gradle.properties` приложения:
31
+
32
+ ```properties
33
+ newArchEnabled=true
34
+ ```
35
+
36
+ Пересоберите проект:
37
+
38
+ ```sh
39
+ cd android && ./gradlew clean
40
+ ```
41
+
42
+ ### iOS
43
+
44
+ ```sh
45
+ cd ios && pod install
46
+ ```
47
+
48
+ Убедитесь, что в Podfile включена New Architecture (по умолчанию в RN 0.76+).
49
+
50
+ ## API
51
+
52
+ ### `isRooted(): Promise<boolean>`
53
+
54
+ Возвращает `true`, если устройство, по мнению нативных эвристик, скомпрометировано:
55
+
56
+ - **Android** — [RootBeer Fresh](https://github.com/kimchangyoun/rootbeerFresh)
57
+ - **iOS** — [DTTJailbreakDetection](https://github.com/thii/DTTJailbreakDetection)
58
+
59
+ ```ts
60
+ import { isRooted } from 'react-native-security-pack';
61
+
62
+ const rooted = await isRooted();
63
+ if (rooted) {
64
+ // заблокировать чувствительный сценарий
65
+ }
66
+ ```
67
+
68
+ ### `containsSignatures(signatures: string[]): Promise<boolean>`
69
+
70
+ Проверяет, совпадает ли **хотя бы один** переданный SHA-1 отпечаток с сертификатом, которым подписан установленный APK.
71
+
72
+ - Отпечатки можно передавать в любом регистре — сравнение нечувствительно к регистру.
73
+ - На **iOS** всегда возвращает `true` (у iOS нет APK-подписи; используйте другие механизмы защиты).
74
+
75
+ ```ts
76
+ import { containsSignatures } from 'react-native-security-pack';
77
+
78
+ const releaseKey = '5E8F16062EA3CD2C4A0D547876BAA6F38CABF625';
79
+
80
+ const valid = await containsSignatures([releaseKey]);
81
+ if (!valid) {
82
+ // возможная пересборка / репак APK
83
+ }
84
+ ```
85
+
86
+ #### Как получить SHA-1 подписи
87
+
88
+ ```sh
89
+ # debug keystore (пример)
90
+ keytool -list -v -keystore android/app/debug.keystore -alias androiddebugkey -storepass android -keypass android
91
+
92
+ # release (ваш keystore)
93
+ keytool -list -v -keystore your-release.keystore -alias your-alias
94
+ ```
95
+
96
+ Скопируйте значение **SHA1** без двоеточий или с ними — библиотека нормализует регистр.
97
+
98
+ ## Пример
99
+
100
+ ```tsx
101
+ import { useEffect, useState } from 'react';
102
+ import { containsSignatures, isRooted } from 'react-native-security-pack';
103
+
104
+ export function SecurityCheck() {
105
+ const [state, setState] = useState({ rooted: false, signatureOk: false });
106
+
107
+ useEffect(() => {
108
+ isRooted().then((rooted) => setState((s) => ({ ...s, rooted })));
109
+ containsSignatures(['YOUR_RELEASE_SHA1']).then((signatureOk) =>
110
+ setState((s) => ({ ...s, signatureOk }))
111
+ );
112
+ }, []);
113
+
114
+ return null;
115
+ }
116
+ ```
117
+
118
+ Запуск example-приложения из корня репозитория:
6
119
 
7
120
  ```sh
8
- npm install react-native-security-pack
121
+ yarn install
122
+ yarn prepare # nitrogen + сборка JS
123
+ yarn example android
124
+ yarn example ios
9
125
  ```
10
126
 
11
- ## Usage
127
+ ## Миграция с v1
12
128
 
129
+ | v1 | v2 |
130
+ |----|-----|
131
+ | TurboModule / legacy bridge | Nitro Hybrid Object |
132
+ | `codegenConfig` в package.json | `nitro.json` + Nitrogen |
133
+ | Работало без New Architecture | **Только** New Architecture |
134
+ | Без peer `react-native-nitro-modules` | Peer-зависимость обязательна |
135
+
136
+ Публичный JS API (`isRooted`, `containsSignatures`) **не изменился**.
137
+
138
+ ## Разработка библиотеки
139
+
140
+ ```sh
141
+ yarn install
142
+ yarn specs # npx nitrogen — регенерация nitrogen/generated
143
+ yarn prepare # specs + react-native-builder-bob
144
+ yarn test
145
+ yarn typecheck
146
+ ```
147
+
148
+ Нативные реализации:
149
+
150
+ - `android/src/main/java/com/leerman/rnsecuritypack/HybridSecurityPack.kt`
151
+ - `ios/HybridSecurityPack.swift`
152
+ - Спека: `src/specs/SecurityPack.nitro.ts`
153
+
154
+ После изменения `.nitro.ts` снова выполните `yarn specs`.
155
+
156
+ ## Тестирование (Jest)
157
+
158
+ Добавьте `moduleNameMapper` в конфигурацию Jest:
13
159
 
14
160
  ```js
15
- import { multiply } from 'react-native-security-pack';
161
+ // jest.config.js
162
+ module.exports = {
163
+ // ...
164
+ moduleNameMapper: {
165
+ 'react-native-security-pack': 'react-native-security-pack/jest/mock',
166
+ },
167
+ };
168
+ ```
169
+
170
+ По умолчанию мок возвращает:
16
171
 
17
- // ...
172
+ | Функция | Значение |
173
+ |---------|----------|
174
+ | `isRooted()` | `false` |
175
+ | `containsSignatures(...)` | `true` |
18
176
 
19
- const result = await multiply(3, 7);
177
+ Мок построен на `jest.fn()`, поэтому можно переопределять поведение в конкретных тестах:
178
+
179
+ ```ts
180
+ import { isRooted, containsSignatures } from 'react-native-security-pack';
181
+
182
+ jest.mocked(isRooted).mockResolvedValueOnce(true);
183
+ jest.mocked(containsSignatures).mockResolvedValueOnce(false);
20
184
  ```
21
185
 
186
+ ## Устранение неполадок
187
+
188
+ Частые проблемы и их решения собраны в [TROUBLESHOOTING.md](TROUBLESHOOTING.md).
22
189
 
23
- ## Contributing
190
+ ## Ограничения
24
191
 
25
- See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
192
+ Проверки root/jailbreak и подписи APK **эвристики**. Опытный атакующий может их обойти. Используйте как один слой защиты вместе с серверной валидацией, certificate pinning, Play Integrity / App Attest и т.д.
26
193
 
27
- ## License
194
+ ## Лицензия
28
195
 
29
- MIT
196
+ MIT — см. [LICENSE](LICENSE).
30
197
 
31
- ---
198
+ ## Авторы
32
199
 
33
- Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
200
+ Andrew Timofeev ([@leerman](https://github.com/leerman))
201
+ Aleksandr Nikolaevich ([@AleksandrNikolaevich](https://github.com/AleksandrNikolaevich))
@@ -0,0 +1,24 @@
1
+ project(RNSecurityPack)
2
+ cmake_minimum_required(VERSION 3.9.0)
3
+
4
+ set(PACKAGE_NAME RNSecurityPack)
5
+ set(CMAKE_VERBOSE_MAKEFILE ON)
6
+ set(CMAKE_CXX_STANDARD 20)
7
+
8
+ add_library(${PACKAGE_NAME} SHARED
9
+ src/main/cpp/cpp-adapter.cpp
10
+ )
11
+
12
+ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/RNSecurityPack+autolinking.cmake)
13
+
14
+ include_directories(
15
+ "src/main/cpp"
16
+ )
17
+
18
+ find_library(LOG_LIB log)
19
+
20
+ target_link_libraries(
21
+ ${PACKAGE_NAME}
22
+ ${LOG_LIB}
23
+ android
24
+ )
@@ -1,16 +1,11 @@
1
1
  buildscript {
2
- // Buildscript is evaluated before everything else so we can't use getExtOrDefault
3
- def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["SecurityPack_kotlinVersion"]
4
-
5
2
  repositories {
6
3
  google()
7
4
  mavenCentral()
8
5
  }
9
6
 
10
7
  dependencies {
11
- classpath "com.android.tools.build:gradle:7.2.1"
12
- // noinspection DifferentKotlinGradleVersion
13
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
8
+ classpath "com.android.tools.build:gradle:8.7.2"
14
9
  }
15
10
  }
16
11
 
@@ -24,40 +19,26 @@ def isNewArchitectureEnabled() {
24
19
  }
25
20
 
26
21
  apply plugin: "com.android.library"
27
- apply plugin: "kotlin-android"
22
+ apply plugin: "org.jetbrains.kotlin.android"
23
+ apply from: "../nitrogen/generated/android/RNSecurityPack+autolinking.gradle"
24
+ apply from: "./fix-prefab.gradle"
28
25
 
29
26
  if (isNewArchitectureEnabled()) {
30
27
  apply plugin: "com.facebook.react"
31
28
  }
32
29
 
33
30
  def getExtOrDefault(name) {
34
- return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["SecurityPack_" + name]
31
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["RNSecurityPack_" + name]
35
32
  }
36
33
 
37
34
  def getExtOrIntegerDefault(name) {
38
- return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["SecurityPack_" + name]).toInteger()
39
- }
40
-
41
- def supportsNamespace() {
42
- def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
43
- def major = parsed[0].toInteger()
44
- def minor = parsed[1].toInteger()
45
-
46
- // Namespace support was added in 7.3.0
47
- return (major == 7 && minor >= 3) || major >= 8
35
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RNSecurityPack_" + name]).toInteger()
48
36
  }
49
37
 
50
38
  android {
51
- if (supportsNamespace()) {
52
- namespace "com.leerman.rnsecuritypack"
53
-
54
- sourceSets {
55
- main {
56
- manifest.srcFile "src/main/AndroidManifestNew.xml"
57
- }
58
- }
59
- }
39
+ namespace "com.leerman.rnsecuritypack"
60
40
 
41
+ ndkVersion getExtOrDefault("ndkVersion")
61
42
  compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
62
43
 
63
44
  defaultConfig {
@@ -65,10 +46,54 @@ android {
65
46
  targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
66
47
  buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
67
48
 
49
+ externalNativeBuild {
50
+ cmake {
51
+ cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
52
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
53
+ abiFilters(*reactNativeArchitectures())
54
+
55
+ buildTypes {
56
+ debug {
57
+ cppFlags "-O1 -g"
58
+ }
59
+ release {
60
+ cppFlags "-O2"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ externalNativeBuild {
68
+ cmake {
69
+ path "CMakeLists.txt"
70
+ }
71
+ }
72
+
73
+ packagingOptions {
74
+ excludes = [
75
+ "META-INF",
76
+ "META-INF/**",
77
+ "**/libc++_shared.so",
78
+ "**/libfbjni.so",
79
+ "**/libjsi.so",
80
+ "**/libfolly_json.so",
81
+ "**/libfolly_runtime.so",
82
+ "**/libglog.so",
83
+ "**/libhermes.so",
84
+ "**/libhermes-executor-debug.so",
85
+ "**/libhermes_executor.so",
86
+ "**/libreactnative.so",
87
+ "**/libreactnativejni.so",
88
+ "**/libturbomodulejsijni.so",
89
+ "**/libreact_nativemodule_core.so",
90
+ "**/libjscexecutor.so",
91
+ ]
68
92
  }
69
93
 
70
94
  buildFeatures {
71
95
  buildConfig true
96
+ prefab true
72
97
  }
73
98
 
74
99
  buildTypes {
@@ -85,46 +110,16 @@ android {
85
110
  sourceCompatibility JavaVersion.VERSION_1_8
86
111
  targetCompatibility JavaVersion.VERSION_1_8
87
112
  }
88
-
89
- sourceSets {
90
- main {
91
- if (isNewArchitectureEnabled()) {
92
- java.srcDirs += [
93
- "src/newarch",
94
- // Codegen specs
95
- "generated/java",
96
- "generated/jni"
97
- ]
98
- } else {
99
- java.srcDirs += ["src/oldarch"]
100
- }
101
- }
102
- }
103
113
  }
104
114
 
105
115
  repositories {
106
116
  mavenCentral()
107
117
  google()
108
- maven { url 'https://jitpack.io' }
118
+ maven { url "https://jitpack.io" }
109
119
  }
110
120
 
111
- def kotlin_version = getExtOrDefault("kotlinVersion")
112
-
113
121
  dependencies {
114
- // For < 0.71, this will be from the local maven repo
115
- // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
116
- //noinspection GradleDynamicVersion
117
122
  implementation "com.facebook.react:react-native:+"
118
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
119
-
120
- implementation 'com.github.kimchangyoun:rootbeerFresh:0.0.10'
121
- // implementation 'com.scottyab:rootbeer-lib:0.1.0'
122
- }
123
-
124
- if (isNewArchitectureEnabled()) {
125
- react {
126
- jsRootDir = file("../src/")
127
- libraryName = "SecurityPack"
128
- codegenJavaPackageName = "com.leerman.rnsecuritypack"
129
- }
123
+ implementation project(":react-native-nitro-modules")
124
+ implementation "com.github.kimchangyoun:rootbeerFresh:0.0.10"
130
125
  }
@@ -0,0 +1,44 @@
1
+ tasks.configureEach { task ->
2
+ def prefabConfigurePattern = ~/^prefab(.+)ConfigurePackage$/
3
+ def matcher = task.name =~ prefabConfigurePattern
4
+ if (matcher.matches()) {
5
+ def variantName = matcher[0][1]
6
+ task.outputs.upToDateWhen { false }
7
+ task.dependsOn("externalNativeBuild${variantName}")
8
+ }
9
+ }
10
+
11
+ afterEvaluate {
12
+ def abis = reactNativeArchitectures()
13
+ rootProject.allprojects.each { proj ->
14
+ if (proj === rootProject) return
15
+
16
+ def dependsOnThisLib = proj.configurations.findAll { it.canBeResolved }.any { config ->
17
+ config.dependencies.any { dep ->
18
+ dep.group == project.group && dep.name == project.name
19
+ }
20
+ }
21
+ if (!dependsOnThisLib && proj != project) return
22
+
23
+ if (!proj.plugins.hasPlugin('com.android.application') && !proj.plugins.hasPlugin('com.android.library')) {
24
+ return
25
+ }
26
+
27
+ def variants = proj.android.hasProperty('applicationVariants') ? proj.android.applicationVariants : proj.android.libraryVariants
28
+ variants.all { variant ->
29
+ def variantName = variant.name
30
+ abis.each { abi ->
31
+ def searchDir = new File(proj.projectDir, ".cxx/${variantName}")
32
+ if (!searchDir.exists()) return
33
+ def matches = []
34
+ searchDir.eachDir { randomDir ->
35
+ def prefabFile = new File(randomDir, "${abi}/prefab_config.json")
36
+ if (prefabFile.exists()) matches << prefabFile
37
+ }
38
+ matches.each { prefabConfig ->
39
+ prefabConfig.setLastModified(System.currentTimeMillis())
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
@@ -1,5 +1,5 @@
1
- SecurityPack_kotlinVersion=1.7.0
2
- SecurityPack_minSdkVersion=21
3
- SecurityPack_targetSdkVersion=31
4
- SecurityPack_compileSdkVersion=31
5
- SecurityPack_ndkversion=21.4.7075529
1
+ RNSecurityPack_kotlinVersion=2.0.21
2
+ RNSecurityPack_minSdkVersion=24
3
+ RNSecurityPack_targetSdkVersion=35
4
+ RNSecurityPack_compileSdkVersion=35
5
+ RNSecurityPack_ndkVersion=27.1.12297006
@@ -0,0 +1,6 @@
1
+ #include "RNSecurityPackOnLoad.hpp"
2
+ #include <jni.h>
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::rnsecuritypack::initialize(vm);
6
+ }
@@ -0,0 +1,23 @@
1
+ package com.leerman.rnsecuritypack
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfoProvider
7
+ import com.margelo.nitro.rnsecuritypack.RNSecurityPackOnLoad
8
+
9
+ class RNSecurityPackPackage : BaseReactPackage() {
10
+ override fun getModule(
11
+ name: String,
12
+ reactContext: ReactApplicationContext,
13
+ ): NativeModule? = null
14
+
15
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider =
16
+ ReactModuleInfoProvider { emptyMap() }
17
+
18
+ companion object {
19
+ init {
20
+ RNSecurityPackOnLoad.initializeNative()
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,85 @@
1
+ package com.margelo.nitro.rnsecuritypack
2
+
3
+ import android.content.pm.PackageManager
4
+ import android.os.Build
5
+ import android.util.Log
6
+ import androidx.annotation.Keep
7
+ import com.facebook.proguard.annotations.DoNotStrip
8
+ import com.kimchangyoun.rootbeerFresh.RootBeer
9
+ import com.margelo.nitro.NitroModules
10
+ import com.margelo.nitro.core.Promise
11
+ import java.security.MessageDigest
12
+
13
+ @Keep
14
+ @DoNotStrip
15
+ class HybridSecurityPack : HybridSecurityPackSpec() {
16
+ private val context =
17
+ NitroModules.applicationContext
18
+ ?: throw IllegalStateException("Android application context is not available")
19
+
20
+ override fun getSignatures(): Promise<Array<String>> {
21
+ Log.d(TAG, "getSignatures()")
22
+ return Promise.async {
23
+ try {
24
+ val packageName = context.packageName
25
+ val signatures =
26
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
27
+ val signingInfo =
28
+ context.packageManager.getPackageInfo(
29
+ packageName,
30
+ PackageManager.GET_SIGNING_CERTIFICATES,
31
+ ).signingInfo
32
+ ?: return@async emptyArray()
33
+
34
+ if (signingInfo.hasMultipleSigners()) {
35
+ signingInfo.apkContentsSigners
36
+ } else {
37
+ signingInfo.signingCertificateHistory
38
+ }
39
+ } else {
40
+ @Suppress("DEPRECATION")
41
+ context.packageManager.getPackageInfo(
42
+ packageName,
43
+ PackageManager.GET_SIGNATURES,
44
+ ).signatures ?: emptyArray()
45
+ }
46
+
47
+ signatures
48
+ .map { certificate ->
49
+ val digest = MessageDigest.getInstance("SHA")
50
+ digest.update(certificate.toByteArray())
51
+ bytesToHex(digest.digest())
52
+ }
53
+ .toTypedArray()
54
+ } catch (e: Exception) {
55
+ Log.e(TAG, "getSignatures failed", e)
56
+ emptyArray()
57
+ }
58
+ }
59
+ }
60
+
61
+ override fun isRooted(): Promise<Boolean> {
62
+ Log.d(TAG, "isRooted()")
63
+ return Promise.async {
64
+ RootBeer(context).isRooted
65
+ }
66
+ }
67
+
68
+ private fun bytesToHex(bytes: ByteArray): String {
69
+ val hexArray = charArrayOf(
70
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
71
+ 'A', 'B', 'C', 'D', 'E', 'F',
72
+ )
73
+ val hexChars = CharArray(bytes.size * 2)
74
+ for (j in bytes.indices) {
75
+ val v = bytes[j].toInt() and 0xFF
76
+ hexChars[j * 2] = hexArray[v ushr 4]
77
+ hexChars[j * 2 + 1] = hexArray[v and 0x0F]
78
+ }
79
+ return String(hexChars)
80
+ }
81
+
82
+ companion object {
83
+ private const val TAG = "HybridSecurityPack"
84
+ }
85
+ }
@@ -0,0 +1,17 @@
1
+ import DTTJailbreakDetection
2
+ import NitroModules
3
+
4
+ class HybridSecurityPack: HybridSecurityPackSpec {
5
+ func getSignatures() throws -> Promise<[String]> {
6
+ // APK signing certificates are Android-only.
7
+ return Promise.async {
8
+ []
9
+ }
10
+ }
11
+
12
+ func isRooted() throws -> Promise<Bool> {
13
+ return Promise.async {
14
+ DTTJailbreakDetection.isJailbroken()
15
+ }
16
+ }
17
+ }
package/jest/mock.js ADDED
@@ -0,0 +1,7 @@
1
+ /* eslint-env jest */
2
+ 'use strict';
3
+
4
+ module.exports = {
5
+ isRooted: jest.fn(() => Promise.resolve(false)),
6
+ containsSignatures: jest.fn(() => Promise.resolve(true)),
7
+ };
@@ -6,29 +6,36 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.containsSignatures = containsSignatures;
7
7
  exports.isRooted = isRooted;
8
8
  var _reactNative = require("react-native");
9
- const LINKING_ERROR = `The package 'react-native-security-pack' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
10
- ios: "- You have run 'pod install'\n",
11
- default: ''
12
- }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
13
-
14
- // @ts-expect-error
15
- const isTurboModuleEnabled = global.__turboModuleProxy != null;
16
- const SecurityPackModule = isTurboModuleEnabled ? require('./NativeSecurityPack').default : _reactNative.NativeModules.SecurityPack;
17
- const SecurityPack = SecurityPackModule ? SecurityPackModule : new Proxy({}, {
18
- get() {
19
- throw new Error(LINKING_ERROR);
9
+ var _reactNativeNitroModules = require("react-native-nitro-modules");
10
+ let securityPack = null;
11
+ function getSecurityPack() {
12
+ if (securityPack == null) {
13
+ securityPack = _reactNativeNitroModules.NitroModules.createHybridObject('SecurityPack');
20
14
  }
21
- });
15
+ return securityPack;
16
+ }
22
17
  async function getSignatures() {
23
- return (await SecurityPack.getSignatures()).map(item => item.toUpperCase());
18
+ const signatures = await getSecurityPack().getSignatures();
19
+ return signatures.map(item => item.toUpperCase());
24
20
  }
21
+
22
+ /**
23
+ * Checks whether the app's signing certificate matches any of the given SHA-1
24
+ * fingerprints (hex, case-insensitive).
25
+ *
26
+ * On iOS this always returns `true` because APK signatures are Android-only.
27
+ */
25
28
  async function containsSignatures(sigs) {
26
- if (_reactNative.Platform.OS === 'ios') return true;
29
+ if (_reactNative.Platform.OS === 'ios') {
30
+ return true;
31
+ }
27
32
  const signatures = await getSignatures();
28
- const sigUpper = sigs.map(item => item.toUpperCase());
29
- return signatures.some(item => sigUpper.includes(item));
33
+ const expected = sigs.map(item => item.toUpperCase());
34
+ return signatures.some(item => expected.includes(item));
30
35
  }
36
+
37
+ /** Returns `true` when the device appears to be rooted (Android) or jailbroken (iOS). */
31
38
  async function isRooted() {
32
- return SecurityPack.isRooted();
39
+ return await getSecurityPack().isRooted();
33
40
  }
34
41
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","isTurboModuleEnabled","global","__turboModuleProxy","SecurityPackModule","NativeModules","SecurityPack","Proxy","get","Error","getSignatures","map","item","toUpperCase","containsSignatures","sigs","OS","signatures","sigUpper","some","includes","isRooted"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GACjB,qFAAqF,GACrFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;;AAEjC;AACA,MAAMC,oBAAoB,GAAGC,MAAM,CAACC,kBAAkB,IAAI,IAAI;AAE9D,MAAMC,kBAAkB,GAAGH,oBAAoB,GAC3CN,OAAO,CAAC,sBAAsB,CAAC,CAACK,OAAO,GACvCK,0BAAa,CAACC,YAAY;AAE9B,MAAMA,YAAY,GAAGF,kBAAkB,GACnCA,kBAAkB,GAClB,IAAIG,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACb,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAEL,eAAec,aAAaA,CAAA,EAAsB;EAChD,OAAO,CAAC,MAAMJ,YAAY,CAACI,aAAa,CAAC,CAAC,EAAEC,GAAG,CAAEC,IAAY,IAC3DA,IAAI,CAACC,WAAW,CAAC,CACnB,CAAC;AACH;AAEO,eAAeC,kBAAkBA,CAACC,IAAc,EAAoB;EACzE,IAAIlB,qBAAQ,CAACmB,EAAE,KAAK,KAAK,EAAE,OAAO,IAAI;EAEtC,MAAMC,UAAoB,GAAG,MAAMP,aAAa,CAAC,CAAC;EAClD,MAAMQ,QAAQ,GAAGH,IAAI,CAACJ,GAAG,CAAEC,IAAI,IAAKA,IAAI,CAACC,WAAW,CAAC,CAAC,CAAC;EACvD,OAAOI,UAAU,CAACE,IAAI,CAAEP,IAAI,IAAKM,QAAQ,CAACE,QAAQ,CAACR,IAAI,CAAC,CAAC;AAC3D;AAEO,eAAeS,QAAQA,CAAA,EAAqB;EACjD,OAAOf,YAAY,CAACe,QAAQ,CAAC,CAAC;AAChC","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","_reactNativeNitroModules","securityPack","getSecurityPack","NitroModules","createHybridObject","getSignatures","signatures","map","item","toUpperCase","containsSignatures","sigs","Platform","OS","expected","some","includes","isRooted"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,wBAAA,GAAAD,OAAA;AAGA,IAAIE,YAAqC,GAAG,IAAI;AAEhD,SAASC,eAAeA,CAAA,EAAqB;EAC3C,IAAID,YAAY,IAAI,IAAI,EAAE;IACxBA,YAAY,GACVE,qCAAY,CAACC,kBAAkB,CAAmB,cAAc,CAAC;EACrE;EACA,OAAOH,YAAY;AACrB;AAEA,eAAeI,aAAaA,CAAA,EAAsB;EAChD,MAAMC,UAAU,GAAG,MAAMJ,eAAe,CAAC,CAAC,CAACG,aAAa,CAAC,CAAC;EAC1D,OAAOC,UAAU,CAACC,GAAG,CAAEC,IAAI,IAAKA,IAAI,CAACC,WAAW,CAAC,CAAC,CAAC;AACrD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,eAAeC,kBAAkBA,CAACC,IAAc,EAAoB;EACzE,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,OAAO,IAAI;EACb;EAEA,MAAMP,UAAU,GAAG,MAAMD,aAAa,CAAC,CAAC;EACxC,MAAMS,QAAQ,GAAGH,IAAI,CAACJ,GAAG,CAAEC,IAAI,IAAKA,IAAI,CAACC,WAAW,CAAC,CAAC,CAAC;EACvD,OAAOH,UAAU,CAACS,IAAI,CAAEP,IAAI,IAAKM,QAAQ,CAACE,QAAQ,CAACR,IAAI,CAAC,CAAC;AAC3D;;AAEA;AACO,eAAeS,QAAQA,CAAA,EAAqB;EACjD,OAAO,MAAMf,eAAe,CAAC,CAAC,CAACe,QAAQ,CAAC,CAAC;AAC3C","ignoreList":[]}