@burnt-labs/expo-satya-attest 3.2.0 → 3.3.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 +109 -2
- package/PROVIDER_CONFIG.md +134 -1
- package/README.md +32 -13
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/satyaattest/SatyaAttestModule.kt +6 -0
- 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 +1 -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/SatyaProviderAttestButton.js +9 -1
- package/build/SatyaProviderAttestButton.js.map +1 -1
- package/build/components/providerAttest/ProviderAttestModal.d.ts.map +1 -1
- package/build/components/providerAttest/ProviderAttestModal.js +25 -15
- package/build/components/providerAttest/ProviderAttestModal.js.map +1 -1
- package/build/components/providerAttest/backendVerifier.d.ts +9 -0
- package/build/components/providerAttest/backendVerifier.d.ts.map +1 -1
- package/build/components/providerAttest/backendVerifier.js +44 -6
- package/build/components/providerAttest/backendVerifier.js.map +1 -1
- package/build/components/providerAttest/copy.d.ts +12 -0
- package/build/components/providerAttest/copy.d.ts.map +1 -1
- package/build/components/providerAttest/copy.js +20 -0
- package/build/components/providerAttest/copy.js.map +1 -1
- package/build/components/providerAttest/loginSubmitDetector.d.ts +24 -0
- package/build/components/providerAttest/loginSubmitDetector.d.ts.map +1 -0
- package/build/components/providerAttest/loginSubmitDetector.js +65 -0
- package/build/components/providerAttest/loginSubmitDetector.js.map +1 -0
- package/build/components/providerAttest/popupRelay.d.ts +14 -0
- package/build/components/providerAttest/popupRelay.d.ts.map +1 -1
- package/build/components/providerAttest/popupRelay.js +27 -0
- package/build/components/providerAttest/popupRelay.js.map +1 -1
- package/build/components/providerAttest/teels/useTeelsProviderFlow.d.ts.map +1 -1
- package/build/components/providerAttest/teels/useTeelsProviderFlow.js +3 -0
- package/build/components/providerAttest/teels/useTeelsProviderFlow.js.map +1 -1
- package/build/components/providerAttest/types.d.ts +7 -1
- package/build/components/providerAttest/types.d.ts.map +1 -1
- package/build/components/providerAttest/types.js.map +1 -1
- package/build/components/providerAttest/urlUtils.d.ts +12 -0
- package/build/components/providerAttest/urlUtils.d.ts.map +1 -1
- package/build/components/providerAttest/urlUtils.js +23 -0
- package/build/components/providerAttest/urlUtils.js.map +1 -1
- package/build/components/providerAttest/useManagedPopupController.d.ts.map +1 -1
- package/build/components/providerAttest/useManagedPopupController.js +18 -2
- package/build/components/providerAttest/useManagedPopupController.js.map +1 -1
- package/build/components/providerAttest/useNativeReplayRunner.d.ts.map +1 -1
- package/build/components/providerAttest/useNativeReplayRunner.js +3 -37
- package/build/components/providerAttest/useNativeReplayRunner.js.map +1 -1
- package/build/components/providerAttest/useProviderAttestFlow.d.ts +1 -0
- package/build/components/providerAttest/useProviderAttestFlow.d.ts.map +1 -1
- package/build/components/providerAttest/useProviderAttestFlow.js +146 -1
- package/build/components/providerAttest/useProviderAttestFlow.js.map +1 -1
- package/build/components/providerAttest/useProviderFlowLifecycle.d.ts +6 -2
- package/build/components/providerAttest/useProviderFlowLifecycle.d.ts.map +1 -1
- package/build/components/providerAttest/useProviderFlowLifecycle.js +5 -1
- package/build/components/providerAttest/useProviderFlowLifecycle.js.map +1 -1
- package/build/components/providerAttest/useProviderInjectedScripts.d.ts +2 -1
- package/build/components/providerAttest/useProviderInjectedScripts.d.ts.map +1 -1
- package/build/components/providerAttest/useProviderInjectedScripts.js +3 -3
- package/build/components/providerAttest/useProviderInjectedScripts.js.map +1 -1
- package/build/components/providerAttest/useProviderMessageHandler.d.ts +10 -3
- package/build/components/providerAttest/useProviderMessageHandler.d.ts.map +1 -1
- package/build/components/providerAttest/useProviderMessageHandler.js +101 -2
- package/build/components/providerAttest/useProviderMessageHandler.js.map +1 -1
- package/build/components/providerAttest/useProviderNavigationHandlers.d.ts +4 -2
- package/build/components/providerAttest/useProviderNavigationHandlers.d.ts.map +1 -1
- package/build/components/providerAttest/useProviderNavigationHandlers.js +40 -8
- package/build/components/providerAttest/useProviderNavigationHandlers.js.map +1 -1
- package/build/components/providerAttest/useVerificationPresentation.d.ts +5 -0
- package/build/components/providerAttest/useVerificationPresentation.d.ts.map +1 -1
- package/build/components/providerAttest/useVerificationPresentation.js +63 -1
- package/build/components/providerAttest/useVerificationPresentation.js.map +1 -1
- package/build/components/providerAttest/verificationPresentation.d.ts +34 -1
- package/build/components/providerAttest/verificationPresentation.d.ts.map +1 -1
- package/build/components/providerAttest/verificationPresentation.js +42 -4
- package/build/components/providerAttest/verificationPresentation.js.map +1 -1
- package/build/providerRegistry/index.d.ts +1 -0
- package/build/providerRegistry/index.d.ts.map +1 -1
- package/build/providerRegistry/index.js +1 -0
- package/build/providerRegistry/index.js.map +1 -1
- package/build/providerRegistry/loginSubmitSignal.d.ts +27 -0
- package/build/providerRegistry/loginSubmitSignal.d.ts.map +1 -0
- package/build/providerRegistry/loginSubmitSignal.js +385 -0
- package/build/providerRegistry/loginSubmitSignal.js.map +1 -0
- package/build/providerRegistry/rules.js +15 -0
- package/build/providerRegistry/rules.js.map +1 -1
- package/build/providerRegistry/template.d.ts.map +1 -1
- package/build/providerRegistry/template.js +57 -2
- package/build/providerRegistry/template.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/types/provider.types.d.ts +72 -1
- package/build/types/provider.types.d.ts.map +1 -1
- package/build/types/provider.types.js.map +1 -1
- package/build/webview/index.d.ts +3 -3
- package/build/webview/index.d.ts.map +1 -1
- package/build/webview/index.js +4 -4
- package/build/webview/index.js.map +1 -1
- package/build/webview/scripts/requestInterceptorScript.d.ts +3 -1
- package/build/webview/scripts/requestInterceptorScript.d.ts.map +1 -1
- package/build/webview/scripts/requestInterceptorScript.js +346 -23
- package/build/webview/scripts/requestInterceptorScript.js.map +1 -1
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/Info.plist +5 -5
- 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 +13 -0
- package/package.json +11 -1
- package/src/SatyaAttestModule.ts +1 -0
- package/src/SatyaAttestModule.web.ts +3 -0
- package/src/SatyaProviderAttestButton.tsx +8 -1
- package/src/components/providerAttest/ProviderAttestModal.tsx +30 -18
- package/src/components/providerAttest/backendVerifier.ts +52 -6
- package/src/components/providerAttest/copy.ts +25 -0
- package/src/components/providerAttest/loginSubmitDetector.ts +91 -0
- package/src/components/providerAttest/popupRelay.ts +30 -0
- package/src/components/providerAttest/teels/useTeelsProviderFlow.ts +3 -0
- package/src/components/providerAttest/types.ts +8 -0
- package/src/components/providerAttest/urlUtils.ts +22 -0
- package/src/components/providerAttest/useManagedPopupController.ts +18 -2
- package/src/components/providerAttest/useNativeReplayRunner.ts +16 -42
- package/src/components/providerAttest/useProviderAttestFlow.ts +159 -2
- package/src/components/providerAttest/useProviderFlowLifecycle.ts +9 -0
- package/src/components/providerAttest/useProviderInjectedScripts.ts +10 -4
- package/src/components/providerAttest/useProviderMessageHandler.ts +141 -4
- package/src/components/providerAttest/useProviderNavigationHandlers.ts +55 -7
- package/src/components/providerAttest/useVerificationPresentation.ts +73 -0
- package/src/components/providerAttest/verificationPresentation.ts +53 -5
- package/src/providerRegistry/index.ts +12 -0
- package/src/providerRegistry/loginSubmitSignal.ts +532 -0
- package/src/providerRegistry/rules.ts +13 -0
- package/src/providerRegistry/template.ts +59 -1
- package/src/sdkMetadata.generated.ts +1 -1
- package/src/types/provider.types.ts +56 -1
- package/src/webview/index.ts +10 -4
- package/src/webview/scripts/requestInterceptorScript.ts +359 -23
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,113 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 3.3.0 - 2026-08-14
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **iOS crash on launch for any consumer using `prefetch`.** The hidden WebView
|
|
8
|
+
that warms the WebKit process was sourced from `{ uri: 'about:blank' }`. A
|
|
9
|
+
source URL with no host is loaded by react-native-webview through
|
|
10
|
+
`-[WKWebView loadFileURL:]`, which raises `NSInvalidArgumentException`
|
|
11
|
+
("about:blank is not a file URL") and terminates the app. It mounts as soon
|
|
12
|
+
as the provider resolves, so the crash landed at startup, before any provider
|
|
13
|
+
flow. It now warms via an `html` source, which takes `loadHTMLString` instead.
|
|
14
|
+
- Three further routes could hand the same hostless URL to a WebView and crash
|
|
15
|
+
it mid-flow: a managed popup opened for the common
|
|
16
|
+
`window.open('about:blank')` + `w.location = url` pattern; a popup navigating
|
|
17
|
+
its opener; and a main-frame navigation fed back into the source prop. All
|
|
18
|
+
three now require a loadable http(s) document URL. `isWebViewSafeUrl` was not
|
|
19
|
+
sufficient — it is a navigation-policy check that deliberately permits
|
|
20
|
+
`about:`. As a backstop, the source prop itself refuses a hostless URL rather
|
|
21
|
+
than trusting its input. `about:blank` is preserved on Android, where it is
|
|
22
|
+
the deliberate bootstrap URL and loads without incident.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **Pre-emptive login cover (`auth.submitSignal`).** The privacy cover can now
|
|
27
|
+
appear the moment a login is submitted, instead of waiting for the provider
|
|
28
|
+
injection's `__satyaReady` signal. That signal can only fire once the
|
|
29
|
+
authenticated DOM exists — and on Android provider injection is deliberately
|
|
30
|
+
excluded from the document-start payload — so the destination page was
|
|
31
|
+
briefly visible after every sign-in. A provider opts in with
|
|
32
|
+
an ordered `auth.submitSignal[]`. Each entry has a unique stable `id`, a
|
|
33
|
+
canonical HTTPS `url`, and declares `requestMatchRules` matched against the
|
|
34
|
+
already-intercepted fetch/XHR traffic (no new injected JavaScript) and/or a
|
|
35
|
+
`navigationUrlPattern` for form-POST logins that never reach the interceptor.
|
|
36
|
+
Rules must include a `urlContains` or `urlRegex` so a signal cannot match
|
|
37
|
+
every request.
|
|
38
|
+
- Providers can declare up to 16 login routes (for example password, OAuth,
|
|
39
|
+
and magic-link endpoints). Entries are ORed in declaration order; the first
|
|
40
|
+
matching entry owns the attempt, and only that entry's response rules and
|
|
41
|
+
timeout apply. Request and response evidence cannot be mixed across entries.
|
|
42
|
+
- Login request matching now also supports `bodyContains` and `bodyRegex` for
|
|
43
|
+
endpoints whose URL is shared across operations. Optional
|
|
44
|
+
`responseMatchRules` support `bodyContains` and `bodyRegex` success markers.
|
|
45
|
+
Response matching scans a bounded clone inside the WebView and sends only a
|
|
46
|
+
one private boolean over the React Native bridge; response contents remain local.
|
|
47
|
+
- Login-submit validation caps every trimmed matcher string—including header
|
|
48
|
+
keys and JSON paths—at 2048 characters and each rule list at 16 entries,
|
|
49
|
+
plus 32 regexes / 8192 regex characters across the provider. All regex
|
|
50
|
+
matchers must compile; backreferences and expressions with unsafe
|
|
51
|
+
backtracking are rejected by bounded static analysis before they can run
|
|
52
|
+
on-device. Body regexes should be anchored, with `bodyContains` used for
|
|
53
|
+
substring checks.
|
|
54
|
+
- Authenticates interceptor request/response messages with a native-generated,
|
|
55
|
+
per-flow capability so provider subframes cannot forge login-cover signals.
|
|
56
|
+
- Normalizes fetch and URL-encoded request bodies for login matching; bounded
|
|
57
|
+
XHR matching fails closed when a faithful body representation is unavailable.
|
|
58
|
+
- The pre-emptive cover is **provisional**, because logins fail routinely. It
|
|
59
|
+
reverts on its own rather than trapping the user behind a spinner: a non-2xx
|
|
60
|
+
response to the matched login request uncovers immediately, so a wrong
|
|
61
|
+
password, MFA prompt, or captcha stays visible; a 2xx extends the wait to
|
|
62
|
+
`max(timeoutMs, 8s)`
|
|
63
|
+
for `__satyaReady`; an unanswered submission lapses after 4s
|
|
64
|
+
(the selected `auth.submitSignal[].timeoutMs`, 1000–15000). Reverting is not sticky, so a
|
|
65
|
+
retry covers again. `__satyaReady` promotes the provisional cover to the
|
|
66
|
+
confirmed one, which keeps its existing 12s stalled watchdog.
|
|
67
|
+
- A main-frame navigation while the provisional cover is up promotes it to the
|
|
68
|
+
same `max(timeoutMs, 8s)` window an accepted 2xx grants, bounded at 3 extensions. This keeps
|
|
69
|
+
supported main-frame redirect chains covered independently of response-body
|
|
70
|
+
semantics. A rejection that re-renders in place still lapses on `timeoutMs`;
|
|
71
|
+
a provider that navigates on rejection may consume a bounded extension.
|
|
72
|
+
A late accepted response followed by all three extensions can keep the cover
|
|
73
|
+
up for 36s at the defaults, or 75s at `timeoutMs: 15000`. Exhausting the
|
|
74
|
+
windows uncovers and continues; it never fails the run, because a slow
|
|
75
|
+
provider must not lose a capture that is still progressing.
|
|
76
|
+
- `auth.submitSignal.ignoreResponseStatus` covers login endpoints whose status
|
|
77
|
+
is not a reliable success signal. Without `responseMatchRules`, the response
|
|
78
|
+
remains uncorrelated and the cover lapses on `timeoutMs`. With response rules,
|
|
79
|
+
the in-WebView body result decides acceptance while the status is ignored.
|
|
80
|
+
When the flag is absent/false, both a 2xx status and all configured response
|
|
81
|
+
rules must match.
|
|
82
|
+
- While provisional, the cover reads "Signing you in..." rather than
|
|
83
|
+
"Verifying your account..." — nothing has been verified at that point — and
|
|
84
|
+
offers no actions, since only the confirmed cover can stall.
|
|
85
|
+
|
|
86
|
+
### Notes
|
|
87
|
+
|
|
88
|
+
- The cover remains **presentation-only**. The pre-emptive signal never marks
|
|
89
|
+
the session logged in, releases `capture.requireLoginSignal`, authorizes a
|
|
90
|
+
capture, or affects replay, disclosure, or verifier policy; a matched login
|
|
91
|
+
request still passes through every normal capture rule. Only `__satyaReady`
|
|
92
|
+
gates capture.
|
|
93
|
+
- `auth` remains copied verbatim into the hashed security policy, so
|
|
94
|
+
`auth.submitSignal` is covered without adding a new policy projection.
|
|
95
|
+
The Rust verifier's canonical object-key ordering now follows JavaScript's
|
|
96
|
+
UTF-16 ordering, and SDK/Devtool validation rejects unpaired surrogate
|
|
97
|
+
strings, preventing cross-language hash drift in additive `auth` metadata.
|
|
98
|
+
Exact TypeScript/Rust golden vectors cover ordered signal arrays. Providers
|
|
99
|
+
that do not adopt the field keep an **unchanged policy hash**.
|
|
100
|
+
- `auth` was previously documented as preserved-but-uninterpreted metadata and
|
|
101
|
+
was not validated at all. Sibling keys are still preserved untouched, but a
|
|
102
|
+
non-object `auth` is now rejected instead of passing through silently — it
|
|
103
|
+
now carries configuration the SDK acts on, and a malformed value would
|
|
104
|
+
otherwise disable the cover with nothing to explain why.
|
|
105
|
+
- Popup close is not treated as authentication. This release does not observe
|
|
106
|
+
provisional submit matchers inside native Android popup WebViews, and managed
|
|
107
|
+
popup form navigations do not feed `navigationUrlPattern` into the detector.
|
|
108
|
+
Providers can match an observed session/status request issued by the opener
|
|
109
|
+
after popup close; otherwise concealment waits for the opener's
|
|
110
|
+
`__satyaReady`, preserving the previous popup timing.
|
|
4
111
|
|
|
5
112
|
## 3.2.0 - 2026-08-07
|
|
6
113
|
|
|
@@ -155,7 +262,7 @@ default-deny provider allowlist.
|
|
|
155
262
|
id was swallowed by the policy-refresh `try` and resurfaced after the user
|
|
156
263
|
had already completed login, mislabeled as a native-module failure.
|
|
157
264
|
- **Empty overrides no longer erase configuration.** `initSatyaAttest({ appId:
|
|
158
|
-
|
|
265
|
+
'' })` (a common `props.appId ?? ''` pattern) wiped a valid env-derived app
|
|
159
266
|
id, and an empty `providerRegistryApi` silently repointed a staging build at
|
|
160
267
|
production.
|
|
161
268
|
|
package/PROVIDER_CONFIG.md
CHANGED
|
@@ -25,6 +25,7 @@ inside a provider:
|
|
|
25
25
|
Registry { schemaVersion?, providers[] }
|
|
26
26
|
└─ Provider top-level proof config
|
|
27
27
|
├─ login { url } → page opened in the WebView
|
|
28
|
+
├─ auth? { submitSignal? } → pre-emptive login cover (optional)
|
|
28
29
|
├─ endpoints[] one replayable request each
|
|
29
30
|
│ ├─ requestMatchRules[] which WebView request to capture
|
|
30
31
|
│ ├─ revealRules[] what the artifact may disclose
|
|
@@ -102,7 +103,7 @@ field table (`Req?` = required `yes` / optional `no`).
|
|
|
102
103
|
| `requiresLocation` | `boolean` | Enables geolocation only for this provider's managed WebView. Defaults to `false`; the host app must opt in with the config plugin's `enableWebViewGeolocation` option. Android runtime access is requested after the provider resolves and before its WebView loads. |
|
|
103
104
|
| `userAgent` | `{ ios, android }` | Per-platform UA (each `string` or `null`) for the WebView when no `webViewUserAgent` prop is set. Use when the provider serves different pages to mobile vs desktop and replay must match. |
|
|
104
105
|
| `injection` | `string` / `string[]` / `null` | Trusted WebView JavaScript run on every page. See §9. |
|
|
105
|
-
| `auth` | `object` |
|
|
106
|
+
| `auth` | `object` | Authentication metadata. Only `submitSignal` (§2.1) is interpreted; every sibling key is preserved untouched. Must be an object when present. |
|
|
106
107
|
|
|
107
108
|
Unknown top-level keys are cloned through but ignored by native replay/verification —
|
|
108
109
|
never put security-critical behavior in an undocumented key.
|
|
@@ -125,6 +126,123 @@ The page opened in the managed WebView. Use the provider's normal sign-in / acco
|
|
|
125
126
|
> `login.injection` is **invalid** — provider JavaScript always lives at the top-level
|
|
126
127
|
> `injection` (§9).
|
|
127
128
|
|
|
129
|
+
### 2.1 `auth.submitSignal` (optional) — covering before the landing page paints
|
|
130
|
+
|
|
131
|
+
`__satyaReady` (§9) can only fire once the authenticated DOM exists, so the provider's
|
|
132
|
+
destination page is briefly visible after sign-in. `submitSignal` moves the cover earlier:
|
|
133
|
+
the SDK covers the WebView as soon as it sees the login being submitted.
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
"login": { "url": "https://acme.example/login" },
|
|
137
|
+
"auth": {
|
|
138
|
+
"submitSignal": [
|
|
139
|
+
{
|
|
140
|
+
"id": "PasswordLogin",
|
|
141
|
+
"url": "https://acme.example/api/v1/auth/login",
|
|
142
|
+
"requestMatchRules": [
|
|
143
|
+
{ "type": "methodEquals", "pattern": "POST" },
|
|
144
|
+
{ "type": "urlContains", "pattern": "/api/v1/auth/login" },
|
|
145
|
+
{ "type": "bodyContains", "pattern": "\"grantType\":\"password\"" }
|
|
146
|
+
],
|
|
147
|
+
"responseMatchRules": [
|
|
148
|
+
{ "type": "bodyContains", "pattern": "\"authenticated\":true" },
|
|
149
|
+
{ "type": "bodyRegex", "pattern": "^\\{\"authenticated\":true,\"sessionId\":\"[^\"]+\"\\}$" }
|
|
150
|
+
],
|
|
151
|
+
"ignoreResponseStatus": true,
|
|
152
|
+
"timeoutMs": 4000
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
| Field | Req? | Type | Description |
|
|
159
|
+
|---|---|---|---|
|
|
160
|
+
| `id` | yes | `string` | Unique stable signal identifier. Starts with a letter, then letters/numbers/`_`/`-`; maximum 64 characters. |
|
|
161
|
+
| `url` | yes | `string` | Canonical HTTPS login endpoint, without credentials or surrounding whitespace; maximum 2048 characters. Every request URL rule must match it, and navigation matching is restricted to this origin. |
|
|
162
|
+
| `requestMatchRules` | no\* | `array` | ANDed rules matched against intercepted `fetch`/`XHR` traffic. Supports `methodEquals`, `urlContains`, `urlRegex`, `headerEquals`, `bodyJsonPathEquals`, `bodyContains`, and `bodyRegex`. Must include a `urlContains` (≥4 chars) or `urlRegex` rule. |
|
|
163
|
+
| `responseMatchRules` | no | `array` | Optional ANDed success-envelope rules. Supports `bodyContains` and `bodyRegex`. Requires `requestMatchRules` so the response can be correlated to a URL-bound login request. Matching reads at most the first 65,536 response characters inside the WebView; only a private boolean crosses the React Native bridge. |
|
|
164
|
+
| `navigationUrlPattern` | no\* | `string` | Regex matched against same-origin main-frame navigations. For classic `<form>` POST logins, which never reach the request interceptor. |
|
|
165
|
+
| `timeoutMs` | no | `integer` | 1000–15000, default 4000. How long an unanswered submission stays covered. |
|
|
166
|
+
| `ignoreResponseStatus` | no | `boolean` | Without `responseMatchRules`, `true` skips response correlation and the cover lapses on `timeoutMs`. With `responseMatchRules`, status is ignored but the response-body boolean still decides acceptance. When false/absent, acceptance requires both 2xx and all configured response rules. |
|
|
167
|
+
|
|
168
|
+
`submitSignal` is a non-empty array with at most 16 entries. A provider can list one entry
|
|
169
|
+
per login route (password, OAuth callback, magic link, and so on). Entries are ORed in
|
|
170
|
+
declaration order and the first matching entry owns the attempt; rules within that entry
|
|
171
|
+
are ANDed. The selected entry alone supplies response rules and `timeoutMs`, so request and
|
|
172
|
+
response evidence is never mixed across login routes. IDs must be unique.
|
|
173
|
+
|
|
174
|
+
\* At least one of `requestMatchRules` / `navigationUrlPattern` is required for each entry.
|
|
175
|
+
Sibling `auth` keys are preserved and never interpreted, so a provider may keep its own
|
|
176
|
+
metadata alongside it. A non-object `auth`, an object-form `submitSignal`, and unknown keys
|
|
177
|
+
inside a signal are rejected outright. Every trimmed matcher string—including header keys
|
|
178
|
+
and JSON paths—is capped at 2048 characters, every rule array is capped at 16 entries, and
|
|
179
|
+
the complete provider may contain at most 32 regexes totaling 8192 characters. Every regex
|
|
180
|
+
must compile. To keep matchers safe for on-device request/response processing,
|
|
181
|
+
backreferences and expressions with unsafe backtracking are rejected by bounded static analysis.
|
|
182
|
+
Anchor body regexes to the complete expected body; use `bodyContains` for substring checks.
|
|
183
|
+
Fetch bodies are normalized through the browser `Request` API. XHR supports text,
|
|
184
|
+
`URLSearchParams`, and byte-buffer request bodies; XHR `FormData`/`Blob` request matching and
|
|
185
|
+
`responseType="json"` response matching fail closed because no bounded faithful wire encoding is
|
|
186
|
+
available. Prefer `fetch` or a text XHR response when body rules are required.
|
|
187
|
+
|
|
188
|
+
**The cover is provisional and reverts on its own** — logins fail routinely, and a wrong
|
|
189
|
+
password must not sit behind a spinner:
|
|
190
|
+
|
|
191
|
+
| Outcome | Behavior |
|
|
192
|
+
|---|---|
|
|
193
|
+
| Matched request answered non-2xx | Uncovers immediately, so the provider's error, MFA prompt, or captcha is visible |
|
|
194
|
+
| Matched request answered 2xx | Waits for `max(timeoutMs, 8s)` for `__satyaReady` |
|
|
195
|
+
| `responseMatchRules` configured | Accepts only when every body rule matches; also requires 2xx unless `ignoreResponseStatus` is true |
|
|
196
|
+
| No response observed | Lapses after `timeoutMs` |
|
|
197
|
+
| `ignoreResponseStatus: true`, no response rules | Response is not correlated; always lapses after `timeoutMs` |
|
|
198
|
+
| Main-frame navigation while covered | Grants the same `max(timeoutMs, 8s)` accepted window (up to 3 times) for supported redirect chains |
|
|
199
|
+
| `__satyaReady` arrives | Promotes to the confirmed cover, with its usual 12s stalled watchdog |
|
|
200
|
+
|
|
201
|
+
Reverting is not sticky: a retried login covers again.
|
|
202
|
+
|
|
203
|
+
> **Check what a failed login actually returns.** Many login APIs answer `200` with an
|
|
204
|
+
> error envelope rather than a 4xx. Add `responseMatchRules` for a stable success marker so
|
|
205
|
+
> a rejected 200 response uncovers immediately. Use `ignoreResponseStatus: true` together
|
|
206
|
+
> with response rules only when the HTTP status is unreliable. The response is cloned and
|
|
207
|
+
> scanned inside the WebView; its contents never cross the bridge, only the match boolean.
|
|
208
|
+
|
|
209
|
+
`timeoutMs` does not have to cover the provider's slowest sign-in. A main-frame navigation
|
|
210
|
+
while the cover is up promotes it to the same `max(timeoutMs, 8s)` window an accepted 2xx would grant
|
|
211
|
+
(bounded at 3 extensions), which keeps supported redirect chains covered. A rejected login
|
|
212
|
+
that re-renders in place still uncovers after one `timeoutMs`; a provider that navigates on
|
|
213
|
+
rejection may consume a bounded extension. Set `timeoutMs` to how long you are willing to
|
|
214
|
+
hide a **failed** login, not to how long a successful one takes.
|
|
215
|
+
|
|
216
|
+
If every window still expires without `__satyaReady`, the cover simply lifts and the flow
|
|
217
|
+
continues. A late accepted response followed by all three navigation extensions can keep it
|
|
218
|
+
covered for up to 36s at the defaults, or 75s with `timeoutMs: 15000`. It never fails the run:
|
|
219
|
+
the cover is presentation-only, and a slow provider must not lose a capture that is still
|
|
220
|
+
progressing.
|
|
221
|
+
|
|
222
|
+
> The remaining latency is the provider injection's own detection speed. Between the last
|
|
223
|
+
> navigation and `__satyaReady`, only `timeoutMs` is holding the cover. An injection that
|
|
224
|
+
> polls slowly (say `setInterval(…, 1500)` and waits for full DOM hydration) can exceed it
|
|
225
|
+
> and let the destination page flash. Prefer an auth-cookie check at ≤1s (§9).
|
|
226
|
+
|
|
227
|
+
> Prefer `requestMatchRules` — the SDK already intercepts every `fetch`/`XHR`, so no new
|
|
228
|
+
> injected JavaScript is involved. Scope the rules to the login endpoint itself; a signal
|
|
229
|
+
> that also matches ordinary page traffic will cover the user at random moments.
|
|
230
|
+
> `navigationUrlPattern` must match the **post-login** URL, not the login page's own loads.
|
|
231
|
+
|
|
232
|
+
> **Popup limitation.** Popup close is not an authentication signal. The current SDK does
|
|
233
|
+
> not observe `submitSignal` requests inside native Android popup WebViews, and managed-popup
|
|
234
|
+
> form navigations do not feed `navigationUrlPattern` into the provisional-cover detector.
|
|
235
|
+
> If the opener/main WebView immediately issues an observed session/status `fetch`/`XHR`
|
|
236
|
+
> after close, match that request instead. Otherwise the popup may remain visible until the
|
|
237
|
+
> opener emits `__satyaReady`; do not invent a popup-close heuristic.
|
|
238
|
+
|
|
239
|
+
`submitSignal` is presentation-only. It never releases `capture.requireLoginSignal`,
|
|
240
|
+
authorizes a capture, or affects replay or verification — a matched login request still
|
|
241
|
+
passes through every normal capture rule. **Still emit `__satyaReady`** (§9): it is what
|
|
242
|
+
gates capture and what promotes the cover. Because `auth` is copied verbatim into the
|
|
243
|
+
hashed security policy, adding `submitSignal` changes the provider's `policyHash`; not
|
|
244
|
+
adding it leaves the hash unchanged.
|
|
245
|
+
|
|
128
246
|
---
|
|
129
247
|
|
|
130
248
|
## 3. `endpoints[]` — the Endpoint object
|
|
@@ -561,6 +679,13 @@ it while a logged-out state is still possible: a premature signal covers the log
|
|
|
561
679
|
although the stalled cover offers a way back, that is a degraded experience. (This signal is
|
|
562
680
|
unrelated to the registry catalog flag `metadata.isSatyaReady`.)
|
|
563
681
|
|
|
682
|
+
Because `__satyaReady` cannot fire until the authenticated DOM exists, even a fast detector
|
|
683
|
+
leaves the destination page briefly visible. To close that gap, also declare
|
|
684
|
+
`auth.submitSignal` (§2.1), which covers the WebView the moment the login is submitted and
|
|
685
|
+
reverts on its own if the login turns out to have failed. The two are complementary:
|
|
686
|
+
`submitSignal` decides how early the cover appears, `__satyaReady` still gates capture and
|
|
687
|
+
promotes the provisional cover to the confirmed one.
|
|
688
|
+
|
|
564
689
|
> This is distinct from endpoint `capture`: `injection` is page JavaScript at the provider
|
|
565
690
|
> level; `capture` is per-endpoint active-fetch/readiness config.
|
|
566
691
|
|
|
@@ -690,6 +815,14 @@ console.log(body.match(/octolytics-actor-login" content="(.*?)"/)?.[1]);
|
|
|
690
815
|
is an SDK/verifier session option (§8.1),
|
|
691
816
|
- `injection` is a non-empty string / non-empty string array when present; `login.injection`
|
|
692
817
|
and endpoint `injection` are rejected,
|
|
818
|
+
- `auth.submitSignal` (when present) is an array of 1–16 entries with unique `id` values and
|
|
819
|
+
canonical HTTPS `url` values; each entry has only `id`, `url`, `requestMatchRules`,
|
|
820
|
+
`responseMatchRules`, `navigationUrlPattern`, `timeoutMs`, `ignoreResponseStatus`; declares at
|
|
821
|
+
least one request/navigation detector; request rules use supported request types, include a
|
|
822
|
+
URL-bounding `urlContains`/`urlRegex`, and match the entry's `url`; response rules use only
|
|
823
|
+
`bodyContains`/`bodyRegex` and require request rules; request and response rule arrays contain
|
|
824
|
+
at most 16 entries; every trimmed matcher string is ≤2048 characters; patterns compile;
|
|
825
|
+
`timeoutMs` is an integer in 1000–15000 (§2.1),
|
|
693
826
|
- raw `allowedRequestHeaders`, `allowedResponseBodyJsonPaths`, and `privacyPolicy` are
|
|
694
827
|
rejected (the loader derives them from `revealRules`),
|
|
695
828
|
- SPKI pins are SHA-256 base64,
|
package/README.md
CHANGED
|
@@ -190,7 +190,7 @@ New SDK artifacts also include envelope metadata:
|
|
|
190
190
|
"attestationIdVersion": "statement-sha256-96-v1",
|
|
191
191
|
"producer": {
|
|
192
192
|
"sdk": "@burnt-labs/expo-satya-attest",
|
|
193
|
-
"sdkVersion": "3.
|
|
193
|
+
"sdkVersion": "3.3.0",
|
|
194
194
|
"artifactSchemaVersion": "1.1.0",
|
|
195
195
|
"coreVersion": "0.1.0"
|
|
196
196
|
}
|
|
@@ -337,7 +337,7 @@ is a release tarball produced by `npm pack`, because it contains the same files
|
|
|
337
337
|
would publish:
|
|
338
338
|
|
|
339
339
|
```bash
|
|
340
|
-
npm install https://github.com/<owner>/<repo>/releases/download/expo-satya-attest-v3.
|
|
340
|
+
npm install https://github.com/<owner>/<repo>/releases/download/expo-satya-attest-v3.3.0/burnt-labs-expo-satya-attest-3.3.0.tgz
|
|
341
341
|
npx expo install react-native-webview react-native-safe-area-context
|
|
342
342
|
```
|
|
343
343
|
|
|
@@ -345,8 +345,8 @@ Installing from a Git ref also works when that ref has the SDK package at the re
|
|
|
345
345
|
root, such as a dedicated SDK repo or a subtree/split branch:
|
|
346
346
|
|
|
347
347
|
```bash
|
|
348
|
-
npm install github:<owner>/<sdk-repo>#v3.
|
|
349
|
-
npm install git+https://github.com/<owner>/<sdk-repo>.git#v3.
|
|
348
|
+
npm install github:<owner>/<sdk-repo>#v3.3.0
|
|
349
|
+
npm install git+https://github.com/<owner>/<sdk-repo>.git#v3.3.0
|
|
350
350
|
npx expo install react-native-webview react-native-safe-area-context
|
|
351
351
|
```
|
|
352
352
|
|
|
@@ -423,15 +423,34 @@ pill (lock icon + domain), a reload button, and a page-load line that advances w
|
|
|
423
423
|
loads and clears when it finishes; both the main page and the managed OAuth popup fade in
|
|
424
424
|
over their first load instead of flashing white.
|
|
425
425
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
426
|
+
SDK 3.3.0 providers can declare an ordered `auth.submitSignal[]` to start a provisional
|
|
427
|
+
"Signing you in..." cover as soon as a tightly scoped main-WebView login request or
|
|
428
|
+
navigation is observed. Request matching supports URL-, header-, JSON-path-, and raw-body
|
|
429
|
+
rules. Each entry has a unique `id` and canonical HTTPS `url`; entries are ORed in order,
|
|
430
|
+
the first match wins, and that same entry owns response matching and timeout behavior.
|
|
431
|
+
Optional response body rules are evaluated on a bounded clone inside the WebView; only
|
|
432
|
+
a private boolean crosses the React Native bridge. A rejection uncovers, an unanswered
|
|
433
|
+
submission lapses on timeout, and bounded main-frame navigation extensions keep supported
|
|
434
|
+
redirect chains concealed.
|
|
435
|
+
|
|
436
|
+
Login-cover configuration is capped at 32 regexes totaling 8192 characters per provider,
|
|
437
|
+
in addition to the per-pattern and per-rule-list limits. Body matching supports normalized
|
|
438
|
+
fetch bodies and text XHR; bounded matching fails closed for XHR `responseType="json"` and
|
|
439
|
+
XHR `FormData`/`Blob` request bodies.
|
|
440
|
+
|
|
441
|
+
Once the provider's injection confirms authentication with `__satyaReady`, the sheet
|
|
442
|
+
promotes to the "Verifying your account…" cover while capture and native replay continue
|
|
443
|
+
underneath. Only `__satyaReady` releases readiness-gated capture; both covers remain
|
|
444
|
+
presentation-only and never change replay or verification policy. If confirmed capture
|
|
445
|
+
does not start within a short watchdog window, the cover offers a "Return to provider"
|
|
446
|
+
path that keeps the flow alive. Providers without `auth.submitSignal` retain the previous
|
|
447
|
+
timing and policy hash.
|
|
448
|
+
|
|
449
|
+
Popup close is not an authentication signal. This release does not observe provisional
|
|
450
|
+
submit matchers inside native Android popup WebViews or managed-popup form navigations. A
|
|
451
|
+
provider may instead match an observed session/status request that the opener issues after
|
|
452
|
+
popup close; otherwise concealment waits for the opener's `__satyaReady`. See
|
|
453
|
+
`PROVIDER_CONFIG.md` §2.1 for the complete schema and limitations.
|
|
435
454
|
|
|
436
455
|
Pass `presentation="fullScreen"` to keep the legacy full-window takeover. Set `prefetch`
|
|
437
456
|
to resolve the provider policy and warm the WebView engine at mount so the sheet opens
|
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.3.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.3.0"
|
|
14
14
|
// StrongBox key attestation needs API 28+; basic Keystore attestation API 24+.
|
|
15
15
|
minSdkVersion 24
|
|
16
16
|
}
|
|
@@ -107,6 +107,12 @@ class SatyaAttestModule : Module() {
|
|
|
107
107
|
|
|
108
108
|
Function("satyaCoreVersion") { satyaCoreVersion() }
|
|
109
109
|
|
|
110
|
+
Function("createWebViewBridgeCapability") {
|
|
111
|
+
val bytes = ByteArray(32)
|
|
112
|
+
SecureRandom().nextBytes(bytes)
|
|
113
|
+
Base64.encodeToString(bytes, Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING)
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
AsyncFunction("initialize") { configJson: String -> transportConfigJson = configJson }
|
|
111
117
|
|
|
112
118
|
AsyncFunction("dispose") { transportConfigJson = "{}" }
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -2,6 +2,7 @@ import { NativeModule } from 'expo';
|
|
|
2
2
|
import { VerifyResult } from './types';
|
|
3
3
|
declare class SatyaAttestModule extends NativeModule<Record<string, never>> {
|
|
4
4
|
satyaCoreVersion(): string;
|
|
5
|
+
createWebViewBridgeCapability(): string;
|
|
5
6
|
attestNativeReplay(providerTemplateJson: string, capturedRequestJson?: string | null): Promise<string>;
|
|
6
7
|
attestNativeReplayBundle(providerTemplateJson: string, capturedRequestsJson: string, partialEndpointSelectionJson?: string | null): Promise<string>;
|
|
7
8
|
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;
|
|
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;IAEvC,kBAAkB,CAChB,oBAAoB,EAAE,MAAM,EAC5B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAClC,OAAO,CAAC,MAAM,CAAC;IAElB,wBAAwB,CACtB,oBAAoB,EAAE,MAAM,EAC5B,oBAAoB,EAAE,MAAM,EAC5B,4BAA4B,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3C,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;AAmCzD,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 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"]}
|
|
@@ -2,6 +2,7 @@ import { NativeModule } from 'expo';
|
|
|
2
2
|
import { VerifyResult } from './types';
|
|
3
3
|
declare class SatyaAttestModule extends NativeModule<Record<string, never>> {
|
|
4
4
|
satyaCoreVersion(): string;
|
|
5
|
+
createWebViewBridgeCapability(): string;
|
|
5
6
|
attestNativeReplay(_providerTemplateJson: string, _capturedRequestJson?: string | null): Promise<string>;
|
|
6
7
|
attestNativeReplayBundle(_providerTemplateJson: string, _capturedRequestsJson: string, _partialEndpointSelectionJson?: string | null): Promise<string>;
|
|
7
8
|
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;
|
|
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,CAAC,EAAE,MAAM,GAAG,IAAI,GACnC,OAAO,CAAC,MAAM,CAAC;IAGZ,wBAAwB,CAC5B,qBAAqB,EAAE,MAAM,EAC7B,qBAAqB,EAAE,MAAM,EAC7B,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,GAC5C,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"}
|
|
@@ -5,6 +5,9 @@ class SatyaAttestModule extends NativeModule {
|
|
|
5
5
|
satyaCoreVersion() {
|
|
6
6
|
throw unsupportedPlatformError();
|
|
7
7
|
}
|
|
8
|
+
createWebViewBridgeCapability() {
|
|
9
|
+
throw unsupportedPlatformError();
|
|
10
|
+
}
|
|
8
11
|
async attestNativeReplay(_providerTemplateJson, _capturedRequestJson) {
|
|
9
12
|
throw unsupportedPlatformError();
|
|
10
13
|
}
|
|
@@ -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,KAAK,CAAC,kBAAkB,CACtB,qBAA6B,EAC7B,oBAAoC;QAEpC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,wBAAwB,CAC5B,qBAA6B,EAC7B,qBAA6B,EAC7B,6BAA6C;QAE7C,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 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,CACtB,qBAA6B,EAC7B,oBAAoC;QAEpC,MAAM,wBAAwB,EAAE,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,wBAAwB,CAC5B,qBAA6B,EAC7B,qBAA6B,EAC7B,6BAA6C;QAE7C,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"]}
|
|
@@ -43,7 +43,15 @@ function ProviderAttestButtonView({ props, flow, }) {
|
|
|
43
43
|
{flow.running ? 'Generating Attestation' : flow.buttonLabel}
|
|
44
44
|
</Text>
|
|
45
45
|
</Pressable>) : null}
|
|
46
|
-
{flow.prefetch && !flow.modalVisible && WarmWebView ? (<WarmWebView
|
|
46
|
+
{flow.prefetch && !flow.modalVisible && WarmWebView ? (<WarmWebView
|
|
47
|
+
// Warms the WebKit process before the real WebView opens. This must be
|
|
48
|
+
// an `html` source rather than a blank-page URI: react-native-webview
|
|
49
|
+
// loads any hostless URI with `-[WKWebView loadFileURL:]`, which
|
|
50
|
+
// raises NSInvalidArgumentException and crashes the app on iOS. An
|
|
51
|
+
// html source takes the `loadHTMLString` branch and warms the same
|
|
52
|
+
// way. This view mounts outside the modal as soon as the provider
|
|
53
|
+
// resolves, so a crash here lands at launch, not during the flow.
|
|
54
|
+
source={{ html: '<html></html>' }} style={styles.warmWebView} pointerEvents="none" javaScriptEnabled={false} accessibilityElementsHidden importantForAccessibility="no-hide-descendants"/>) : null}
|
|
47
55
|
<ProviderAttestModal flow={flow}/>
|
|
48
56
|
</>);
|
|
49
57
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SatyaProviderAttestButton.js","sourceRoot":"","sources":["../src/SatyaProviderAttestButton.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SatyaProviderAttestButton.js","sourceRoot":"","sources":["../src/SatyaProviderAttestButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAC;AACtF,OAAO,EACL,kBAAkB,GAEnB,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wDAAwD,CAAC;AAE9F,OAAO,EACL,qBAAqB,GAEtB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAA2B,MAAM,eAAe,CAAC;AAc/E,MAAM,UAAU,yBAAyB,CAAC,KAAqC;IAC7E,0EAA0E;IAC1E,4EAA4E;IAC5E,uDAAuD;IACvD,MAAM,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAqB,GAAG,EAAE,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC9E,MAAM,SAAS,GAAG,kBAAkB,CAClC;QACE,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,kBAAkB,EAAE,KAAK,CAAC,gBAAgB,EAAE,UAAU;KACvD,EACD,OAAO,CACR,CAAC;IAEF,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC/B,OAAO,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,EAAG,CAAC;IACvE,CAAC;IACD,OAAO,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAG,CAAC;AAClD,CAAC;AAMD,SAAS,sBAAsB,CAAC,EAAE,KAAK,EAAyB;IAC9D,MAAM,IAAI,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAG,CAAC;AAChE,CAAC;AAED,SAAS,qBAAqB,CAAC,EAC7B,KAAK,EACL,SAAS,GAGV;IACC,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACxD,OAAO,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAG,CAAC;AAChE,CAAC;AAED,SAAS,wBAAwB,CAAC,EAChC,KAAK,EACL,IAAI,GAIL;IACC,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC;IACvE,MAAM,kBAAkB,GAAG,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC;IACtD,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC;IAEzC,OAAO,CACL,EACE;MAAA,CAAC,kBAAkB,CAAC,CAAC,CAAC,CACpB,CAAC,SAAS,CACR,KAAK,CAAC,CAAC;gBACL,MAAM,CAAC,MAAM;gBACb,EAAE,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAC3C,UAAU,IAAI,MAAM,CAAC,cAAc;aACpC,CAAC,CACF,QAAQ,CAAC,CAAC,UAAU,CAAC,CACrB,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CACvB;UAAA,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,EAAG,CAAC,CAAC,CAAC,IAAI,CACzF;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAC7B;YAAA,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAC7D;UAAA,EAAE,IAAI,CACR;QAAA,EAAE,SAAS,CAAC,CACb,CAAC,CAAC,CAAC,IAAI,CACR;MAAA,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,WAAW,CAAC,CAAC,CAAC,CACpD,CAAC,WAAW;QACV,uEAAuE;QACvE,sEAAsE;QACtE,iEAAiE;QACjE,mEAAmE;QACnE,mEAAmE;QACnE,kEAAkE;QAClE,kEAAkE;QAClE,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAClC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC1B,aAAa,CAAC,MAAM,CACpB,iBAAiB,CAAC,CAAC,KAAK,CAAC,CACzB,2BAA2B,CAC3B,yBAAyB,CAAC,qBAAqB,EAC/C,CACH,CAAC,CAAC,CAAC,IAAI,CACR;MAAA,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAClC;IAAA,GAAG,CACJ,CAAC;AACJ,CAAC","sourcesContent":["import React, { useState } from 'react';\nimport { ActivityIndicator, Pressable, Text } from 'react-native';\n\nimport { ProviderAttestModal } from './components/providerAttest/ProviderAttestModal';\nimport {\n selectProviderFlow,\n type SatyaProviderFlowSelection,\n} from './components/providerAttest/flowSelection';\nimport { styles } from './components/providerAttest/styles';\nimport { useTeelsProviderFlow } from './components/providerAttest/teels/useTeelsProviderFlow';\nimport type { SatyaProviderAttestButtonProps } from './components/providerAttest/types';\nimport {\n useProviderAttestFlow,\n type ProviderAttestFlow,\n} from './components/providerAttest/useProviderAttestFlow';\nimport { getSatyaRuntimeConfig, type SatyaRuntimeConfig } from './satyaConfig';\n\nexport type {\n SatyaBackendVerifyResult,\n SatyaProviderAttestButtonProps,\n SatyaProviderAttestationResult,\n SatyaProviderAttestPresentation,\n SatyaProviderAttestTheme,\n SatyaProviderFlowPhase,\n SatyaProviderFlowProgress,\n SatyaTeelsAttestation,\n SatyaTeelsClaimData,\n} from './components/providerAttest/types';\n\nexport function SatyaProviderAttestButton(props: SatyaProviderAttestButtonProps) {\n // Bind the runtime config once at mount (the init-before-mount contract),\n // but recompute the flow selection from live props so a providerId/template\n // switch cannot leave the button running a stale flow.\n const [runtime] = useState<SatyaRuntimeConfig>(() => getSatyaRuntimeConfig());\n const selection = selectProviderFlow(\n {\n providerId: props.providerId,\n providerTemplateId: props.providerTemplate?.providerId,\n },\n runtime\n );\n\n if (selection.type === 'teels') {\n return <TeelsProviderFlowHost props={props} selection={selection} />;\n }\n return <NativeProviderFlowHost props={props} />;\n}\n\ninterface ProviderFlowHostProps {\n props: SatyaProviderAttestButtonProps;\n}\n\nfunction NativeProviderFlowHost({ props }: ProviderFlowHostProps) {\n const flow = useProviderAttestFlow(props);\n return <ProviderAttestButtonView props={props} flow={flow} />;\n}\n\nfunction TeelsProviderFlowHost({\n props,\n selection,\n}: ProviderFlowHostProps & {\n selection: Extract<SatyaProviderFlowSelection, { type: 'teels' }>;\n}) {\n const flow = useTeelsProviderFlow(props, { selection });\n return <ProviderAttestButtonView props={props} flow={flow} />;\n}\n\nfunction ProviderAttestButtonView({\n props,\n flow,\n}: {\n props: SatyaProviderAttestButtonProps;\n flow: ProviderAttestFlow;\n}) {\n const isDisabled = props.disabled || flow.running || flow.modalVisible;\n const shouldRenderButton = props.renderButton ?? true;\n const WarmWebView = flow.ResolvedWebView;\n\n return (\n <>\n {shouldRenderButton ? (\n <Pressable\n style={[\n styles.button,\n { backgroundColor: flow.theme.accentColor },\n isDisabled && styles.buttonDisabled,\n ]}\n disabled={isDisabled}\n onPress={flow.openFlow}>\n {flow.running ? <ActivityIndicator color=\"#ffffff\" style={styles.buttonSpinner} /> : null}\n <Text style={styles.buttonText}>\n {flow.running ? 'Generating Attestation' : flow.buttonLabel}\n </Text>\n </Pressable>\n ) : null}\n {flow.prefetch && !flow.modalVisible && WarmWebView ? (\n <WarmWebView\n // Warms the WebKit process before the real WebView opens. This must be\n // an `html` source rather than a blank-page URI: react-native-webview\n // loads any hostless URI with `-[WKWebView loadFileURL:]`, which\n // raises NSInvalidArgumentException and crashes the app on iOS. An\n // html source takes the `loadHTMLString` branch and warms the same\n // way. This view mounts outside the modal as soon as the provider\n // resolves, so a crash here lands at launch, not during the flow.\n source={{ html: '<html></html>' }}\n style={styles.warmWebView}\n pointerEvents=\"none\"\n javaScriptEnabled={false}\n accessibilityElementsHidden\n importantForAccessibility=\"no-hide-descendants\"\n />\n ) : null}\n <ProviderAttestModal flow={flow} />\n </>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderAttestModal.d.ts","sourceRoot":"","sources":["../../../src/components/providerAttest/ProviderAttestModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ProviderAttestModal.d.ts","sourceRoot":"","sources":["../../../src/components/providerAttest/ProviderAttestModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAuC3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAGlE,UAAU,wBAAwB;IAChC,IAAI,EAAE,kBAAkB,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,EAAE,wBAAwB,qBAMrE"}
|