@burnt-labs/expo-satya-attest 3.1.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.
Files changed (173) hide show
  1. package/CHANGELOG.md +124 -2
  2. package/PROVIDER_CONFIG.md +200 -1
  3. package/README.md +142 -13
  4. package/android/build.gradle +2 -2
  5. package/android/src/main/java/expo/modules/satyaattest/SatyaAttestModule.kt +6 -0
  6. package/android/src/main/jniLibs/arm64-v8a/libsatya_ffi.so +0 -0
  7. package/android/src/main/jniLibs/armeabi-v7a/libsatya_ffi.so +0 -0
  8. package/android/src/main/jniLibs/x86_64/libsatya_ffi.so +0 -0
  9. package/build/SatyaAttestModule.d.ts +1 -0
  10. package/build/SatyaAttestModule.d.ts.map +1 -1
  11. package/build/SatyaAttestModule.js.map +1 -1
  12. package/build/SatyaAttestModule.web.d.ts +1 -0
  13. package/build/SatyaAttestModule.web.d.ts.map +1 -1
  14. package/build/SatyaAttestModule.web.js +3 -0
  15. package/build/SatyaAttestModule.web.js.map +1 -1
  16. package/build/SatyaProviderAttestButton.d.ts +1 -1
  17. package/build/SatyaProviderAttestButton.d.ts.map +1 -1
  18. package/build/SatyaProviderAttestButton.js +35 -3
  19. package/build/SatyaProviderAttestButton.js.map +1 -1
  20. package/build/components/providerAttest/ProviderAttestModal.d.ts.map +1 -1
  21. package/build/components/providerAttest/ProviderAttestModal.js +57 -23
  22. package/build/components/providerAttest/ProviderAttestModal.js.map +1 -1
  23. package/build/components/providerAttest/backendVerifier.d.ts +9 -0
  24. package/build/components/providerAttest/backendVerifier.d.ts.map +1 -1
  25. package/build/components/providerAttest/backendVerifier.js +44 -6
  26. package/build/components/providerAttest/backendVerifier.js.map +1 -1
  27. package/build/components/providerAttest/copy.d.ts +13 -0
  28. package/build/components/providerAttest/copy.d.ts.map +1 -1
  29. package/build/components/providerAttest/copy.js +35 -0
  30. package/build/components/providerAttest/copy.js.map +1 -1
  31. package/build/components/providerAttest/flowSelection.d.ts +18 -0
  32. package/build/components/providerAttest/flowSelection.d.ts.map +1 -0
  33. package/build/components/providerAttest/flowSelection.js +25 -0
  34. package/build/components/providerAttest/flowSelection.js.map +1 -0
  35. package/build/components/providerAttest/loginSubmitDetector.d.ts +24 -0
  36. package/build/components/providerAttest/loginSubmitDetector.d.ts.map +1 -0
  37. package/build/components/providerAttest/loginSubmitDetector.js +65 -0
  38. package/build/components/providerAttest/loginSubmitDetector.js.map +1 -0
  39. package/build/components/providerAttest/popupRelay.d.ts +14 -0
  40. package/build/components/providerAttest/popupRelay.d.ts.map +1 -1
  41. package/build/components/providerAttest/popupRelay.js +27 -0
  42. package/build/components/providerAttest/popupRelay.js.map +1 -1
  43. package/build/components/providerAttest/teels/resolveTeelsProvider.d.ts +26 -0
  44. package/build/components/providerAttest/teels/resolveTeelsProvider.d.ts.map +1 -0
  45. package/build/components/providerAttest/teels/resolveTeelsProvider.js +71 -0
  46. package/build/components/providerAttest/teels/resolveTeelsProvider.js.map +1 -0
  47. package/build/components/providerAttest/teels/teelsProtocol.d.ts +41 -0
  48. package/build/components/providerAttest/teels/teelsProtocol.d.ts.map +1 -0
  49. package/build/components/providerAttest/teels/teelsProtocol.js +257 -0
  50. package/build/components/providerAttest/teels/teelsProtocol.js.map +1 -0
  51. package/build/components/providerAttest/teels/useTeelsProviderFlow.d.ts +11 -0
  52. package/build/components/providerAttest/teels/useTeelsProviderFlow.d.ts.map +1 -0
  53. package/build/components/providerAttest/teels/useTeelsProviderFlow.js +492 -0
  54. package/build/components/providerAttest/teels/useTeelsProviderFlow.js.map +1 -0
  55. package/build/components/providerAttest/types.d.ts +19 -2
  56. package/build/components/providerAttest/types.d.ts.map +1 -1
  57. package/build/components/providerAttest/types.js.map +1 -1
  58. package/build/components/providerAttest/urlUtils.d.ts +12 -0
  59. package/build/components/providerAttest/urlUtils.d.ts.map +1 -1
  60. package/build/components/providerAttest/urlUtils.js +23 -0
  61. package/build/components/providerAttest/urlUtils.js.map +1 -1
  62. package/build/components/providerAttest/useManagedPopupController.d.ts.map +1 -1
  63. package/build/components/providerAttest/useManagedPopupController.js +18 -2
  64. package/build/components/providerAttest/useManagedPopupController.js.map +1 -1
  65. package/build/components/providerAttest/useNativeReplayRunner.d.ts.map +1 -1
  66. package/build/components/providerAttest/useNativeReplayRunner.js +3 -37
  67. package/build/components/providerAttest/useNativeReplayRunner.js.map +1 -1
  68. package/build/components/providerAttest/useProviderAttestFlow.d.ts +10 -1
  69. package/build/components/providerAttest/useProviderAttestFlow.d.ts.map +1 -1
  70. package/build/components/providerAttest/useProviderAttestFlow.js +146 -1
  71. package/build/components/providerAttest/useProviderAttestFlow.js.map +1 -1
  72. package/build/components/providerAttest/useProviderFlowLifecycle.d.ts +6 -2
  73. package/build/components/providerAttest/useProviderFlowLifecycle.d.ts.map +1 -1
  74. package/build/components/providerAttest/useProviderFlowLifecycle.js +5 -1
  75. package/build/components/providerAttest/useProviderFlowLifecycle.js.map +1 -1
  76. package/build/components/providerAttest/useProviderInjectedScripts.d.ts +2 -1
  77. package/build/components/providerAttest/useProviderInjectedScripts.d.ts.map +1 -1
  78. package/build/components/providerAttest/useProviderInjectedScripts.js +3 -3
  79. package/build/components/providerAttest/useProviderInjectedScripts.js.map +1 -1
  80. package/build/components/providerAttest/useProviderMessageHandler.d.ts +10 -3
  81. package/build/components/providerAttest/useProviderMessageHandler.d.ts.map +1 -1
  82. package/build/components/providerAttest/useProviderMessageHandler.js +101 -2
  83. package/build/components/providerAttest/useProviderMessageHandler.js.map +1 -1
  84. package/build/components/providerAttest/useProviderNavigationHandlers.d.ts +4 -2
  85. package/build/components/providerAttest/useProviderNavigationHandlers.d.ts.map +1 -1
  86. package/build/components/providerAttest/useProviderNavigationHandlers.js +40 -8
  87. package/build/components/providerAttest/useProviderNavigationHandlers.js.map +1 -1
  88. package/build/components/providerAttest/useVerificationPresentation.d.ts +5 -0
  89. package/build/components/providerAttest/useVerificationPresentation.d.ts.map +1 -1
  90. package/build/components/providerAttest/useVerificationPresentation.js +63 -1
  91. package/build/components/providerAttest/useVerificationPresentation.js.map +1 -1
  92. package/build/components/providerAttest/verificationPresentation.d.ts +34 -1
  93. package/build/components/providerAttest/verificationPresentation.d.ts.map +1 -1
  94. package/build/components/providerAttest/verificationPresentation.js +42 -4
  95. package/build/components/providerAttest/verificationPresentation.js.map +1 -1
  96. package/build/index.d.ts +1 -1
  97. package/build/index.d.ts.map +1 -1
  98. package/build/index.js.map +1 -1
  99. package/build/providerRegistry/index.d.ts +1 -0
  100. package/build/providerRegistry/index.d.ts.map +1 -1
  101. package/build/providerRegistry/index.js +1 -0
  102. package/build/providerRegistry/index.js.map +1 -1
  103. package/build/providerRegistry/loginSubmitSignal.d.ts +27 -0
  104. package/build/providerRegistry/loginSubmitSignal.d.ts.map +1 -0
  105. package/build/providerRegistry/loginSubmitSignal.js +385 -0
  106. package/build/providerRegistry/loginSubmitSignal.js.map +1 -0
  107. package/build/providerRegistry/rules.js +15 -0
  108. package/build/providerRegistry/rules.js.map +1 -1
  109. package/build/providerRegistry/template.d.ts.map +1 -1
  110. package/build/providerRegistry/template.js +57 -2
  111. package/build/providerRegistry/template.js.map +1 -1
  112. package/build/satyaConfig.d.ts +7 -0
  113. package/build/satyaConfig.d.ts.map +1 -1
  114. package/build/satyaConfig.js +15 -1
  115. package/build/satyaConfig.js.map +1 -1
  116. package/build/sdkMetadata.generated.d.ts +1 -1
  117. package/build/sdkMetadata.generated.js +1 -1
  118. package/build/sdkMetadata.generated.js.map +1 -1
  119. package/build/types/error.types.d.ts +5 -1
  120. package/build/types/error.types.d.ts.map +1 -1
  121. package/build/types/error.types.js +13 -0
  122. package/build/types/error.types.js.map +1 -1
  123. package/build/types/provider.types.d.ts +72 -1
  124. package/build/types/provider.types.d.ts.map +1 -1
  125. package/build/types/provider.types.js.map +1 -1
  126. package/build/webview/index.d.ts +3 -3
  127. package/build/webview/index.d.ts.map +1 -1
  128. package/build/webview/index.js +4 -4
  129. package/build/webview/index.js.map +1 -1
  130. package/build/webview/scripts/requestInterceptorScript.d.ts +3 -1
  131. package/build/webview/scripts/requestInterceptorScript.d.ts.map +1 -1
  132. package/build/webview/scripts/requestInterceptorScript.js +346 -23
  133. package/build/webview/scripts/requestInterceptorScript.js.map +1 -1
  134. package/ios/Frameworks/libsatya_ffi-rs.xcframework/Info.plist +5 -5
  135. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/libsatya_ffi.a +0 -0
  136. package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64_x86_64-simulator/libsatya_ffi.a +0 -0
  137. package/ios/SatyaAttest.podspec +1 -1
  138. package/ios/SatyaAttestModule.swift +13 -0
  139. package/package.json +12 -2
  140. package/src/SatyaAttestModule.ts +1 -0
  141. package/src/SatyaAttestModule.web.ts +3 -0
  142. package/src/SatyaProviderAttestButton.tsx +64 -3
  143. package/src/components/providerAttest/ProviderAttestModal.tsx +77 -26
  144. package/src/components/providerAttest/backendVerifier.ts +52 -6
  145. package/src/components/providerAttest/copy.ts +41 -0
  146. package/src/components/providerAttest/flowSelection.ts +44 -0
  147. package/src/components/providerAttest/loginSubmitDetector.ts +91 -0
  148. package/src/components/providerAttest/popupRelay.ts +30 -0
  149. package/src/components/providerAttest/teels/resolveTeelsProvider.ts +135 -0
  150. package/src/components/providerAttest/teels/teelsProtocol.ts +294 -0
  151. package/src/components/providerAttest/teels/useTeelsProviderFlow.ts +651 -0
  152. package/src/components/providerAttest/types.ts +27 -1
  153. package/src/components/providerAttest/urlUtils.ts +22 -0
  154. package/src/components/providerAttest/useManagedPopupController.ts +18 -2
  155. package/src/components/providerAttest/useNativeReplayRunner.ts +16 -42
  156. package/src/components/providerAttest/useProviderAttestFlow.ts +171 -3
  157. package/src/components/providerAttest/useProviderFlowLifecycle.ts +9 -0
  158. package/src/components/providerAttest/useProviderInjectedScripts.ts +10 -4
  159. package/src/components/providerAttest/useProviderMessageHandler.ts +141 -4
  160. package/src/components/providerAttest/useProviderNavigationHandlers.ts +55 -7
  161. package/src/components/providerAttest/useVerificationPresentation.ts +73 -0
  162. package/src/components/providerAttest/verificationPresentation.ts +53 -5
  163. package/src/index.ts +2 -0
  164. package/src/providerRegistry/index.ts +12 -0
  165. package/src/providerRegistry/loginSubmitSignal.ts +532 -0
  166. package/src/providerRegistry/rules.ts +13 -0
  167. package/src/providerRegistry/template.ts +59 -1
  168. package/src/satyaConfig.ts +29 -1
  169. package/src/sdkMetadata.generated.ts +1 -1
  170. package/src/types/error.types.ts +14 -0
  171. package/src/types/provider.types.ts +56 -1
  172. package/src/webview/index.ts +10 -4
  173. package/src/webview/scripts/requestInterceptorScript.ts +359 -23
package/CHANGELOG.md CHANGED
@@ -1,6 +1,128 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
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.
111
+
112
+ ## 3.2.0 - 2026-08-07
113
+
114
+ ### Added
115
+
116
+ - An opt-in, SDK-only TeeLS hosted passthrough selected with
117
+ `initSatyaAttest({ providerId, appId, teelsFlow: true })`. The flow preserves
118
+ normal provider grants, performs one existing provider-policy access preflight,
119
+ opens the registry login URL in an origin-bound WebView bridge, and returns the
120
+ opaque JSON result through `onTeelsComplete` without native replay, SATYA
121
+ artifact construction, local verification, or verifier artifact submission.
122
+ - TeeLS-specific progress phases and errors for null/invalid results, hosted
123
+ failures, timeout, and WebView failure. The feature is disabled by default;
124
+ omitting `teelsFlow` in a later init restores native routing for subsequently
125
+ mounted buttons.
4
126
 
5
127
  ## 3.1.0 - 2026-07-31
6
128
 
@@ -140,7 +262,7 @@ default-deny provider allowlist.
140
262
  id was swallowed by the policy-refresh `try` and resurfaced after the user
141
263
  had already completed login, mislabeled as a native-module failure.
142
264
  - **Empty overrides no longer erase configuration.** `initSatyaAttest({ appId:
143
- '' })` (a common `props.appId ?? ''` pattern) wiped a valid env-derived app
265
+ '' })` (a common `props.appId ?? ''` pattern) wiped a valid env-derived app
144
266
  id, and an empty `providerRegistryApi` silently repointed a staging build at
145
267
  production.
146
268
 
@@ -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` | Provider-auth metadata. Preserved but not interpreted by the managed flow. |
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,9 +679,82 @@ 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
 
692
+ ### Hosted TeeLS passthrough provider injection
693
+
694
+ An SDK session initialized with `teelsFlow: true` may use a normal granted
695
+ provider as a hosted TeeLS passthrough. There is no Registry flow discriminator:
696
+ the SDK binds TeeLS mode to the configured provider/app pair, performs the
697
+ normal provider-policy access preflight, opens `login.url`, and skips request
698
+ capture and native replay.
699
+
700
+ Keep the provider structurally valid for the normal Registry. Its existing
701
+ endpoint, SNI, pins, grants, and verifier policy remain ordinary provider
702
+ policy even though the TeeLS attempt does not fire or replay that endpoint.
703
+ The hosted page origin may therefore differ from the inert endpoint/SNI host;
704
+ the TeeLS WebView origin is always derived from `login.url`, while the access
705
+ preflight continues to validate the governed provider policy.
706
+
707
+ Generate the canonical adapter injection from the Expo SDK checkout:
708
+
709
+ ```bash
710
+ cd platform_sdks/expo-satya-attest
711
+ node scripts/generate-hosted-teels-provider-injection.js \
712
+ --origin https://hosted-teels.example \
713
+ --json
714
+ ```
715
+
716
+ Put the resulting JSON string in the provider's top-level `injection`. The
717
+ adapter is additive. It reuses, in order:
718
+
719
+ 1. standard `TeeLS.create({ onSuccess, onError })` callbacks by intercepting the
720
+ initial `window.TeeLS` assignment before the hosted bundle runs;
721
+ 2. the `teels:attestation` `CustomEvent`, reading
722
+ `event.detail.attestation` and optional `event.detail.data`; and
723
+ 3. the durable `window.__teels.attestation` snapshot for success recovery when
724
+ the adapter attaches after completion.
725
+
726
+ The adapter calls the page's original callbacks first and forwards to SATYA in
727
+ `finally`, preserving callback arguments, `this`, return values, thrown errors,
728
+ the returned TeeLS handle, and every other TeeLS SDK export. The second argument
729
+ to SATYA is always the attestation; if present, the first `onSuccess` argument is
730
+ forwarded as `claimData` and added to the completion payload as `claimData`.
731
+ Null success maps to `attestation_missing`; all other TeeLS errors map to
732
+ `teels_flow_failed`.
733
+ The SDK bridge and adapter both enforce exactly-once terminal settlement.
734
+
735
+ The terminal API is distinct from native login readiness and supports the optional
736
+ `claimData` passthrough:
737
+
738
+ ```js
739
+ window.__SATYA_TEELS_BRIDGE__.complete(attestation, claimData);
740
+ window.__SATYA_TEELS_BRIDGE__.fail('attestation_missing');
741
+ window.__SATYA_TEELS_BRIDGE__.fail('teels_flow_failed');
742
+ ```
743
+
744
+ Do not emit or overload `__satyaReady` for TeeLS completion. Do not post the
745
+ opaque result through the native-replay interceptor. The adapter must remain
746
+ main-frame and exact-origin scoped and must tolerate being evaluated only once;
747
+ SATYA installs the bridge before executing the Registry injection.
748
+
749
+ Success can be recovered from the durable snapshot after a late injection, but
750
+ a past error cannot. Before using a hosted provider beyond development, prove
751
+ on physical iOS and Android—both with the external TeeLS bundle cached and
752
+ uncached—that `injectedJavaScriptBeforeContentLoaded` wraps `TeeLS.create`
753
+ before the page calls it. If that ordering cannot be established, add a minimal
754
+ page-owned error seam instead of relying on best-effort console interception.
755
+ Also confirm the hosted TeeLS SDK invokes its configured `onError` for every
756
+ terminal failure; a rendered SDK error alone cannot be observed by the adapter.
757
+
567
758
  ---
568
759
 
569
760
  ## 10. Writing regex patterns (HTML / text bodies)
@@ -624,6 +815,14 @@ console.log(body.match(/octolytics-actor-login" content="(.*?)"/)?.[1]);
624
815
  is an SDK/verifier session option (§8.1),
625
816
  - `injection` is a non-empty string / non-empty string array when present; `login.injection`
626
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),
627
826
  - raw `allowedRequestHeaders`, `allowedResponseBodyJsonPaths`, and `privacyPolicy` are
628
827
  rejected (the loader derives them from `revealRules`),
629
828
  - SPKI pins are SHA-256 base64,
package/README.md CHANGED
@@ -26,6 +26,9 @@ with `CONFIG_INVALID`. An unregistered or unapproved id fails at the verifier
26
26
  with `APP_NOT_REGISTERED` / `APP_DISABLED`, and an ungranted provider fails with
27
27
  `PROVIDER_ACCESS_DENIED`. See
28
28
  [`docs/MULTI_TENANT_VERIFICATION.md`](../../docs/MULTI_TENANT_VERIFICATION.md).
29
+ Flows also fail with `app_platform_not_configured` when the app has no
30
+ registered identity for the current platform, so register every platform you
31
+ develop and test on.
29
32
 
30
33
  ## Current Flow
31
34
 
@@ -51,6 +54,113 @@ The earlier mock and plain `webview-observed` modes are no longer exposed throug
51
54
  high-level Expo client because they do not prove a provider response fetched through a
52
55
  pinned native TLS connection.
53
56
 
57
+ ## TeeLS Hosted Passthrough (Opt-In)
58
+
59
+ The SDK also has an isolated, opt-in TeeLS hosted flow. It uses a normal
60
+ registry provider and the normal app/provider grant, but it does **not** run
61
+ request capture, native replay, SATYA artifact construction, local SATYA
62
+ verification, or verifier artifact submission. SATYA performs one provider-policy
63
+ request before opening the WebView solely to confirm that the configured app is
64
+ active and has access to the provider.
65
+
66
+ Enable the flow for exactly one provider/app pair at initialization:
67
+
68
+ ```tsx
69
+ import {
70
+ initSatyaAttest,
71
+ SatyaProviderAttestButton,
72
+ type SatyaTeelsAttestation,
73
+ type SatyaTeelsClaimData,
74
+ } from '@burnt-labs/expo-satya-attest';
75
+
76
+ initSatyaAttest({
77
+ providerId: 'satya.teels.v1',
78
+ appId: 'app_your-registered-app-id',
79
+ teelsFlow: true,
80
+ });
81
+
82
+ function TeelsAttestButton() {
83
+ const verifyTeelsResult = async (
84
+ attestation: SatyaTeelsAttestation,
85
+ claimData?: SatyaTeelsClaimData
86
+ ) => {
87
+ // Required: verify the TeeLS quote, freshness, and expected data binding
88
+ // in your application or backend before trusting the result.
89
+ // `claimData` is the first argument to TeeLS success, usually the
90
+ // JSON-safe payload forwarded by the hosted provider.
91
+ };
92
+
93
+ return (
94
+ <SatyaProviderAttestButton
95
+ providerId="satya.teels.v1"
96
+ transportConfig={{
97
+ verifierUrl: 'https://satya-verifier-v2-staging.burnt.com',
98
+ appId: 'app_your-registered-app-id',
99
+ }}
100
+ onTeelsComplete={verifyTeelsResult}
101
+ onError={(error) => console.error(error.code, error.message)}
102
+ />
103
+ );
104
+ }
105
+ ```
106
+
107
+ The provider's existing `login.url` opens in the SDK WebView and its normal
108
+ Registry `injection` adapts the hosted page to the SDK-owned bridge. A page that
109
+ already uses the standard TeeLS callbacks and EarnOS success event/snapshot
110
+ does not need frontend changes. See
111
+ [Provider Config](./PROVIDER_CONFIG.md#hosted-teels-passthrough-provider-injection)
112
+ for the adapter and device-validation contract.
113
+
114
+ Only a non-null, JSON-safe attestation object can complete the flow. If provided,
115
+ `claimData` is additionally forwarded as a second argument to `onTeelsComplete`.
116
+ Success is returned only through `onTeelsComplete`; invalid/null data, hosted
117
+ failures, timeout, WebView failure, and access denial use the normal `onError`
118
+ path. Closing the sheet before a terminal result uses `onCancel`.
119
+
120
+ Native-replay-only props are not used by TeeLS. A component may keep an
121
+ `onComplete` handler for normal mode, but TeeLS never calls it. Initialize the
122
+ SDK before mounting the button. A later init with `teelsFlow: false` or with
123
+ the option omitted disables TeeLS for subsequently mounted buttons; normal
124
+ providers continue to use the existing native replay flow unchanged.
125
+
126
+ The returned object is an opaque, unverified TeeLS result and is delivered as
127
+ the first argument. `claimData` is the hosted-provider payload whose inner
128
+ `data` object is hashed into the quote's `report_data`; treat both as
129
+ untrusted input until verified. Do not treat callback delivery as a SATYA
130
+ verification claim, and do not log or persist the result by default.
131
+
132
+ ### Verifying the TeeLS result
133
+
134
+ The SATYA SDK performs no verification of the TeeLS result — it neither
135
+ verifies the quote nor checks that the claim data matches it. Before trusting
136
+ the result, the consuming application or its backend must verify it:
137
+
138
+ 1. **DCAP quote.** `attestation.quote` is a hex-encoded Intel TDX quote. Post
139
+ it to the independent TeeLS verifier service and require `success: true`,
140
+ `quote.verified: true`, and a `tcb_status` your policy accepts:
141
+
142
+ ```bash
143
+ curl -X POST https://attest.burnt.com/verify \
144
+ -H 'content-type: application/json' \
145
+ -d '{"hex":"<quote hex>"}'
146
+ ```
147
+
148
+ 2. **Measurements.** Compare the verified quote's `mrtd` and `rtmr0`–`rtmr3`
149
+ against the expected-measurements registry published independently by the
150
+ verifier (`GET https://attest.burnt.com/measurements`); require a match
151
+ against one of its `valid[]` sets.
152
+ 3. **Data binding.** Use `reportdata` from the **verified quote response**
153
+ (never the advisory `attestation.reportDataHex` field — it is
154
+ server-supplied). Its first 32 bytes must equal
155
+ `SHA-256(JSON.stringify(data))` over the exact result-data object the page
156
+ delivered (in this flow, `claimData.data`; remaining bytes are
157
+ zero-padded). When the provider binds a policy hash, the envelope is
158
+ `{ data, policyHash }` instead of bare `data`. Any mismatch means the claim
159
+ data was substituted after attestation.
160
+
161
+ The result carries no nonce, so enforce your own freshness and replay policy
162
+ wherever the attestation crosses a trust boundary.
163
+
54
164
  ## Native Trust Tiers
55
165
 
56
166
  | Platform | Witness key | Platform evidence | Typical tier |
@@ -80,7 +190,7 @@ New SDK artifacts also include envelope metadata:
80
190
  "attestationIdVersion": "statement-sha256-96-v1",
81
191
  "producer": {
82
192
  "sdk": "@burnt-labs/expo-satya-attest",
83
- "sdkVersion": "3.1.0",
193
+ "sdkVersion": "3.3.0",
84
194
  "artifactSchemaVersion": "1.1.0",
85
195
  "coreVersion": "0.1.0"
86
196
  }
@@ -227,7 +337,7 @@ is a release tarball produced by `npm pack`, because it contains the same files
227
337
  would publish:
228
338
 
229
339
  ```bash
230
- npm install https://github.com/<owner>/<repo>/releases/download/expo-satya-attest-v3.1.0/burnt-labs-expo-satya-attest-3.1.0.tgz
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
231
341
  npx expo install react-native-webview react-native-safe-area-context
232
342
  ```
233
343
 
@@ -235,8 +345,8 @@ Installing from a Git ref also works when that ref has the SDK package at the re
235
345
  root, such as a dedicated SDK repo or a subtree/split branch:
236
346
 
237
347
  ```bash
238
- npm install github:<owner>/<sdk-repo>#v3.1.0
239
- npm install git+https://github.com/<owner>/<sdk-repo>.git#v3.1.0
348
+ npm install github:<owner>/<sdk-repo>#v3.3.0
349
+ npm install git+https://github.com/<owner>/<sdk-repo>.git#v3.3.0
240
350
  npx expo install react-native-webview react-native-safe-area-context
241
351
  ```
242
352
 
@@ -313,15 +423,34 @@ pill (lock icon + domain), a reload button, and a page-load line that advances w
313
423
  loads and clears when it finishes; both the main page and the managed OAuth popup fade in
314
424
  over their first load instead of flashing white.
315
425
 
316
- Once the provider's injection confirms the session is authenticated (the `__satyaReady`
317
- login signal), the sheet conceals the provider page behind a "Verifying your account…"
318
- cover while capture and native replay continue underneath, so users see only the login
319
- window and never the SDK driving the authenticated site. The cover is presentation-only
320
- (capture gating and verification are unchanged); if capture does not start within a
321
- short watchdog window it offers a "Return to provider" path that keeps the flow alive.
322
- Providers whose injection does not emit `__satyaReady` keep the previous behavior and
323
- are covered from request capture onward. See `PROVIDER_CONFIG.md` for the signal
324
- contract.
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.
325
454
 
326
455
  Pass `presentation="fullScreen"` to keep the legacy full-window takeover. Set `prefetch`
327
456
  to resolve the provider policy and warm the WebView engine at mount so the sheet opens
@@ -4,13 +4,13 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'expo.modules.satyaattest'
7
- version = '3.1.0'
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.1.0"
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 = "{}" }
@@ -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;IAE1B,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
+ {"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;AAkCzD,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\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"]}
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"]}