@burnt-labs/expo-satya-attest 0.1.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/LICENSE +21 -0
- package/PROVIDER_REGISTRY.md +271 -0
- package/PUBLISHING.md +291 -0
- package/README.md +374 -0
- package/android/build.gradle +37 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/satyaattest/SatyaAttestModule.kt +620 -0
- package/android/src/main/java/uniffi/satya_ffi/satya_ffi.kt +1423 -0
- package/android/src/main/jniLibs/arm64-v8a/libsatya_ffi.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libsatya_ffi.so +0 -0
- package/android/src/main/jniLibs/x86_64/libsatya_ffi.so +0 -0
- package/app.plugin.js +131 -0
- package/build/SatyaAttest.types.d.ts +200 -0
- package/build/SatyaAttest.types.d.ts.map +1 -0
- package/build/SatyaAttest.types.js +10 -0
- package/build/SatyaAttest.types.js.map +1 -0
- package/build/SatyaAttestModule.d.ts +29 -0
- package/build/SatyaAttestModule.d.ts.map +1 -0
- package/build/SatyaAttestModule.js +3 -0
- package/build/SatyaAttestModule.js.map +1 -0
- package/build/SatyaAttestModule.web.d.ts +14 -0
- package/build/SatyaAttestModule.web.d.ts.map +1 -0
- package/build/SatyaAttestModule.web.js +28 -0
- package/build/SatyaAttestModule.web.js.map +1 -0
- package/build/SatyaMobileClient.d.ts +37 -0
- package/build/SatyaMobileClient.d.ts.map +1 -0
- package/build/SatyaMobileClient.js +82 -0
- package/build/SatyaMobileClient.js.map +1 -0
- package/build/SatyaProviderAttestButton.d.ts +99 -0
- package/build/SatyaProviderAttestButton.d.ts.map +1 -0
- package/build/SatyaProviderAttestButton.js +801 -0
- package/build/SatyaProviderAttestButton.js.map +1 -0
- package/build/index.d.ts +13 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +16 -0
- package/build/index.js.map +1 -0
- package/build/providerPolicy.d.ts +10 -0
- package/build/providerPolicy.d.ts.map +1 -0
- package/build/providerPolicy.js +81 -0
- package/build/providerPolicy.js.map +1 -0
- package/build/providerRegistry.d.ts +17 -0
- package/build/providerRegistry.d.ts.map +1 -0
- package/build/providerRegistry.js +522 -0
- package/build/providerRegistry.js.map +1 -0
- package/build/providerWebview.d.ts +37 -0
- package/build/providerWebview.d.ts.map +1 -0
- package/build/providerWebview.js +524 -0
- package/build/providerWebview.js.map +1 -0
- package/build/providers.json +981 -0
- package/expo-module.config.json +9 -0
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/Info.plist +29 -0
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/Headers/module.modulemap +7 -0
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/Headers/satya_ffi.swift +989 -0
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/Headers/satya_ffiFFI.h +585 -0
- package/ios/Frameworks/libsatya_ffi-rs.xcframework/ios-arm64/libsatya_ffi.a +0 -0
- package/ios/Generated/satya_ffi.swift +989 -0
- package/ios/SatyaAttest.podspec +27 -0
- package/ios/SatyaAttestModule.swift +932 -0
- package/package.json +83 -0
- package/scripts/build-rust-android.sh +51 -0
- package/scripts/build-rust-ios.sh +129 -0
- package/src/SatyaAttest.types.ts +239 -0
- package/src/SatyaAttestModule.ts +36 -0
- package/src/SatyaAttestModule.web.ts +36 -0
- package/src/SatyaMobileClient.ts +122 -0
- package/src/SatyaProviderAttestButton.tsx +1142 -0
- package/src/index.ts +48 -0
- package/src/providerPolicy.ts +122 -0
- package/src/providerRegistry.ts +683 -0
- package/src/providerWebview.ts +548 -0
- package/src/providers.json +981 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Provider Registry
|
|
2
|
+
|
|
3
|
+
`@burnt-labs/expo-satya-attest` ships with a built-in provider registry at
|
|
4
|
+
[`src/providers.json`](./src/providers.json). Apps can also supply their own registry
|
|
5
|
+
when they want to keep provider templates outside the SDK package.
|
|
6
|
+
|
|
7
|
+
Use a custom registry when:
|
|
8
|
+
|
|
9
|
+
- your app needs providers that are not in the SDK package,
|
|
10
|
+
- your app wants to pin a private allow-list,
|
|
11
|
+
- your team wants to update provider templates through its own release process.
|
|
12
|
+
|
|
13
|
+
## Loading A Custom Registry
|
|
14
|
+
|
|
15
|
+
For a hosted registry:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { SatyaProviderAttestButton } from '@burnt-labs/expo-satya-attest';
|
|
19
|
+
|
|
20
|
+
export function PayrollProof() {
|
|
21
|
+
return (
|
|
22
|
+
<SatyaProviderAttestButton
|
|
23
|
+
providerId="acme.payroll.v1"
|
|
24
|
+
providerRegistrySource={{
|
|
25
|
+
url: 'https://example.com/.well-known/satya/providers.json',
|
|
26
|
+
timeoutMs: 10000,
|
|
27
|
+
maxBytes: 524288,
|
|
28
|
+
}}
|
|
29
|
+
providerPolicyRefresh="verifier-required"
|
|
30
|
+
transportConfig={{
|
|
31
|
+
notaryUrl: 'https://verifier.example.com',
|
|
32
|
+
cloudProjectNumber: 0,
|
|
33
|
+
}}
|
|
34
|
+
verifyBackend
|
|
35
|
+
buttonLabel="Open payroll"
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For an in-app registry object:
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { SatyaProviderAttestButton, type SatyaProviderRegistry } from '@burnt-labs/expo-satya-attest';
|
|
45
|
+
|
|
46
|
+
const registry: SatyaProviderRegistry = {
|
|
47
|
+
schemaVersion: '0.1.0',
|
|
48
|
+
providers: [
|
|
49
|
+
// provider templates
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
<SatyaProviderAttestButton
|
|
54
|
+
providerId="acme.payroll.v1"
|
|
55
|
+
providerRegistrySource={registry}
|
|
56
|
+
providerPolicyRefresh="verifier-required"
|
|
57
|
+
transportConfig={{ notaryUrl: 'https://verifier.example.com' }}
|
|
58
|
+
/>;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
To populate your own selector UI:
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { listProviderRefs, loadProviderRegistry } from '@burnt-labs/expo-satya-attest';
|
|
65
|
+
|
|
66
|
+
const registry = await loadProviderRegistry({
|
|
67
|
+
url: 'https://example.com/.well-known/satya/providers.json',
|
|
68
|
+
});
|
|
69
|
+
const providers = listProviderRefs(registry);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`providerTemplate` still works for one-off integrations and wins over
|
|
73
|
+
`providerRegistrySource` when both are supplied.
|
|
74
|
+
|
|
75
|
+
## Registry URL Rules
|
|
76
|
+
|
|
77
|
+
Hosted registries are fetched with `GET` and must use HTTPS by default.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
providerRegistrySource={{
|
|
81
|
+
url: 'https://example.com/.well-known/satya/providers.json',
|
|
82
|
+
headers: { Authorization: 'Bearer ...' },
|
|
83
|
+
timeoutMs: 10000,
|
|
84
|
+
maxBytes: 524288
|
|
85
|
+
}}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Security rules enforced by the SDK:
|
|
89
|
+
|
|
90
|
+
- `https://` is required by default.
|
|
91
|
+
- URL credentials such as `https://user:pass@example.com/...` are rejected.
|
|
92
|
+
- Request headers cannot contain newline characters.
|
|
93
|
+
- Fetches are timeout bounded.
|
|
94
|
+
- Response bodies are size bounded.
|
|
95
|
+
- The JSON is validated and cloned before use.
|
|
96
|
+
|
|
97
|
+
`allowInsecureHttp: true` exists only for local development:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
providerRegistrySource={{
|
|
101
|
+
url: 'http://127.0.0.1:8080/providers.json',
|
|
102
|
+
allowInsecureHttp: true
|
|
103
|
+
}}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Do not use insecure HTTP for production registries. A registry controls which provider
|
|
107
|
+
host, template hash, parser hash, request match rules, and reveal rules the SDK uses.
|
|
108
|
+
|
|
109
|
+
## File Format
|
|
110
|
+
|
|
111
|
+
Top-level shape:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"schemaVersion": "0.1.0",
|
|
116
|
+
"providers": []
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Provider template shape:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"schemaVersion": "0.1.0",
|
|
125
|
+
"providerId": "acme.payroll.v1",
|
|
126
|
+
"label": "Acme Payroll",
|
|
127
|
+
"description": "Current employee payroll proof",
|
|
128
|
+
"displayName": "Acme Payroll",
|
|
129
|
+
"version": "v1",
|
|
130
|
+
"target": {
|
|
131
|
+
"scheme": "https",
|
|
132
|
+
"host": "payroll.example.com",
|
|
133
|
+
"port": 443
|
|
134
|
+
},
|
|
135
|
+
"webLogin": {
|
|
136
|
+
"startUrl": "https://payroll.example.com/login",
|
|
137
|
+
"callbackUrl": "https://payroll.example.com/",
|
|
138
|
+
"oauthHosts": ["payroll.example.com"]
|
|
139
|
+
},
|
|
140
|
+
"userAgent": {
|
|
141
|
+
"ios": null,
|
|
142
|
+
"android": null
|
|
143
|
+
},
|
|
144
|
+
"proofTarget": {
|
|
145
|
+
"method": "GET",
|
|
146
|
+
"url": "https://payroll.example.com/api/current-user",
|
|
147
|
+
"requestMatchRules": [
|
|
148
|
+
{
|
|
149
|
+
"type": "methodEquals",
|
|
150
|
+
"pattern": "GET"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"type": "urlContains",
|
|
154
|
+
"pattern": "/api/current-user"
|
|
155
|
+
}
|
|
156
|
+
],
|
|
157
|
+
"revealRules": [
|
|
158
|
+
{
|
|
159
|
+
"action": "REVEAL",
|
|
160
|
+
"direction": "RECV",
|
|
161
|
+
"part": "BODY",
|
|
162
|
+
"params": {
|
|
163
|
+
"type": "json",
|
|
164
|
+
"path": "$.employeeId"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
"maxSentData": 4096,
|
|
169
|
+
"maxRecvData": 131072
|
|
170
|
+
},
|
|
171
|
+
"privacyPolicy": {
|
|
172
|
+
"allowedRequestHeaders": ["accept", "cookie", "content-type", "user-agent"],
|
|
173
|
+
"allowedResponseBodyJsonPaths": ["$.employeeId"]
|
|
174
|
+
},
|
|
175
|
+
"tlsPolicy": {
|
|
176
|
+
"requireTls13": true,
|
|
177
|
+
"allowZeroRtt": false,
|
|
178
|
+
"allowResumption": false,
|
|
179
|
+
"allowKeyUpdate": false,
|
|
180
|
+
"preferredCipher": "TLS_CHACHA20_POLY1305_SHA256",
|
|
181
|
+
"maxSentBytes": 4096,
|
|
182
|
+
"maxRecvBytes": 131072
|
|
183
|
+
},
|
|
184
|
+
"tlsIdentityPolicy": {
|
|
185
|
+
"expectedSni": "payroll.example.com",
|
|
186
|
+
"allowedAlpn": ["h2", "http/1.1"],
|
|
187
|
+
"spkiSha256Hex": null,
|
|
188
|
+
"spkiSha256B64Pins": ["KWQsjul7mJDk+i6fAisGLhWLd43FUs5ayVmkz5Y54DU="],
|
|
189
|
+
"tlsTrustStorePolicy": "web-pki-os-roots-no-user-roots",
|
|
190
|
+
"userRootsAllowed": false,
|
|
191
|
+
"redirectPolicyId": "no-cross-origin-redirects-v1"
|
|
192
|
+
},
|
|
193
|
+
"templateGovernance": {
|
|
194
|
+
"templateHash": "prod-acme-payroll-v1-template",
|
|
195
|
+
"parserHash": "prod-acme-payroll-v1-parser",
|
|
196
|
+
"fixtureSetHash": "prod-acme-payroll-v1-fixtures",
|
|
197
|
+
"governancePolicyVersion": "prod-governance-v1",
|
|
198
|
+
"providerActivationState": "active"
|
|
199
|
+
},
|
|
200
|
+
"freshness": {
|
|
201
|
+
"mode": "notary_nonce",
|
|
202
|
+
"echoCapable": false,
|
|
203
|
+
"injection": null,
|
|
204
|
+
"reflectionPath": null,
|
|
205
|
+
"cacheKeyAffecting": true,
|
|
206
|
+
"semanticallyInert": true
|
|
207
|
+
},
|
|
208
|
+
"credentialCustody": {
|
|
209
|
+
"model": "webview_session_cookie",
|
|
210
|
+
"allowImportedCookies": false,
|
|
211
|
+
"accountBindingRequired": true
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Validation Rules
|
|
217
|
+
|
|
218
|
+
The SDK rejects custom registries unless each provider satisfies these checks:
|
|
219
|
+
|
|
220
|
+
- provider ids are unique and non-empty,
|
|
221
|
+
- `target.scheme` is `https`,
|
|
222
|
+
- `target.port` is `443`,
|
|
223
|
+
- `proofTarget.url` is HTTPS,
|
|
224
|
+
- `proofTarget.url` host matches `target.host`,
|
|
225
|
+
- `proofTarget.url` host matches `tlsIdentityPolicy.expectedSni`,
|
|
226
|
+
- `tlsIdentityPolicy.tlsTrustStorePolicy` is `web-pki-os-roots-no-user-roots`,
|
|
227
|
+
- `tlsIdentityPolicy.userRootsAllowed` is `false`,
|
|
228
|
+
- SPKI pins are valid SHA-256 base64 strings when present,
|
|
229
|
+
- `templateGovernance.templateHash` and `parserHash` are non-empty,
|
|
230
|
+
- `privacyPolicy.allowedRequestHeaders` is non-empty,
|
|
231
|
+
- `privacyPolicy.allowedResponseBodyJsonPaths` is non-empty,
|
|
232
|
+
- `proofTarget.requestMatchRules` includes a `methodEquals` rule matching
|
|
233
|
+
`proofTarget.method`,
|
|
234
|
+
- `proofTarget.requestMatchRules` includes a `urlContains` rule matching the
|
|
235
|
+
`proofTarget.url` path or query.
|
|
236
|
+
|
|
237
|
+
The SDK validates the registry before opening the WebView and the native iOS/Android
|
|
238
|
+
modules repeat critical checks before replay.
|
|
239
|
+
|
|
240
|
+
## Security Review Notes
|
|
241
|
+
|
|
242
|
+
Threat model: a provider registry controls the login URL, request matching rules, replay
|
|
243
|
+
URL, trusted SNI, template hash, parser hash, reveal rules, and optional SPKI pins. Treat
|
|
244
|
+
it as trusted policy, not as ordinary app content.
|
|
245
|
+
|
|
246
|
+
Confirmed protections in the SDK:
|
|
247
|
+
|
|
248
|
+
- Remote registries are HTTPS-only by default, with timeout and size limits.
|
|
249
|
+
- Registry URLs with embedded credentials are rejected.
|
|
250
|
+
- Registry request headers are sanitized for newline injection.
|
|
251
|
+
- Templates are validated and cloned before use.
|
|
252
|
+
- Custom templates cannot enable user-installed roots.
|
|
253
|
+
- Replay URL, target host, and expected SNI must agree.
|
|
254
|
+
- Request matching must bind both method and URL.
|
|
255
|
+
- Verifier SPKI policy is still checked against provider id, host, template hash, and
|
|
256
|
+
parser hash before those pins are used.
|
|
257
|
+
- Backend verification independently re-derives trusted template and pin policy.
|
|
258
|
+
|
|
259
|
+
Residual risks and required operating practices:
|
|
260
|
+
|
|
261
|
+
- A malicious host app can intentionally pass a malicious registry or template. The SDK is
|
|
262
|
+
not a trust boundary against the application that embeds it.
|
|
263
|
+
- A compromised registry host can change templates. Production backends must reject
|
|
264
|
+
unknown `templateHash` / `parserHash` values and should use
|
|
265
|
+
`providerPolicyRefresh="verifier-required"`.
|
|
266
|
+
- Do not put secrets in registry URLs. Use short-lived headers if a private registry needs
|
|
267
|
+
authentication.
|
|
268
|
+
- Do not use `allowInsecureHttp` outside local development.
|
|
269
|
+
- Keep verifier provider policy in sync with custom registry templates. The client-side
|
|
270
|
+
registry protects replay setup; the verifier policy decides whether an artifact is
|
|
271
|
+
acceptable.
|
package/PUBLISHING.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# Publishing `@burnt-labs/expo-satya-attest`
|
|
2
|
+
|
|
3
|
+
This SDK should publish as an npm package. Expo and React Native apps install native
|
|
4
|
+
modules from npm, then CocoaPods and Gradle consume the iOS/Android native code from
|
|
5
|
+
`node_modules`. You do not need a separate CocoaPods trunk package or Maven package for
|
|
6
|
+
the current layout.
|
|
7
|
+
|
|
8
|
+
Use GitHub Releases only as an optional companion for binary provenance, checksums, or
|
|
9
|
+
very large native artifacts. The npm tarball still needs the native artifacts unless the
|
|
10
|
+
package is redesigned to download or build them during install, which is not recommended
|
|
11
|
+
for a plug-and-play Expo SDK.
|
|
12
|
+
|
|
13
|
+
## Package Name
|
|
14
|
+
|
|
15
|
+
Use the scoped public package owned by the Burnt npm organization:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
@burnt-labs/expo-satya-attest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Check before release:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm view @burnt-labs/expo-satya-attest version
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
If npm returns `E404`, the package has not been published yet. The `NPM_TOKEN` used by
|
|
28
|
+
GitHub Actions must belong to an npm account or automation token with publish rights for
|
|
29
|
+
the `@burnt-labs` scope. Scoped public publishes must use `npm publish --access public`.
|
|
30
|
+
|
|
31
|
+
## Native Artifacts That Must Ship
|
|
32
|
+
|
|
33
|
+
The SDK wraps Rust through UniFFI, so the npm package must include prebuilt native
|
|
34
|
+
artifacts. Consumers should not have to install Rust, Android NDK, cargo-ndk, or Xcode
|
|
35
|
+
toolchains just to install the SDK.
|
|
36
|
+
|
|
37
|
+
Required Android files:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
android/src/main/java/uniffi/satya_ffi/satya_ffi.kt
|
|
41
|
+
android/src/main/jniLibs/arm64-v8a/libsatya_ffi.so
|
|
42
|
+
android/src/main/jniLibs/armeabi-v7a/libsatya_ffi.so
|
|
43
|
+
android/src/main/jniLibs/x86_64/libsatya_ffi.so
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Required iOS files:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
ios/Generated/satya_ffi.swift
|
|
50
|
+
ios/Frameworks/libsatya_ffi-rs.xcframework/
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
These outputs are gitignored because they are generated build products. A release job
|
|
54
|
+
must build them before `npm publish`, or the release manager must build them locally
|
|
55
|
+
before publishing.
|
|
56
|
+
|
|
57
|
+
Build them from the module directory:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd platform_sdks/expo-satya-attest
|
|
61
|
+
npm run build:native:android
|
|
62
|
+
npm run build:native:ios
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
iOS artifacts can only be built on macOS with Xcode command line tools. Android artifacts
|
|
66
|
+
need the Android NDK, JDK 17, `cargo-ndk`, and Rust Android targets.
|
|
67
|
+
|
|
68
|
+
The iOS build strips local/debug symbols from the static archives by default. For a
|
|
69
|
+
diagnostic unstripped iOS build:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
SATYA_IOS_STRIP=0 npm run build:native:ios
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
By default, the iOS release build includes only the physical-device `arm64` slice. That
|
|
76
|
+
is intentional: the real App Attest flow does not work on the iOS simulator, and shipping
|
|
77
|
+
simulator slices makes the npm package much larger without helping the production claim
|
|
78
|
+
path.
|
|
79
|
+
|
|
80
|
+
## Release Checks
|
|
81
|
+
|
|
82
|
+
Install dependencies:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
cd platform_sdks/expo-satya-attest
|
|
86
|
+
npm install
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Run the full release gate:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npm run release:check
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
This runs:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npm run check:metadata
|
|
99
|
+
npm run clean
|
|
100
|
+
npm run build
|
|
101
|
+
npm run lint
|
|
102
|
+
npm run test:providers
|
|
103
|
+
npm run check:example
|
|
104
|
+
npm run check:native-artifacts
|
|
105
|
+
npm run check:pack
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
What each check covers:
|
|
109
|
+
|
|
110
|
+
| Check | Purpose |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `check:metadata` | Confirms package metadata, README, LICENSE, plugin, and module config exist. |
|
|
113
|
+
| `clean` + `build` | Rebuilds TypeScript output in `build/`. |
|
|
114
|
+
| `lint` | Runs ESLint over `src/`. |
|
|
115
|
+
| `test:providers` | Validates provider ids, template hashes, parser hashes, request match rules, HTTPS proof URLs, SNI, and SPKI pins. |
|
|
116
|
+
| `check:example` | Type-checks the Expo example when its dependencies are installed. |
|
|
117
|
+
| `check:native-artifacts` | Fails if Android `.so`, generated Kotlin, iOS XCFramework, or generated Swift glue are missing. |
|
|
118
|
+
| `check:pack` | Runs `npm pack --dry-run --json` and verifies the actual tarball contents. |
|
|
119
|
+
|
|
120
|
+
The package uses a `files` whitelist in `package.json`, so `node_modules`, the example
|
|
121
|
+
app, `.env` files, `.DS_Store`, build caches, and generated tarballs are kept out of the
|
|
122
|
+
npm package.
|
|
123
|
+
|
|
124
|
+
## Dry Run
|
|
125
|
+
|
|
126
|
+
After `release:check` passes, inspect the package:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npm run pack:dry-run
|
|
130
|
+
npm publish --dry-run
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Check that the tarball contains:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
build/
|
|
137
|
+
src/providers.json
|
|
138
|
+
app.plugin.js
|
|
139
|
+
expo-module.config.json
|
|
140
|
+
android/src/main/
|
|
141
|
+
ios/SatyaAttest.podspec
|
|
142
|
+
ios/SatyaAttestModule.swift
|
|
143
|
+
ios/Generated/
|
|
144
|
+
ios/Frameworks/
|
|
145
|
+
README.md
|
|
146
|
+
LICENSE
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Check that it does not contain:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
expo-satya-attest-example/
|
|
153
|
+
node_modules/
|
|
154
|
+
.env
|
|
155
|
+
.DS_Store
|
|
156
|
+
*.tgz
|
|
157
|
+
internal/module_scripts/
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Publish
|
|
161
|
+
|
|
162
|
+
Log in and publish:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm login
|
|
166
|
+
npm publish
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
For a scoped public package, use:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
npm publish --access public
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
For prereleases:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm version prerelease --preid alpha
|
|
179
|
+
npm publish --tag alpha
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
For stable releases:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
npm version patch
|
|
186
|
+
npm publish
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Post-Publish Smoke Test
|
|
190
|
+
|
|
191
|
+
Create a temporary Expo app and install from npm:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npx create-expo-app SatyaSmoke
|
|
195
|
+
cd SatyaSmoke
|
|
196
|
+
npx expo install @burnt-labs/expo-satya-attest react-native-webview
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Add the plugin to `app.json`:
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"expo": {
|
|
204
|
+
"plugins": [["@burnt-labs/expo-satya-attest", { "appAttestEnvironment": "development" }]]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Render `SatyaProviderAttestButton`, rebuild a development client, and run on a real
|
|
210
|
+
device:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
npx expo run:ios
|
|
214
|
+
npx expo run:android
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The app still needs access to a running `satya-verifier-service` for verifier-backed SPKI
|
|
218
|
+
policy refresh and backend artifact verification.
|
|
219
|
+
|
|
220
|
+
## GitHub And Local Install Smoke Tests
|
|
221
|
+
|
|
222
|
+
Consumers may also install the SDK from a local directory or GitHub release tarball.
|
|
223
|
+
Both paths must include the same built files as the npm package.
|
|
224
|
+
|
|
225
|
+
Local directory smoke test:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
cd platform_sdks/expo-satya-attest
|
|
229
|
+
npm run release:check
|
|
230
|
+
|
|
231
|
+
cd /private/tmp/SatyaSmoke
|
|
232
|
+
npm install /path/to/tls-app-attest/platform_sdks/expo-satya-attest
|
|
233
|
+
npx expo install react-native-webview
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
GitHub release tarball smoke test:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
cd /private/tmp/SatyaSmoke
|
|
240
|
+
npm install https://github.com/<owner>/<repo>/releases/download/expo-satya-attest-v0.1.0/burnt-labs-expo-satya-attest-0.1.0.tgz
|
|
241
|
+
npx expo install react-native-webview
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
For a raw Git install, publish the SDK from a dedicated repo or a subtree/split branch
|
|
245
|
+
where the SDK package is at the Git root:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
npm install github:<owner>/<sdk-repo>#v0.1.0
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Do not document a normal monorepo Git URL as plug-and-play unless the Git ref has
|
|
252
|
+
`platform_sdks/expo-satya-attest` split to the package root. npm does not install a
|
|
253
|
+
package from a GitHub subdirectory directly, and this SDK needs its prebuilt native
|
|
254
|
+
artifacts in the installed package.
|
|
255
|
+
|
|
256
|
+
## Binary Size Guidance
|
|
257
|
+
|
|
258
|
+
The native Rust artifacts are expected and should ship in the npm package. They are not
|
|
259
|
+
"extra" optional files for this SDK because the native replay path depends on them.
|
|
260
|
+
|
|
261
|
+
Keep watching:
|
|
262
|
+
|
|
263
|
+
- `npm run check:native-artifacts` for Android/iOS unpacked binary size.
|
|
264
|
+
- `npm run check:pack` for npm tarball and unpacked package size.
|
|
265
|
+
- Whether every release includes only the ABIs you actually support.
|
|
266
|
+
|
|
267
|
+
Current default iOS output includes only device `arm64`. If you need simulator artifacts
|
|
268
|
+
for local fallback/debug work, opt in explicitly:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
SATYA_IOS_INCLUDE_SIMULATOR=1 npm run build:native:ios
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
For Apple-Silicon-simulator-only fallback builds:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
SATYA_IOS_SIMULATOR_TARGETS="aarch64-apple-ios-sim" npm run build:native:ios
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Do not publish simulator slices unless you intentionally support a simulator fallback
|
|
281
|
+
experience. They are not useful for real App Attest verification.
|
|
282
|
+
|
|
283
|
+
If the tarball becomes too large for npm or painful for app installs, the next design
|
|
284
|
+
step is a binary-release model:
|
|
285
|
+
|
|
286
|
+
1. Publish checksummed XCFramework and Android AAR/native artifacts to GitHub Releases.
|
|
287
|
+
2. Update the podspec/Gradle integration to consume those artifacts deterministically.
|
|
288
|
+
3. Keep install scripts fail-closed and checksum verified.
|
|
289
|
+
|
|
290
|
+
Do that only if size forces it. For the current plug-and-play SDK shape, bundling the
|
|
291
|
+
native artifacts inside the npm package is simpler and safer for users.
|