@burnt-labs/expo-satya-attest 3.9.0 → 3.10.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 +25 -4
- package/PUBLISHING.md +17 -12
- package/README.md +8 -3
- package/TEELS_OBSERVABILITY.md +128 -0
- package/android/build.gradle +2 -2
- package/build/components/providerAttest/copy.d.ts.map +1 -1
- package/build/components/providerAttest/copy.js +5 -0
- package/build/components/providerAttest/copy.js.map +1 -1
- package/build/components/providerAttest/teels/teelsFailure.d.ts +2 -0
- package/build/components/providerAttest/teels/teelsFailure.d.ts.map +1 -1
- package/build/components/providerAttest/teels/teelsFailure.js +31 -5
- package/build/components/providerAttest/teels/teelsFailure.js.map +1 -1
- package/build/components/providerAttest/teels/teelsProtocol.d.ts +5 -0
- package/build/components/providerAttest/teels/teelsProtocol.d.ts.map +1 -1
- package/build/components/providerAttest/teels/teelsProtocol.js +42 -14
- package/build/components/providerAttest/teels/teelsProtocol.js.map +1 -1
- package/build/components/providerAttest/teels/useTeelsProviderFlow.d.ts.map +1 -1
- package/build/components/providerAttest/teels/useTeelsProviderFlow.js +63 -21
- package/build/components/providerAttest/teels/useTeelsProviderFlow.js.map +1 -1
- package/build/components/providerAttest/useFunnelEmitter.d.ts +1 -1
- package/build/components/providerAttest/useFunnelEmitter.d.ts.map +1 -1
- package/build/components/providerAttest/useFunnelEmitter.js +40 -5
- package/build/components/providerAttest/useFunnelEmitter.js.map +1 -1
- package/build/sdkEventLog.d.ts +12 -0
- package/build/sdkEventLog.d.ts.map +1 -1
- package/build/sdkEventLog.js +42 -4
- package/build/sdkEventLog.js.map +1 -1
- package/build/sdkMetadata.generated.d.ts +1 -1
- package/build/sdkMetadata.generated.d.ts.map +1 -1
- package/build/sdkMetadata.generated.js +1 -1
- package/build/sdkMetadata.generated.js.map +1 -1
- package/build/sdkTelemetry.d.ts +6 -0
- package/build/sdkTelemetry.d.ts.map +1 -0
- package/build/sdkTelemetry.js +32 -0
- package/build/sdkTelemetry.js.map +1 -0
- package/build/tee/client.d.ts +1 -1
- package/build/tee/client.d.ts.map +1 -1
- package/build/teelsStageHistory.d.ts +8 -0
- package/build/teelsStageHistory.d.ts.map +1 -0
- package/build/teelsStageHistory.js +30 -0
- package/build/teelsStageHistory.js.map +1 -0
- package/build/teelsTelemetry.d.ts +98 -0
- package/build/teelsTelemetry.d.ts.map +1 -0
- package/build/teelsTelemetry.js +147 -0
- package/build/teelsTelemetry.js.map +1 -0
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/libsatya_ffi.a +1 -1
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64_x86_64-simulator/libsatya_ffi.a +1 -1
- package/ios/SatyaAttest.podspec +1 -1
- package/package.json +3 -2
- package/src/components/providerAttest/copy.ts +4 -0
- package/src/components/providerAttest/teels/teelsFailure.ts +36 -5
- package/src/components/providerAttest/teels/teelsProtocol.ts +59 -14
- package/src/components/providerAttest/teels/useTeelsProviderFlow.ts +74 -24
- package/src/components/providerAttest/useFunnelEmitter.ts +45 -5
- package/src/sdkEventLog.ts +54 -4
- package/src/sdkMetadata.generated.ts +1 -1
- package/src/sdkTelemetry.ts +35 -0
- package/src/teelsStageHistory.ts +39 -0
- package/src/teelsTelemetry.ts +158 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 3.
|
|
3
|
+
## 3.10.0 - 2026-09-22
|
|
4
|
+
|
|
5
|
+
- Keep monitoring ingestion unchanged: SDK-owned versioned `logData` metadata lets Devtool classify warnings and completion without new event types, service deployments, or database migrations.
|
|
6
|
+
|
|
7
|
+
Release candidate; npm publication is required after review and release validation.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
11
|
+
- TeeLS stage history in existing event logData, safe structured error causes and recovery guidance through
|
|
12
|
+
the hosted adapter, SDK callbacks and event ingestion. Wrong credentials,
|
|
13
|
+
declined challenges and cancellations are unsuccessful warning outcomes.
|
|
14
|
+
- Existing `ATTESTATION_GENERATED` records hosted artifact receipt with
|
|
15
|
+
`flowOutcome: completed`, separately from independent `ATTESTATION_VERIFIED`.
|
|
16
|
+
The seven event types remain unchanged. Shared telemetry identifies flow type, schema
|
|
17
|
+
version, event sequence and elapsed attempt time. See
|
|
18
|
+
[TeeLS observability](./TEELS_OBSERVABILITY.md) for rollout sequencing and
|
|
19
|
+
required hosted Provider Registry injection updates.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Hosted TeeLS consent dismissal ("Not now") records a cancellation warning
|
|
24
|
+
immediately instead of timing out. Modal teardown from success/error callbacks
|
|
25
|
+
preserves the original result without duplicate terminal events.
|
|
26
|
+
|
|
27
|
+
## 3.9.0 - 2026-09-17
|
|
7
28
|
|
|
8
29
|
### Added
|
|
9
30
|
|
|
@@ -54,7 +75,7 @@ matrix are still pending.
|
|
|
54
75
|
cleared. Keep `isolation: 'provider'` when turning automatic reset off.
|
|
55
76
|
- Reset removes cookies, including persistent/HttpOnly cookies, but leaves local
|
|
56
77
|
storage and caches intact. External-browser and remote hosted TeeLS sessions
|
|
57
|
-
are outside its scope. See [release gates](./PUBLISHING.md#
|
|
78
|
+
are outside its scope. See [release gates](./PUBLISHING.md#release-preparation).
|
|
58
79
|
|
|
59
80
|
## 3.8.0 - 2026-09-14
|
|
60
81
|
|
package/PUBLISHING.md
CHANGED
|
@@ -10,12 +10,17 @@ very large native artifacts. The npm tarball still needs the native artifacts un
|
|
|
10
10
|
package is redesigned to download or build them during install, which is not recommended
|
|
11
11
|
for a plug-and-play Expo SDK.
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
The next prepared minor release is **3.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
## Release preparation
|
|
14
|
+
|
|
15
|
+
The next prepared minor release is **3.10.0**. Version 3.9.0 is already published.
|
|
16
|
+
This release adds TeeLS error context, warning outcomes and stage history in
|
|
17
|
+
`logData`; the original seven event types are unchanged. It requires an npm
|
|
18
|
+
publish after review and validation. Follow the [TeeLS rollout guide](./TEELS_OBSERVABILITY.md)
|
|
19
|
+
for Devtool deployment, hosted adapter updates and the persisted-event device canary.
|
|
20
|
+
No provider-monitor deployment or database migration is required; existing automated
|
|
21
|
+
alerts retain their current counting behavior.
|
|
22
|
+
A version bump or passing package checks does not establish native device readiness:
|
|
23
|
+
complete the gates below before tagging a stable release.
|
|
19
24
|
|
|
20
25
|
1. Keep `package.json`, both root version fields in `package-lock.json`,
|
|
21
26
|
`ios/SatyaAttest.podspec`, Android `version` / `versionName`, generated SDK
|
|
@@ -48,7 +53,7 @@ Local cookie cleanup does not reset remote hosted TeeLS sessions.
|
|
|
48
53
|
The package check requires both native session managers, the WebView snapshot
|
|
49
54
|
helper, adapter script, Android keep rules and public JS/declarations. Host tests
|
|
50
55
|
use synthetic stores and adapter fixtures; they are not substitutes for device
|
|
51
|
-
cookie isolation tests. Until the app builds and device matrix pass, treat 3.
|
|
56
|
+
cookie isolation tests. Until the app builds and device matrix pass, treat 3.10.0
|
|
52
57
|
as release preparation, not a validated stable release.
|
|
53
58
|
|
|
54
59
|
## TEE release requirements
|
|
@@ -256,7 +261,7 @@ internal/module_scripts/
|
|
|
256
261
|
After the release gates pass and publication is authorized, use the consolidated
|
|
257
262
|
`publish-expo-satya-attest.yml` workflow. A stable tag must match the committed
|
|
258
263
|
package version and point to a commit on `main`; for this prepared release the
|
|
259
|
-
package-specific tag is `expo-satya-attest-v3.
|
|
264
|
+
package-specific tag is `expo-satya-attest-v3.10.0`. Creating/pushing that tag starts
|
|
260
265
|
publication. Manual workflow dispatch is a dry-run.
|
|
261
266
|
|
|
262
267
|
The workflow builds native artifacts, runs the release checks, and publishes
|
|
@@ -274,13 +279,13 @@ Every push to `main` publishes a snapshot package to the public npm registry wit
|
|
|
274
279
|
unique prerelease version:
|
|
275
280
|
|
|
276
281
|
```text
|
|
277
|
-
3.
|
|
282
|
+
3.10.1-snapshot.<run>.<attempt>.sha-<commit>
|
|
278
283
|
```
|
|
279
284
|
|
|
280
285
|
The snapshot job (in `publish-expo-satya-attest.yml`) increments the package's patch base
|
|
281
|
-
in CI before publishing. For example, if `package.json` is `3.
|
|
282
|
-
is based on `3.
|
|
283
|
-
`3.
|
|
286
|
+
in CI before publishing. For example, if `package.json` is `3.10.0`, the snapshot version
|
|
287
|
+
is based on `3.10.1`:
|
|
288
|
+
`3.10.1-snapshot.<run>.<attempt>.sha-<commit>`. Snapshots are development builds and
|
|
284
289
|
do not imply completion of the physical-device gates.
|
|
285
290
|
|
|
286
291
|
Snapshots use the `snapshot` dist-tag so test apps do not need to know the generated
|
package/README.md
CHANGED
|
@@ -5,9 +5,11 @@ the Rust `satya-sdk` / `satya-ffi` pipeline for artifact construction and verifi
|
|
|
5
5
|
policy, while Swift and Kotlin provide platform-specific WebView capture, native HTTPS
|
|
6
6
|
replay, hardware-backed signing, and platform attestation evidence.
|
|
7
7
|
|
|
8
|
-
**3.
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
**3.10.0 release candidate:** this source adds TeeLS error context, warning outcomes
|
|
9
|
+
and stage history within the existing seven logging event types. An npm publish
|
|
10
|
+
is required after review and release validation. See the [changelog](./CHANGELOG.md),
|
|
11
|
+
[release requirements](./PUBLISHING.md#release-preparation), and
|
|
12
|
+
[TeeLS rollout guide](./TEELS_OBSERVABILITY.md).
|
|
11
13
|
|
|
12
14
|
The SDK supports native app attestation, opt-in [TEE replay](./TEE_REPLAY.md),
|
|
13
15
|
single-endpoint and composite proofs, provider-selective partial completion,
|
|
@@ -336,6 +338,9 @@ does not need frontend changes. See
|
|
|
336
338
|
[Provider Config](./PROVIDER_CONFIG.md#hosted-teels-passthrough-provider-injection)
|
|
337
339
|
for the adapter and device-validation contract.
|
|
338
340
|
|
|
341
|
+
For stage events, warning outcomes, safe error details and deployment order, see
|
|
342
|
+
[TeeLS observability](./TEELS_OBSERVABILITY.md).
|
|
343
|
+
|
|
339
344
|
Only a non-null, JSON-safe attestation object can complete the flow. If provided,
|
|
340
345
|
`claimData` is additionally forwarded as a second argument to `onTeelsComplete`.
|
|
341
346
|
Success is returned only through `onTeelsComplete`; invalid/null data, hosted
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# TeeLS flow observability
|
|
2
|
+
|
|
3
|
+
TeeLS uses the shared SATYA event logger and session trace. `FAILED` remains an
|
|
4
|
+
unsuccessful terminal. Confirmed wrong credentials, invalid/expired OTP, declined
|
|
5
|
+
approval, cancellation and replaced attempts carry `failureClass: user_action`
|
|
6
|
+
and `logLevel: warn`. Technical errors use `error`; unknown causes stay separately
|
|
7
|
+
classified and count as unsuccessful in reliability metrics. HTTP 400/401/403
|
|
8
|
+
alone never establishes incorrect credentials.
|
|
9
|
+
|
|
10
|
+
## Events and safe context
|
|
11
|
+
|
|
12
|
+
Every managed attempt emits `telemetrySchemaVersion: 1`, `flowType` (`teels`,
|
|
13
|
+
`native_replay` or `tee_replay`), `attemptIndex`, monotonic `eventSequence`,
|
|
14
|
+
`eventId`, and `totalElapsedMs`. The SDK session remains stable over user retries;
|
|
15
|
+
the WebView bridge attempt ID changes. TeeLS's optional UUID is `teelsSessionId`,
|
|
16
|
+
separate from the SDK session. An internal TeeLS auth retry is not a new SDK
|
|
17
|
+
attempt and may repeat stages.
|
|
18
|
+
|
|
19
|
+
The event enum remains fixed at its existing seven values. TeeLS uses
|
|
20
|
+
`PROVIDER_INIT`, observed `LOGIN_COMPLETED`, `ATTESTATION_GENERATED`, and `FAILED`.
|
|
21
|
+
Stage observations enrich `logData` rather than creating new event types.
|
|
22
|
+
`teelsStage` is one of `initializing`, `navigating`, `entering_credentials`,
|
|
23
|
+
`submitting`, `awaiting_challenge`, `challenge_submitted`, `logged_in`, `extracting`,
|
|
24
|
+
or `attesting`. `LOGIN_COMPLETED` is emitted once when `logged_in` is observed.
|
|
25
|
+
Duplicate consecutive stages are suppressed and at most 64 transitions are
|
|
26
|
+
accepted per attempt. `teelsStageCount` counts accepted transitions;
|
|
27
|
+
`teelsStageHistory` contains the most recent 12 as `stage:elapsedMs` pairs separated
|
|
28
|
+
by commas, with elapsed times bounded to 24 hours. Only closed stage names and
|
|
29
|
+
numbers are retained. Login, completion, failure, cancellation and supersession
|
|
30
|
+
carry this history. A fresh SDK attempt resets it; internal retries retain it.
|
|
31
|
+
Intermediate history is buffered until one of those events, so an app killed
|
|
32
|
+
beforehand cannot upload it. Stage snapshots in Devtool count milestone/failure
|
|
33
|
+
events, not unique stage reach or native replay/capture measurements.
|
|
34
|
+
|
|
35
|
+
Successful hosted receipt emits one terminal `ATTESTATION_GENERATED` with
|
|
36
|
+
`logData.flowType: "teels"`, `completionMode: "hosted"`, and
|
|
37
|
+
`flowOutcome: "completed"`. It does **not** emit `ATTESTATION_VERIFIED` or assert
|
|
38
|
+
`verifierDecision: ok`. Native generation remains nonterminal. Failed attempts
|
|
39
|
+
carry `flowOutcome: "failed"`. The public `onTeelsComplete(attestation, claimData?)`
|
|
40
|
+
callback is unchanged. Independent verification/relying-party acceptance must be
|
|
41
|
+
reported by the component performing that work; receipt is not proof of acceptance.
|
|
42
|
+
|
|
43
|
+
Failures retain the SATYA public code (for example `SATYA_TEELS_FLOW_FAILED`).
|
|
44
|
+
Safe structured context adds `teelsErrorCode`, `teelsStage`, `teelsSessionId`,
|
|
45
|
+
`httpStatus`, `failureClass`, canonical `errorMessage` and `recoveryAction`.
|
|
46
|
+
The same detail is available in the host error's context. Only catalog codes,
|
|
47
|
+
known stages, valid statuses and UUIDs cross the structured bridge boundary.
|
|
48
|
+
Arbitrary provider text stays out of event ingestion; raw auth bodies,
|
|
49
|
+
credentials, OTP values and challenge destinations are never telemetry fields.
|
|
50
|
+
Legacy `login.auth failed: HTTP NNN (fields flagged: ...)` errors preserve only
|
|
51
|
+
the status in telemetry, not the field names and not a guessed credential cause.
|
|
52
|
+
|
|
53
|
+
## Existing ingestion contract
|
|
54
|
+
|
|
55
|
+
The logger writes an SDK-owned `sdkTelemetry` first property in `logData` after
|
|
56
|
+
sanitization. Its value is `v1|flow|stage|outcome|code`, with ASCII fields padded
|
|
57
|
+
with spaces to widths 13, 20, 9 and 32. Only closed enums enter the header; callers
|
|
58
|
+
cannot supply it. The code is the canonical TeeLS cause, `OTHER_TECHNICAL` for
|
|
59
|
+
other named SDK failures, or empty when unavailable. Failure classification is
|
|
60
|
+
derived from that code. Outcome is checked against the existing event: native
|
|
61
|
+
`ATTESTATION_GENERATED` remains progress, and only explicit completed TeeLS receipt
|
|
62
|
+
is a hosted terminal. The header is preserved first during size fallbacks, unless
|
|
63
|
+
an application's custom logData budget is too small to hold it.
|
|
64
|
+
|
|
65
|
+
Devtool reads this field from the existing blob 10 and validates the same version,
|
|
66
|
+
widths, enums and event consistency in aggregate queries and event details.
|
|
67
|
+
Malformed, scrubbed and legacy records stay unknown for flow/failure aggregates;
|
|
68
|
+
old JSON can still supply error details. The bounded header retains a canonical
|
|
69
|
+
reason even when later JSON is truncated. It is client analytics metadata, not
|
|
70
|
+
security evidence. No additional event or ingestion dimension is required.
|
|
71
|
+
|
|
72
|
+
## Hosted adapter compatibility
|
|
73
|
+
|
|
74
|
+
Regenerate each hosted provider's injection using:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
node scripts/generate-hosted-teels-provider-injection.js \
|
|
78
|
+
--origin https://YOUR-HOSTED-PAGE --json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Publish the generated injection through the normal Provider Registry version and
|
|
82
|
+
policy-hash workflow. Existing registry records do not change when this SDK is
|
|
83
|
+
released. Update all enabled TeeLS providers, including `ronde.teels.v1`,
|
|
84
|
+
`perfect.fitness.teels.v1` and `satya.teels.v1`, using each record's actual origins.
|
|
85
|
+
|
|
86
|
+
The adapter preserves one-argument `onSuccess(attestation)` and legacy
|
|
87
|
+
`onSuccess(data, attestation)`, success event/snapshot paths, and `onError(string)`.
|
|
88
|
+
New `onError(string, detail)` forwards the optional detail as the third argument
|
|
89
|
+
to `bridge.fail`; old mobile bridges ignore it. `onStatus(progress)` is forwarded
|
|
90
|
+
only when `bridge.progress` exists. Protocol version remains 1. Progress never
|
|
91
|
+
sets the terminal latch. Origin/provider/attempt checks apply before accepting
|
|
92
|
+
messages; oversize direct posts are ignored, while the SDK-owned bridge converts
|
|
93
|
+
its own oversize terminal payload into a small correlated error.
|
|
94
|
+
|
|
95
|
+
`onClose` before a terminal result forwards `USER_CANCELLED`, including the
|
|
96
|
+
hosted consent screen's **Not now** action even with `dismissible: false`.
|
|
97
|
+
Teardown during a success/error callback preserves that callback's result;
|
|
98
|
+
later closes cannot emit another terminal event. Original host callbacks retain
|
|
99
|
+
their receiver, arguments, return values and exceptions. Regenerate the hosted
|
|
100
|
+
injection to enable this behavior; publishing the mobile SDK alone is insufficient.
|
|
101
|
+
|
|
102
|
+
## Reporting and rollout
|
|
103
|
+
|
|
104
|
+
These SDK changes ship in **3.10.0** and require publishing
|
|
105
|
+
`@burnt-labs/expo-satya-attest@3.10.0` to npm, then adoption by consuming apps.
|
|
106
|
+
Merging this PR alone does not make the stable package available.
|
|
107
|
+
|
|
108
|
+
Deploy the Devtool reader update, then adopt the SATYA SDK update and publish
|
|
109
|
+
compatible hosted injections alongside TeeLS server/web callbacks. Existing
|
|
110
|
+
monitoring ingestion already preserves these seven event types, warning severity
|
|
111
|
+
and safe logData; this release requires no monitoring-service change or database
|
|
112
|
+
migration. Existing automated alerts keep their current failure-counting behavior. This change adds no native API, but does not waive
|
|
113
|
+
the release/device validation required by the SDK's other pending changes.
|
|
114
|
+
|
|
115
|
+
Devtool displays wrong credentials/cancellation as **Failed · warning** in yellow.
|
|
116
|
+
Completion includes all unsuccessful attempts. Technical reliability excludes
|
|
117
|
+
only confirmed user-action warnings; unknown failures remain in its denominator.
|
|
118
|
+
Both use sample-weighted terminal event counts, not exact unique-attempt conversion.
|
|
119
|
+
Source monitor snapshots and EarnOS worker analytics have independent windows and
|
|
120
|
+
denominators. Existing EarnOS session events do not automatically gain SDK fields.
|
|
121
|
+
|
|
122
|
+
Canary a controlled wrong-password attempt, cancellation, a technical error and
|
|
123
|
+
retry→success on supported iOS/Android runtimes. Verify persisted AE rows and the
|
|
124
|
+
Devtool trace (code, stage, safe reason, color, one terminal), not merely HTTP 202.
|
|
125
|
+
The ingestion endpoint can also accept but decline an unregistered provider.
|
|
126
|
+
Check older SDKs with the new adapter and newer SDKs with cached older pages.
|
|
127
|
+
Rollback emitters/hosted injection versions if needed; leave the compatible
|
|
128
|
+
Devtool reader in place. Old unknown records must not be relabeled as bad credentials.
|
package/android/build.gradle
CHANGED
|
@@ -4,14 +4,14 @@ plugins {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
group = 'expo.modules.satyaattest'
|
|
7
|
-
version = '3.
|
|
7
|
+
version = '3.10.0'
|
|
8
8
|
|
|
9
9
|
android {
|
|
10
10
|
namespace "expo.modules.satyaattest"
|
|
11
11
|
defaultConfig {
|
|
12
12
|
consumerProguardFiles 'consumer-rules.pro'
|
|
13
13
|
versionCode 1
|
|
14
|
-
versionName "3.
|
|
14
|
+
versionName "3.10.0"
|
|
15
15
|
// StrongBox key attestation needs API 28+; basic Keystore attestation API 24+.
|
|
16
16
|
minSdkVersion 24
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAoCtD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,CAI1F;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAIpE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAeA;AAED,wBAAgB,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CA+B3E;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAiBhF"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TEELS_ERROR_INFO } from '../../teelsTelemetry';
|
|
1
2
|
import { SatyaErrorCode } from '../../types/error.types';
|
|
2
3
|
/**
|
|
3
4
|
* Gate refusals are permanent for this build+provider: the app is not
|
|
@@ -102,6 +103,10 @@ export function friendlyTeelsError(message, code) {
|
|
|
102
103
|
return 'The TeeLS flow timed out. Please try again.';
|
|
103
104
|
}
|
|
104
105
|
if (code === SatyaErrorCode.TEELS_FLOW_FAILED) {
|
|
106
|
+
for (const info of Object.values(TEELS_ERROR_INFO)) {
|
|
107
|
+
if (message.endsWith(': ' + info.message))
|
|
108
|
+
return info.message + ' ' + info.recoveryAction;
|
|
109
|
+
}
|
|
105
110
|
return 'The TeeLS flow could not complete. Please try again.';
|
|
106
111
|
}
|
|
107
112
|
return friendlyError(message, code);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SatyaProviderFlowPhase } from './types';\nimport { SatyaErrorCode } from '../../types/error.types';\n\n/**\n * Gate refusals are permanent for this build+provider: the app is not\n * registered/approved, or the provider is not granted to it. Retrying cannot\n * help, so the copy must say what is wrong and the UI must not offer \"Try\n * again\" (see isRetryableError).\n */\nconst GATE_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_ACCESS_DENIED]:\n 'This provider is not enabled for this app yet. Contact the app owner to request access.',\n [SatyaErrorCode.APP_NOT_REGISTERED]:\n 'This app is not registered for verification. Contact the app owner.',\n [SatyaErrorCode.APP_DISABLED]:\n 'Verification is turned off for this app right now. Contact the app owner.',\n [SatyaErrorCode.APP_ID_REQUIRED]:\n 'This app is not set up for verification yet. Contact the app owner.',\n [SatyaErrorCode.APP_BINDING_MISMATCH]:\n 'This app build cannot be verified. Contact the app owner.',\n [SatyaErrorCode.APP_PLATFORM_NOT_CONFIGURED]:\n 'This device platform is not set up for verification in this app. Contact the app owner.',\n};\n\n/**\n * Provider/template configuration problems: not the user's fault and not\n * fixable by retrying — same treatment as gate refusals.\n */\nconst CONFIG_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_TEMPLATE_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n [SatyaErrorCode.PROVIDER_POLICY_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n};\n\n/** Prefer the verifier's explicit answer; otherwise classify local SDK codes. */\nexport function isRetryableError(code?: string | null, retryable?: boolean | null): boolean {\n if (typeof retryable === 'boolean') return retryable;\n if (!code) return true;\n return !(code in GATE_ERROR_COPY) && !(code in CONFIG_ERROR_COPY);\n}\n\nexport function processingCopy(phase: SatyaProviderFlowPhase): string {\n if (phase === 'backendVerify') return 'Finishing verification...';\n if (phase === 'nativeReplay') return 'Securely verifying your account...';\n return 'Verifying your account...';\n}\n\n/**\n * Copy for the cover, which is shown from the moment a login is submitted.\n * The pending tier deliberately does not claim verification has started — at\n * that point the credentials have only been sent.\n */\nexport function coverCopy(options: { pending: boolean; stalled: boolean }): {\n title: string;\n subtitle: string;\n} {\n if (options.stalled) {\n return {\n title: 'Still verifying...',\n subtitle:\n 'This is taking longer than expected. You can return to the provider without ending verification.',\n };\n }\n if (options.pending) {\n return { title: 'Signing you in...', subtitle: 'Just a moment.' };\n }\n return {\n title: 'Verifying your account...',\n subtitle: 'Keep this screen open - it only takes a moment.',\n };\n}\n\nexport function preparingCopy(providerName?: string): string {\n return providerName ? `Connecting to ${providerName}...` : 'Connecting securely...';\n}\n\nexport function friendlyError(message: string, code?: string | null): string {\n // Prefer the typed code: gate refusals and configuration errors have\n // precise, actionable copy and must never fall through to the generic\n // \"try again\" string.\n if (code && GATE_ERROR_COPY[code]) return GATE_ERROR_COPY[code];\n if (code && CONFIG_ERROR_COPY[code]) return CONFIG_ERROR_COPY[code];\n const m = (message || '').toLowerCase();\n if (m.includes('location permission') || m.includes('location access')) {\n return 'Location access is required for this provider. Allow it and try again.';\n }\n if (\n m.includes('403') ||\n m.includes('forbidden') ||\n m.includes('cloudflare') ||\n m.includes('bot')\n ) {\n return 'This provider is blocking automated verification right now. Please try again later.';\n }\n if (m.includes('network') || m.includes('timeout') || m.includes('timed out')) {\n return 'There was a network problem. Check your connection and try again.';\n }\n if (m.includes('request failed from') || m.includes('policy fetch')) {\n return 'Could not reach the verification service. Check your connection and try again.';\n }\n if (m.includes('pin') || m.includes('certificate') || m.includes('tls') || m.includes('secure')) {\n return 'We could not establish a secure connection to this provider. Please try again.';\n }\n if (m.includes('claim') || m.includes('reveal') || m.includes('match')) {\n return 'We could not read the expected details. Make sure you are fully signed in, then try again.';\n }\n return 'Something went wrong. Please try again.';\n}\n\nexport function friendlyTeelsError(message: string, code?: string | null): string {\n if (code === SatyaErrorCode.TEELS_ATTESTATION_MISSING) {\n return 'The provider completed without returning a TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_BRIDGE_INVALID) {\n return 'The provider returned an invalid TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_TIMEOUT) {\n return 'The TeeLS flow timed out. Please try again.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_FAILED) {\n return 'The TeeLS flow could not complete. Please try again.';\n }\n return friendlyError(message, code);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../../src/components/providerAttest/copy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SatyaProviderFlowPhase } from './types';\nimport { TEELS_ERROR_INFO } from '../../teelsTelemetry';\nimport { SatyaErrorCode } from '../../types/error.types';\n\n/**\n * Gate refusals are permanent for this build+provider: the app is not\n * registered/approved, or the provider is not granted to it. Retrying cannot\n * help, so the copy must say what is wrong and the UI must not offer \"Try\n * again\" (see isRetryableError).\n */\nconst GATE_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_ACCESS_DENIED]:\n 'This provider is not enabled for this app yet. Contact the app owner to request access.',\n [SatyaErrorCode.APP_NOT_REGISTERED]:\n 'This app is not registered for verification. Contact the app owner.',\n [SatyaErrorCode.APP_DISABLED]:\n 'Verification is turned off for this app right now. Contact the app owner.',\n [SatyaErrorCode.APP_ID_REQUIRED]:\n 'This app is not set up for verification yet. Contact the app owner.',\n [SatyaErrorCode.APP_BINDING_MISMATCH]:\n 'This app build cannot be verified. Contact the app owner.',\n [SatyaErrorCode.APP_PLATFORM_NOT_CONFIGURED]:\n 'This device platform is not set up for verification in this app. Contact the app owner.',\n};\n\n/**\n * Provider/template configuration problems: not the user's fault and not\n * fixable by retrying — same treatment as gate refusals.\n */\nconst CONFIG_ERROR_COPY: Record<string, string> = {\n [SatyaErrorCode.PROVIDER_TEMPLATE_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n [SatyaErrorCode.PROVIDER_POLICY_INVALID]:\n 'This provider is not set up correctly in this app yet. Contact the app owner.',\n};\n\n/** Prefer the verifier's explicit answer; otherwise classify local SDK codes. */\nexport function isRetryableError(code?: string | null, retryable?: boolean | null): boolean {\n if (typeof retryable === 'boolean') return retryable;\n if (!code) return true;\n return !(code in GATE_ERROR_COPY) && !(code in CONFIG_ERROR_COPY);\n}\n\nexport function processingCopy(phase: SatyaProviderFlowPhase): string {\n if (phase === 'backendVerify') return 'Finishing verification...';\n if (phase === 'nativeReplay') return 'Securely verifying your account...';\n return 'Verifying your account...';\n}\n\n/**\n * Copy for the cover, which is shown from the moment a login is submitted.\n * The pending tier deliberately does not claim verification has started — at\n * that point the credentials have only been sent.\n */\nexport function coverCopy(options: { pending: boolean; stalled: boolean }): {\n title: string;\n subtitle: string;\n} {\n if (options.stalled) {\n return {\n title: 'Still verifying...',\n subtitle:\n 'This is taking longer than expected. You can return to the provider without ending verification.',\n };\n }\n if (options.pending) {\n return { title: 'Signing you in...', subtitle: 'Just a moment.' };\n }\n return {\n title: 'Verifying your account...',\n subtitle: 'Keep this screen open - it only takes a moment.',\n };\n}\n\nexport function preparingCopy(providerName?: string): string {\n return providerName ? `Connecting to ${providerName}...` : 'Connecting securely...';\n}\n\nexport function friendlyError(message: string, code?: string | null): string {\n // Prefer the typed code: gate refusals and configuration errors have\n // precise, actionable copy and must never fall through to the generic\n // \"try again\" string.\n if (code && GATE_ERROR_COPY[code]) return GATE_ERROR_COPY[code];\n if (code && CONFIG_ERROR_COPY[code]) return CONFIG_ERROR_COPY[code];\n const m = (message || '').toLowerCase();\n if (m.includes('location permission') || m.includes('location access')) {\n return 'Location access is required for this provider. Allow it and try again.';\n }\n if (\n m.includes('403') ||\n m.includes('forbidden') ||\n m.includes('cloudflare') ||\n m.includes('bot')\n ) {\n return 'This provider is blocking automated verification right now. Please try again later.';\n }\n if (m.includes('network') || m.includes('timeout') || m.includes('timed out')) {\n return 'There was a network problem. Check your connection and try again.';\n }\n if (m.includes('request failed from') || m.includes('policy fetch')) {\n return 'Could not reach the verification service. Check your connection and try again.';\n }\n if (m.includes('pin') || m.includes('certificate') || m.includes('tls') || m.includes('secure')) {\n return 'We could not establish a secure connection to this provider. Please try again.';\n }\n if (m.includes('claim') || m.includes('reveal') || m.includes('match')) {\n return 'We could not read the expected details. Make sure you are fully signed in, then try again.';\n }\n return 'Something went wrong. Please try again.';\n}\n\nexport function friendlyTeelsError(message: string, code?: string | null): string {\n if (code === SatyaErrorCode.TEELS_ATTESTATION_MISSING) {\n return 'The provider completed without returning a TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_BRIDGE_INVALID) {\n return 'The provider returned an invalid TeeLS attestation.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_TIMEOUT) {\n return 'The TeeLS flow timed out. Please try again.';\n }\n if (code === SatyaErrorCode.TEELS_FLOW_FAILED) {\n for (const info of Object.values(TEELS_ERROR_INFO)) {\n if (message.endsWith(': ' + info.message)) return info.message + ' ' + info.recoveryAction;\n }\n return 'The TeeLS flow could not complete. Please try again.';\n }\n return friendlyError(message, code);\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TeelsBridgeMessageResult } from './teelsProtocol';
|
|
2
2
|
import type { SdkEventLogData } from '../../../sdkEventLog';
|
|
3
|
+
import { type TeelsErrorDetail } from '../../../teelsTelemetry';
|
|
3
4
|
import { type SatyaError } from '../../../types/error.types';
|
|
4
5
|
type TeelsBridgeErrorResult = Extract<TeelsBridgeMessageResult, {
|
|
5
6
|
kind: 'error';
|
|
@@ -7,6 +8,7 @@ type TeelsBridgeErrorResult = Extract<TeelsBridgeMessageResult, {
|
|
|
7
8
|
export interface TeelsFailureTelemetry {
|
|
8
9
|
errorMessage: string;
|
|
9
10
|
httpStatus?: number;
|
|
11
|
+
detail?: TeelsErrorDetail;
|
|
10
12
|
}
|
|
11
13
|
export interface TeelsBridgeFailure {
|
|
12
14
|
error: SatyaError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teelsFailure.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE/F,KAAK,sBAAsB,GAAG,OAAO,CAAC,wBAAwB,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEnF,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"teelsFailure.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE/F,KAAK,sBAAsB,GAAG,OAAO,CAAC,wBAAwB,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEnF,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEtD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,sBAAsB,GAAG,kBAAkB,CA+B3F;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,oBAAoB,EAC3B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,eAAe,CAuBjB"}
|
|
@@ -1,13 +1,30 @@
|
|
|
1
|
+
import { TEELS_ERROR_INFO } from '../../../teelsTelemetry';
|
|
1
2
|
import { SATYA_ERROR_MESSAGES, satyaError } from '../../../types/error.types';
|
|
2
3
|
export function createTeelsBridgeFailure(result) {
|
|
3
4
|
const baseMessage = SATYA_ERROR_MESSAGES[result.code];
|
|
5
|
+
const detail = result.errorDetail;
|
|
6
|
+
const info = detail ? TEELS_ERROR_INFO[detail.code] : undefined;
|
|
4
7
|
return {
|
|
5
|
-
error: satyaError(result.code, result.detail
|
|
8
|
+
error: satyaError(result.code, info?.message ?? result.detail, detail
|
|
9
|
+
? {
|
|
10
|
+
teelsErrorCode: detail.code,
|
|
11
|
+
teelsStage: detail.stage,
|
|
12
|
+
httpStatus: detail.httpStatus,
|
|
13
|
+
teelsSessionId: detail.sessionId,
|
|
14
|
+
failureClass: info?.failureClass,
|
|
15
|
+
recoveryAction: info?.recoveryAction,
|
|
16
|
+
}
|
|
17
|
+
: undefined),
|
|
6
18
|
telemetry: {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
19
|
+
...(detail ? { detail } : {}),
|
|
20
|
+
errorMessage: info
|
|
21
|
+
? info.message
|
|
22
|
+
: result.telemetryDetail
|
|
23
|
+
? baseMessage + ': ' + result.telemetryDetail
|
|
24
|
+
: baseMessage,
|
|
25
|
+
...(typeof (detail?.httpStatus ?? result.httpStatus) === 'number'
|
|
26
|
+
? { httpStatus: detail?.httpStatus ?? result.httpStatus }
|
|
27
|
+
: {}),
|
|
11
28
|
},
|
|
12
29
|
};
|
|
13
30
|
}
|
|
@@ -23,6 +40,15 @@ export function buildTeelsFailureLogData(input, providerId, funnelStage) {
|
|
|
23
40
|
funnelStage,
|
|
24
41
|
retryable: typeof context.retryable === 'boolean' ? context.retryable : undefined,
|
|
25
42
|
httpStatus: telemetry?.httpStatus,
|
|
43
|
+
...(telemetry?.detail
|
|
44
|
+
? {
|
|
45
|
+
teelsErrorCode: telemetry.detail.code,
|
|
46
|
+
...(telemetry.detail.stage ? { teelsStage: telemetry.detail.stage } : {}),
|
|
47
|
+
...(telemetry.detail.sessionId ? { teelsSessionId: telemetry.detail.sessionId } : {}),
|
|
48
|
+
failureClass: TEELS_ERROR_INFO[telemetry.detail.code].failureClass,
|
|
49
|
+
recoveryAction: TEELS_ERROR_INFO[telemetry.detail.code].recoveryAction,
|
|
50
|
+
}
|
|
51
|
+
: {}),
|
|
26
52
|
errorId: error.errorId,
|
|
27
53
|
};
|
|
28
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teelsFailure.js","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAmB,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"teelsFailure.js","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsFailure.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TeelsBridgeMessageResult } from './teelsProtocol';\nimport type { SdkEventLogData } from '../../../sdkEventLog';\nimport { TEELS_ERROR_INFO, type TeelsErrorDetail } from '../../../teelsTelemetry';\nimport { SATYA_ERROR_MESSAGES, satyaError, type SatyaError } from '../../../types/error.types';\n\ntype TeelsBridgeErrorResult = Extract<TeelsBridgeMessageResult, { kind: 'error' }>;\n\nexport interface TeelsFailureTelemetry {\n errorMessage: string;\n httpStatus?: number;\n detail?: TeelsErrorDetail;\n}\n\nexport interface TeelsBridgeFailure {\n error: SatyaError;\n telemetry: TeelsFailureTelemetry;\n}\n\nexport type TeelsFailureLogInput =\n | { source: 'sdk'; error: SatyaError }\n | { source: 'bridge'; failure: TeelsBridgeFailure };\n\nexport function createTeelsBridgeFailure(result: TeelsBridgeErrorResult): TeelsBridgeFailure {\n const baseMessage = SATYA_ERROR_MESSAGES[result.code];\n const detail = result.errorDetail;\n const info = detail ? TEELS_ERROR_INFO[detail.code] : undefined;\n return {\n error: satyaError(\n result.code,\n info?.message ?? result.detail,\n detail\n ? {\n teelsErrorCode: detail.code,\n teelsStage: detail.stage,\n httpStatus: detail.httpStatus,\n teelsSessionId: detail.sessionId,\n failureClass: info?.failureClass,\n recoveryAction: info?.recoveryAction,\n }\n : undefined\n ),\n telemetry: {\n ...(detail ? { detail } : {}),\n errorMessage: info\n ? info.message\n : result.telemetryDetail\n ? baseMessage + ': ' + result.telemetryDetail\n : baseMessage,\n ...(typeof (detail?.httpStatus ?? result.httpStatus) === 'number'\n ? { httpStatus: detail?.httpStatus ?? result.httpStatus }\n : {}),\n },\n };\n}\n\nexport function buildTeelsFailureLogData(\n input: TeelsFailureLogInput,\n providerId: string,\n funnelStage: string\n): SdkEventLogData {\n const error = input.source === 'bridge' ? input.failure.error : input.error;\n const telemetry = input.source === 'bridge' ? input.failure.telemetry : undefined;\n const context = (error.context ?? {}) as Record<string, unknown>;\n return {\n providerId,\n errorCode: error.code,\n errorMessage: telemetry ? telemetry.errorMessage : error.message,\n sdkStage: error.stage,\n funnelStage,\n retryable: typeof context.retryable === 'boolean' ? context.retryable : undefined,\n httpStatus: telemetry?.httpStatus,\n ...(telemetry?.detail\n ? {\n teelsErrorCode: telemetry.detail.code,\n ...(telemetry.detail.stage ? { teelsStage: telemetry.detail.stage } : {}),\n ...(telemetry.detail.sessionId ? { teelsSessionId: telemetry.detail.sessionId } : {}),\n failureClass: TEELS_ERROR_INFO[telemetry.detail.code].failureClass,\n recoveryAction: TEELS_ERROR_INFO[telemetry.detail.code].recoveryAction,\n }\n : {}),\n errorId: error.errorId,\n };\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type TeelsErrorDetail, type TeelsProgress } from '../../../teelsTelemetry';
|
|
1
2
|
import type { SatyaProviderInjection } from '../../../types';
|
|
2
3
|
import { type SatyaErrorCodeValue } from '../../../types/error.types';
|
|
3
4
|
import type { SatyaTeelsAttestation, SatyaTeelsClaimData } from '../types';
|
|
@@ -20,6 +21,9 @@ export interface TeelsBridgeCompletePayload {
|
|
|
20
21
|
}
|
|
21
22
|
export type TeelsBridgeMessageResult = {
|
|
22
23
|
kind: 'ignore';
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'progress';
|
|
26
|
+
progress: TeelsProgress;
|
|
23
27
|
} | {
|
|
24
28
|
kind: 'complete';
|
|
25
29
|
payload: TeelsBridgeCompletePayload;
|
|
@@ -28,6 +32,7 @@ export type TeelsBridgeMessageResult = {
|
|
|
28
32
|
code: SatyaErrorCodeValue;
|
|
29
33
|
detail?: string;
|
|
30
34
|
telemetryDetail?: string;
|
|
35
|
+
errorDetail?: TeelsErrorDetail;
|
|
31
36
|
httpStatus?: number;
|
|
32
37
|
};
|
|
33
38
|
export declare function createTeelsAttemptId(cryptoSource?: Pick<Crypto, 'getRandomValues' | 'randomUUID'> | null | undefined): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"teelsProtocol.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsProtocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE3E,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,8BAA8B,QAAa,CAAC;AACzD,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAC1D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAC7C,eAAO,MAAM,qBAAqB,QAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"teelsProtocol.d.ts","sourceRoot":"","sources":["../../../../src/components/providerAttest/teels/teelsProtocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,gBAAgB,EACrB,KAAK,aAAa,EACnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtF,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE3E,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAC/C,eAAO,MAAM,8BAA8B,QAAa,CAAC;AACzD,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAC1D,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAC7C,eAAO,MAAM,qBAAqB,QAAa,CAAC;AAOhD,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,EAAE,qBAAqB,CAAC;IACnC,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,0BAA0B,CAAA;CAAE,GACzD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,mBAAmB,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEN,wBAAgB,oBAAoB,CAClC,YAAY,GACR,IAAI,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,GAC9C,IAAI,GACJ,SAA6B,GAChC,MAAM,CAaR;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,sBAAsB,CAAC;CAC3C,GAAG,MAAM,CAoJT;AAED,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,CAwF1B;AAsDD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAgCtF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWpD;AAYD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TEELS_ERROR_INFO, TEELS_STAGES, isTeelsStage, readTeelsErrorDetail, safeTeelsSessionId, } from '../../../teelsTelemetry';
|
|
1
2
|
import { SatyaErrorCode } from '../../../types/error.types';
|
|
2
3
|
export const TEELS_BRIDGE_PROTOCOL_VERSION = 1;
|
|
3
4
|
export const TEELS_BRIDGE_MAX_MESSAGE_BYTES = 256 * 1024;
|
|
@@ -7,6 +8,7 @@ export const TEELS_BRIDGE_MAX_NODES = 10_000;
|
|
|
7
8
|
export const TEELS_FLOW_TIMEOUT_MS = 5 * 60_000;
|
|
8
9
|
const TEELS_COMPLETE_MESSAGE = '__satyaTeelsComplete';
|
|
9
10
|
const TEELS_ERROR_MESSAGE = '__satyaTeelsError';
|
|
11
|
+
const TEELS_PROGRESS_MESSAGE = '__satyaTeelsProgress';
|
|
10
12
|
let teelsAttemptSequence = 0;
|
|
11
13
|
export function createTeelsAttemptId(cryptoSource = globalThis.crypto) {
|
|
12
14
|
if (typeof cryptoSource?.randomUUID === 'function')
|
|
@@ -50,12 +52,12 @@ export function buildTeelsBridgeScript(options) {
|
|
|
50
52
|
}
|
|
51
53
|
return bytes;
|
|
52
54
|
};
|
|
53
|
-
const post = (message) => {
|
|
55
|
+
const post = (message, isTerminal = true) => {
|
|
54
56
|
if (terminal || !window.ReactNativeWebView || typeof window.ReactNativeWebView.postMessage !== 'function') return false;
|
|
55
57
|
let serialized;
|
|
56
58
|
try { serialized = JSON.stringify(message); } catch (_) { return false; }
|
|
57
59
|
if (byteLength(serialized) > maxMessageBytes) return false;
|
|
58
|
-
terminal =
|
|
60
|
+
terminal = isTerminal;
|
|
59
61
|
window.ReactNativeWebView.postMessage(serialized);
|
|
60
62
|
return true;
|
|
61
63
|
};
|
|
@@ -87,10 +89,17 @@ export function buildTeelsBridgeScript(options) {
|
|
|
87
89
|
}
|
|
88
90
|
return bounded ? bounded + ellipsis : undefined;
|
|
89
91
|
};
|
|
90
|
-
const
|
|
92
|
+
const projectDetail = (value) => {
|
|
93
|
+
if (!value || typeof value !== 'object' || !${JSON.stringify(Object.keys(TEELS_ERROR_INFO))}.includes(value.code)) return undefined;
|
|
94
|
+
return { code: value.code,
|
|
95
|
+
...(${JSON.stringify(TEELS_STAGES)}.includes(value.stage) ? { stage: value.stage } : {}),
|
|
96
|
+
...(Number.isInteger(value.httpStatus) && value.httpStatus >= 100 && value.httpStatus <= 599 ? { httpStatus: value.httpStatus } : {}),
|
|
97
|
+
...(typeof value.sessionId === 'string' && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value.sessionId) ? { sessionId: value.sessionId } : {}) };
|
|
98
|
+
};
|
|
99
|
+
const postError = (code, errorMessage, errorDetail) => {
|
|
91
100
|
const normalizedCode = code === 'attestation_missing' ? 'attestation_missing' : code === 'bridge_invalid' ? 'bridge_invalid' : 'teels_flow_failed';
|
|
92
101
|
const detail = normalizedCode === 'teels_flow_failed' ? normalizeErrorMessage(errorMessage) : undefined;
|
|
93
|
-
return post({ type: ${JSON.stringify(TEELS_ERROR_MESSAGE)}, version: protocolVersion, providerId, attemptId, code: normalizedCode, ...(detail ? { errorMessage: detail } : {}) });
|
|
102
|
+
return post({ type: ${JSON.stringify(TEELS_ERROR_MESSAGE)}, version: protocolVersion, providerId, attemptId, code: normalizedCode, errorDetail: projectDetail(errorDetail), ...(detail ? { errorMessage: detail } : {}) });
|
|
94
103
|
};
|
|
95
104
|
const validate = (root) => {
|
|
96
105
|
if (!root || typeof root !== 'object' || Array.isArray(root)) return false;
|
|
@@ -136,8 +145,13 @@ export function buildTeelsBridgeScript(options) {
|
|
|
136
145
|
if (byteLength(serialized) > maxMessageBytes) { postError('bridge_invalid'); return; }
|
|
137
146
|
post(message);
|
|
138
147
|
},
|
|
139
|
-
fail(code, errorMessage) {
|
|
140
|
-
postError(code === 'attestation_missing' ? 'attestation_missing' : 'teels_flow_failed', errorMessage);
|
|
148
|
+
fail(code, errorMessage, errorDetail) {
|
|
149
|
+
postError(code === 'attestation_missing' ? 'attestation_missing' : 'teels_flow_failed', errorMessage, errorDetail);
|
|
150
|
+
},
|
|
151
|
+
progress(value) {
|
|
152
|
+
if (!value || !${JSON.stringify(TEELS_STAGES)}.includes(value.stage)) return;
|
|
153
|
+
const safe = projectDetail({ ...value, code: 'TEELS_UNKNOWN_ERROR' });
|
|
154
|
+
post({ type: ${JSON.stringify(TEELS_PROGRESS_MESSAGE)}, version: protocolVersion, providerId, attemptId, stage: safe.stage, sessionId: safe.sessionId }, false);
|
|
141
155
|
}
|
|
142
156
|
};
|
|
143
157
|
Object.defineProperties(bridge, {
|
|
@@ -156,12 +170,14 @@ export function buildTeelsBridgeScript(options) {
|
|
|
156
170
|
})();`;
|
|
157
171
|
}
|
|
158
172
|
export function parseTeelsBridgeMessage(raw, context) {
|
|
159
|
-
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
173
|
+
// Untrusted frames/old pages cannot settle an attempt, including oversized input.
|
|
174
|
+
if (!isExactOrigin(context.nativeEventUrl, context.expectedOrigin) ||
|
|
175
|
+
!isExactOrigin(context.committedUrl, context.expectedOrigin))
|
|
176
|
+
return { kind: 'ignore' };
|
|
177
|
+
// Our bridge turns oversize terminal payloads into a small correlated error.
|
|
178
|
+
// Do not parse oversized direct posts or guess their provider/attempt from text.
|
|
179
|
+
if (utf8ByteLength(raw) > TEELS_BRIDGE_MAX_MESSAGE_BYTES)
|
|
180
|
+
return { kind: 'ignore' };
|
|
165
181
|
let decoded;
|
|
166
182
|
try {
|
|
167
183
|
decoded = JSON.parse(raw);
|
|
@@ -172,7 +188,9 @@ export function parseTeelsBridgeMessage(raw, context) {
|
|
|
172
188
|
if (!isRecord(decoded))
|
|
173
189
|
return { kind: 'ignore' };
|
|
174
190
|
const type = decoded.type;
|
|
175
|
-
if (type !== TEELS_COMPLETE_MESSAGE &&
|
|
191
|
+
if (type !== TEELS_COMPLETE_MESSAGE &&
|
|
192
|
+
type !== TEELS_ERROR_MESSAGE &&
|
|
193
|
+
type !== TEELS_PROGRESS_MESSAGE) {
|
|
176
194
|
return { kind: 'ignore' };
|
|
177
195
|
}
|
|
178
196
|
// Origin before correlation and version: only messages from the exact
|
|
@@ -187,6 +205,14 @@ export function parseTeelsBridgeMessage(raw, context) {
|
|
|
187
205
|
if (decoded.version !== TEELS_BRIDGE_PROTOCOL_VERSION) {
|
|
188
206
|
return { kind: 'error', code: SatyaErrorCode.TEELS_BRIDGE_INVALID };
|
|
189
207
|
}
|
|
208
|
+
if (type === TEELS_PROGRESS_MESSAGE) {
|
|
209
|
+
return isTeelsStage(decoded.stage)
|
|
210
|
+
? {
|
|
211
|
+
kind: 'progress',
|
|
212
|
+
progress: { stage: decoded.stage, sessionId: safeTeelsSessionId(decoded.sessionId) },
|
|
213
|
+
}
|
|
214
|
+
: { kind: 'ignore' };
|
|
215
|
+
}
|
|
190
216
|
if (type === TEELS_ERROR_MESSAGE) {
|
|
191
217
|
if (decoded.code === 'attestation_missing') {
|
|
192
218
|
return { kind: 'error', code: SatyaErrorCode.TEELS_ATTESTATION_MISSING };
|
|
@@ -194,11 +220,13 @@ export function parseTeelsBridgeMessage(raw, context) {
|
|
|
194
220
|
if (decoded.code === 'teels_flow_failed') {
|
|
195
221
|
const detail = normalizeTeelsErrorMessage(decoded.errorMessage);
|
|
196
222
|
const telemetry = projectTeelsErrorForTelemetry(detail);
|
|
223
|
+
const errorDetail = readTeelsErrorDetail(decoded.errorDetail);
|
|
197
224
|
return {
|
|
198
225
|
kind: 'error',
|
|
199
226
|
code: SatyaErrorCode.TEELS_FLOW_FAILED,
|
|
200
227
|
...(detail ? { detail } : {}),
|
|
201
228
|
...telemetry,
|
|
229
|
+
...(errorDetail ? { errorDetail } : {}),
|
|
202
230
|
};
|
|
203
231
|
}
|
|
204
232
|
if (decoded.code === 'bridge_invalid') {
|
|
@@ -241,7 +269,7 @@ function projectTeelsErrorForTelemetry(detail) {
|
|
|
241
269
|
// Closed, PII-free grammar for the currently deployed hosted provider. Keep
|
|
242
270
|
// arbitrary TeeLS text local in SatyaError; the public ingest gets only this
|
|
243
271
|
// known stage plus an integer status.
|
|
244
|
-
const match = /^login\.auth failed: HTTP ([1-5]\d{2})
|
|
272
|
+
const match = /^login\.auth failed: HTTP ([1-5]\d{2})(?: \(fields flagged: [^\r\n()]{1,256}\))?$/i.exec(detail);
|
|
245
273
|
if (!match)
|
|
246
274
|
return {};
|
|
247
275
|
const httpStatus = Number(match[1]);
|