react-native-ssl-manager 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -0
- package/android/src/main/java/com/usesslpinning/PinnedOkHttpClient.kt +106 -0
- package/android/ssl-pinning-setup.gradle +185 -8
- package/app.plugin.js +99 -3
- package/package.json +2 -12
- package/react-native-ssl-manager.podspec +1 -1
- package/scripts/bun-postinstall.js +99 -0
- package/scripts/nsc-utils.js +82 -0
- package/scripts/postinstall.js +180 -0
- package/scripts/test-bun.js +64 -0
- package/lib/commonjs/index.js +0 -42
- package/lib/commonjs/index.js.map +0 -1
- package/lib/module/index.js +0 -33
- package/lib/module/index.js.map +0 -1
- package/lib/typescript/src/index.d.ts +0 -15
- package/lib/typescript/src/index.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -223,6 +223,118 @@ Your `ssl_config.json` should follow this structure:
|
|
|
223
223
|
- ❌ **Don't rename** the file - it must be exactly `ssl_config.json`
|
|
224
224
|
- ❌ **Don't place** in subdirectories - must be in project root
|
|
225
225
|
|
|
226
|
+
## Supported Networking Stacks
|
|
227
|
+
|
|
228
|
+
This library provides SSL pinning coverage across both platforms. The table below shows which networking stacks are covered and by which mechanism.
|
|
229
|
+
|
|
230
|
+
| Stack | Platform | Covered | Mechanism |
|
|
231
|
+
|-------|----------|---------|-----------|
|
|
232
|
+
| `fetch` / `axios` (React Native) | iOS | Yes | TrustKit swizzling (`kTSKSwizzleNetworkDelegates`) |
|
|
233
|
+
| `URLSession` (Foundation) | iOS | Yes | TrustKit swizzling |
|
|
234
|
+
| `SDWebImage` | iOS | Yes | TrustKit swizzling (uses URLSession) |
|
|
235
|
+
| `Alamofire` | iOS | Yes | TrustKit swizzling (uses URLSession) |
|
|
236
|
+
| Most URLSession-based libraries | iOS | Yes* | TrustKit swizzling |
|
|
237
|
+
| `fetch` / `axios` (React Native) | Android | Yes | OkHttpClientFactory + Network Security Config |
|
|
238
|
+
| OkHttp (direct) | Android | Yes | Network Security Config |
|
|
239
|
+
| Cronet (`react-native-nitro-fetch`) | Android | Best-effort* | Network Security Config |
|
|
240
|
+
| Android WebView | Android | Yes | Network Security Config |
|
|
241
|
+
| Coil / Ktor with OkHttp engine | Android | Yes | Network Security Config |
|
|
242
|
+
| Glide / OkHttp3 (`react-native-fast-image`) | Android | Yes | Network Security Config |
|
|
243
|
+
| `HttpURLConnection` | Android | Yes | Network Security Config |
|
|
244
|
+
|
|
245
|
+
### How It Works
|
|
246
|
+
|
|
247
|
+
**iOS**: TrustKit is initialized with `kTSKSwizzleNetworkDelegates: true`, which swizzles most `URLSession` delegates at the OS level. This means most libraries that use `URLSession` under the hood (including SDWebImage, Alamofire, and React Native's networking layer) are automatically covered without any additional configuration.
|
|
248
|
+
|
|
249
|
+
**Android**: The library auto-generates `network_security_config.xml` from `ssl_config.json` at build time and patches `AndroidManifest.xml` to reference it. Android's Network Security Config is enforced at the platform level for all networking stacks that use the default `TrustManager` — including OkHttp, WebView, Coil, Glide, and `HttpURLConnection`. Cronet coverage is best-effort and depends on whether Cronet uses the platform default TrustManager.
|
|
250
|
+
|
|
251
|
+
### Known Limitations
|
|
252
|
+
|
|
253
|
+
- **iOS**: Libraries that implement custom TLS stacks (not using `URLSession`) are NOT covered by TrustKit swizzling.
|
|
254
|
+
- **iOS**: Apps with complex custom `URLSessionDelegate` implementations or other method-swizzling libraries may experience conflicts with TrustKit's swizzling. TrustKit's own documentation notes swizzling is designed for "simple apps".
|
|
255
|
+
- **Android**: Libraries that build OkHttp with a custom `TrustManager` that bypasses the system default may bypass Network Security Config.
|
|
256
|
+
- **Android (Cronet)**: Cronet may use its own TLS stack rather than the platform default `TrustManager`, in which case NSC pin-sets are not enforced. For authoritative Cronet pinning, use `CronetEngine.Builder.addPublicKeyPins()` directly.
|
|
257
|
+
|
|
258
|
+
### PinnedOkHttpClient (Android)
|
|
259
|
+
|
|
260
|
+
For native module authors who need a pinned OkHttp client (e.g., custom Glide modules, Ktor engines), the library exposes a public singleton:
|
|
261
|
+
|
|
262
|
+
```kotlin
|
|
263
|
+
import com.usesslpinning.PinnedOkHttpClient
|
|
264
|
+
|
|
265
|
+
// Get a pinned OkHttpClient instance
|
|
266
|
+
val client = PinnedOkHttpClient.getInstance(context)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### Glide Integration
|
|
270
|
+
|
|
271
|
+
```kotlin
|
|
272
|
+
@GlideModule
|
|
273
|
+
class MyAppGlideModule : AppGlideModule() {
|
|
274
|
+
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
|
275
|
+
val client = PinnedOkHttpClient.getInstance(context)
|
|
276
|
+
registry.replace(
|
|
277
|
+
GlideUrl::class.java,
|
|
278
|
+
InputStream::class.java,
|
|
279
|
+
OkHttpUrlLoader.Factory(client)
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
#### Coil Integration
|
|
286
|
+
|
|
287
|
+
```kotlin
|
|
288
|
+
val imageLoader = ImageLoader.Builder(context)
|
|
289
|
+
.okHttpClient { PinnedOkHttpClient.getInstance(context) }
|
|
290
|
+
.build()
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### Ktor OkHttp Engine
|
|
294
|
+
|
|
295
|
+
```kotlin
|
|
296
|
+
val httpClient = HttpClient(OkHttp) {
|
|
297
|
+
engine {
|
|
298
|
+
preconfigured = PinnedOkHttpClient.getInstance(context)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### Ktor CIO Engine (Manual Pinning)
|
|
304
|
+
|
|
305
|
+
The CIO engine uses its own TLS stack and is **not** covered by Network Security Config or `PinnedOkHttpClient`. You must configure a custom `TrustManager` manually:
|
|
306
|
+
|
|
307
|
+
```kotlin
|
|
308
|
+
import io.ktor.client.*
|
|
309
|
+
import io.ktor.client.engine.cio.*
|
|
310
|
+
import java.security.cert.X509Certificate
|
|
311
|
+
import javax.net.ssl.X509TrustManager
|
|
312
|
+
|
|
313
|
+
val httpClient = HttpClient(CIO) {
|
|
314
|
+
engine {
|
|
315
|
+
https {
|
|
316
|
+
trustManager = object : X509TrustManager {
|
|
317
|
+
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
|
|
318
|
+
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
|
|
319
|
+
// Validate the leaf certificate's public key pin against
|
|
320
|
+
// your expected SHA-256 hashes from ssl_config.json
|
|
321
|
+
val leafCert = chain[0]
|
|
322
|
+
val publicKeyHash = java.security.MessageDigest
|
|
323
|
+
.getInstance("SHA-256")
|
|
324
|
+
.digest(leafCert.publicKey.encoded)
|
|
325
|
+
val pin = android.util.Base64.encodeToString(publicKeyHash, android.util.Base64.NO_WRAP)
|
|
326
|
+
val expectedPins = listOf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") // from ssl_config.json
|
|
327
|
+
if (pin !in expectedPins) {
|
|
328
|
+
throw javax.net.ssl.SSLPeerUnverifiedException("Certificate pin mismatch for CIO engine")
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
226
338
|
## Important Notes ⚠️
|
|
227
339
|
|
|
228
340
|
### Restarting After SSL Pinning Changes
|
|
@@ -305,6 +417,90 @@ const handleSSLToggle = async (enabled: boolean) => {
|
|
|
305
417
|
- Regularly update certificates before expiration
|
|
306
418
|
- Maintain multiple backup certificates
|
|
307
419
|
|
|
420
|
+
## Supported Networking Stacks
|
|
421
|
+
|
|
422
|
+
This library provides platform-level SSL pinning coverage across both iOS and Android. The table below shows which networking stacks are covered on each platform and the mechanism used.
|
|
423
|
+
|
|
424
|
+
| Stack | Platform | Covered | Mechanism |
|
|
425
|
+
|-------|----------|---------|-----------|
|
|
426
|
+
| `fetch` / `axios` (React Native) | iOS | Yes | TrustKit URLSession swizzling |
|
|
427
|
+
| `fetch` / `axios` (React Native) | Android | Yes | OkHttpClientFactory + Network Security Config |
|
|
428
|
+
| `URLSession` (Foundation) | iOS | Yes | TrustKit swizzling (`kTSKSwizzleNetworkDelegates`) |
|
|
429
|
+
| `SDWebImage` | iOS | Yes | TrustKit swizzling (uses URLSession internally) |
|
|
430
|
+
| `Alamofire` | iOS | Yes | TrustKit swizzling (uses URLSession internally) |
|
|
431
|
+
| Most URLSession-based libraries | iOS | Yes* | TrustKit swizzling |
|
|
432
|
+
| OkHttp | Android | Yes | Network Security Config + CertificatePinner |
|
|
433
|
+
| Cronet (`react-native-nitro-fetch`) | Android | Best-effort* | Network Security Config |
|
|
434
|
+
| Android WebView | Android | Yes | Network Security Config |
|
|
435
|
+
| Coil / Ktor with OkHttp engine | Android | Yes | Network Security Config |
|
|
436
|
+
| Glide / OkHttp3 (`react-native-fast-image`) | Android | Yes | Network Security Config |
|
|
437
|
+
| `HttpURLConnection` | Android | Yes | Network Security Config |
|
|
438
|
+
|
|
439
|
+
### iOS Coverage
|
|
440
|
+
|
|
441
|
+
On iOS, TrustKit is initialized with `kTSKSwizzleNetworkDelegates: true`, which automatically swizzles most `URLSession` delegates. This means **most libraries that use `URLSession` under the hood** are covered without additional configuration — including `SDWebImage`, `Alamofire`, and React Native's built-in networking.
|
|
442
|
+
|
|
443
|
+
**Known limitations:**
|
|
444
|
+
- Custom TLS stacks that do not use `URLSession` (e.g., custom OpenSSL bindings) are NOT covered by TrustKit swizzling.
|
|
445
|
+
- Apps with complex custom `URLSessionDelegate` implementations or other method-swizzling libraries may experience conflicts with TrustKit's swizzling.
|
|
446
|
+
|
|
447
|
+
### Android Coverage
|
|
448
|
+
|
|
449
|
+
On Android, the library generates a `network_security_config.xml` at build time from your `ssl_config.json`. This is enforced at the OS level for all networking stacks that use the platform default `TrustManager`, covering OkHttp, WebView, Coil, Glide, and `HttpURLConnection` without per-library configuration. Cronet coverage is best-effort (see below).
|
|
450
|
+
|
|
451
|
+
**Known limitations:**
|
|
452
|
+
- Libraries that build OkHttp with a custom `TrustManager` that bypasses the system default may not be covered by Network Security Config.
|
|
453
|
+
- **Cronet**: No authoritative documentation confirms Cronet always respects NSC `<pin-set>` directives. Cronet has its own pinning API (`CronetEngine.Builder.addPublicKeyPins()`), which should be used for guaranteed Cronet pinning.
|
|
454
|
+
|
|
455
|
+
### PinnedOkHttpClient API (Android)
|
|
456
|
+
|
|
457
|
+
For native module authors who need a pre-configured pinned OkHttp client, the library exposes `PinnedOkHttpClient`:
|
|
458
|
+
|
|
459
|
+
```kotlin
|
|
460
|
+
// Get the singleton pinned client
|
|
461
|
+
val client = PinnedOkHttpClient.getInstance(context)
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
The client reads `ssl_config.json` and configures `CertificatePinner` when SSL pinning is enabled. It returns a plain `OkHttpClient` when pinning is disabled. The singleton is automatically invalidated when the pinning state changes.
|
|
465
|
+
|
|
466
|
+
#### Glide Integration
|
|
467
|
+
|
|
468
|
+
```kotlin
|
|
469
|
+
@GlideModule
|
|
470
|
+
class MyAppGlideModule : AppGlideModule() {
|
|
471
|
+
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
|
472
|
+
val client = PinnedOkHttpClient.getInstance(context)
|
|
473
|
+
registry.replace(
|
|
474
|
+
GlideUrl::class.java,
|
|
475
|
+
InputStream::class.java,
|
|
476
|
+
OkHttpUrlLoader.Factory(client)
|
|
477
|
+
)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
#### Coil Integration
|
|
483
|
+
|
|
484
|
+
```kotlin
|
|
485
|
+
val imageLoader = ImageLoader.Builder(context)
|
|
486
|
+
.okHttpClient { PinnedOkHttpClient.getInstance(context) }
|
|
487
|
+
.build()
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
#### Ktor OkHttp Engine Integration
|
|
491
|
+
|
|
492
|
+
```kotlin
|
|
493
|
+
val httpClient = HttpClient(OkHttp) {
|
|
494
|
+
engine {
|
|
495
|
+
preconfigured = PinnedOkHttpClient.getInstance(context)
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
#### Ktor CIO Engine (Manual Pinning)
|
|
501
|
+
|
|
502
|
+
The CIO engine uses its own TLS stack and is **not** covered by Network Security Config or `PinnedOkHttpClient`. See the [Ktor CIO Engine manual pinning example](#ktor-cio-engine-manual-pinning) above for a complete code sample using a custom `TrustManager`.
|
|
503
|
+
|
|
308
504
|
## ✅ Completed Roadmap
|
|
309
505
|
|
|
310
506
|
### Recently Completed Features
|
|
@@ -344,6 +540,9 @@ const handleSSLToggle = async (enabled: boolean) => {
|
|
|
344
540
|
- Web support for React Native Web
|
|
345
541
|
- Additional certificate formats support
|
|
346
542
|
|
|
543
|
+
- 📦 **Optional Library Artifacts**
|
|
544
|
+
- `react-native-ssl-manager-glide` — first-class Glide integration with pre-configured `AppGlideModule` (currently manual via `PinnedOkHttpClient`)
|
|
545
|
+
|
|
347
546
|
## 🧪 Testing Your SSL Implementation
|
|
348
547
|
|
|
349
548
|
### Using the Example App
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
package com.usesslpinning
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import okhttp3.CertificatePinner
|
|
5
|
+
import okhttp3.OkHttpClient
|
|
6
|
+
import org.json.JSONObject
|
|
7
|
+
import java.io.IOException
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Public singleton providing a pinned OkHttpClient for native module authors.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* val client = PinnedOkHttpClient.getInstance(context)
|
|
14
|
+
*
|
|
15
|
+
* The client is configured with CertificatePinner from ssl_config.json when
|
|
16
|
+
* SSL pinning is enabled. When disabled, a plain OkHttpClient is returned.
|
|
17
|
+
*
|
|
18
|
+
* The singleton is invalidated when the pinning state changes via setUseSSLPinning.
|
|
19
|
+
*/
|
|
20
|
+
object PinnedOkHttpClient {
|
|
21
|
+
|
|
22
|
+
@Volatile
|
|
23
|
+
private var instance: OkHttpClient? = null
|
|
24
|
+
|
|
25
|
+
@Volatile
|
|
26
|
+
private var lastPinningState: Boolean? = null
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns a singleton OkHttpClient configured with certificate pinning
|
|
30
|
+
* from ssl_config.json (when SSL pinning is enabled).
|
|
31
|
+
*/
|
|
32
|
+
@JvmStatic
|
|
33
|
+
fun getInstance(context: Context): OkHttpClient {
|
|
34
|
+
val prefs = context.getSharedPreferences("AppSettings", Context.MODE_PRIVATE)
|
|
35
|
+
val useSSLPinning = prefs.getBoolean("useSSLPinning", true)
|
|
36
|
+
|
|
37
|
+
// Invalidate if pinning state changed
|
|
38
|
+
if (useSSLPinning != lastPinningState) {
|
|
39
|
+
instance = null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return instance ?: synchronized(this) {
|
|
43
|
+
instance ?: buildClient(context, useSSLPinning).also {
|
|
44
|
+
instance = it
|
|
45
|
+
lastPinningState = useSSLPinning
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Invalidate the cached client. Called when setUseSSLPinning changes state.
|
|
52
|
+
*/
|
|
53
|
+
@JvmStatic
|
|
54
|
+
fun invalidate() {
|
|
55
|
+
synchronized(this) {
|
|
56
|
+
instance = null
|
|
57
|
+
lastPinningState = null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private fun buildClient(context: Context, useSSLPinning: Boolean): OkHttpClient {
|
|
62
|
+
val builder = OkHttpClient.Builder()
|
|
63
|
+
|
|
64
|
+
if (useSSLPinning) {
|
|
65
|
+
try {
|
|
66
|
+
val configJson = readSslConfig(context)
|
|
67
|
+
if (configJson != null) {
|
|
68
|
+
val pinnerBuilder = CertificatePinner.Builder()
|
|
69
|
+
val sha256Keys = configJson.getJSONObject("sha256Keys")
|
|
70
|
+
val hostnames = sha256Keys.keys()
|
|
71
|
+
while (hostnames.hasNext()) {
|
|
72
|
+
val hostname = hostnames.next()
|
|
73
|
+
val keysArray = sha256Keys.getJSONArray(hostname)
|
|
74
|
+
for (i in 0 until keysArray.length()) {
|
|
75
|
+
pinnerBuilder.add(hostname, keysArray.getString(i))
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
builder.certificatePinner(pinnerBuilder.build())
|
|
79
|
+
}
|
|
80
|
+
} catch (_: Exception) {
|
|
81
|
+
// SSL pinning setup failed — return plain client
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return builder.build()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private fun readSslConfig(context: Context): JSONObject? {
|
|
89
|
+
// Check runtime config first (set via JS API)
|
|
90
|
+
val prefs = context.getSharedPreferences("AppSettings", Context.MODE_PRIVATE)
|
|
91
|
+
val runtimeConfig = prefs.getString("sslConfig", null)
|
|
92
|
+
if (!runtimeConfig.isNullOrEmpty()) {
|
|
93
|
+
return JSONObject(runtimeConfig)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Fall back to bundled asset
|
|
97
|
+
return try {
|
|
98
|
+
val inputStream = context.assets.open("ssl_config.json")
|
|
99
|
+
val bytes = inputStream.readBytes()
|
|
100
|
+
inputStream.close()
|
|
101
|
+
JSONObject(String(bytes, Charsets.UTF_8))
|
|
102
|
+
} catch (_: IOException) {
|
|
103
|
+
null
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -20,6 +20,146 @@ def ensureAssetsDir() {
|
|
|
20
20
|
def assetsDir = file("${projectDir}/src/main/assets")
|
|
21
21
|
def destFile = file("${projectDir}/src/main/assets/ssl_config.json")
|
|
22
22
|
|
|
23
|
+
import groovy.xml.XmlParser
|
|
24
|
+
import groovy.xml.XmlNodePrinter
|
|
25
|
+
import groovy.xml.MarkupBuilder
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate network_security_config.xml from ssl_config.json
|
|
29
|
+
* Returns true if XML was generated, false otherwise
|
|
30
|
+
*/
|
|
31
|
+
def generateNetworkSecurityConfigXml(File sslConfigFile, File xmlOutputFile) {
|
|
32
|
+
if (!sslConfigFile || !sslConfigFile.exists()) {
|
|
33
|
+
println "⚠️ SSL Config not found, skipping Network Security Config XML generation"
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def json = new groovy.json.JsonSlurper().parse(sslConfigFile)
|
|
38
|
+
def sha256Keys = json?.sha256Keys
|
|
39
|
+
if (!sha256Keys || sha256Keys.isEmpty()) {
|
|
40
|
+
println "⚠️ No sha256Keys found in ssl_config.json, skipping XML generation"
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Calculate default expiration: 1 year from now
|
|
45
|
+
def cal = Calendar.getInstance()
|
|
46
|
+
cal.add(Calendar.YEAR, 1)
|
|
47
|
+
def expirationDate = String.format("%tF", cal) // YYYY-MM-DD format
|
|
48
|
+
|
|
49
|
+
// Ensure output directory exists
|
|
50
|
+
def xmlDir = xmlOutputFile.parentFile
|
|
51
|
+
if (!xmlDir.exists()) xmlDir.mkdirs()
|
|
52
|
+
|
|
53
|
+
// Check for existing NSC and merge if present
|
|
54
|
+
if (xmlOutputFile.exists()) {
|
|
55
|
+
println "🔄 Existing network_security_config.xml found, merging pin entries"
|
|
56
|
+
mergeNetworkSecurityConfigXml(xmlOutputFile, sha256Keys, expirationDate)
|
|
57
|
+
} else {
|
|
58
|
+
writeNewNetworkSecurityConfigXml(xmlOutputFile, sha256Keys, expirationDate)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Write a fresh network_security_config.xml
|
|
66
|
+
*/
|
|
67
|
+
def writeNewNetworkSecurityConfigXml(File xmlFile, Map sha256Keys, String expirationDate) {
|
|
68
|
+
def writer = new StringWriter()
|
|
69
|
+
def xml = new MarkupBuilder(writer)
|
|
70
|
+
xml.setDoubleQuotes(true)
|
|
71
|
+
|
|
72
|
+
writer.write('<?xml version="1.0" encoding="utf-8"?>\n')
|
|
73
|
+
xml.'network-security-config' {
|
|
74
|
+
sha256Keys.each { domain, pins ->
|
|
75
|
+
'domain-config'('cleartextTrafficPermitted': 'false') {
|
|
76
|
+
'domain'('includeSubdomains': 'true', domain)
|
|
77
|
+
'pin-set'('expiration': expirationDate) {
|
|
78
|
+
pins.each { pinValue ->
|
|
79
|
+
def cleanPin = pinValue.replaceFirst('^sha256/', '')
|
|
80
|
+
'pin'('digest': 'SHA-256', cleanPin)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
xmlFile.text = writer.toString()
|
|
88
|
+
println "✅ Generated network_security_config.xml with ${sha256Keys.size()} domain(s)"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Merge pin-set entries into an existing network_security_config.xml
|
|
93
|
+
* Preserves existing config (debug-overrides, base-config, other domain-configs)
|
|
94
|
+
* Replaces pin-set for domains that already exist, adds new domain-configs otherwise
|
|
95
|
+
*/
|
|
96
|
+
def mergeNetworkSecurityConfigXml(File xmlFile, Map sha256Keys, String expirationDate) {
|
|
97
|
+
def parser = new XmlParser()
|
|
98
|
+
def root = parser.parse(xmlFile)
|
|
99
|
+
|
|
100
|
+
sha256Keys.each { domain, pins ->
|
|
101
|
+
// Find existing domain-config for this domain
|
|
102
|
+
def existingDomainConfig = root.'domain-config'.find { dc ->
|
|
103
|
+
dc.'domain'.any { d -> d.text() == domain }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (existingDomainConfig) {
|
|
107
|
+
println "⚠️ Replacing existing pin-set for domain: ${domain}"
|
|
108
|
+
// Remove old pin-set(s)
|
|
109
|
+
existingDomainConfig.'pin-set'.each { existingDomainConfig.remove(it) }
|
|
110
|
+
// Add new pin-set
|
|
111
|
+
def pinSetNode = new Node(existingDomainConfig, 'pin-set', [expiration: expirationDate])
|
|
112
|
+
pins.each { pinValue ->
|
|
113
|
+
def cleanPin = pinValue.replaceFirst('^sha256/', '')
|
|
114
|
+
new Node(pinSetNode, 'pin', [digest: 'SHA-256'], cleanPin)
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
// Add new domain-config
|
|
118
|
+
def domainConfigNode = new Node(root, 'domain-config', [cleartextTrafficPermitted: 'false'])
|
|
119
|
+
new Node(domainConfigNode, 'domain', [includeSubdomains: 'true'], domain)
|
|
120
|
+
def pinSetNode = new Node(domainConfigNode, 'pin-set', [expiration: expirationDate])
|
|
121
|
+
pins.each { pinValue ->
|
|
122
|
+
def cleanPin = pinValue.replaceFirst('^sha256/', '')
|
|
123
|
+
new Node(pinSetNode, 'pin', [digest: 'SHA-256'], cleanPin)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Write merged XML back
|
|
129
|
+
def writer = new StringWriter()
|
|
130
|
+
writer.write('<?xml version="1.0" encoding="utf-8"?>\n')
|
|
131
|
+
def printer = new XmlNodePrinter(new PrintWriter(writer))
|
|
132
|
+
printer.setPreserveWhitespace(true)
|
|
133
|
+
printer.print(root)
|
|
134
|
+
xmlFile.text = writer.toString()
|
|
135
|
+
println "✅ Merged pin entries into existing network_security_config.xml"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Patch AndroidManifest.xml to reference network_security_config if not already set
|
|
140
|
+
*/
|
|
141
|
+
def patchAndroidManifest(File manifestFile) {
|
|
142
|
+
if (!manifestFile || !manifestFile.exists()) {
|
|
143
|
+
println "⚠️ AndroidManifest.xml not found, skipping manifest patching"
|
|
144
|
+
return false
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
def content = manifestFile.text
|
|
148
|
+
if (content.contains('android:networkSecurityConfig')) {
|
|
149
|
+
println "ℹ️ AndroidManifest already has networkSecurityConfig reference, preserving existing"
|
|
150
|
+
return false
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Add networkSecurityConfig attribute to <application> tag
|
|
154
|
+
content = content.replaceFirst(
|
|
155
|
+
'(<application\\b[^>]*)(>)',
|
|
156
|
+
'$1 android:networkSecurityConfig="@xml/network_security_config"$2'
|
|
157
|
+
)
|
|
158
|
+
manifestFile.text = content
|
|
159
|
+
println "✅ Added networkSecurityConfig reference to AndroidManifest.xml"
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
162
|
+
|
|
23
163
|
plugins.withId('com.android.application') {
|
|
24
164
|
|
|
25
165
|
// ===== AGP 7/8: androidComponents DSL =====
|
|
@@ -64,10 +204,29 @@ plugins.withId('com.android.application') {
|
|
|
64
204
|
}
|
|
65
205
|
}
|
|
66
206
|
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
tasks.
|
|
70
|
-
|
|
207
|
+
// ===== Generate Network Security Config XML =====
|
|
208
|
+
def nscTaskName = "generateNetworkSecurityConfig${vNameCap}"
|
|
209
|
+
tasks.register(nscTaskName) {
|
|
210
|
+
group = "SSL Pinning"
|
|
211
|
+
description = "Generate network_security_config.xml for ${vName}"
|
|
212
|
+
|
|
213
|
+
doLast {
|
|
214
|
+
def sourceFile = findSslConfigFile()
|
|
215
|
+
def xmlDir = file("${projectDir}/src/main/res/xml")
|
|
216
|
+
def xmlFile = file("${xmlDir}/network_security_config.xml")
|
|
217
|
+
if (generateNetworkSecurityConfigXml(sourceFile, xmlFile)) {
|
|
218
|
+
// Patch manifest
|
|
219
|
+
def manifestFile = file("${projectDir}/src/main/AndroidManifest.xml")
|
|
220
|
+
patchAndroidManifest(manifestFile)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Hook both tasks before merge/assemble/install
|
|
226
|
+
tasks.matching { it.name == "merge${vNameCap}Assets" }.configureEach { dependsOn taskName; dependsOn nscTaskName }
|
|
227
|
+
tasks.matching { it.name == "install${vNameCap}" }.configureEach { dependsOn taskName; dependsOn nscTaskName }
|
|
228
|
+
tasks.matching { it.name == "assemble${vNameCap}" }.configureEach { dependsOn taskName; dependsOn nscTaskName }
|
|
229
|
+
tasks.matching { it.name == "merge${vNameCap}Resources" }.configureEach { dependsOn nscTaskName }
|
|
71
230
|
}
|
|
72
231
|
}
|
|
73
232
|
|
|
@@ -114,15 +273,33 @@ plugins.withId('com.android.application') {
|
|
|
114
273
|
}
|
|
115
274
|
}
|
|
116
275
|
|
|
276
|
+
// ===== Generate Network Security Config XML (legacy path) =====
|
|
277
|
+
def nscTaskName = "generateNetworkSecurityConfig${vNameCap}"
|
|
278
|
+
def nscTask = tasks.create(nscTaskName) {
|
|
279
|
+
group = "SSL Pinning"
|
|
280
|
+
description = "Generate network_security_config.xml for ${vNameCap}"
|
|
281
|
+
|
|
282
|
+
doLast {
|
|
283
|
+
def sourceFile = findSslConfigFile()
|
|
284
|
+
def xmlDir = file("${projectDir}/src/main/res/xml")
|
|
285
|
+
def xmlFile = file("${xmlDir}/network_security_config.xml")
|
|
286
|
+
if (generateNetworkSecurityConfigXml(sourceFile, xmlFile)) {
|
|
287
|
+
def manifestFile = file("${projectDir}/src/main/AndroidManifest.xml")
|
|
288
|
+
patchAndroidManifest(manifestFile)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
117
293
|
try {
|
|
118
294
|
if (variant.hasProperty("mergeAssetsProvider")) {
|
|
119
|
-
variant.mergeAssetsProvider.configure { dependsOn copyTask }
|
|
295
|
+
variant.mergeAssetsProvider.configure { dependsOn copyTask; dependsOn nscTask }
|
|
120
296
|
} else {
|
|
121
|
-
tasks.named("merge${vNameCap}Assets").configure { dependsOn copyTask }
|
|
297
|
+
tasks.named("merge${vNameCap}Assets").configure { dependsOn copyTask; dependsOn nscTask }
|
|
122
298
|
}
|
|
123
299
|
} catch (ignored) { }
|
|
124
|
-
try { tasks.named("
|
|
125
|
-
try { tasks.named("
|
|
300
|
+
try { tasks.named("merge${vNameCap}Resources").configure { dependsOn nscTask } } catch (ignored) { }
|
|
301
|
+
try { tasks.named("install${vNameCap}").configure { dependsOn copyTask; dependsOn nscTask } } catch (ignored) { }
|
|
302
|
+
try { tasks.named("assemble${vNameCap}").configure { dependsOn copyTask; dependsOn nscTask } } catch (ignored) { }
|
|
126
303
|
}
|
|
127
304
|
}
|
|
128
305
|
}
|
package/app.plugin.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
const {
|
|
2
|
-
withInfoPlist,
|
|
3
2
|
withDangerousMod,
|
|
4
|
-
withXcodeProject,
|
|
5
3
|
withAndroidManifest,
|
|
6
|
-
withMainApplication,
|
|
7
4
|
} = require('@expo/config-plugins');
|
|
8
5
|
const fs = require('fs');
|
|
9
6
|
const path = require('path');
|
|
@@ -24,6 +21,8 @@ function withSslManager(config, options = {}) {
|
|
|
24
21
|
config = withAndroidSslPinning(config);
|
|
25
22
|
config = withAndroidMainApplication(config);
|
|
26
23
|
config = withAndroidAssets(config, { sslConfigPath });
|
|
24
|
+
config = withAndroidNetworkSecurityConfig(config, { sslConfigPath });
|
|
25
|
+
config = withAndroidNscManifest(config);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
// Add iOS configuration
|
|
@@ -290,4 +289,101 @@ function withIosAssets(config, options) {
|
|
|
290
289
|
return config;
|
|
291
290
|
}
|
|
292
291
|
|
|
292
|
+
const { generateNscXml, mergeNscXml } = require('./scripts/nsc-utils');
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Read ssl_config.json and return parsed sha256Keys, or null if not found
|
|
296
|
+
*/
|
|
297
|
+
function readSslConfig(projectRoot, sslConfigPath) {
|
|
298
|
+
const sourceConfigPath = path.resolve(projectRoot, sslConfigPath);
|
|
299
|
+
if (!fs.existsSync(sourceConfigPath)) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
const config = JSON.parse(fs.readFileSync(sourceConfigPath, 'utf8'));
|
|
304
|
+
return config.sha256Keys || null;
|
|
305
|
+
} catch {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Generate network_security_config.xml during Expo prebuild
|
|
312
|
+
*/
|
|
313
|
+
function withAndroidNetworkSecurityConfig(config, options) {
|
|
314
|
+
return withDangerousMod(config, [
|
|
315
|
+
'android',
|
|
316
|
+
async (config) => {
|
|
317
|
+
const { sslConfigPath = 'ssl_config.json' } = options;
|
|
318
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
319
|
+
const sha256Keys = readSslConfig(projectRoot, sslConfigPath);
|
|
320
|
+
|
|
321
|
+
if (!sha256Keys || Object.keys(sha256Keys).length === 0) {
|
|
322
|
+
console.warn(
|
|
323
|
+
'⚠️ No SSL pins found, skipping network_security_config.xml generation'
|
|
324
|
+
);
|
|
325
|
+
return config;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const xmlDir = path.join(
|
|
329
|
+
config.modRequest.platformProjectRoot,
|
|
330
|
+
'app/src/main/res/xml'
|
|
331
|
+
);
|
|
332
|
+
const xmlPath = path.join(xmlDir, 'network_security_config.xml');
|
|
333
|
+
|
|
334
|
+
if (!fs.existsSync(xmlDir)) {
|
|
335
|
+
fs.mkdirSync(xmlDir, { recursive: true });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (fs.existsSync(xmlPath)) {
|
|
339
|
+
// Merge with existing
|
|
340
|
+
const existingXml = fs.readFileSync(xmlPath, 'utf8');
|
|
341
|
+
const mergedXml = mergeNscXml(existingXml, sha256Keys);
|
|
342
|
+
fs.writeFileSync(xmlPath, mergedXml);
|
|
343
|
+
console.log(
|
|
344
|
+
'✅ Merged SSL pins into existing network_security_config.xml'
|
|
345
|
+
);
|
|
346
|
+
} else {
|
|
347
|
+
// Generate new
|
|
348
|
+
const xml = generateNscXml(sha256Keys);
|
|
349
|
+
fs.writeFileSync(xmlPath, xml);
|
|
350
|
+
console.log('✅ Generated network_security_config.xml');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return config;
|
|
354
|
+
},
|
|
355
|
+
]);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Patch AndroidManifest to reference network_security_config.xml
|
|
360
|
+
*/
|
|
361
|
+
function withAndroidNscManifest(config) {
|
|
362
|
+
return withAndroidManifest(config, (config) => {
|
|
363
|
+
const manifest = config.modResults;
|
|
364
|
+
const application = manifest.manifest.application?.[0];
|
|
365
|
+
|
|
366
|
+
if (!application) {
|
|
367
|
+
return config;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (!application.$) {
|
|
371
|
+
application.$ = {};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (application.$['android:networkSecurityConfig']) {
|
|
375
|
+
console.log(
|
|
376
|
+
'ℹ️ AndroidManifest already has networkSecurityConfig, preserving existing'
|
|
377
|
+
);
|
|
378
|
+
return config;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
application.$['android:networkSecurityConfig'] =
|
|
382
|
+
'@xml/network_security_config';
|
|
383
|
+
console.log('✅ Added networkSecurityConfig to AndroidManifest.xml');
|
|
384
|
+
|
|
385
|
+
return config;
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
293
389
|
module.exports = withSslManager;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-ssl-manager",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "React Native SSL Pinning provides seamless SSL certificate pinning integration for enhanced network security in React Native apps. This module enables developers to easily implement and manage certificate pinning, protecting applications against man-in-the-middle (MITM) attacks. With dynamic configuration options and the ability to toggle SSL pinning, it's particularly useful for development and testing scenarios.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"react-native-ssl-manager.podspec",
|
|
35
35
|
"expo-module.config.json",
|
|
36
36
|
"react-native.config.js",
|
|
37
|
-
"scripts
|
|
37
|
+
"scripts",
|
|
38
38
|
"!**/__tests__",
|
|
39
39
|
"!**/__fixtures__",
|
|
40
40
|
"!**/__mocks__",
|
|
@@ -137,11 +137,6 @@
|
|
|
137
137
|
"react-native": "*"
|
|
138
138
|
}
|
|
139
139
|
},
|
|
140
|
-
"codegenConfig": {
|
|
141
|
-
"name": "RNUseSslPinningSpec",
|
|
142
|
-
"type": "modules",
|
|
143
|
-
"jsSrcsDir": "src"
|
|
144
|
-
},
|
|
145
140
|
"jest": {
|
|
146
141
|
"preset": "react-native",
|
|
147
142
|
"modulePathIgnorePatterns": [
|
|
@@ -204,11 +199,6 @@
|
|
|
204
199
|
"trailingComma": "es5",
|
|
205
200
|
"useTabs": false
|
|
206
201
|
},
|
|
207
|
-
"codegenConfig": {
|
|
208
|
-
"name": "RNUseSslPinningSpec",
|
|
209
|
-
"type": "modules",
|
|
210
|
-
"jsSrcsDir": "src"
|
|
211
|
-
},
|
|
212
202
|
"dependencies": {
|
|
213
203
|
"@babel/runtime": "^7.23.0",
|
|
214
204
|
"postinstall": "^0.10.3"
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
// React Native SSL Manager Post-Install Setup for Bun
|
|
4
|
+
// Automatically applies Gradle script for SSL config auto-copy
|
|
5
|
+
|
|
6
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
7
|
+
import { join, dirname } from 'path';
|
|
8
|
+
|
|
9
|
+
console.log('🔧 React Native SSL Manager - Bun Post-install setup');
|
|
10
|
+
|
|
11
|
+
// Find project root (where bun.lockb is)
|
|
12
|
+
let projectRoot = process.cwd();
|
|
13
|
+
while (projectRoot !== '/' && !existsSync(join(projectRoot, 'bun.lockb'))) {
|
|
14
|
+
projectRoot = dirname(projectRoot);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (projectRoot === '/') {
|
|
18
|
+
console.log('❌ Could not find project root with bun.lockb');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log(`📂 Project root: ${projectRoot}`);
|
|
23
|
+
console.log(`📦 Package manager: Bun`);
|
|
24
|
+
|
|
25
|
+
// Check if this is a React Native project
|
|
26
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
27
|
+
if (!existsSync(packageJsonPath)) {
|
|
28
|
+
console.log('❌ package.json not found');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
33
|
+
const hasReactNative =
|
|
34
|
+
packageJson.dependencies &&
|
|
35
|
+
(packageJson.dependencies['react-native'] ||
|
|
36
|
+
packageJson.devDependencies?.['react-native']);
|
|
37
|
+
|
|
38
|
+
if (!hasReactNative) {
|
|
39
|
+
console.log('ℹ️ Not a React Native project, skipping setup');
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Setup Android Gradle script
|
|
44
|
+
const androidBuildGradlePath = join(
|
|
45
|
+
projectRoot,
|
|
46
|
+
'android',
|
|
47
|
+
'app',
|
|
48
|
+
'build.gradle'
|
|
49
|
+
);
|
|
50
|
+
const sslGradleScriptPath = join(
|
|
51
|
+
__dirname,
|
|
52
|
+
'..',
|
|
53
|
+
'android',
|
|
54
|
+
'ssl-pinning-setup.gradle'
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (existsSync(androidBuildGradlePath)) {
|
|
58
|
+
console.log('📱 Android project detected');
|
|
59
|
+
|
|
60
|
+
// Read current build.gradle
|
|
61
|
+
let buildGradleContent = readFileSync(androidBuildGradlePath, 'utf8');
|
|
62
|
+
|
|
63
|
+
// Check if our script is already applied
|
|
64
|
+
const scriptApplyLine =
|
|
65
|
+
"apply from: '../../node_modules/react-native-ssl-manager/android/ssl-pinning-setup.gradle'";
|
|
66
|
+
|
|
67
|
+
if (!buildGradleContent.includes('ssl-pinning-setup.gradle')) {
|
|
68
|
+
console.log('🔄 Adding SSL config auto-copy script to build.gradle');
|
|
69
|
+
|
|
70
|
+
// Add script at the end
|
|
71
|
+
buildGradleContent += `\n\n// React Native SSL Manager - Auto-copy SSL config\n${scriptApplyLine}\n`;
|
|
72
|
+
|
|
73
|
+
// Write back to file
|
|
74
|
+
writeFileSync(androidBuildGradlePath, buildGradleContent);
|
|
75
|
+
console.log('✅ SSL config auto-copy script added successfully');
|
|
76
|
+
console.log('💡 SSL config will now be automatically copied on build');
|
|
77
|
+
} else {
|
|
78
|
+
console.log('✅ SSL config auto-copy script already present');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(
|
|
82
|
+
'📋 Run "cd android && ./gradlew checkSslConfig" to verify setup'
|
|
83
|
+
);
|
|
84
|
+
} else {
|
|
85
|
+
console.log('ℹ️ Android build.gradle not found, skipping Android setup');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check for ssl_config.json in project root
|
|
89
|
+
const sslConfigPath = join(projectRoot, 'ssl_config.json');
|
|
90
|
+
if (existsSync(sslConfigPath)) {
|
|
91
|
+
console.log('✅ ssl_config.json found at project root');
|
|
92
|
+
} else {
|
|
93
|
+
console.log('⚠️ ssl_config.json not found at project root');
|
|
94
|
+
console.log(
|
|
95
|
+
'💡 Create ssl_config.json at project root for SSL pinning to work'
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log('🎉 React Native SSL Manager Bun setup complete!');
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for Network Security Config XML generation.
|
|
3
|
+
* Used by app.plugin.js, postinstall.js, and tests.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate network_security_config.xml content from sha256Keys
|
|
8
|
+
*/
|
|
9
|
+
function generateNscXml(sha256Keys) {
|
|
10
|
+
// Default expiration: 1 year from now
|
|
11
|
+
const expDate = new Date();
|
|
12
|
+
expDate.setFullYear(expDate.getFullYear() + 1);
|
|
13
|
+
const expiration = expDate.toISOString().split('T')[0]; // YYYY-MM-DD
|
|
14
|
+
|
|
15
|
+
let xml = '<?xml version="1.0" encoding="utf-8"?>\n';
|
|
16
|
+
xml += '<network-security-config>\n';
|
|
17
|
+
|
|
18
|
+
for (const [domain, pins] of Object.entries(sha256Keys)) {
|
|
19
|
+
xml += ' <domain-config cleartextTrafficPermitted="false">\n';
|
|
20
|
+
xml += ` <domain includeSubdomains="true">${domain}</domain>\n`;
|
|
21
|
+
xml += ` <pin-set expiration="${expiration}">\n`;
|
|
22
|
+
for (const pin of pins) {
|
|
23
|
+
const cleanPin = pin.replace(/^sha256\//, '');
|
|
24
|
+
xml += ` <pin digest="SHA-256">${cleanPin}</pin>\n`;
|
|
25
|
+
}
|
|
26
|
+
xml += ' </pin-set>\n';
|
|
27
|
+
xml += ' </domain-config>\n';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
xml += '</network-security-config>\n';
|
|
31
|
+
return xml;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Merge pin-set entries into existing NSC XML string.
|
|
36
|
+
* Preserves existing config, replaces pin-set for matching domains, adds new ones.
|
|
37
|
+
*/
|
|
38
|
+
function mergeNscXml(existingXml, sha256Keys) {
|
|
39
|
+
const expDate = new Date();
|
|
40
|
+
expDate.setFullYear(expDate.getFullYear() + 1);
|
|
41
|
+
const expiration = expDate.toISOString().split('T')[0];
|
|
42
|
+
|
|
43
|
+
for (const [domain, pins] of Object.entries(sha256Keys)) {
|
|
44
|
+
const pinSetXml = pins
|
|
45
|
+
.map((pin) => {
|
|
46
|
+
const cleanPin = pin.replace(/^sha256\//, '');
|
|
47
|
+
return ` <pin digest="SHA-256">${cleanPin}</pin>`;
|
|
48
|
+
})
|
|
49
|
+
.join('\n');
|
|
50
|
+
|
|
51
|
+
const domainConfigBlock =
|
|
52
|
+
` <domain-config cleartextTrafficPermitted="false">\n` +
|
|
53
|
+
` <domain includeSubdomains="true">${domain}</domain>\n` +
|
|
54
|
+
` <pin-set expiration="${expiration}">\n` +
|
|
55
|
+
`${pinSetXml}\n` +
|
|
56
|
+
` </pin-set>\n` +
|
|
57
|
+
` </domain-config>`;
|
|
58
|
+
|
|
59
|
+
// Check if domain already exists in the XML
|
|
60
|
+
const domainRegex = new RegExp(
|
|
61
|
+
`<domain-config[^>]*>\\s*<domain[^>]*>${domain.replace(/\./g, '\\.')}</domain>[\\s\\S]*?</domain-config>`,
|
|
62
|
+
'g'
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (domainRegex.test(existingXml)) {
|
|
66
|
+
console.warn(`⚠️ Replacing existing pin-set for domain: ${domain}`);
|
|
67
|
+
// Reset regex lastIndex since test() advanced it
|
|
68
|
+
domainRegex.lastIndex = 0;
|
|
69
|
+
existingXml = existingXml.replace(domainRegex, domainConfigBlock);
|
|
70
|
+
} else {
|
|
71
|
+
// Insert before closing </network-security-config>
|
|
72
|
+
existingXml = existingXml.replace(
|
|
73
|
+
'</network-security-config>',
|
|
74
|
+
`${domainConfigBlock}\n</network-security-config>`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return existingXml;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = { generateNscXml, mergeNscXml };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// React Native SSL Manager Post-Install Setup
|
|
4
|
+
// Automatically applies Gradle script for SSL config auto-copy
|
|
5
|
+
// Supports both npm/yarn and bun package managers
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
console.log('🔧 React Native SSL Manager - Post-install setup');
|
|
11
|
+
|
|
12
|
+
// Find project root (where node_modules is)
|
|
13
|
+
let projectRoot = process.cwd();
|
|
14
|
+
while (
|
|
15
|
+
projectRoot !== '/' &&
|
|
16
|
+
!fs.existsSync(path.join(projectRoot, 'node_modules')) &&
|
|
17
|
+
!fs.existsSync(path.join(projectRoot, 'bun.lockb'))
|
|
18
|
+
) {
|
|
19
|
+
projectRoot = path.dirname(projectRoot);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (projectRoot === '/') {
|
|
23
|
+
console.log('❌ Could not find project root');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Detect package manager
|
|
28
|
+
const isBun = fs.existsSync(path.join(projectRoot, 'bun.lockb'));
|
|
29
|
+
const packageManager = isBun ? 'Bun' : 'npm/yarn';
|
|
30
|
+
|
|
31
|
+
console.log(`📂 Project root: ${projectRoot}`);
|
|
32
|
+
console.log(`📦 Package manager: ${packageManager}`);
|
|
33
|
+
|
|
34
|
+
// Check if this is a React Native project
|
|
35
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
36
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
37
|
+
console.log('❌ package.json not found');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
42
|
+
const hasReactNative =
|
|
43
|
+
packageJson.dependencies &&
|
|
44
|
+
(packageJson.dependencies['react-native'] ||
|
|
45
|
+
packageJson.devDependencies?.['react-native']);
|
|
46
|
+
|
|
47
|
+
if (!hasReactNative) {
|
|
48
|
+
console.log('ℹ️ Not a React Native project, skipping setup');
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Setup Android Gradle script
|
|
53
|
+
const androidBuildGradlePath = path.join(
|
|
54
|
+
projectRoot,
|
|
55
|
+
'android',
|
|
56
|
+
'app',
|
|
57
|
+
'build.gradle'
|
|
58
|
+
);
|
|
59
|
+
const sslGradleScriptPath = path.join(
|
|
60
|
+
__dirname,
|
|
61
|
+
'..',
|
|
62
|
+
'android',
|
|
63
|
+
'ssl-pinning-setup.gradle'
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (fs.existsSync(androidBuildGradlePath)) {
|
|
67
|
+
console.log('📱 Android project detected');
|
|
68
|
+
|
|
69
|
+
// Read current build.gradle
|
|
70
|
+
let buildGradleContent = fs.readFileSync(androidBuildGradlePath, 'utf8');
|
|
71
|
+
|
|
72
|
+
// Check if our script is already applied
|
|
73
|
+
const scriptApplyLine =
|
|
74
|
+
"apply from: '../../node_modules/react-native-ssl-manager/android/ssl-pinning-setup.gradle'";
|
|
75
|
+
|
|
76
|
+
if (!buildGradleContent.includes('ssl-pinning-setup.gradle')) {
|
|
77
|
+
console.log('🔄 Adding SSL config auto-copy script to build.gradle');
|
|
78
|
+
|
|
79
|
+
// Add script at the end
|
|
80
|
+
buildGradleContent += `\n\n// React Native SSL Manager - Auto-copy SSL config\n${scriptApplyLine}\n`;
|
|
81
|
+
|
|
82
|
+
// Write back to file
|
|
83
|
+
fs.writeFileSync(androidBuildGradlePath, buildGradleContent);
|
|
84
|
+
console.log('✅ SSL config auto-copy script added successfully');
|
|
85
|
+
console.log('💡 SSL config will now be automatically copied on build');
|
|
86
|
+
} else {
|
|
87
|
+
console.log('✅ SSL config auto-copy script already present');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(
|
|
91
|
+
'📋 Run "cd android && ./gradlew checkSslConfig" to verify setup'
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
console.log('ℹ️ Android build.gradle not found, skipping Android setup');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Check for ssl_config.json in project root
|
|
98
|
+
const sslConfigPath = path.join(projectRoot, 'ssl_config.json');
|
|
99
|
+
if (fs.existsSync(sslConfigPath)) {
|
|
100
|
+
console.log('✅ ssl_config.json found at project root');
|
|
101
|
+
} else {
|
|
102
|
+
console.log('⚠️ ssl_config.json not found at project root');
|
|
103
|
+
console.log(
|
|
104
|
+
'💡 Create ssl_config.json at project root for SSL pinning to work'
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Generate Network Security Config XML for Android
|
|
109
|
+
const { generateNscXml, mergeNscXml } = require('./nsc-utils');
|
|
110
|
+
const androidDir = path.join(projectRoot, 'android');
|
|
111
|
+
if (fs.existsSync(androidDir) && fs.existsSync(sslConfigPath)) {
|
|
112
|
+
console.log('🔄 Generating Android Network Security Config XML...');
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const sslConfig = JSON.parse(fs.readFileSync(sslConfigPath, 'utf8'));
|
|
116
|
+
const sha256Keys = sslConfig.sha256Keys;
|
|
117
|
+
|
|
118
|
+
if (sha256Keys && Object.keys(sha256Keys).length > 0) {
|
|
119
|
+
const xmlDir = path.join(
|
|
120
|
+
androidDir,
|
|
121
|
+
'app',
|
|
122
|
+
'src',
|
|
123
|
+
'main',
|
|
124
|
+
'res',
|
|
125
|
+
'xml'
|
|
126
|
+
);
|
|
127
|
+
const xmlPath = path.join(xmlDir, 'network_security_config.xml');
|
|
128
|
+
|
|
129
|
+
if (fs.existsSync(xmlPath)) {
|
|
130
|
+
// Merge with existing NSC
|
|
131
|
+
const existingXml = fs.readFileSync(xmlPath, 'utf8');
|
|
132
|
+
const mergedXml = mergeNscXml(existingXml, sha256Keys);
|
|
133
|
+
fs.writeFileSync(xmlPath, mergedXml);
|
|
134
|
+
console.log(
|
|
135
|
+
'✅ Merged SSL pins into existing network_security_config.xml'
|
|
136
|
+
);
|
|
137
|
+
} else {
|
|
138
|
+
// Generate new XML
|
|
139
|
+
if (!fs.existsSync(xmlDir)) {
|
|
140
|
+
fs.mkdirSync(xmlDir, { recursive: true });
|
|
141
|
+
}
|
|
142
|
+
const xml = generateNscXml(sha256Keys);
|
|
143
|
+
fs.writeFileSync(xmlPath, xml);
|
|
144
|
+
console.log('✅ Generated network_security_config.xml');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Patch AndroidManifest.xml
|
|
148
|
+
const manifestPath = path.join(
|
|
149
|
+
androidDir,
|
|
150
|
+
'app',
|
|
151
|
+
'src',
|
|
152
|
+
'main',
|
|
153
|
+
'AndroidManifest.xml'
|
|
154
|
+
);
|
|
155
|
+
if (fs.existsSync(manifestPath)) {
|
|
156
|
+
let manifestContent = fs.readFileSync(manifestPath, 'utf8');
|
|
157
|
+
if (!manifestContent.includes('android:networkSecurityConfig')) {
|
|
158
|
+
manifestContent = manifestContent.replace(
|
|
159
|
+
/(<application\b[^>]*)(>)/,
|
|
160
|
+
'$1 android:networkSecurityConfig="@xml/network_security_config"$2'
|
|
161
|
+
);
|
|
162
|
+
fs.writeFileSync(manifestPath, manifestContent);
|
|
163
|
+
console.log('✅ Added networkSecurityConfig to AndroidManifest.xml');
|
|
164
|
+
} else {
|
|
165
|
+
console.log(
|
|
166
|
+
'ℹ️ AndroidManifest already has networkSecurityConfig reference'
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
console.log('⚠️ No sha256Keys in ssl_config.json, skipping XML generation');
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.warn('⚠️ Failed to generate Network Security Config XML:', error.message);
|
|
175
|
+
}
|
|
176
|
+
} else if (!fs.existsSync(androidDir)) {
|
|
177
|
+
console.log('ℹ️ No android/ directory found, skipping NSC XML generation');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.log('🎉 React Native SSL Manager setup complete!');
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
// Test script to verify Bun compatibility with react-native-ssl-manager
|
|
4
|
+
|
|
5
|
+
import { readFileSync, existsSync } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
|
|
8
|
+
console.log('🧪 Testing Bun compatibility...');
|
|
9
|
+
|
|
10
|
+
// Test 1: Check if bunfig.toml exists
|
|
11
|
+
const bunfigPath = join(process.cwd(), 'bunfig.toml');
|
|
12
|
+
if (existsSync(bunfigPath)) {
|
|
13
|
+
console.log('✅ bunfig.toml found');
|
|
14
|
+
} else {
|
|
15
|
+
console.log('❌ bunfig.toml not found');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Test 2: Check package.json for Bun support
|
|
19
|
+
const packageJsonPath = join(process.cwd(), 'package.json');
|
|
20
|
+
if (existsSync(packageJsonPath)) {
|
|
21
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
22
|
+
|
|
23
|
+
if (packageJson.engines?.bun) {
|
|
24
|
+
console.log(`✅ Bun engine requirement: ${packageJson.engines.bun}`);
|
|
25
|
+
} else {
|
|
26
|
+
console.log('❌ No Bun engine requirement in package.json');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (packageJson.scripts['bun:install']) {
|
|
30
|
+
console.log('✅ Bun install script found');
|
|
31
|
+
} else {
|
|
32
|
+
console.log('❌ Bun install script not found');
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
console.log('❌ package.json not found');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Test 3: Check if Bun postinstall script exists
|
|
39
|
+
const bunPostinstallPath = join(process.cwd(), 'scripts', 'bun-postinstall.js');
|
|
40
|
+
if (existsSync(bunPostinstallPath)) {
|
|
41
|
+
console.log('✅ Bun postinstall script found');
|
|
42
|
+
} else {
|
|
43
|
+
console.log('❌ Bun postinstall script not found');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Test 4: Check source files for Bun compatibility
|
|
47
|
+
const sourceFiles = [
|
|
48
|
+
'src/index.tsx',
|
|
49
|
+
'src/NativeUseSslPinning.ts',
|
|
50
|
+
'src/UseSslPinning.types.ts',
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
for (const file of sourceFiles) {
|
|
54
|
+
const filePath = join(process.cwd(), file);
|
|
55
|
+
if (existsSync(filePath)) {
|
|
56
|
+
console.log(`✅ ${file} exists`);
|
|
57
|
+
} else {
|
|
58
|
+
console.log(`❌ ${file} not found`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log('\n🎉 Bun compatibility test completed!');
|
|
63
|
+
console.log('💡 Run "bun install" to test installation');
|
|
64
|
+
console.log('💡 Run "bun run build" to test build process');
|
package/lib/commonjs/index.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.setUseSSLPinning = exports.initializeSslPinning = exports.getUseSSLPinning = void 0;
|
|
7
|
-
var _reactNative = require("react-native");
|
|
8
|
-
const LINKING_ERROR = `The package 'react-native-ssl-manager' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
|
|
9
|
-
ios: "- You have run 'pod install'\n",
|
|
10
|
-
default: ''
|
|
11
|
-
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
|
12
|
-
const UseSslPinning = _reactNative.NativeModules.UseSslPinning ? _reactNative.NativeModules.UseSslPinning : new Proxy({}, {
|
|
13
|
-
get() {
|
|
14
|
-
throw new Error(LINKING_ERROR);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
const setUseSSLPinning = usePinning => {
|
|
18
|
-
UseSslPinning.setUseSSLPinning(usePinning);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Retrieves the current state of SSL pinning usage.
|
|
23
|
-
*
|
|
24
|
-
* @returns A promise that resolves to a boolean indicating whether SSL pinning is being used.
|
|
25
|
-
*/
|
|
26
|
-
exports.setUseSSLPinning = setUseSSLPinning;
|
|
27
|
-
const getUseSSLPinning = async () => {
|
|
28
|
-
return await UseSslPinning.getUseSSLPinning();
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Initializes SSL pinning with the provided configuration.
|
|
33
|
-
*
|
|
34
|
-
* @param {string} configJsonString - The JSON string containing the SSL pinning configuration.
|
|
35
|
-
* @returns {Promise<any>} A promise that resolves when the SSL pinning is initialized.
|
|
36
|
-
*/
|
|
37
|
-
exports.getUseSSLPinning = getUseSSLPinning;
|
|
38
|
-
const initializeSslPinning = async configJsonString => {
|
|
39
|
-
return await UseSslPinning.initializeSslPinning(configJsonString);
|
|
40
|
-
};
|
|
41
|
-
exports.initializeSslPinning = initializeSslPinning;
|
|
42
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","UseSslPinning","NativeModules","Proxy","get","Error","setUseSSLPinning","usePinning","exports","getUseSSLPinning","initializeSslPinning","configJsonString"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,aAAa,GACjB,mFAAmF,GACnFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,aAAa,GAAGC,0BAAa,CAACD,aAAa,GAC7CC,0BAAa,CAACD,aAAa,GAC3B,IAAIE,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACT,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAEE,MAAMU,gBAAgB,GAAIC,UAAmB,IAAW;EAC7DN,aAAa,CAACK,gBAAgB,CAACC,UAAU,CAAC;AAC5C,CAAC;;AAED;AACA;AACA;AACA;AACA;AAJAC,OAAA,CAAAF,gBAAA,GAAAA,gBAAA;AAKO,MAAMG,gBAAgB,GAAG,MAAAA,CAAA,KAA8B;EAC5D,OAAO,MAAMR,aAAa,CAACQ,gBAAgB,CAAC,CAAC;AAC/C,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AALAD,OAAA,CAAAC,gBAAA,GAAAA,gBAAA;AAMO,MAAMC,oBAAoB,GAAG,MAClCC,gBAAwB,IACP;EACjB,OAAO,MAAMV,aAAa,CAACS,oBAAoB,CAACC,gBAAgB,CAAC;AACnE,CAAC;AAACH,OAAA,CAAAE,oBAAA,GAAAA,oBAAA","ignoreList":[]}
|
package/lib/module/index.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { NativeModules, Platform } from 'react-native';
|
|
2
|
-
const LINKING_ERROR = `The package 'react-native-ssl-manager' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
|
|
3
|
-
ios: "- You have run 'pod install'\n",
|
|
4
|
-
default: ''
|
|
5
|
-
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
|
|
6
|
-
const UseSslPinning = NativeModules.UseSslPinning ? NativeModules.UseSslPinning : new Proxy({}, {
|
|
7
|
-
get() {
|
|
8
|
-
throw new Error(LINKING_ERROR);
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
export const setUseSSLPinning = usePinning => {
|
|
12
|
-
UseSslPinning.setUseSSLPinning(usePinning);
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Retrieves the current state of SSL pinning usage.
|
|
17
|
-
*
|
|
18
|
-
* @returns A promise that resolves to a boolean indicating whether SSL pinning is being used.
|
|
19
|
-
*/
|
|
20
|
-
export const getUseSSLPinning = async () => {
|
|
21
|
-
return await UseSslPinning.getUseSSLPinning();
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Initializes SSL pinning with the provided configuration.
|
|
26
|
-
*
|
|
27
|
-
* @param {string} configJsonString - The JSON string containing the SSL pinning configuration.
|
|
28
|
-
* @returns {Promise<any>} A promise that resolves when the SSL pinning is initialized.
|
|
29
|
-
*/
|
|
30
|
-
export const initializeSslPinning = async configJsonString => {
|
|
31
|
-
return await UseSslPinning.initializeSslPinning(configJsonString);
|
|
32
|
-
};
|
|
33
|
-
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","UseSslPinning","Proxy","get","Error","setUseSSLPinning","usePinning","getUseSSLPinning","initializeSslPinning","configJsonString"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AAEtD,MAAMC,aAAa,GACjB,mFAAmF,GACnFD,QAAQ,CAACE,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,aAAa,GAAGN,aAAa,CAACM,aAAa,GAC7CN,aAAa,CAACM,aAAa,GAC3B,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACP,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAEL,OAAO,MAAMQ,gBAAgB,GAAIC,UAAmB,IAAW;EAC7DL,aAAa,CAACI,gBAAgB,CAACC,UAAU,CAAC;AAC5C,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,gBAAgB,GAAG,MAAAA,CAAA,KAA8B;EAC5D,OAAO,MAAMN,aAAa,CAACM,gBAAgB,CAAC,CAAC;AAC/C,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,oBAAoB,GAAG,MAClCC,gBAAwB,IACP;EACjB,OAAO,MAAMR,aAAa,CAACO,oBAAoB,CAACC,gBAAgB,CAAC;AACnE,CAAC","ignoreList":[]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare const setUseSSLPinning: (usePinning: boolean) => void;
|
|
2
|
-
/**
|
|
3
|
-
* Retrieves the current state of SSL pinning usage.
|
|
4
|
-
*
|
|
5
|
-
* @returns A promise that resolves to a boolean indicating whether SSL pinning is being used.
|
|
6
|
-
*/
|
|
7
|
-
export declare const getUseSSLPinning: () => Promise<boolean>;
|
|
8
|
-
/**
|
|
9
|
-
* Initializes SSL pinning with the provided configuration.
|
|
10
|
-
*
|
|
11
|
-
* @param {string} configJsonString - The JSON string containing the SSL pinning configuration.
|
|
12
|
-
* @returns {Promise<any>} A promise that resolves when the SSL pinning is initialized.
|
|
13
|
-
*/
|
|
14
|
-
export declare const initializeSslPinning: (configJsonString: string) => Promise<any>;
|
|
15
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAmBA,eAAO,MAAM,gBAAgB,eAAgB,OAAO,KAAG,IAEtD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,QAAa,QAAQ,OAAO,CAExD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,qBACb,MAAM,KACvB,QAAQ,GAAG,CAEb,CAAC"}
|