@burnt-labs/expo-satya-attest 3.11.1 → 3.12.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 (61) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/PROVIDER_CONFIG.md +7 -2
  3. package/PUBLISHING.md +12 -10
  4. package/README.md +41 -3
  5. package/android/build.gradle +2 -2
  6. package/android/src/main/java/expo/modules/satyaattest/SatyaAttestModule.kt +26 -17
  7. package/android/src/main/java/expo/modules/satyaattest/SatyaCompositeReplay.kt +5 -5
  8. package/android/src/main/java/uniffi/satya_ffi/satya_ffi.kt +65 -0
  9. package/android/src/main/jniLibs/arm64-v8a/libsatya_ffi.so +0 -0
  10. package/android/src/main/jniLibs/armeabi-v7a/libsatya_ffi.so +0 -0
  11. package/android/src/main/jniLibs/x86_64/libsatya_ffi.so +0 -0
  12. package/build/SatyaMobileClient.d.ts.map +1 -1
  13. package/build/SatyaMobileClient.js +3 -0
  14. package/build/SatyaMobileClient.js.map +1 -1
  15. package/build/components/providerAttest/backendVerifier.d.ts.map +1 -1
  16. package/build/components/providerAttest/backendVerifier.js +12 -14
  17. package/build/components/providerAttest/backendVerifier.js.map +1 -1
  18. package/build/components/providerAttest/useNativeReplayRunner.d.ts.map +1 -1
  19. package/build/components/providerAttest/useNativeReplayRunner.js +10 -11
  20. package/build/components/providerAttest/useNativeReplayRunner.js.map +1 -1
  21. package/build/sdkMetadata.generated.d.ts +1 -1
  22. package/build/sdkMetadata.generated.js +1 -1
  23. package/build/sdkMetadata.generated.js.map +1 -1
  24. package/build/tee/claims.d.ts.map +1 -1
  25. package/build/tee/claims.js +22 -10
  26. package/build/tee/claims.js.map +1 -1
  27. package/build/tee/client.d.ts +2 -1
  28. package/build/tee/client.d.ts.map +1 -1
  29. package/build/tee/client.js +29 -4
  30. package/build/tee/client.js.map +1 -1
  31. package/build/utils/dataLimits.d.ts +12 -0
  32. package/build/utils/dataLimits.d.ts.map +1 -0
  33. package/build/utils/dataLimits.js +73 -0
  34. package/build/utils/dataLimits.js.map +1 -0
  35. package/build/utils/streamingFetch.d.ts +2 -0
  36. package/build/utils/streamingFetch.d.ts.map +1 -0
  37. package/build/utils/streamingFetch.js +4 -0
  38. package/build/utils/streamingFetch.js.map +1 -0
  39. package/build/utils/streamingFetch.native.d.ts +2 -0
  40. package/build/utils/streamingFetch.native.d.ts.map +1 -0
  41. package/build/utils/streamingFetch.native.js +6 -0
  42. package/build/utils/streamingFetch.native.js.map +1 -0
  43. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/Headers/satya_ffi.swift +44 -0
  44. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/Headers/satya_ffiFFI.h +22 -0
  45. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/libsatya_ffi.a +2 -2
  46. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64_x86_64-simulator/Headers/satya_ffi.swift +44 -0
  47. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64_x86_64-simulator/Headers/satya_ffiFFI.h +22 -0
  48. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64_x86_64-simulator/libsatya_ffi.a +2 -2
  49. package/ios/Generated/satya_ffi.swift +44 -0
  50. package/ios/SatyaAttest.podspec +1 -1
  51. package/ios/SatyaAttestModule.swift +77 -37
  52. package/package.json +1 -1
  53. package/src/SatyaMobileClient.ts +3 -0
  54. package/src/components/providerAttest/backendVerifier.ts +15 -14
  55. package/src/components/providerAttest/useNativeReplayRunner.ts +10 -11
  56. package/src/sdkMetadata.generated.ts +1 -1
  57. package/src/tee/claims.ts +24 -10
  58. package/src/tee/client.ts +43 -4
  59. package/src/utils/dataLimits.ts +69 -0
  60. package/src/utils/streamingFetch.native.ts +6 -0
  61. package/src/utils/streamingFetch.ts +3 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.12.0 - 2026-10-07
4
+
5
+ ### Added
6
+
7
+ - Support claims up to 8 MiB in native and TEE replay, replacing the 64/256 KiB
8
+ restrictions without requiring provider opt-in.
9
+ - Enforce a shared 80 MiB budget for revealed claim values across endpoints and a
10
+ separate 80 MiB serialized attestation limit. Exceeding either fails the proof,
11
+ including partial-completion plans. Unrevealed response bytes are not charged
12
+ to the disclosure budget; bounded response parsing remains enforced.
13
+ - Bound verifier/proxy uploads, response reads, canonical JSON processing and
14
+ large-job concurrency while preserving signature and policy validation.
15
+ - Share bounded reveal-regex execution across Android, iOS and TEE. Ordinary
16
+ patterns use a linear matcher; advanced patterns require inputs of at most 1 KiB.
17
+
18
+ ### Compatibility and rollout
19
+
20
+ - Rebuild consuming iOS and Android apps and deploy the matching verifier/proxy
21
+ and measured TEE service before relying on the larger limits. Approve the new
22
+ TEE measurements in the verifier policy.
23
+ - Artifact metadata, JSON escaping and TEE base64 encoding count toward the
24
+ serialized limit, so usable claim capacity may be below 80 MiB.
25
+ - Buffered iOS replay retains a conservative 16 MiB raw-response cap (128 MiB
26
+ per run); Android and TEE allow 96/768 MiB. Raw-response guards are independent
27
+ of the 8/80 MiB disclosure limits and can reject large unrevealed fields.
28
+
3
29
  ## 3.11.1 - 2026-10-07
4
30
 
5
31
  ### Fixed
@@ -357,8 +357,13 @@ The three `params.type` values:
357
357
  case-insensitively across all reveals.
358
358
 
359
359
  Native replay applies these to the pinned response and emits each match as a claim. The
360
- body is size-bounded (8 MiB) before regex runs. Patterns come only from the trusted
361
- registry, never from page content. See §10 for regex authoring tips.
360
+ body is size-bounded before regex runs (16 MiB on iOS; 96 MiB on Android and TEE);
361
+ a revealed claim is capped at 8 MiB of serialized JSON. Native and TEE replay share a
362
+ linear matcher for ordinary patterns (at most 4096 UTF-8 bytes). Advanced patterns,
363
+ including lookarounds/backreferences, allow at most 256 pattern bytes and 1024 input
364
+ bytes with bounded backtracking; violations fail the proof. Use `jsonRegex` to select
365
+ a small field first. Patterns come only from the trusted registry, never from page content.
366
+ See §10 for regex authoring tips.
362
367
 
363
368
  ### 5.1 Claim presence and empty account states
364
369
 
package/PUBLISHING.md CHANGED
@@ -12,10 +12,12 @@ for a plug-and-play Expo SDK.
12
12
 
13
13
  ## Release preparation
14
14
 
15
- The next prepared patch release is **3.11.1**. It fixes premature Android HTTP/2
16
- connection eviction during composite replay. Rebuild consuming Android apps for
17
- this native fix; no provider configuration change is required. Version 3.11.1 was
18
- unused on npm when checked on 2026-10-07; confirm again immediately before publishing.
15
+ The next prepared release is **3.12.0**. It raises individual claims to 8 MiB
16
+ and enforces separate 80 MiB budgets for revealed values and serialized artifacts.
17
+ Rebuild consuming iOS and Android apps. Deploy the matching verifier/proxy and
18
+ measured TEE service, then approve its measurements in the trusted verifier policy
19
+ before clients rely on the larger limits. No provider opt-in is required. Version
20
+ 3.12.0 was unused on npm when checked on 2026-10-07; confirm again before publishing.
19
21
 
20
22
  Observability v2 was introduced in 3.11.0; its existing rollout requirements follow.
21
23
 
@@ -61,7 +63,7 @@ Local cookie cleanup does not reset remote hosted TeeLS sessions.
61
63
  The package check requires both native session managers, the WebView snapshot
62
64
  helper, adapter script, Android keep rules and public JS/declarations. Host tests
63
65
  use synthetic stores and adapter fixtures; they are not substitutes for device
64
- cookie isolation tests. Until the app builds and device matrix pass, treat 3.11.1
66
+ cookie isolation tests. Until the app builds and device matrix pass, treat 3.12.0
65
67
  as release preparation, not a validated stable release.
66
68
 
67
69
  ## TEE release requirements
@@ -269,7 +271,7 @@ internal/module_scripts/
269
271
  After the release gates pass and publication is authorized, use the consolidated
270
272
  `publish-expo-satya-attest.yml` workflow. A stable tag must match the committed
271
273
  package version and point to a commit on `main`; for this prepared release the
272
- package-specific tag is `expo-satya-attest-v3.11.1`. Creating/pushing that tag starts
274
+ package-specific tag is `expo-satya-attest-v3.12.0`. Creating/pushing that tag starts
273
275
  publication. Manual workflow dispatch is a dry-run.
274
276
 
275
277
  The workflow builds native artifacts, runs the release checks, and publishes
@@ -287,13 +289,13 @@ Every push to `main` publishes a snapshot package to the public npm registry wit
287
289
  unique prerelease version:
288
290
 
289
291
  ```text
290
- 3.11.2-snapshot.<run>.<attempt>.sha-<commit>
292
+ 3.12.1-snapshot.<run>.<attempt>.sha-<commit>
291
293
  ```
292
294
 
293
295
  The snapshot job (in `publish-expo-satya-attest.yml`) increments the package's patch base
294
- in CI before publishing. For example, if `package.json` is `3.11.1`, the snapshot version
295
- is based on `3.11.2`:
296
- `3.11.2-snapshot.<run>.<attempt>.sha-<commit>`. Snapshots are development builds and
296
+ in CI before publishing. For example, if `package.json` is `3.12.0`, the snapshot version
297
+ is based on `3.12.1`:
298
+ `3.12.1-snapshot.<run>.<attempt>.sha-<commit>`. Snapshots are development builds and
297
299
  do not imply completion of the physical-device gates.
298
300
 
299
301
  Snapshots use the `snapshot` dist-tag so test apps do not need to know the generated
package/README.md CHANGED
@@ -5,8 +5,9 @@ the Rust `satya-sdk` / `satya-ffi` pipeline for artifact construction and verifi
5
5
  policy, while Swift and Kotlin provide platform-specific WebView capture, native HTTPS
6
6
  replay, hardware-backed signing, and platform attestation evidence.
7
7
 
8
- **3.11.1:** Fixes premature Android HTTP/2 connection cleanup during native replay.
9
- Rebuild the Android app to include the fix; provider configuration is unchanged.
8
+ **3.12.0:** Supports 8 MiB claims with shared 80 MiB disclosure and artifact budgets.
9
+ Rebuild consuming native apps and deploy the matching verifier/TEE services;
10
+ provider configuration is unchanged.
10
11
  Observability v2 remains opt-in. See the [changelog](./CHANGELOG.md),
11
12
  [observability rollout guide](./TEELS_OBSERVABILITY.md) and
12
13
  [release requirements](./PUBLISHING.md#release-preparation).
@@ -996,7 +997,44 @@ disabled and only 2xx responses accepted. `onProgress` reports `proofPlanId`, `e
996
997
 
997
998
  - **1–8 endpoints** per plan, ordered; the order is order-sensitive and participates in
998
999
  `policyHash`.
999
- - **Per-response 8 MiB** and **aggregate 16 MiB** response-byte caps across the plan.
1000
+ - **8 MiB per claim value**, measured as UTF-8 serialized JSON, including quotes and
1001
+ escapes; native uses its existing Rust serialization and TEE preserves exact numbers.
1002
+ - **80 MiB of revealed claim values across all endpoints** and a separate **80 MiB
1003
+ serialized attestation** limit, including metadata and signatures. Each logical claim
1004
+ counts, including overlapping reveals. Raw unrevealed fields do not debit the claim
1005
+ budget. An overflow aborts the proof and stops subsequent replay endpoints, including
1006
+ plans that otherwise allow partial completion. These limits apply automatically.
1007
+ - For example, ten values of exactly 8 MiB exhaust the logical disclosure budget;
1008
+ the full attestation cap can reject earlier because it also includes overhead.
1009
+ A TEE submission includes base64, leaving less than 60 MiB for inner artifact bytes.
1010
+ - Separate raw-response guards allow **16 MiB per endpoint / 128 MiB per run on
1011
+ iOS**, whose buffered extraction makes full-body copies. Android and TEE allow
1012
+ **96 MiB per endpoint / 768 MiB per run**, with bounded decompression. Large
1013
+ unrevealed fields can hit these guards before the disclosure budget.
1014
+ The compatible verifier reply carries plain and
1015
+ exact base64 values and is read with a **240 MiB wire cap**; this does not enlarge
1016
+ the 80 MiB disclosure budget.
1017
+ - Rust JSON processing bounds depth, number tokens and structural work (4,259,840
1018
+ units per document/proof: one per value plus three per object member). This covers
1019
+ TEE response parsing and native selected claims/artifacts, including duplicated
1020
+ disclosure representations. Android and iOS parse raw JSON before selecting claims;
1021
+ their raw-body byte caps do not bound native object counts. Dense unrevealed fields
1022
+ can therefore still amplify native memory use. Capture, endpoint-count and freshness
1023
+ guards remain in force.
1024
+ - Native and TEE reveals share a bounded Rust regex matcher. Ordinary patterns use
1025
+ a linear engine; advanced patterns (such as lookarounds/backreferences) are limited
1026
+ to 256 pattern bytes, 1 KiB inputs and bounded backtracking. Invalid or over-budget
1027
+ patterns fail the proof. Use `jsonRegex` to select a small field before advanced matching.
1028
+ - Large server jobs are admitted automatically above the previous small-data ceilings
1029
+ (2 MiB verifier uploads; 8 MiB raw replay input or 512 KiB retained replay output),
1030
+ with one large job and up to 16 active jobs per process; overload fails explicitly without replay retries.
1031
+ Verifier uploads require 4 KiB/s progress with at most 10 seconds of startup/burst
1032
+ allowance, plus 10-second idle / 120-second total deadlines. At most 12 uploads
1033
+ may wait for data, leaving four slots for already-buffered requests. These process
1034
+ limits complement edge DDoS controls. Release qualification still requires
1035
+ physical-device memory tests and deployed mixed-load tests. Native verifier/TEE
1036
+ responses use Expo streaming fetch. Custom TEE fetch overrides must provide
1037
+ streaming bodies; non-streaming responses are rejected.
1000
1038
  - Capture selection runs for at most the plan's `maxDurationMs` (an integer in
1001
1039
  `[1000, 120000]` ms). A readiness signal starts the window when received; otherwise the
1002
1040
  first accepted capture starts it. Later readiness never resets an earlier start.
@@ -4,14 +4,14 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'expo.modules.satyaattest'
7
- version = '3.11.1'
7
+ version = '3.12.0'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.satyaattest"
11
11
  defaultConfig {
12
12
  consumerProguardFiles 'consumer-rules.pro'
13
13
  versionCode 1
14
- versionName "3.11.1"
14
+ versionName "3.12.0"
15
15
  // StrongBox key attestation needs API 28+; basic Keystore attestation API 24+.
16
16
  minSdkVersion 24
17
17
  }
@@ -64,6 +64,8 @@ import org.json.JSONTokener
64
64
  import uniffi.satya_ffi.WitnessStatementSigner
65
65
  import uniffi.satya_ffi.generateNativeReplayBundle
66
66
  import uniffi.satya_ffi.generateNativeReplayObservation
67
+ import uniffi.satya_ffi.measureRevealClaimValue
68
+ import uniffi.satya_ffi.matchRevealRegex
67
69
  import uniffi.satya_ffi.prepareNativeReplayBundle
68
70
  import uniffi.satya_ffi.satyaCoreVersion
69
71
  import uniffi.satya_ffi.verifyKaggleArtifact
@@ -71,7 +73,17 @@ import uniffi.satya_ffi.verifyKaggleArtifact
71
73
  private const val KEY_ALIAS_PREFIX = "satya-w-witness-"
72
74
 
73
75
  // Cap replay bodies before JSON/regex claim extraction.
74
- private const val MAX_RESPONSE_BODY_BYTES = 8L * 1024 * 1024
76
+ private const val MAX_RESPONSE_BODY_BYTES = 96L * 1024 * 1024
77
+
78
+ private class NativeRevealBudget {
79
+ private var used = 0L
80
+ fun add(value: Any) {
81
+ val wrapped = JSONArray().put(value).toString()
82
+ val bytes = measureRevealClaimValue(wrapped.substring(1, wrapped.length - 1)).toLong()
83
+ require(bytes <= 80L * 1024 * 1024 - used) { "revealed claim values exceed 80 MiB" }
84
+ used += bytes
85
+ }
86
+ }
75
87
 
76
88
  private const val PLAY_INTEGRITY_BIND_DOMAIN = "satya-w-playintegrity-bind-v1"
77
89
 
@@ -762,6 +774,7 @@ class SatyaAttestModule : Module() {
762
774
  "composite replay start plan=$proofPlanId endpoints=${orderedRequests.size}",
763
775
  )
764
776
  var totalResponseBytes = 0L
777
+ val claimBudget = NativeRevealBudget()
765
778
  val observations = ArrayList<CompositeExchangeObservation>(orderedRequests.size)
766
779
  try {
767
780
  for (exchangeRequest in orderedRequests) {
@@ -782,6 +795,7 @@ class SatyaAttestModule : Module() {
782
795
  trustPolicy = trustPolicy,
783
796
  cookieJar = cookieJar,
784
797
  priorResponseBytes = totalResponseBytes,
798
+ claimBudget = claimBudget,
785
799
  deadlineAtMonotonicMs = deadlineAtMonotonicMs,
786
800
  )
787
801
  }
@@ -852,6 +866,7 @@ class SatyaAttestModule : Module() {
852
866
  trustPolicy: String,
853
867
  cookieJar: ProofCookieJar,
854
868
  priorResponseBytes: Long,
869
+ claimBudget: NativeRevealBudget,
855
870
  deadlineAtMonotonicMs: Long,
856
871
  ): CompositeExchangeObservation {
857
872
  val endpointMethod = endpoint.optString("method", "GET")
@@ -1003,7 +1018,7 @@ class SatyaAttestModule : Module() {
1003
1018
 
1004
1019
  // Extract ONLY this endpoint's governed reveals.
1005
1020
  val reveals = compositeRevealRules(endpoint)
1006
- val claimsJson = extractRevealClaims(responseBody.text, reveals)
1021
+ val claimsJson = extractRevealClaims(responseBody.text, reveals, claimBudget)
1007
1022
  val claims = (0 until claimsJson.length()).map { index ->
1008
1023
  val claim = claimsJson.getJSONObject(index)
1009
1024
  CompositeClaim(
@@ -1752,10 +1767,12 @@ class SatyaAttestModule : Module() {
1752
1767
  aliasesByPath: Map<String, String>,
1753
1768
  ): JSONArray {
1754
1769
  val root = JSONObject(body)
1770
+ val budget = NativeRevealBudget()
1755
1771
  val claims = JSONArray()
1756
1772
  for (index in 0 until jsonPaths.length()) {
1757
1773
  val path = jsonPaths.getString(index)
1758
1774
  val value = jsonPathGet(root, path) ?: continue
1775
+ budget.add(value)
1759
1776
  claims.put(
1760
1777
  JSONObject().apply {
1761
1778
  put("name", aliasesByPath[path] ?: claimName(path))
@@ -1768,7 +1785,7 @@ class SatyaAttestModule : Module() {
1768
1785
  }
1769
1786
 
1770
1787
  // Structured JSON/regex claim extraction.
1771
- private fun extractRevealClaims(body: String, reveals: JSONArray): JSONArray {
1788
+ private fun extractRevealClaims(body: String, reveals: JSONArray, budget: NativeRevealBudget = NativeRevealBudget()): JSONArray {
1772
1789
  val claims = JSONArray()
1773
1790
  val seenAliases = mutableMapOf<String, String>()
1774
1791
  var jsonRoot: Any? = null
@@ -1804,6 +1821,7 @@ class SatyaAttestModule : Module() {
1804
1821
  else -> null
1805
1822
  }
1806
1823
  if (value == null || value == JSONObject.NULL) continue
1824
+ budget.add(value)
1807
1825
  // Regex-only reveals use the alias as the disclosure path.
1808
1826
  val sourcePath = when (type) {
1809
1827
  "json", "jsonRegex" -> path
@@ -1821,20 +1839,11 @@ class SatyaAttestModule : Module() {
1821
1839
  }
1822
1840
 
1823
1841
  private fun applyRevealRegex(input: String, pattern: String, group: Any?): String? {
1824
- if (pattern.isEmpty()) return null
1825
- val matcher = runCatching { java.util.regex.Pattern.compile(pattern).matcher(input) }
1826
- .getOrNull() ?: return null
1827
- if (!matcher.find()) return null
1828
- val namedGroup = (group as? String)?.takeIf { it.toIntOrNull() == null }
1829
- if (namedGroup != null) {
1830
- return runCatching { matcher.group(namedGroup) }.getOrNull()
1831
- }
1832
- val groupIndex = when (group) {
1833
- is Number -> group.toInt()
1834
- is String -> group.toIntOrNull() ?: 1
1835
- else -> if (matcher.groupCount() >= 1) 1 else 0
1836
- }
1837
- return runCatching { matcher.group(groupIndex) }.getOrNull()
1842
+ return matchRevealRegex(input, pattern, when (group) {
1843
+ is String -> group
1844
+ is Number -> group.toInt().toString()
1845
+ else -> null
1846
+ })
1838
1847
  }
1839
1848
 
1840
1849
  // Buffer one byte past the cap so oversize bodies fail closed.
@@ -470,16 +470,16 @@ data class CompositeExchangeObservation(
470
470
  )
471
471
 
472
472
  /**
473
- * Per-response (8 MiB) and aggregate (16 MiB) response-byte caps for the
473
+ * Per-response (96 MiB) and aggregate (768 MiB) response-byte caps for the
474
474
  * composite bundle, mirroring the Rust `MAX_EXCHANGE_RESPONSE_BYTES` /
475
475
  * `MAX_TOTAL_RESPONSE_BYTES`. Pure so the accounting can be unit-tested without a
476
476
  * live OkHttp call.
477
477
  */
478
478
  object CompositeByteBudget {
479
- const val MAX_EXCHANGE_RESPONSE_BYTES: Long = 8L * 1024 * 1024
480
- const val MAX_BUNDLE_RESPONSE_BYTES: Long = 16L * 1024 * 1024
479
+ const val MAX_EXCHANGE_RESPONSE_BYTES: Long = 96L * 1024 * 1024
480
+ const val MAX_BUNDLE_RESPONSE_BYTES: Long = 8 * MAX_EXCHANGE_RESPONSE_BYTES
481
481
 
482
- /** Rejects a single exchange whose response exceeds 8 MiB; returns the count. */
482
+ /** Rejects a single exchange whose response exceeds 96 MiB; returns the count. */
483
483
  fun requireExchangeWithinCap(byteCount: Long): Long {
484
484
  require(byteCount in 0..MAX_EXCHANGE_RESPONSE_BYTES) {
485
485
  "composite replay response exceeds $MAX_EXCHANGE_RESPONSE_BYTES bytes"
@@ -489,7 +489,7 @@ object CompositeByteBudget {
489
489
 
490
490
  /**
491
491
  * Adds one exchange's bytes to the running total, enforcing both the
492
- * per-exchange 8 MiB cap and the aggregate 16 MiB cap. Returns the new total.
492
+ * per-exchange 96 MiB cap and the aggregate 768 MiB cap. Returns the new total.
493
493
  */
494
494
  fun accumulate(priorTotal: Long, exchangeBytes: Long): Long {
495
495
  requireExchangeWithinCap(exchangeBytes)
@@ -661,6 +661,10 @@ internal object IntegrityCheckingUniffiLib {
661
661
  ): Short
662
662
  external fun uniffi_satya_ffi_checksum_func_generate_native_replay_observation(
663
663
  ): Short
664
+ external fun uniffi_satya_ffi_checksum_func_match_reveal_regex(
665
+ ): Short
666
+ external fun uniffi_satya_ffi_checksum_func_measure_reveal_claim_value(
667
+ ): Short
664
668
  external fun uniffi_satya_ffi_checksum_func_prepare_native_replay_bundle(
665
669
  ): Short
666
670
  external fun uniffi_satya_ffi_checksum_func_satya_core_version(
@@ -689,6 +693,10 @@ internal object UniffiLib {
689
693
  ): RustBuffer.ByValue
690
694
  external fun uniffi_satya_ffi_fn_func_generate_native_replay_observation(`replayJson`: RustBuffer.ByValue,`evidenceJson`: RustBuffer.ByValue,`signer`: Long,uniffi_out_err: UniffiRustCallStatus,
691
695
  ): RustBuffer.ByValue
696
+ external fun uniffi_satya_ffi_fn_func_match_reveal_regex(`input`: RustBuffer.ByValue,`pattern`: RustBuffer.ByValue,`group`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus,
697
+ ): RustBuffer.ByValue
698
+ external fun uniffi_satya_ffi_fn_func_measure_reveal_claim_value(`valueJson`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus,
699
+ ): Long
692
700
  external fun uniffi_satya_ffi_fn_func_prepare_native_replay_bundle(`replayBundleJson`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus,
693
701
  ): RustBuffer.ByValue
694
702
  external fun uniffi_satya_ffi_fn_func_satya_core_version(uniffi_out_err: UniffiRustCallStatus,
@@ -820,6 +828,12 @@ private fun uniffiCheckApiChecksums(lib: IntegrityCheckingUniffiLib) {
820
828
  if (lib.uniffi_satya_ffi_checksum_func_generate_native_replay_observation() != 992.toShort()) {
821
829
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
822
830
  }
831
+ if (lib.uniffi_satya_ffi_checksum_func_match_reveal_regex() != 15030.toShort()) {
832
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
833
+ }
834
+ if (lib.uniffi_satya_ffi_checksum_func_measure_reveal_claim_value() != 26745.toShort()) {
835
+ throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
836
+ }
823
837
  if (lib.uniffi_satya_ffi_checksum_func_prepare_native_replay_bundle() != 12159.toShort()) {
824
838
  throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
825
839
  }
@@ -956,6 +970,29 @@ public abstract class FfiConverterCallbackInterface<CallbackInterface: Any>: Ffi
956
970
  }
957
971
  }
958
972
 
973
+ /**
974
+ * @suppress
975
+ */
976
+ public object FfiConverterULong: FfiConverter<ULong, Long> {
977
+ override fun lift(value: Long): ULong {
978
+ return value.toULong()
979
+ }
980
+
981
+ override fun read(buf: ByteBuffer): ULong {
982
+ return lift(buf.getLong())
983
+ }
984
+
985
+ override fun lower(value: ULong): Long {
986
+ return value.toLong()
987
+ }
988
+
989
+ override fun allocationSize(value: ULong) = 8UL
990
+
991
+ override fun write(value: ULong, buf: ByteBuffer) {
992
+ buf.putLong(value.toLong())
993
+ }
994
+ }
995
+
959
996
  /**
960
997
  * @suppress
961
998
  */
@@ -1364,6 +1401,34 @@ public object FfiConverterOptionalString: FfiConverterRustBuffer<kotlin.String?>
1364
1401
  }
1365
1402
 
1366
1403
 
1404
+ /**
1405
+ * Match native reveals with the same bounded engine as TEE replay.
1406
+ */
1407
+ @Throws(FfiException::class) fun `matchRevealRegex`(`input`: kotlin.String, `pattern`: kotlin.String, `group`: kotlin.String?): kotlin.String? {
1408
+ return FfiConverterOptionalString.lift(
1409
+ uniffiRustCallWithError(FfiException) { _status ->
1410
+ UniffiLib.uniffi_satya_ffi_fn_func_match_reveal_regex(
1411
+
1412
+ FfiConverterString.lower(`input`),FfiConverterString.lower(`pattern`),FfiConverterOptionalString.lower(`group`),_status)
1413
+ }
1414
+ )
1415
+ }
1416
+
1417
+
1418
+ /**
1419
+ * Count with the same serializer as native commitments, including quotes and escapes.
1420
+ */
1421
+ @Throws(FfiException::class) fun `measureRevealClaimValue`(`valueJson`: kotlin.String): kotlin.ULong {
1422
+ return FfiConverterULong.lift(
1423
+ uniffiRustCallWithError(FfiException) { _status ->
1424
+ UniffiLib.uniffi_satya_ffi_fn_func_measure_reveal_claim_value(
1425
+
1426
+ FfiConverterString.lower(`valueJson`),_status)
1427
+ }
1428
+ )
1429
+ }
1430
+
1431
+
1367
1432
  /**
1368
1433
  * Phase one of the composite flow: parse and fully validate a trusted-native
1369
1434
  * replay bundle, fix the session id / nonce / issuance window, and return the
@@ -1 +1 @@
1
- {"version":3,"file":"SatyaMobileClient.d.ts","sourceRoot":"","sources":["../src/SatyaMobileClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,wBAAwB,EACxB,iCAAiC,EAClC,MAAM,mCAAmC,CAAC;AAS3C,OAAO,EACL,aAAa,EACb,uBAAuB,EAGvB,qBAAqB,EACrB,aAAa,EACb,oBAAoB,EACpB,YAAY,EACb,MAAM,SAAS,CAAC;AAQjB,KAAK,gBAAgB,GAAG,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;AA0B1D,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,eAAe,EAAE,oBAAoB,CAAC;IACtC,eAAe,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACjD,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,4BAA4B;IAC3C,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,eAAe,EAAE,oBAAoB,CAAC;IACtC,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC1D,+EAA+E;IAC/E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAOD,oFAAoF;AACpF,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,iCAAiC,CAAC;AAEvF,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACjD;AAcD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+B;IAEzD,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI;IAOzD,OAAO,CAAC,IAAI;IAYZ,+EAA+E;IACzE,YAAY,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAmBjF,+EAA+E;IACzE,kBAAkB,CAAC,IAAI,EAAE,4BAA4B,GAAG,OAAO,CAAC,sBAAsB,CAAC;YAyB/E,YAAY;IAiEpB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwI9E;;;;;OAKG;IACG,wBAAwB,CAAC,IAAI,EAAE,4BAA4B,GAAG,OAAO,CAAC,aAAa,CAAC;IA0SpF,MAAM,CACV,YAAY,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,oBAAoB,GACrC,OAAO,CAAC,YAAY,CAAC;IAmDxB,WAAW,IAAI,MAAM;IAIrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAGzB"}
1
+ {"version":3,"file":"SatyaMobileClient.d.ts","sourceRoot":"","sources":["../src/SatyaMobileClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,wBAAwB,EACxB,iCAAiC,EAClC,MAAM,mCAAmC,CAAC;AAS3C,OAAO,EACL,aAAa,EACb,uBAAuB,EAGvB,qBAAqB,EACrB,aAAa,EACb,oBAAoB,EACpB,YAAY,EACb,MAAM,SAAS,CAAC;AASjB,KAAK,gBAAgB,GAAG,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;AA0B1D,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,eAAe,EAAE,oBAAoB,CAAC;IACtC,eAAe,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACjD,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,4BAA4B;IAC3C,gBAAgB,EAAE,qBAAqB,CAAC;IACxC,eAAe,EAAE,oBAAoB,CAAC;IACtC,iEAAiE;IACjE,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC1D,+EAA+E;IAC/E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,oEAAoE;IACpE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAOD,oFAAoF;AACpF,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,iCAAiC,CAAC;AAEvF,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,aAAa,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACjD;AAcD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+B;IAEzD,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI;IAOzD,OAAO,CAAC,IAAI;IAYZ,+EAA+E;IACzE,YAAY,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAmBjF,+EAA+E;IACzE,kBAAkB,CAAC,IAAI,EAAE,4BAA4B,GAAG,OAAO,CAAC,sBAAsB,CAAC;YAyB/E,YAAY;IAiEpB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,aAAa,CAAC;IAyI9E;;;;;OAKG;IACG,wBAAwB,CAAC,IAAI,EAAE,4BAA4B,GAAG,OAAO,CAAC,aAAa,CAAC;IA2SpF,MAAM,CACV,YAAY,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,oBAAoB,GACrC,OAAO,CAAC,YAAY,CAAC;IAmDxB,WAAW,IAAI,MAAM;IAIrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAGzB"}
@@ -6,6 +6,7 @@ import { nativeReplayBundleArgs } from './nativeReplayArgs';
6
6
  import { reportProviderIngest } from './providerMonitor';
7
7
  import { getSatyaRuntimeConfig, isPartialEndpointsAllowedForProvider, resolveAppId, } from './satyaConfig';
8
8
  import { SatyaErrorCode, asSatyaError, satyaError, } from './types/error.types';
9
+ import { assertArtifactSize } from './utils/dataLimits';
9
10
  const REPLAY_PROGRESS = [
10
11
  ['witnessEnrollment', 'Enrolling witness key', 0.12],
11
12
  ['sessionChallenge', 'Creating session challenge', 0.24],
@@ -166,6 +167,7 @@ export class SatyaMobileClient {
166
167
  try {
167
168
  artifact = attachArtifactProducer(JSON.parse(raw), this.coreVersion());
168
169
  raw = JSON.stringify(artifact);
170
+ assertArtifactSize(raw);
169
171
  }
170
172
  catch (cause) {
171
173
  const error = satyaError(SatyaErrorCode.ARTIFACT_VERIFICATION_FAILED, 'native replay returned invalid artifact JSON', {
@@ -350,6 +352,7 @@ export class SatyaMobileClient {
350
352
  try {
351
353
  artifact = attachArtifactProducer(JSON.parse(raw), this.coreVersion());
352
354
  raw = JSON.stringify(artifact);
355
+ assertArtifactSize(raw);
353
356
  }
354
357
  catch (cause) {
355
358
  const error = satyaError(SatyaErrorCode.ARTIFACT_VERIFICATION_FAILED, 'native replay bundle returned invalid artifact JSON', {