@umutcansu/react-native-pinvault 2.6.0 → 2.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.7.0 — 2026-10-15
4
+
5
+ ### Changed
6
+
7
+ - **Release builds take `tokenHosts` only from the native security file**,
8
+ as they already did `clientCertHosts`: where the file has the block but
9
+ names no `tokenHosts`, a `tokenHosts` from JS is refused
10
+ (`E_INVALID_CONFIG`, "declare tokenHosts for Config API … there"). The
11
+ library's default sends `PinVault-Token` to the block's own Config API only,
12
+ so a `tokenHosts` from JS would add hosts that receive the device's token.
13
+ Debug builds and files that name the hosts are unchanged. Move your
14
+ `tokenHosts` into `pinvault-security.json` (Android: `res/raw`, iOS: the
15
+ bundle) if a release build now refuses to start.
16
+
17
+ ## 2.6.1 — 2026-10-15
18
+
19
+ ### Fixed
20
+
21
+ - **iOS: without `tokenHosts`, only the block's own Config API carries
22
+ `PinVault-Token`** (as Android has since 2.4.1). A block without
23
+ `tokenHosts` sent the token (and `PinVault-Proof`) to every host pinned by
24
+ its live config, so a pinned CDN or analytics host received it. Name your
25
+ API hosts in `tokenHosts` if they need the token.
26
+
27
+ ### Changed
28
+
29
+ - Depends on PinVault 2.6.1 (Maven Central, Swift package tag `v2.6.1`).
30
+
3
31
  ## 2.6.0 — 2026-10-14
4
32
 
5
33
  ### Fixed
package/README.md CHANGED
@@ -29,9 +29,9 @@ npm install @umutcansu/react-native-pinvault
29
29
  cd ios && pod install
30
30
  ```
31
31
 
32
- The native libraries come with it, at the package's own version: npm 2.6.0
33
- uses `io.github.umutcansu:pinvault:2.6.0` from Maven Central and the Swift
34
- package at tag `v2.6.0`. The New Architecture must stay on (React Native's
32
+ The native libraries come with it, at the package's own version: npm 2.7.0
33
+ uses `io.github.umutcansu:pinvault:2.7.0` from Maven Central and the Swift
34
+ package at tag `v2.7.0`. The New Architecture must stay on (React Native's
35
35
  default since 0.76).
36
36
 
37
37
  **iOS.** The pod depends on the PinVault Swift package through React Native's
@@ -273,9 +273,10 @@ parsed as strictly; a broken file rejects `start` with `E_INVALID_CONFIG`
273
273
  - a block's `url`, `enrollmentUrl`, `renewalUrl`, `tokenHosts` and
274
274
  `clientCertHosts` are fixed where the file gives them (where the block talks to, and who gets its token and identity),
275
275
  and `attestation: true` / `proofOfPossession: true` there cannot be turned off from JS;
276
- in a release build JS may give `clientCertHosts` only where the file names
277
- them (the bundle cannot hand the device's identity to another host;
278
- `tokenHosts` from JS only narrows the library's default);
276
+ in a release build JS may give `clientCertHosts` and `tokenHosts` only where
277
+ the file names them (the bundle cannot hand the device's identity or its
278
+ `PinVault-Token` to another host; the library's default sends the token to the
279
+ block's own Config API only);
279
280
  - `require` only tightens: a protection it turns on stays on whatever JS says,
280
281
  its `requireCaTrust` hosts are added to JS's, the expected signer / bundle /
281
282
  team ids and iOS `userAuthStrength` are fixed, and `expiredConfigGraceSeconds`
@@ -4,7 +4,7 @@ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
4
 
5
5
  # PinVault for iOS is a Swift package (Package.swift at the repository root,
6
6
  # product "PinVault"). React Native's spm_dependency adds it to the Pods project:
7
- # - consumers: the git URL at the tag of this package's version (v2.6.0);
7
+ # - consumers: the git URL at the tag of this package's version (v2.7.0);
8
8
  # - development: PINVAULT_IOS_PACKAGE_PATH = a PinVault checkout (the sample's
9
9
  # Podfile sets it to this repository), the counterpart of pinvault.localPath.
10
10
  pinvault_url = "https://github.com/umutcansu/PinVault.git"
@@ -9,7 +9,7 @@ buildscript {
9
9
  kotlinVersion: "2.2.0",
10
10
  minSdkVersion: 24,
11
11
  compileSdkVersion: 36,
12
- pinvaultVersion: "2.6.0",
12
+ pinvaultVersion: "2.7.0",
13
13
  ]
14
14
  ext.pinvaultRnExt = { prop ->
15
15
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : PinVaultRN[prop]
@@ -286,11 +286,18 @@ internal object ConfigParser {
286
286
  throw BridgeInputException("${b.path}.proofOfPossession: the app's native security file turns it on; JS cannot turn it off")
287
287
  }
288
288
  val proof = jsProof == true || nativeBlock?.proofOfPossession == true
289
+ // Who gets the device's token is the file's call in a release build, like the identity
290
+ // below: the library's default is the block's own Config API only, so a tokenHosts from
291
+ // JS would ADD hosts that receive the token.
292
+ if (release && nativeBlock != null && nativeBlock.tokenHosts == null && jsTokenHosts != null) {
293
+ throw BridgeInputException("${b.path}.tokenHosts: a release build takes it only from the app's native security file " +
294
+ "(${native?.source}); declare tokenHosts for Config API '$id' there")
295
+ }
289
296
  val tokenHosts = nativeBlock?.tokenHosts?.also { n ->
290
297
  if (jsTokenHosts != null && !NativeSecurity.sameKeys(jsTokenHosts.map(String::lowercase), n.map(String::lowercase))) fixed("tokenHosts")
291
298
  } ?: jsTokenHosts
292
299
  // Who gets the device's identity is the file's call in a release build: JS cannot
293
- // add a host the file does not name (tokenHosts only narrows the library's default).
300
+ // add a host the file does not name.
294
301
  if (release && nativeBlock != null && nativeBlock.clientCertHosts == null && clientCertHosts != null) {
295
302
  throw BridgeInputException("${b.path}.clientCertHosts: a release build takes it only from the app's native security file " +
296
303
  "(${native?.source}); declare clientCertHosts for Config API '$id' there")
@@ -50,7 +50,9 @@ import java.io.IOException
50
50
  * JS are refused unless the file allows them for that block;
51
51
  * - `url`, `tokenHosts` and `clientCertHosts` of a block are fixed where the
52
52
  * file gives them, and `attestation: true` / `proofOfPossession: true` there
53
- * cannot be switched off;
53
+ * cannot be switched off; in a release build JS may give `tokenHosts` and
54
+ * `clientCertHosts` only where the file names them (who gets the device's
55
+ * token and identity is the file's call);
54
56
  * - `require` only tightens: a protection it turns on stays on whatever JS
55
57
  * says, `requireCaTrust` hosts are added to JS's, `expectedSignerSha256` is
56
58
  * fixed, and `expiredConfigGraceSeconds` is the most JS may ask for;
@@ -295,6 +295,13 @@ public enum ConfigParser {
295
295
  }
296
296
  let proof = jsProof == true || nativeBlock?.proofOfPossession == true
297
297
  let lower: ([String]) -> [String] = { $0.map { $0.lowercased() } }
298
+ // Who gets the device's token is the file's call in a release build, like the identity
299
+ // below: the library's default is the block's own Config API only, so a tokenHosts from
300
+ // JS would ADD hosts that receive the token.
301
+ if release, let nativeBlock, nativeBlock.tokenHosts == nil, jsTokenHosts != nil {
302
+ throw BridgeInputError("\(b.path).tokenHosts: a release build takes it only from the app's native security file "
303
+ + "(\(native?.source ?? "")); declare tokenHosts for Config API '\(id)' there")
304
+ }
298
305
  var tokenHosts = jsTokenHosts
299
306
  if let n = nativeBlock?.tokenHosts {
300
307
  if let j = jsTokenHosts, !NativeSecurity.sameKeys(lower(j), lower(n)) { throw fixed("tokenHosts") }
@@ -311,7 +318,7 @@ public enum ConfigParser {
311
318
  fixedRenewalUrl = n
312
319
  }
313
320
  // Who gets the device's identity is the file's call in a release build: JS cannot
314
- // add a host the file does not name (tokenHosts only narrows the library's default).
321
+ // add a host the file does not name.
315
322
  if release, let nativeBlock, nativeBlock.clientCertHosts == nil, clientCertHosts != nil {
316
323
  throw BridgeInputError("\(b.path).clientCertHosts: a release build takes it only from the app's native security file "
317
324
  + "(\(native?.source ?? "")); declare clientCertHosts for Config API '\(id)' there")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umutcansu/react-native-pinvault",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "PinVault for React Native: dynamic certificate pinning with signed remote configs, mTLS enrollment and signed vault files, as a thin bridge over the native PinVault libraries",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",