@burnt-labs/expo-satya-attest 3.7.1 → 3.8.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 +42 -0
- package/PROVIDER_CONFIG.md +5 -0
- package/PUBLISHING.md +30 -0
- package/README.md +40 -10
- package/TEE_REPLAY.md +231 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/satyaattest/SatyaAttestModule.kt +19 -2
- package/android/src/main/jniLibs/arm64-v8a/libsatya_ffi.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libsatya_ffi.so +0 -0
- package/android/src/main/jniLibs/x86_64/libsatya_ffi.so +0 -0
- package/build/SatyaAttestModule.d.ts +7 -0
- package/build/SatyaAttestModule.d.ts.map +1 -1
- package/build/SatyaAttestModule.js.map +1 -1
- package/build/SatyaAttestModule.web.d.ts +1 -0
- package/build/SatyaAttestModule.web.d.ts.map +1 -1
- package/build/SatyaAttestModule.web.js +3 -0
- package/build/SatyaAttestModule.web.js.map +1 -1
- package/build/SatyaMobileClient.d.ts +10 -2
- package/build/SatyaMobileClient.d.ts.map +1 -1
- package/build/SatyaMobileClient.js +105 -2
- package/build/SatyaMobileClient.js.map +1 -1
- package/build/SatyaProviderAttestButton.d.ts +2 -1
- package/build/SatyaProviderAttestButton.d.ts.map +1 -1
- package/build/SatyaProviderAttestButton.js +23 -3
- package/build/SatyaProviderAttestButton.js.map +1 -1
- package/build/components/providerAttest/flowSelection.d.ts +18 -0
- package/build/components/providerAttest/flowSelection.d.ts.map +1 -1
- package/build/components/providerAttest/flowSelection.js +37 -1
- package/build/components/providerAttest/flowSelection.js.map +1 -1
- package/build/components/providerAttest/providerResolution.d.ts.map +1 -1
- package/build/components/providerAttest/providerResolution.js +18 -1
- package/build/components/providerAttest/providerResolution.js.map +1 -1
- package/build/components/providerAttest/replayRewrite.d.ts +2 -0
- package/build/components/providerAttest/replayRewrite.d.ts.map +1 -1
- package/build/components/providerAttest/replayRewrite.js +9 -0
- package/build/components/providerAttest/replayRewrite.js.map +1 -1
- package/build/components/providerAttest/tee/teeResult.d.ts +6 -0
- package/build/components/providerAttest/tee/teeResult.d.ts.map +1 -0
- package/build/components/providerAttest/tee/teeResult.js +27 -0
- package/build/components/providerAttest/tee/teeResult.js.map +1 -0
- package/build/components/providerAttest/tee/useTeeReplaySwap.d.ts +53 -0
- package/build/components/providerAttest/tee/useTeeReplaySwap.d.ts.map +1 -0
- package/build/components/providerAttest/tee/useTeeReplaySwap.js +421 -0
- package/build/components/providerAttest/tee/useTeeReplaySwap.js.map +1 -0
- package/build/components/providerAttest/types.d.ts +11 -1
- package/build/components/providerAttest/types.d.ts.map +1 -1
- package/build/components/providerAttest/types.js.map +1 -1
- package/build/components/providerAttest/useFunnelEmitter.d.ts +2 -7
- package/build/components/providerAttest/useFunnelEmitter.d.ts.map +1 -1
- package/build/components/providerAttest/useFunnelEmitter.js +9 -9
- package/build/components/providerAttest/useFunnelEmitter.js.map +1 -1
- package/build/components/providerAttest/useProviderAttestFlow.d.ts +2 -2
- package/build/components/providerAttest/useProviderAttestFlow.d.ts.map +1 -1
- package/build/components/providerAttest/useProviderAttestFlow.js +120 -8
- package/build/components/providerAttest/useProviderAttestFlow.js.map +1 -1
- package/build/components/providerAttest/useProviderFlowLifecycle.d.ts +4 -2
- package/build/components/providerAttest/useProviderFlowLifecycle.d.ts.map +1 -1
- package/build/components/providerAttest/useProviderFlowLifecycle.js +14 -4
- package/build/components/providerAttest/useProviderFlowLifecycle.js.map +1 -1
- package/build/index.d.ts +4 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -0
- package/build/index.js.map +1 -1
- package/build/providerRegistry/template.d.ts.map +1 -1
- package/build/providerRegistry/template.js +6 -3
- package/build/providerRegistry/template.js.map +1 -1
- package/build/satyaConfig.d.ts +21 -0
- package/build/satyaConfig.d.ts.map +1 -1
- package/build/satyaConfig.js +80 -1
- package/build/satyaConfig.js.map +1 -1
- package/build/sdkEventLog.d.ts +2 -0
- package/build/sdkEventLog.d.ts.map +1 -1
- package/build/sdkEventLog.js +21 -0
- package/build/sdkEventLog.js.map +1 -1
- package/build/sdkMetadata.generated.d.ts +1 -1
- package/build/sdkMetadata.generated.js +1 -1
- package/build/sdkMetadata.generated.js.map +1 -1
- package/build/tee/claims.d.ts +10 -0
- package/build/tee/claims.d.ts.map +1 -0
- package/build/tee/claims.js +54 -0
- package/build/tee/claims.js.map +1 -0
- package/build/tee/client.d.ts +112 -0
- package/build/tee/client.d.ts.map +1 -0
- package/build/tee/client.js +514 -0
- package/build/tee/client.js.map +1 -0
- package/build/tee/cookies.d.ts +3 -0
- package/build/tee/cookies.d.ts.map +1 -0
- package/build/tee/cookies.js +14 -0
- package/build/tee/cookies.js.map +1 -0
- package/build/tee/crypto.d.ts +19 -0
- package/build/tee/crypto.d.ts.map +1 -0
- package/build/tee/crypto.js +111 -0
- package/build/tee/crypto.js.map +1 -0
- package/build/tee/errors.d.ts +98 -0
- package/build/tee/errors.d.ts.map +1 -0
- package/build/tee/errors.js +149 -0
- package/build/tee/errors.js.map +1 -0
- package/build/tee/index.d.ts +11 -0
- package/build/tee/index.d.ts.map +1 -0
- package/build/tee/index.js +7 -0
- package/build/tee/index.js.map +1 -0
- package/build/tee/mobileRelay.d.ts +35 -0
- package/build/tee/mobileRelay.d.ts.map +1 -0
- package/build/tee/mobileRelay.js +353 -0
- package/build/tee/mobileRelay.js.map +1 -0
- package/build/tee/quoteBinding.d.ts +26 -0
- package/build/tee/quoteBinding.d.ts.map +1 -0
- package/build/tee/quoteBinding.js +159 -0
- package/build/tee/quoteBinding.js.map +1 -0
- package/build/tee/relayGuard.d.ts +20 -0
- package/build/tee/relayGuard.d.ts.map +1 -0
- package/build/tee/relayGuard.js +55 -0
- package/build/tee/relayGuard.js.map +1 -0
- package/build/tee/secureRandom.d.ts +24 -0
- package/build/tee/secureRandom.d.ts.map +1 -0
- package/build/tee/secureRandom.js +103 -0
- package/build/tee/secureRandom.js.map +1 -0
- package/build/tee/telemetry.d.ts +16 -0
- package/build/tee/telemetry.d.ts.map +1 -0
- package/build/tee/telemetry.js +75 -0
- package/build/tee/telemetry.js.map +1 -0
- package/build/tee/types.d.ts +85 -0
- package/build/tee/types.d.ts.map +1 -0
- package/build/tee/types.js +3 -0
- package/build/tee/types.js.map +1 -0
- package/build/tee-entry.d.ts +9 -0
- package/build/tee-entry.d.ts.map +1 -0
- package/build/tee-entry.js +19 -0
- package/build/tee-entry.js.map +1 -0
- package/build/types/error.types.d.ts +16 -1
- package/build/types/error.types.d.ts.map +1 -1
- package/build/types/error.types.js +39 -0
- package/build/types/error.types.js.map +1 -1
- package/build/types/mobile.types.d.ts +2 -0
- package/build/types/mobile.types.d.ts.map +1 -1
- package/build/types/mobile.types.js.map +1 -1
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/libsatya_ffi.a +0 -0
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64_x86_64-simulator/libsatya_ffi.a +0 -0
- package/ios/SatyaAttest.podspec +1 -1
- package/ios/SatyaAttestModule.swift +245 -192
- package/ios/SatyaCompositeReplay.swift +26 -15
- package/ios/SatyaWebViewCookies.swift +86 -0
- package/package.json +12 -5
- package/scripts/build-rust-android.sh +1 -1
- package/src/SatyaAttestModule.ts +7 -0
- package/src/SatyaAttestModule.web.ts +3 -0
- package/src/SatyaMobileClient.ts +180 -3
- package/src/SatyaProviderAttestButton.tsx +42 -6
- package/src/components/providerAttest/flowSelection.ts +55 -2
- package/src/components/providerAttest/providerResolution.ts +18 -1
- package/src/components/providerAttest/replayRewrite.ts +17 -0
- package/src/components/providerAttest/tee/teeResult.ts +36 -0
- package/src/components/providerAttest/tee/useTeeReplaySwap.ts +541 -0
- package/src/components/providerAttest/types.ts +24 -0
- package/src/components/providerAttest/useFunnelEmitter.ts +32 -29
- package/src/components/providerAttest/useProviderAttestFlow.ts +190 -41
- package/src/components/providerAttest/useProviderFlowLifecycle.ts +18 -3
- package/src/index.ts +31 -0
- package/src/providerRegistry/template.ts +8 -3
- package/src/satyaConfig.ts +122 -1
- package/src/sdkEventLog.ts +24 -0
- package/src/sdkMetadata.generated.ts +1 -1
- package/src/tee/claims.ts +70 -0
- package/src/tee/client.ts +755 -0
- package/src/tee/cookies.ts +13 -0
- package/src/tee/crypto.ts +143 -0
- package/src/tee/errors.ts +204 -0
- package/src/tee/index.ts +21 -0
- package/src/tee/mobileRelay.ts +438 -0
- package/src/tee/quoteBinding.ts +184 -0
- package/src/tee/relayGuard.ts +83 -0
- package/src/tee/secureRandom.ts +124 -0
- package/src/tee/telemetry.ts +87 -0
- package/src/tee/types.ts +88 -0
- package/src/tee-entry.ts +31 -0
- package/src/types/error.types.ts +44 -0
- package/src/types/mobile.types.ts +2 -0
- package/tee/package.json +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.8.0 - 2026-09-14
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Await WebKit cookies for iOS native replay, with a bounded timeout and correct
|
|
8
|
+
cookie scoping/expiry. Add iOS and Android cookie-read regression coverage.
|
|
9
|
+
- Preserve verifier rejection details and relay failure causes; report TEE proof-generation health separately from verification.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Add TEE stage logs, typed error reasons and correlated timing/error metadata to the existing SDK events.
|
|
14
|
+
- Opt-in `attestationMode: 'tee-replay'` with the existing registry, WebView,
|
|
15
|
+
capture, proof-plan and partial-proof configuration. Default remains app attestation.
|
|
16
|
+
- One quote authenticates the enclave keys and all replay targets; one signed
|
|
17
|
+
bundle carries full or partial results to `POST /v1/artifacts/verify` (schema 3.1.0).
|
|
18
|
+
- Mode-aware `SatyaMobileClient.attestReplay` / `attestReplayBundle`, online TEE
|
|
19
|
+
verification, typed errors and optional `teeReplayServerUrl` / `teeTrustConfig` restrictions.
|
|
20
|
+
- Device egress relay with provider certificate and hostname checks inside the TEE.
|
|
21
|
+
Provider SPKI pins remain specific to native replay. TEE makes no app/device identity
|
|
22
|
+
or residential-IP/location claim.
|
|
23
|
+
- Credential-free quote preparation during eligible capture and ordered same-origin
|
|
24
|
+
TLS connection reuse within one bundle. Replay requests are never automatically retried.
|
|
25
|
+
- `/tee` `getTeeClaims` returns endpoint-scoped claims with exact JSON text for
|
|
26
|
+
single, multiple and partial runs; requires the matching verifier's claim attribution.
|
|
27
|
+
|
|
28
|
+
### Integration
|
|
29
|
+
|
|
30
|
+
- For TEE, import from `@burnt-labs/expo-satya-attest/tee`, install the optional
|
|
31
|
+
`react-native-tcp-socket` peer and rebuild the native app. WebView cookies and
|
|
32
|
+
secure randomness use this SDK's native bridge; no cookie package, Gradle patch
|
|
33
|
+
or RNG polyfill is required. See [TEE setup](./TEE_REPLAY.md).
|
|
34
|
+
- Existing app-attestation imports and callback types are unchanged and do not
|
|
35
|
+
require the TCP peer. Only `/tee` uses the native/TEE artifact union; see
|
|
36
|
+
[result types](./TEE_REPLAY.md#result-types).
|
|
37
|
+
- This release prioritizes app attestation. TEE service readiness is deferred to
|
|
38
|
+
a follow-up patch release. Deploy and validate the matching verifier and
|
|
39
|
+
measured replay service before enabling TEE.
|
|
40
|
+
TEE verification is online and single-use; preserve opaque artifact bytes.
|
|
41
|
+
- TEE respects explicit transport app IDs and the same provider policy hash rules
|
|
42
|
+
as native mode. Partial init calls preserve the selected mode; switch back explicitly
|
|
43
|
+
with `attestationMode: 'app-attestation'` before remounting the button.
|
|
44
|
+
|
|
3
45
|
## 3.7.1 - 2026-09-09
|
|
4
46
|
|
|
5
47
|
### Fixed
|
package/PROVIDER_CONFIG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Provider Config
|
|
2
2
|
|
|
3
|
+
App-attestation and TEE replay use the same registry configuration. TEE ignores
|
|
4
|
+
SPKI pins while retaining exact host authorization and enclave certificate/hostname
|
|
5
|
+
checks; one quote-bound bundle covers full/partial proof plans. See
|
|
6
|
+
[TEE compatibility and setup](./TEE_REPLAY.md#provider-features).
|
|
7
|
+
|
|
3
8
|
A provider config is **trusted policy** for the native replay flow. One config decides:
|
|
4
9
|
|
|
5
10
|
- which URL may be replayed (`endpoints[].url` + `tlsIdentityPolicy`),
|
package/PUBLISHING.md
CHANGED
|
@@ -10,6 +10,36 @@ very large native artifacts. The npm tarball still needs the native artifacts un
|
|
|
10
10
|
package is redesigned to download or build them during install, which is not recommended
|
|
11
11
|
for a plug-and-play Expo SDK.
|
|
12
12
|
|
|
13
|
+
## 3.8.0 release preparation
|
|
14
|
+
|
|
15
|
+
Version 3.8.0 prioritizes app attestation and can be published before TEE service
|
|
16
|
+
readiness, which is deferred to a follow-up patch release. TEE remains opt-in;
|
|
17
|
+
deploy and validate the matching verifier and measured service before enabling
|
|
18
|
+
it for consumers.
|
|
19
|
+
|
|
20
|
+
Cloudflare operators deploy the durable-state
|
|
21
|
+
migration before the verifier; Phala images are built/pushed manually using
|
|
22
|
+
`deploy/phala/publish.sh`, then pinned by digest. See [TEE setup](./TEE_REPLAY.md).
|
|
23
|
+
|
|
24
|
+
Rebuild all native artifacts from the release commit. TEE consumers use the `/tee`
|
|
25
|
+
entry point and need a native build for the cookie bridge and optional TCP peer;
|
|
26
|
+
app-attestation imports and callback types stay unchanged. No example-only patches are
|
|
27
|
+
required. Keep captured requests, cookies, local env files and test results out
|
|
28
|
+
of both Git and the package. The example and internal tests are excluded by the
|
|
29
|
+
package whitelist; `check:pack` validates the resulting file list.
|
|
30
|
+
|
|
31
|
+
Preparing a tarball does not publish it:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm run release:check
|
|
35
|
+
npm run test:entrypoint-bundles
|
|
36
|
+
npm pack --pack-destination /tmp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Retain the tarball checksum and source commit with release evidence. Run Android
|
|
40
|
+
native unit tests from the example's generated `android/` project with
|
|
41
|
+
`./gradlew :burnt-labs-expo-satya-attest:testDebugUnitTest` after building it.
|
|
42
|
+
|
|
13
43
|
## Package Name
|
|
14
44
|
|
|
15
45
|
Use the scoped public package owned by the Burnt npm organization:
|
package/README.md
CHANGED
|
@@ -5,6 +5,30 @@ 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
|
+
## TEE replay
|
|
9
|
+
|
|
10
|
+
Import from `@burnt-labs/expo-satya-attest/tee` and use
|
|
11
|
+
`initSatyaAttest({ appId, attestationMode: 'tee-replay' })` with the normal
|
|
12
|
+
provider WebView and capture flow. The configured verifier advertises the replay
|
|
13
|
+
service; the SDK seals captured credentials only after quote preflight, relays
|
|
14
|
+
TLS through the device and submits family 3 to the same verification endpoint.
|
|
15
|
+
TEE ignores provider SPKI pins; certificate-chain and hostname verification
|
|
16
|
+
remain mandatory inside the enclave. One initial quote and one signed bundle
|
|
17
|
+
cover all selected endpoints and authenticated partial outcomes. `onComplete`
|
|
18
|
+
returns the opaque schema 3.1 envelope and verified completion metadata.
|
|
19
|
+
|
|
20
|
+
For captured-request integrations, `SatyaMobileClient.attestReplay` and
|
|
21
|
+
`attestReplayBundle` honor the init mode. Explicit `attestNativeReplay*` methods
|
|
22
|
+
remain native APIs. TEE results require online verification; `verify(raw,
|
|
23
|
+
transportConfig)` submits a TEE envelope to the shared endpoint. Finalization is
|
|
24
|
+
single-use, so submitting an already verified proof again is rejected.
|
|
25
|
+
|
|
26
|
+
For TEE, install the optional TCP native peer and rebuild the app; cookie access and randomness use
|
|
27
|
+
the SDK native bridge. See [TEE setup and provider compatibility](./TEE_REPLAY.md).
|
|
28
|
+
|
|
29
|
+
App-attestation-only consumers keep the default import and existing callback
|
|
30
|
+
types. They do not need the TCP package or TEE configuration.
|
|
31
|
+
|
|
8
32
|
## Prerequisite: register your app for an app id
|
|
9
33
|
|
|
10
34
|
**SDK 3.x requires an `appId`.** Register your app at
|
|
@@ -17,16 +41,15 @@ your app its providers, configure the id in any one of:
|
|
|
17
41
|
- `initSatyaAttest({ appId })` at startup, or
|
|
18
42
|
- `EXPO_PUBLIC_SATYA_APP_ID` in the build environment.
|
|
19
43
|
|
|
20
|
-
The app
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
secret. Without a configured app id a verifier-backed flow fails before the
|
|
44
|
+
The app ID is public. Native mode checks registered OS identities and provider
|
|
45
|
+
grants. TEE mode checks the provider grant and enclave evidence without asserting
|
|
46
|
+
app/device identity. Store binaries ship no verifier secret. Without a configured app id a verifier-backed flow fails before the
|
|
24
47
|
provider WebView opens with `APP_ID_REQUIRED`; a malformed id fails validation
|
|
25
48
|
with `CONFIG_INVALID`. An unregistered or unapproved id fails at the verifier
|
|
26
49
|
with `APP_NOT_REGISTERED` / `APP_DISABLED`, and an ungranted provider fails with
|
|
27
50
|
`PROVIDER_ACCESS_DENIED`. See
|
|
28
51
|
[`docs/MULTI_TENANT_VERIFICATION.md`](../../docs/MULTI_TENANT_VERIFICATION.md).
|
|
29
|
-
|
|
52
|
+
Native flows also fail with `app_platform_not_configured` when the app has no
|
|
30
53
|
registered identity for the current platform, so register every platform you
|
|
31
54
|
develop and test on.
|
|
32
55
|
|
|
@@ -47,6 +70,10 @@ therefore bounded, and verified **at their edges** — the interior of each wind
|
|
|
47
70
|
| `react-native` | `>=0.81.0 <0.86.0` | 0.81.5 | 0.85.x |
|
|
48
71
|
| `react-native-safe-area-context` | `>=5.6.0 <6.0.0` | 5.6.x | 5.6.x |
|
|
49
72
|
| `react-native-webview` | `>=13.15.0 <14.0.0` | 13.15.0 | 13.16.x |
|
|
73
|
+
| `react-native-tcp-socket` | `>=6.4.2 <7.0.0` | 6.4.2 | 6.4.x |
|
|
74
|
+
|
|
75
|
+
`react-native-tcp-socket` belongs only to the `/tee` entry point. The root package
|
|
76
|
+
does not impose a TCP dependency or version constraint on app-only consumers.
|
|
50
77
|
|
|
51
78
|
Policy:
|
|
52
79
|
|
|
@@ -65,9 +92,9 @@ Policy:
|
|
|
65
92
|
or the example app) outside its declared range; and this table differing from
|
|
66
93
|
`package.json`.
|
|
67
94
|
|
|
68
|
-
##
|
|
95
|
+
## App-attestation flow (default)
|
|
69
96
|
|
|
70
|
-
|
|
97
|
+
App-attestation mode uses **certificate-pinned native replay**. Third-party apps can
|
|
71
98
|
use the SDK-owned button component for the full managed flow:
|
|
72
99
|
|
|
73
100
|
1. The app renders `SatyaProviderAttestButton` with a provider id and transport config.
|
|
@@ -999,14 +1026,14 @@ HTTPS tunnel or deployed HTTPS endpoint.
|
|
|
999
1026
|
|
|
1000
1027
|
## Provider Health Monitoring
|
|
1001
1028
|
|
|
1002
|
-
Every native replay reports one anonymous health ping to the Burnt provider
|
|
1029
|
+
Every native or TEE replay reports one anonymous health ping to the Burnt provider
|
|
1003
1030
|
monitor (`POST https://provider-monitor.burnt.com/ingest`) so per-provider
|
|
1004
1031
|
success rates and proof-generation latency show up on the shared dashboard. This
|
|
1005
1032
|
is on by default and needs no app configuration or token.
|
|
1006
1033
|
|
|
1007
1034
|
- `outcome: "ok"` fires as soon as the attestation artifact is produced, with
|
|
1008
1035
|
`latencyMs` measured from captured-request handoff to artifact creation.
|
|
1009
|
-
- `outcome: "failed"` fires when the
|
|
1036
|
+
- `outcome: "failed"` fires when the replay pipeline fails to produce an
|
|
1010
1037
|
artifact (no latency attached).
|
|
1011
1038
|
- Artifact verification — the embedded check and the backend verifier — is
|
|
1012
1039
|
outside the ping: its result depends on device trust (App Attest / Play
|
|
@@ -1021,6 +1048,9 @@ unknown provider ids are acknowledged but not recorded.
|
|
|
1021
1048
|
|
|
1022
1049
|
## Funnel Event Logging
|
|
1023
1050
|
|
|
1051
|
+
TEE uses the same events with `mode: "tee-replay"`, structured stage errors and
|
|
1052
|
+
per-stage timings. See [TEE logging and troubleshooting](./TEE_REPLAY.md#logging-and-troubleshooting).
|
|
1053
|
+
|
|
1024
1054
|
The SDK emits seven lifecycle events — `PROVIDER_INIT`, `LOGIN_COMPLETED`,
|
|
1025
1055
|
`ENDPOINT_MATCHED`, `NATIVE_REPLAY_SUCCESS`, `ATTESTATION_GENERATED`,
|
|
1026
1056
|
`ATTESTATION_VERIFIED`, and `FAILED` — to the SDK-logs ingest
|
|
@@ -1031,7 +1061,7 @@ provider-registry Monitoring dashboard. **On by default**; opt out with
|
|
|
1031
1061
|
- **Correlation:** each user task mints one UUID `sessionId`, held constant
|
|
1032
1062
|
across retries (each attempt is numbered with `attemptIndex`) and embedded in
|
|
1033
1063
|
native artifacts as the unsigned `sdkSessionId` envelope field. From
|
|
1034
|
-
`ATTESTATION_GENERATED` on, events also carry the `attestationId` join key
|
|
1064
|
+
`ATTESTATION_GENERATED` on, native events also carry the `attestationId` join key
|
|
1035
1065
|
(for TeeLS flows, the claim's attestation id). The failure screen shows the
|
|
1036
1066
|
`sessionId` with a Copy control for support hand-off. **Deploy the
|
|
1037
1067
|
`sdkSessionId`-aware verifier before rolling out 3.4.0 clients** — older
|
package/TEE_REPLAY.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# TEE replay
|
|
2
|
+
|
|
3
|
+
TEE mode uses the same provider registry, login WebView, capture rules and proof
|
|
4
|
+
plans as app attestation. The captured request is replayed inside the TEE through
|
|
5
|
+
an opaque TLS relay on the user's device. A matching verifier and measured TEE
|
|
6
|
+
service must be deployed once by the operator.
|
|
7
|
+
|
|
8
|
+
## Install and enable
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx expo install @burnt-labs/expo-satya-attest react-native-webview react-native-tcp-socket@6.4.2
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
For TEE, install the optional TCP peer and rebuild the native app. The SDK supplies WebView cookie
|
|
15
|
+
access and OS randomness; no cookie package, patch, RNG import or custom proxy is
|
|
16
|
+
needed. Expo Go cannot load these native modules; use a development or release build.
|
|
17
|
+
Keep the SDK config plugin from the normal installation.
|
|
18
|
+
TCP versions `>=6.4.2 <7.0.0` are checked only when starting the TEE relay;
|
|
19
|
+
app-only integrations may keep their own TCP dependency version.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import { initSatyaAttest, SatyaProviderAttestButton } from '@burnt-labs/expo-satya-attest/tee';
|
|
23
|
+
|
|
24
|
+
initSatyaAttest({
|
|
25
|
+
appId: 'app_your-registered-app-id',
|
|
26
|
+
attestationMode: 'tee-replay',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export function ProveProfile() {
|
|
30
|
+
return (
|
|
31
|
+
<SatyaProviderAttestButton
|
|
32
|
+
providerId="kaggle.current_user.v1"
|
|
33
|
+
transportConfig={{ verifierUrl: 'https://your-verifier.example' }}
|
|
34
|
+
onComplete={(result) => {
|
|
35
|
+
if (result.backendVerify?.ok) {
|
|
36
|
+
// Use the verified claims and completion metadata.
|
|
37
|
+
}
|
|
38
|
+
}}
|
|
39
|
+
onError={(error) => console.warn(error.code)}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Use an active public app ID with the required provider grant. In TEE mode the app
|
|
46
|
+
ID selects registry access; it does not prove the app binary or device identity.
|
|
47
|
+
Play Integrity / App Attest setup is needed only when testing app-attestation mode.
|
|
48
|
+
|
|
49
|
+
The verifier advertises the TEE service URL and checks its quote before the SDK
|
|
50
|
+
releases credentials. `teeReplayServerUrl` optionally restricts that URL;
|
|
51
|
+
`teeTrustConfig` optionally narrows accepted identities. Neither is required in
|
|
52
|
+
the app. HTTPS is required for live verifier/service traffic. Configuration
|
|
53
|
+
mismatches fail the run; TEE never silently falls back to app attestation.
|
|
54
|
+
|
|
55
|
+
## Provider features
|
|
56
|
+
|
|
57
|
+
| Feature | TEE behavior |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| Registry templates | Use the existing provider ID and configuration. Inline `providerTemplate` is unsupported. |
|
|
60
|
+
| WebView / capture | Uses the existing login, OAuth popup, injection, request matching and guarded rewrite flow. |
|
|
61
|
+
| Multiple endpoints | Pass the existing `proofPlanId`. One quote and one signed bundle cover the selected endpoints. |
|
|
62
|
+
| Partial proofs | Opt in with `partialEndpointProviderIds: [providerId]`, as in native mode. Inspect `completionMode`, `endpointIds`, `omittedEndpointIds` and `planComplete` in the verified result. |
|
|
63
|
+
| Dynamic pinned hosts | Registry host-group membership remains enforced. TEE ignores SPKI pins and verifies the certificate chain and hostname inside the enclave. Native replay still enforces pins. |
|
|
64
|
+
| GET / POST and mutations | Existing methods and bodies are replayed. A mutation can execute during capture and again during replay; there are no automatic replay retries. |
|
|
65
|
+
| Account binding | `claim-equality` proves the governed account claims agree. `shared-session` returns `shared-proof-run`, which proves run membership without asserting account equality. |
|
|
66
|
+
| Verification | Online through `POST /v1/artifacts/verify`, which distinguishes native and TEE artifacts. Deferred verification is unsupported. |
|
|
67
|
+
|
|
68
|
+
Partial mode still attempts the full plan. Authenticated unsuccessful responses
|
|
69
|
+
may be recorded as omissions; TLS, policy, parser and transport failures abort the
|
|
70
|
+
run. Required account-binding endpoints cannot be omitted.
|
|
71
|
+
|
|
72
|
+
The relay normally uses the device's egress. The proof does not attest residential
|
|
73
|
+
IP, location or app/device integrity. A compromised phone can interrupt traffic
|
|
74
|
+
or choose credentials it possesses, but cannot forge the enclave's provider TLS
|
|
75
|
+
response or final signature.
|
|
76
|
+
|
|
77
|
+
## Switch modes
|
|
78
|
+
|
|
79
|
+
The `/tee` entry point supports both modes with the same callbacks. Keep using
|
|
80
|
+
the default package import for app-attestation-only integrations: its native
|
|
81
|
+
result types are unchanged, and it does not load or require the TCP peer.
|
|
82
|
+
|
|
83
|
+
Initialize before mounting the button. To change modes, finish or cancel the
|
|
84
|
+
current flow, call `initSatyaAttest({ attestationMode: nextMode })`, then remount
|
|
85
|
+
the button, for example with `key={nextMode}`. Values are `app-attestation` and
|
|
86
|
+
`tee-replay`; omitting the mode preserves its current value on later init calls.
|
|
87
|
+
The example app provides an **Attestation mode** selector and keeps the selected
|
|
88
|
+
provider, proof plan and completion preference when switching.
|
|
89
|
+
|
|
90
|
+
For captured-request integrations, use `SatyaMobileClient.attestReplay` or
|
|
91
|
+
`attestReplayBundle`. Explicit `attestNativeReplay*` methods always remain native.
|
|
92
|
+
TEE methods return an already verified result. Final verification consumes the
|
|
93
|
+
challenge once; do not verify the same completed proof a second time.
|
|
94
|
+
|
|
95
|
+
Preserve `artifactBytesB64` as opaque bytes. Parsing and reserializing the signed
|
|
96
|
+
JSON may round large numbers and invalidate it. Use claim `valueBytesB64` when
|
|
97
|
+
exact JSON numeric values matter.
|
|
98
|
+
|
|
99
|
+
## Result types
|
|
100
|
+
|
|
101
|
+
Existing imports from `@burnt-labs/expo-satya-attest` retain the 3.7.x
|
|
102
|
+
`SatyaProviderAttestationResult` and `onComplete` types. No callback migration is
|
|
103
|
+
needed for app attestation. Using the default button with TEE selected reports
|
|
104
|
+
a configuration error before opening the flow.
|
|
105
|
+
|
|
106
|
+
Only imports from `@burnt-labs/expo-satya-attest/tee` use a native/TEE result union.
|
|
107
|
+
Narrow its artifact before reading fields specific to either mode:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
function handleComplete(result: SatyaProviderAttestationResult) {
|
|
111
|
+
const artifact = result.artifact;
|
|
112
|
+
if ('artifactBytesB64' in artifact) {
|
|
113
|
+
// TEE envelope: retain artifact.artifactBytesB64 and the backend verdict.
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Native artifact: existing artifact.statement handling belongs here.
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Import `SatyaProviderAttestationResult` from the `/tee` entry point for this handler. Shared result/verification
|
|
121
|
+
fields remain available in either mode. TEE claim `value` is a JSON convenience
|
|
122
|
+
representation and can round numbers (or be null outside its numeric range);
|
|
123
|
+
`valueBytesB64` carries the authenticated exact JSON value.
|
|
124
|
+
|
|
125
|
+
## Read claims
|
|
126
|
+
|
|
127
|
+
The signed TEE object uses `body.exchanges[].disclosure[]` for every run: one
|
|
128
|
+
exchange for a single endpoint, several for a proof plan. Each disclosure has
|
|
129
|
+
`name`, `sourcePath` and `value`; the value can contain nested objects and arrays.
|
|
130
|
+
Keep the signed bytes intact and read claims from the trusted verifier response:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { getTeeClaims } from '@burnt-labs/expo-satya-attest/tee';
|
|
134
|
+
|
|
135
|
+
const claims = getTeeClaims(result.backendVerify);
|
|
136
|
+
// Every entry: { endpointId, name, sourcePath, valueJson }
|
|
137
|
+
for (const claim of claims) {
|
|
138
|
+
renderClaim(claim.endpointId, claim.name, claim.valueJson);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`getTeeClaims` requires the matching verifier release: each verified claim carries
|
|
143
|
+
an explicit `endpointId`, original `claimName` and exact `valueBytesB64`. Existing
|
|
144
|
+
`name` and `value` response fields remain available. The helper preserves aliases
|
|
145
|
+
containing `/`, keeps repeated names in different endpoints separate, and rejects
|
|
146
|
+
duplicate endpoint/name pairs or malformed encodings. Omitted endpoints supply no claims;
|
|
147
|
+
use `omittedEndpointIds` and `planComplete` for coverage.
|
|
148
|
+
|
|
149
|
+
`valueJson` is exact JSON text, preserving strings, booleans, nested data, large
|
|
150
|
+
integers and precise decimals. Parse it with your application's JSON parser when
|
|
151
|
+
needed; ordinary `JSON.parse` can round numbers. No lossy fallback is used.
|
|
152
|
+
|
|
153
|
+
This helper extracts data; it does not authenticate a caller-supplied verdict.
|
|
154
|
+
Your backend must authorize using its own successful verifier response, never
|
|
155
|
+
an `ok` flag or claims sent back by an untrusted mobile client. Verification is
|
|
156
|
+
single-use, so route that final verification to your trusted backend and retain
|
|
157
|
+
its result rather than submitting the same proof again.
|
|
158
|
+
|
|
159
|
+
## Logging and troubleshooting
|
|
160
|
+
|
|
161
|
+
TEE uses the same event names and logging service as App Attest. No service
|
|
162
|
+
update or extra logging setup is required. Enable internal SDK logs separately:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
initSatyaAttest({
|
|
166
|
+
appId: 'YOUR_APP_ID',
|
|
167
|
+
attestationMode: 'tee-replay',
|
|
168
|
+
logLevel: 'info', // Stage completions and errors; 'debug' also logs starts.
|
|
169
|
+
eventLogging: true, // Default; sends lifecycle events to SDK Monitoring.
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Internal entries use the `tee` scope and the existing logger/sink. Each stage
|
|
174
|
+
logs its outcome and duration; no packet-by-packet logs are emitted. Use
|
|
175
|
+
`logLevel: 'silent'` to disable internal logging independently of event delivery.
|
|
176
|
+
|
|
177
|
+
The WebView emits `PROVIDER_INIT`, `LOGIN_COMPLETED` and `ENDPOINT_MATCHED` as
|
|
178
|
+
usual. Successful replay emits `NATIVE_REPLAY_SUCCESS` (the existing wire name)
|
|
179
|
+
and `ATTESTATION_GENERATED`; online verification emits `ATTESTATION_VERIFIED`.
|
|
180
|
+
Every TEE event has `logData.mode: "tee-replay"`. Failed attempts emit one
|
|
181
|
+
`FAILED` event with these fields when available:
|
|
182
|
+
|
|
183
|
+
| Field | Meaning |
|
|
184
|
+
| --- | --- |
|
|
185
|
+
| `teeStage` | `configuration`, `challenge`, `session`, `quoteBinding`, `quoteVerification`, `credentials`, `sealing`, `relay`, `replay`, or `verification`. |
|
|
186
|
+
| `errorCode`, `errorReason`, `errorMessage` | SDK error code, a typed local reason, and a safe summary. |
|
|
187
|
+
| `httpStatus`, `requestId` | Service status and server correlation ID, when returned. |
|
|
188
|
+
| `verifierErrorCode`, `verifierErrorClass`, `verifierErrorStage`, `retryable` | Structured verifier or replay-service error metadata; unknown server codes remain readable. |
|
|
189
|
+
| `endpointId`, `proofPlanId`, `exchangeIndex`, `exchangeCount` | Selected proof and endpoint context; relay faults identify the failing slot. |
|
|
190
|
+
| `teeChallengeMs`, `teeSessionMs`, `teeQuoteBindingMs`, `teeQuoteVerificationMs`, `teeCaptureMs`, `teeSealingMs`, `teeRelayMs`, `teeReplayMs`, `teeVerificationMs` | Completed stage durations. `latencyMs` on failure measures the failed stage. |
|
|
191
|
+
| `totalElapsedMs` | Attempt elapsed time, including login/capture for the WebView flow. |
|
|
192
|
+
|
|
193
|
+
`sessionId` is the common event correlation key and travels to verification as
|
|
194
|
+
`sdkSessionId`. The verified event also carries `attestationId`, `completionMode`
|
|
195
|
+
and `planComplete`. Speculative preparation can overlap WebView capture, so stage
|
|
196
|
+
durations should not be summed as wall-clock latency. Successful stages are
|
|
197
|
+
summarized on subsequent lifecycle events rather than adding new event names.
|
|
198
|
+
|
|
199
|
+
`SatyaTeeStage`, `SatyaTeeErrorReason`, `SatyaTeeErrorContext`, `TEE_STAGES` and
|
|
200
|
+
`TEE_ERROR_REASONS` are exported from `/tee`; their definitions live in
|
|
201
|
+
`src/tee/errors.ts`. Errors remain compatible with `SatyaError` and its
|
|
202
|
+
`diagnostics`. `SatyaTeeClient.verify*` preserves its result-returning API and
|
|
203
|
+
adds structured `errorDetail` on a service rejection or malformed verifier response.
|
|
204
|
+
Network failures, timeouts and cancellation still throw.
|
|
205
|
+
|
|
206
|
+
`SatyaMobileClient.attestReplay*` also emits post-capture TEE lifecycle events.
|
|
207
|
+
Low-level `SatyaTeeClient` operations provide internal stage logs and structured
|
|
208
|
+
errors; the caller owns the surrounding UI lifecycle.
|
|
209
|
+
|
|
210
|
+
Events send `logData` as a JSON string, allowlisted and capped at 2 KB. The new TEE stage
|
|
211
|
+
records exclude request headers/bodies, cookies, relay tokens, raw upstream error
|
|
212
|
+
messages, quotes and proofs, even with verbose logging enabled. Shared WebView
|
|
213
|
+
verbose logging remains intended only for local debugging.
|
|
214
|
+
The optional `eventLogBridgeDebug` tail remains off by default. Delivery is
|
|
215
|
+
best effort with the existing queue/backoff; logging failures never retry a
|
|
216
|
+
provider replay or change proof verification.
|
|
217
|
+
|
|
218
|
+
TEE also sends the existing anonymous provider-generation health ping. Producing
|
|
219
|
+
an artifact reports success before final verification; a subsequent verifier
|
|
220
|
+
rejection does not turn that generation into a failure. No additional verifier
|
|
221
|
+
monitor event names are introduced.
|
|
222
|
+
Client setup failures also report failed generation; user cancellation is excluded.
|
|
223
|
+
|
|
224
|
+
## Operator setup
|
|
225
|
+
|
|
226
|
+
See the repository's [TEE protocol and verifier configuration](https://github.com/burnt-labs/tls-app-attest/blob/main/docs/TEE_REPLAY_MODE.md)
|
|
227
|
+
and [Phala deployment guide](https://github.com/burnt-labs/tls-app-attest/blob/main/deploy/phala/README.md).
|
|
228
|
+
Deploy durable state (when using Cloudflare), then the matching verifier, measured
|
|
229
|
+
replay image and SDK. Pin the image digest and accept only verified deployment
|
|
230
|
+
identities. A local verifier can use the atomic file journal with production DCAP
|
|
231
|
+
verification; it does not need a local TEE or Cloudflare deployment.
|
package/android/build.gradle
CHANGED
|
@@ -4,13 +4,13 @@ plugins {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
group = 'expo.modules.satyaattest'
|
|
7
|
-
version = '3.
|
|
7
|
+
version = '3.8.0'
|
|
8
8
|
|
|
9
9
|
android {
|
|
10
10
|
namespace "expo.modules.satyaattest"
|
|
11
11
|
defaultConfig {
|
|
12
12
|
versionCode 1
|
|
13
|
-
versionName "3.
|
|
13
|
+
versionName "3.8.0"
|
|
14
14
|
// StrongBox key attestation needs API 28+; basic Keystore attestation API 24+.
|
|
15
15
|
minSdkVersion 24
|
|
16
16
|
}
|
|
@@ -113,6 +113,22 @@ class SatyaAttestModule : Module() {
|
|
|
113
113
|
Base64.encodeToString(bytes, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING)
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
// OS entropy, encoded as unpadded base64url.
|
|
117
|
+
Function("secureRandomBytes") { count: Int ->
|
|
118
|
+
require(count in 1..4096) { "secureRandomBytes count must be 1..4096" }
|
|
119
|
+
val bytes = ByteArray(count)
|
|
120
|
+
SecureRandom().nextBytes(bytes)
|
|
121
|
+
Base64.encodeToString(bytes, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
AsyncFunction("readWebViewCookies") { url: String ->
|
|
125
|
+
val parsed = url.toHttpUrl()
|
|
126
|
+
require(parsed.isHttps && parsed.username.isEmpty() && parsed.password.isEmpty()) {
|
|
127
|
+
"Cookie URL must be HTTPS without credentials"
|
|
128
|
+
}
|
|
129
|
+
CookieManager.getInstance().getCookie(parsed.toString()) ?: ""
|
|
130
|
+
}.runOnQueue(Queues.MAIN)
|
|
131
|
+
|
|
116
132
|
AsyncFunction("initialize") { configJson: String -> transportConfigJson = configJson }
|
|
117
133
|
|
|
118
134
|
AsyncFunction("dispose") { transportConfigJson = "{}" }
|
|
@@ -495,6 +511,7 @@ class SatyaAttestModule : Module() {
|
|
|
495
511
|
// Backs ProofCookieJar seeding by the real WebView cookie store. Reads only;
|
|
496
512
|
// proof replay never calls setCookie.
|
|
497
513
|
private class CookieManagerGlobalStore : GlobalCookieStore {
|
|
514
|
+
// getCookie reads synchronously; flush() only persists to disk.
|
|
498
515
|
override fun cookieHeader(url: String): String? =
|
|
499
516
|
CookieManager.getInstance().getCookie(url)?.takeIf { it.isNotBlank() }
|
|
500
517
|
|
|
@@ -624,7 +641,7 @@ class SatyaAttestModule : Module() {
|
|
|
624
641
|
replayTargetsById[exchange.endpointId] = target
|
|
625
642
|
}
|
|
626
643
|
|
|
627
|
-
//
|
|
644
|
+
// Finish all WebView cookie reads before replay starts.
|
|
628
645
|
val cookieSeedUrls = effectiveEndpointIds.map { endpointId ->
|
|
629
646
|
replayTargetsById[endpointId]?.url
|
|
630
647
|
?: error("HOST_GROUP_INVALID: no resolved replay target for $endpointId")
|
|
@@ -1211,7 +1228,7 @@ class SatyaAttestModule : Module() {
|
|
|
1211
1228
|
requestBuilder.header(key, value)
|
|
1212
1229
|
}
|
|
1213
1230
|
}
|
|
1214
|
-
|
|
1231
|
+
CookieManagerGlobalStore().cookieHeader(replayUrl)?.let {
|
|
1215
1232
|
requestBuilder.header("Cookie", it)
|
|
1216
1233
|
}
|
|
1217
1234
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3,6 +3,13 @@ import { VerifyResult } from './types';
|
|
|
3
3
|
declare class SatyaAttestModule extends NativeModule<Record<string, never>> {
|
|
4
4
|
satyaCoreVersion(): string;
|
|
5
5
|
createWebViewBridgeCapability(): string;
|
|
6
|
+
/**
|
|
7
|
+
* OS entropy as unpadded base64url. Optional so a JS bundle running against a
|
|
8
|
+
* native binary built before 3.8.0 still type-checks; `tee/secureRandom.ts`
|
|
9
|
+
* falls back to `createWebViewBridgeCapability` in that case.
|
|
10
|
+
*/
|
|
11
|
+
secureRandomBytes?(count: number): string;
|
|
12
|
+
readWebViewCookies(url: string): Promise<string>;
|
|
6
13
|
attestNativeReplay(providerTemplateJson: string, capturedRequestJson: string | null): Promise<string>;
|
|
7
14
|
attestNativeReplayBundle(providerTemplateJson: string, capturedRequestsJson: string, partialEndpointSelectionJson: string | null): Promise<string>;
|
|
8
15
|
verifyArtifact(artifactJson: string): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SatyaAttestModule.d.ts","sourceRoot":"","sources":["../src/SatyaAttestModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,OAAO,iBAAkB,SAAQ,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzE,gBAAgB,IAAI,MAAM;IAC1B,6BAA6B,IAAI,MAAM;
|
|
1
|
+
{"version":3,"file":"SatyaAttestModule.d.ts","sourceRoot":"","sources":["../src/SatyaAttestModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,OAAO,iBAAkB,SAAQ,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzE,gBAAgB,IAAI,MAAM;IAC1B,6BAA6B,IAAI,MAAM;IACvC;;;;OAIG;IACH,iBAAiB,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IACzC,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAShD,kBAAkB,CAChB,oBAAoB,EAAE,MAAM,EAC5B,mBAAmB,EAAE,MAAM,GAAG,IAAI,GACjC,OAAO,CAAC,MAAM,CAAC;IAElB,wBAAwB,CACtB,oBAAoB,EAAE,MAAM,EAC5B,oBAAoB,EAAE,MAAM,EAC5B,4BAA4B,EAAE,MAAM,GAAG,IAAI,GAC1C,OAAO,CAAC,MAAM,CAAC;IAElB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IACtD,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAEnE,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IACxB,iCAAiC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3F,sBAAsB,CACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,OAAO,GAC1B,OAAO,CAAC,OAAO,CAAC;IACnB,qFAAqF;IACrF,wBAAwB,CAAC,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAC/D,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;CACtC;;AAED,wBAAqE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SatyaAttestModule.js","sourceRoot":"","sources":["../src/SatyaAttestModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"SatyaAttestModule.js","sourceRoot":"","sources":["../src/SatyaAttestModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAiDzD,eAAe,mBAAmB,CAAoB,aAAa,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport { VerifyResult } from './types';\n\ndeclare class SatyaAttestModule extends NativeModule<Record<string, never>> {\n satyaCoreVersion(): string;\n createWebViewBridgeCapability(): string;\n /**\n * OS entropy as unpadded base64url. Optional so a JS bundle running against a\n * native binary built before 3.8.0 still type-checks; `tee/secureRandom.ts`\n * falls back to `createWebViewBridgeCapability` in that case.\n */\n secureRandomBytes?(count: number): string;\n readWebViewCookies(url: string): Promise<string>;\n\n // Every parameter below is required, including the nullable ones. Whether iOS\n // tolerates an omitted trailing optional depends on the host app's\n // expo-modules-core (older 3.0.x cores and the optimized JSI path require all\n // of them; 56.x relaxes trailing optionals), and `peerDependencies.expo` is\n // `*`, so this package must satisfy the strictest of them. Marking these `?`\n // would let TypeScript accept a call that crashes on device. See\n // `nativeReplayArgs.ts` for the full mechanism.\n attestNativeReplay(\n providerTemplateJson: string,\n capturedRequestJson: string | null\n ): Promise<string>;\n\n attestNativeReplayBundle(\n providerTemplateJson: string,\n capturedRequestsJson: string,\n partialEndpointSelectionJson: string | null\n ): Promise<string>;\n\n verifyArtifact(artifactJson: string): Promise<boolean>;\n verifyArtifactDetailed(artifactJson: string): Promise<VerifyResult>;\n\n initialize(configJson: string): Promise<void>;\n dispose(): Promise<void>;\n installWebViewDocumentStartScript(viewTag: number, script: string): Promise<boolean | null>;\n setPopupWindowsEnabled(\n viewTag: number,\n enabled: boolean,\n geolocationEnabled: boolean\n ): Promise<boolean>;\n /** Optional for compatibility with native binaries predating privacy concealment. */\n setPopupWindowsConcealed?(concealed: boolean): Promise<boolean>;\n closePopupWindows(): Promise<boolean>;\n}\n\nexport default requireNativeModule<SatyaAttestModule>('SatyaAttest');\n"]}
|
|
@@ -3,6 +3,7 @@ import { VerifyResult } from './types';
|
|
|
3
3
|
declare class SatyaAttestModule extends NativeModule<Record<string, never>> {
|
|
4
4
|
satyaCoreVersion(): string;
|
|
5
5
|
createWebViewBridgeCapability(): string;
|
|
6
|
+
readWebViewCookies(_url: string): Promise<string>;
|
|
6
7
|
attestNativeReplay(_providerTemplateJson: string, _capturedRequestJson: string | null): Promise<string>;
|
|
7
8
|
attestNativeReplayBundle(_providerTemplateJson: string, _capturedRequestsJson: string, _partialEndpointSelectionJson: string | null): Promise<string>;
|
|
8
9
|
verifyArtifact(_artifactJson: string): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SatyaAttestModule.web.d.ts","sourceRoot":"","sources":["../src/SatyaAttestModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAE,MAAM,MAAM,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMvC,cAAM,iBAAkB,SAAQ,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACjE,gBAAgB,IAAI,MAAM;IAG1B,6BAA6B,IAAI,MAAM;IAGjC,kBAAkB,CACtB,qBAAqB,EAAE,MAAM,EAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,GAClC,OAAO,CAAC,MAAM,CAAC;IAGZ,wBAAwB,CAC5B,qBAAqB,EAAE,MAAM,EAC7B,qBAAqB,EAAE,MAAM,EAC7B,6BAA6B,EAAE,MAAM,GAAG,IAAI,GAC3C,OAAO,CAAC,MAAM,CAAC;IAGZ,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAGvD,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAGpE,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAG9C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B;;AAMD,wBAAyE"}
|
|
1
|
+
{"version":3,"file":"SatyaAttestModule.web.d.ts","sourceRoot":"","sources":["../src/SatyaAttestModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAE,MAAM,MAAM,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAMvC,cAAM,iBAAkB,SAAQ,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACjE,gBAAgB,IAAI,MAAM;IAG1B,6BAA6B,IAAI,MAAM;IAGjC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAGjD,kBAAkB,CACtB,qBAAqB,EAAE,MAAM,EAC7B,oBAAoB,EAAE,MAAM,GAAG,IAAI,GAClC,OAAO,CAAC,MAAM,CAAC;IAGZ,wBAAwB,CAC5B,qBAAqB,EAAE,MAAM,EAC7B,qBAAqB,EAAE,MAAM,EAC7B,6BAA6B,EAAE,MAAM,GAAG,IAAI,GAC3C,OAAO,CAAC,MAAM,CAAC;IAGZ,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAGvD,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAGpE,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAG9C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B;;AAMD,wBAAyE"}
|
|
@@ -8,6 +8,9 @@ class SatyaAttestModule extends NativeModule {
|
|
|
8
8
|
createWebViewBridgeCapability() {
|
|
9
9
|
throw unsupportedPlatformError();
|
|
10
10
|
}
|
|
11
|
+
async readWebViewCookies(_url) {
|
|
12
|
+
throw unsupportedPlatformError();
|
|
13
|
+
}
|
|
11
14
|
async attestNativeReplay(_providerTemplateJson, _capturedRequestJson) {
|
|
12
15
|
throw unsupportedPlatformError();
|
|
13
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SatyaAttestModule.web.js","sourceRoot":"","sources":["../src/SatyaAttestModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjE,MAAM,WAAW,GACf,uFAAuF,CAAC;AAE1F,MAAM,iBAAkB,SAAQ,YAAmC;IACjE,gBAAgB;QACd,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,6BAA6B;QAC3B,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,kBAAkB,CACtB,qBAA6B,EAC7B,oBAAmC;QAEnC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,wBAAwB,CAC5B,qBAA6B,EAC7B,qBAA6B,EAC7B,6BAA4C;QAE5C,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,aAAqB;QACxC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,sBAAsB,CAAC,aAAqB;QAChD,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,WAAmB;QAClC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,OAAO;QACX,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;CACF;AAED,SAAS,wBAAwB;IAC/B,MAAM,UAAU,CAAC,cAAc,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;AACrE,CAAC;AAED,eAAe,iBAAiB,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC","sourcesContent":["import { registerWebModule, NativeModule } from 'expo';\n\nimport { VerifyResult } from './types';\nimport { SatyaErrorCode, satyaError } from './types/error.types';\n\nconst UNSUPPORTED =\n 'expo-satya-attest is not available on web (it requires native App Attest / Keystore).';\n\nclass SatyaAttestModule extends NativeModule<Record<string, never>> {\n satyaCoreVersion(): string {\n throw unsupportedPlatformError();\n }\n createWebViewBridgeCapability(): string {\n throw unsupportedPlatformError();\n }\n async attestNativeReplay(\n _providerTemplateJson: string,\n _capturedRequestJson: string | null\n ): Promise<string> {\n throw unsupportedPlatformError();\n }\n async attestNativeReplayBundle(\n _providerTemplateJson: string,\n _capturedRequestsJson: string,\n _partialEndpointSelectionJson: string | null\n ): Promise<string> {\n throw unsupportedPlatformError();\n }\n async verifyArtifact(_artifactJson: string): Promise<boolean> {\n throw unsupportedPlatformError();\n }\n async verifyArtifactDetailed(_artifactJson: string): Promise<VerifyResult> {\n throw unsupportedPlatformError();\n }\n async initialize(_configJson: string): Promise<void> {\n throw unsupportedPlatformError();\n }\n async dispose(): Promise<void> {\n throw unsupportedPlatformError();\n }\n}\n\nfunction unsupportedPlatformError(): never {\n throw satyaError(SatyaErrorCode.UNSUPPORTED_PLATFORM, UNSUPPORTED);\n}\n\nexport default registerWebModule(SatyaAttestModule, 'SatyaAttestModule');\n"]}
|
|
1
|
+
{"version":3,"file":"SatyaAttestModule.web.js","sourceRoot":"","sources":["../src/SatyaAttestModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAGvD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjE,MAAM,WAAW,GACf,uFAAuF,CAAC;AAE1F,MAAM,iBAAkB,SAAQ,YAAmC;IACjE,gBAAgB;QACd,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,6BAA6B;QAC3B,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,kBAAkB,CAAC,IAAY;QACnC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,kBAAkB,CACtB,qBAA6B,EAC7B,oBAAmC;QAEnC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,wBAAwB,CAC5B,qBAA6B,EAC7B,qBAA6B,EAC7B,6BAA4C;QAE5C,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,cAAc,CAAC,aAAqB;QACxC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,sBAAsB,CAAC,aAAqB;QAChD,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,WAAmB;QAClC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,OAAO;QACX,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;CACF;AAED,SAAS,wBAAwB;IAC/B,MAAM,UAAU,CAAC,cAAc,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC;AACrE,CAAC;AAED,eAAe,iBAAiB,CAAC,iBAAiB,EAAE,mBAAmB,CAAC,CAAC","sourcesContent":["import { registerWebModule, NativeModule } from 'expo';\n\nimport { VerifyResult } from './types';\nimport { SatyaErrorCode, satyaError } from './types/error.types';\n\nconst UNSUPPORTED =\n 'expo-satya-attest is not available on web (it requires native App Attest / Keystore).';\n\nclass SatyaAttestModule extends NativeModule<Record<string, never>> {\n satyaCoreVersion(): string {\n throw unsupportedPlatformError();\n }\n createWebViewBridgeCapability(): string {\n throw unsupportedPlatformError();\n }\n async readWebViewCookies(_url: string): Promise<string> {\n throw unsupportedPlatformError();\n }\n async attestNativeReplay(\n _providerTemplateJson: string,\n _capturedRequestJson: string | null\n ): Promise<string> {\n throw unsupportedPlatformError();\n }\n async attestNativeReplayBundle(\n _providerTemplateJson: string,\n _capturedRequestsJson: string,\n _partialEndpointSelectionJson: string | null\n ): Promise<string> {\n throw unsupportedPlatformError();\n }\n async verifyArtifact(_artifactJson: string): Promise<boolean> {\n throw unsupportedPlatformError();\n }\n async verifyArtifactDetailed(_artifactJson: string): Promise<VerifyResult> {\n throw unsupportedPlatformError();\n }\n async initialize(_configJson: string): Promise<void> {\n throw unsupportedPlatformError();\n }\n async dispose(): Promise<void> {\n throw unsupportedPlatformError();\n }\n}\n\nfunction unsupportedPlatformError(): never {\n throw satyaError(SatyaErrorCode.UNSUPPORTED_PLATFORM, UNSUPPORTED);\n}\n\nexport default registerWebModule(SatyaAttestModule, 'SatyaAttestModule');\n"]}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { SatyaBackendVerifyResult } from './components/providerAttest/types';
|
|
1
|
+
import type { SatyaBackendVerifyResult, SatyaTeeProviderAttestationResult } from './components/providerAttest/types';
|
|
2
2
|
import { SatyaArtifact, CapturedProviderRequest, SatyaProviderTemplate, SatyaProgress, SatyaTransportConfig, VerifyResult } from './types';
|
|
3
3
|
type ProgressListener = (progress: SatyaProgress) => void;
|
|
4
4
|
export interface NativeReplayAttestArgs {
|
|
5
5
|
providerTemplate: SatyaProviderTemplate;
|
|
6
6
|
transportConfig: SatyaTransportConfig;
|
|
7
7
|
capturedRequest?: CapturedProviderRequest | null;
|
|
8
|
+
signal?: AbortSignal;
|
|
8
9
|
}
|
|
9
10
|
export interface NativeReplayBundleAttestArgs {
|
|
10
11
|
providerTemplate: SatyaProviderTemplate;
|
|
@@ -15,6 +16,8 @@ export interface NativeReplayBundleAttestArgs {
|
|
|
15
16
|
partialEndpointsAllowed?: boolean;
|
|
16
17
|
signal?: AbortSignal;
|
|
17
18
|
}
|
|
19
|
+
/** Evidence stays discriminated: native signed statement or opaque TEE envelope. */
|
|
20
|
+
export type ModeAwareAttestOutcome = AttestOutcome | SatyaTeeProviderAttestationResult;
|
|
18
21
|
export interface AttestOutcome {
|
|
19
22
|
artifact: SatyaArtifact;
|
|
20
23
|
raw: string;
|
|
@@ -26,6 +29,11 @@ export declare class SatyaMobileClient {
|
|
|
26
29
|
private readonly listeners;
|
|
27
30
|
subscribeProgress(listener: ProgressListener): () => void;
|
|
28
31
|
private emit;
|
|
32
|
+
/** Uses the init mode with the same captured request and registry provider. */
|
|
33
|
+
attestReplay(args: NativeReplayAttestArgs): Promise<ModeAwareAttestOutcome>;
|
|
34
|
+
/** Runs one proof plan using the init mode; TEE success is verified online. */
|
|
35
|
+
attestReplayBundle(args: NativeReplayBundleAttestArgs): Promise<ModeAwareAttestOutcome>;
|
|
36
|
+
private attestTeeRun;
|
|
29
37
|
attestNativeReplay(args: NativeReplayAttestArgs): Promise<AttestOutcome>;
|
|
30
38
|
/**
|
|
31
39
|
* Composite proof-plan replay: one native call replays every plan endpoint
|
|
@@ -34,7 +42,7 @@ export declare class SatyaMobileClient {
|
|
|
34
42
|
* matching — the TypeScript-side record is convenience, not authority.
|
|
35
43
|
*/
|
|
36
44
|
attestNativeReplayBundle(args: NativeReplayBundleAttestArgs): Promise<AttestOutcome>;
|
|
37
|
-
verify(artifactJson: string): Promise<VerifyResult>;
|
|
45
|
+
verify(artifactJson: string, transportConfig?: SatyaTransportConfig): Promise<VerifyResult>;
|
|
38
46
|
coreVersion(): string;
|
|
39
47
|
dispose(): Promise<void>;
|
|
40
48
|
}
|