@zkp2p/zkp2p-attestation 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,7 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.0
4
+
5
+ - BREAKING: Buyer TEE verify request body field renamed from `metadata` to `params`. The server Zod schema rejects the legacy `metadata` field. All `*BuyerTeeMetadata` types in `@zkp2p/zkp2p-attestation` are renamed to `*BuyerTeeParams`, and `BuyerTeeMetadataByPlatform` is now `BuyerTeeParamsByPlatform`.
6
+ - BREAKING: Buyer TEE `params` shape no longer accepts duplicate provider-row fields. `N26BuyerTeeParams` is `{}`. `RevolutBuyerTeeParams`, `CitiBuyerTeeParams`, and `BankOfAmericaBuyerTeeParams` are `{ index }` only — `paymentId`, `transactionId`, and `confirmationNumber` are derived from the selected response row.
7
+ - BREAKING: Drop `jweId` from the buyer TEE session-material plaintext and from `EncryptBuyerTeeSessionMaterialBaseParams`. The server enforces a strict plaintext schema and rejects envelopes that still carry `jweId`. Seller credential upload still uses `jweId`.
8
+ - BREAKING: Drop `issuedAtMs` and `now` from `EncryptBuyerTeeSessionMaterialBaseParams` and from the buyer TEE plaintext schema. The server no longer enforces a 5-minute capture-age window on buyer envelopes; encrypted session material is valid for the lifetime of the upstream session (cookies/PAT). Seller credential upload still carries `issuedAtMs` and is unchanged.
9
+ - Migration: regenerate buyer TEE envelopes after upgrading; do not retry an envelope produced by `<1.3.0`. Update buyer TEE call sites to rename `metadata` to `params` and drop the removed per-platform fields (Revolut `paymentId`, Citi `transactionId`, BoA `confirmationNumber`, N26 `paymentId`).
10
+ - Operational note: a leaked encrypted JWE is now valid for the upstream session lifetime — treat any disclosure as equivalent to leaking the underlying upstream credential and rotate the upstream session.
11
+
12
+ ## 1.2.0
13
+
14
+ - Expand buyer TEE SDK types from Venmo-only to all 15 server-registered platforms.
15
+ - Tie each buyer TEE platform to its valid `actionType`, metadata shape, and named session-material header map.
16
+ - Require documented buyer TEE session-material headers in the per-platform TypeScript types (e.g. Wise `Cookie` or `X-Access-Token`, Revolut `Cookie` and `x-device-id`). A payload missing the required headers is a type error at the call site.
17
+ - Export `AttestationOutput`, `BuyerTeeVerifier`, `/buyer/supported`, and service response types for callers.
18
+ - Add `verifyBuyerTeePayment()` and `uploadSellerCredential()` one-shot helpers that chain attest → encrypt → POST → unwrap and return a typed result.
19
+ - Enforce `timeoutMs` across buyer TEE verify and seller credential upload POST requests, including through response body reads so stalled streams abort.
20
+ - Preserve structured unsuccessful ServiceResponse details on SDK errors via a new `SERVICE_RESPONSE_ERROR` code carrying `details.responseObject` — enables UIs to consume Wise multi-profile `WISE_PROFILE_SELECTION_REQUIRED` payloads and any future business-logic 4xx.
21
+ - Reject successful ServiceResponse envelopes that omit a `responseObject` (defends against bad-deploy / proxy-rewrite cases that would otherwise resolve helpers with `undefined`).
22
+ - Add buyer TEE discriminated-union type tests for Wise metadata/action narrowing and Revolut header enforcement.
23
+ - Drop the deprecated `verifyingContract` from the new buyer TEE verify helper parameters; the server resolves it from `DEPLOYMENT_ENV`.
24
+ - Keep the internal service-response envelope out of the public SDK type exports.
25
+
3
26
  ## 1.1.0
4
27
 
28
+ - Add buyer TEE session-material encryption helpers.
5
29
  - Add platform-aware seller credential upload encryption.
6
30
  - Support Wise seller credential uploads with `platform: "wise"` and no top-level `payeeId`.
7
31
  - Preserve the existing payee-based upload shape for Venmo, Cash App, and PayPal.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zkp2p/zkp2p-attestation
2
2
 
3
- Client-side verifier and encryptor for ZKP2P Nitro seller credential uploads.
3
+ Client-side verifier and encryptor for ZKP2P Nitro seller credential uploads and buyer TEE session-material requests.
4
4
 
5
5
  The package runs in Chrome MV3 service workers, browser DOM contexts, React Native with a Web Crypto polyfill, and Node >= 20. Library entrypoints use `fetch`, `SubtleCrypto`, `crypto.getRandomValues`, and `Uint8Array`; they do not import `node:*` modules or use `Buffer`.
6
6
 
@@ -57,6 +57,17 @@ await fetch(`${attestationServiceUrl}/seller/credentials/wise`, {
57
57
 
58
58
  This fetches `GET /attestation?nonce=...`, verifies the Nitro document to the pinned AWS root and PCR8, extracts the attested seller-upload RSA SPKI, and returns a compact JWE for `POST /seller/credentials/:platform`.
59
59
 
60
+ For the same flow without hand-rolling the POST:
61
+
62
+ ```ts
63
+ const credentialBundle = await nitro.uploadSellerCredential({
64
+ platform: "wise",
65
+ sessionMaterial: {
66
+ apiToken: "<wise-api-token>",
67
+ },
68
+ });
69
+ ```
70
+
60
71
  Venmo, Cash App, and PayPal still require a top-level `payeeId`; existing callers can keep using the same call shape:
61
72
 
62
73
  ```ts
@@ -66,6 +77,73 @@ const encryptedUpload = await nitro.createEncryptedSellerCredentialUpload({
66
77
  });
67
78
  ```
68
79
 
80
+ Buyer TEE requests use the same attested upload key and compact JWE envelope. The typed helper encrypts the captured
81
+ session material, posts `{ encryptedSessionMaterial, params, chainId, intent }` to
82
+ `POST /buyer/verify/:platform/:actionType`, unwraps the service envelope, and returns a typed `AttestationOutput`.
83
+ The service does not enforce capture-age or one-use replay limits for buyer TEE session material; verification depends
84
+ on the upstream session still being active. A leaked encrypted JWE is therefore valid for the upstream session
85
+ lifetime — treat any accidental disclosure as equivalent to leaking the underlying upstream credential (cookies, PAT,
86
+ etc.) and rotate the upstream session.
87
+
88
+ ```ts
89
+ const attestation = await nitro.verifyBuyerTeePayment({
90
+ platform: "venmo",
91
+ actionType: "transfer_venmo",
92
+ sessionMaterial: {
93
+ Cookie: "<captured-cookie-header>",
94
+ "User-Agent": "<captured-user-agent>",
95
+ },
96
+ params: { senderId: "<venmo-account-id>", index: 0 },
97
+ chainId,
98
+ intent,
99
+ });
100
+ ```
101
+
102
+ The helper is a thin wrapper over the existing wire format; callers can still hand-roll the final POST:
103
+
104
+ ```ts
105
+ const encryptedSessionMaterial = await nitro.createEncryptedBuyerTeeSessionMaterial({
106
+ platform: "wise",
107
+ actionType: "transfer_wise",
108
+ sessionMaterial: { "X-Access-Token": "<captured-token>" },
109
+ });
110
+
111
+ await fetch(`${attestationServiceUrl}/buyer/verify/wise/transfer_wise`, {
112
+ method: "POST",
113
+ headers: { "content-type": "application/json" },
114
+ body: JSON.stringify({
115
+ encryptedSessionMaterial,
116
+ params: { profileId: "41246868", transactionId: "123456789" },
117
+ chainId,
118
+ intent,
119
+ }),
120
+ });
121
+ ```
122
+
123
+ Buyer TEE platform matrix:
124
+
125
+ | Platform | `actionType` | Required encrypted session material | Public params fields |
126
+ |---|---|---|---|
127
+ | `venmo` | `transfer_venmo` | `Cookie` | `senderId`, `index` |
128
+ | `cashapp` | `transfer_cashapp` | `Cookie`, `x-csrf-token`, `x-device-name`, `x-request-signature`, `x-request-uuid`, `cash-web-request`, `x-web-device-info`, `x-web-context`, `x-bt-id` | `senderId`, `index` |
129
+ | `luxon` | `transfer_luxon` | `X-Auth-Token` | `transferId` |
130
+ | `monzo` | `transfer_monzo` | `Authorization` | `txId` |
131
+ | `n26` | `transfer_n26` | `Cookie`, `csrf-token`, `body` | `{}` |
132
+ | `wise` | `transfer_wise` | `Cookie` or `X-Access-Token` | `profileId`, `transactionId` |
133
+ | `revolut` | `transfer_revolut` | `Cookie`, `x-device-id` | `index` |
134
+ | `idfc` | `transfer_idfc` | `Cookie` | `senderId`, `index` |
135
+ | `citi` | `transfer_zelle` | `Cookie` | `index` |
136
+ | `chime` | `transfer_chime` | `Cookie`, `body` | `{}` |
137
+ | `chase` | `transfer_zelle` | `Cookie`, `x-jpmc-channel`, `x-jpmc-csrf-token`, `Referer`, `Origin` | `index` |
138
+ | `bankofamerica` | `transfer_zelle` | `Cookie` | `index` |
139
+ | `mercadopago` | `transfer_mercadopago` | `Cookie` | `paymentId`, `urlParamsFrom` |
140
+ | `paypal` | `transfer_paypal` | `Cookie` | `index` |
141
+ | `alipay` | `transfer_alipay` | `Cookie` | `tradeNo` |
142
+
143
+ Per-platform session-material types require these headers using the canonical names shown above while still allowing
144
+ additional captured headers. Captured request bodies are session material because they can contain sensitive data and
145
+ are encrypted before being sent to the service.
146
+
69
147
  ## Cache-Friendly Path
70
148
 
71
149
  ```ts
@@ -80,6 +158,19 @@ const encryptedUpload = await nitro.encryptSellerCredentialUpload({
80
158
  });
81
159
  ```
82
160
 
161
+ For buyer TEE flows with a cached attestation:
162
+
163
+ ```ts
164
+ const encryptedSessionMaterial = await nitro.encryptBuyerTeeSessionMaterial({
165
+ key: verified.attestedSellerUploadKey,
166
+ platform: "venmo",
167
+ actionType: "transfer_venmo",
168
+ sessionMaterial: {
169
+ Cookie: "<captured-cookie-header>",
170
+ },
171
+ });
172
+ ```
173
+
83
174
  The attested SPKI is stable within one enclave process. If the enclave restarts, cached keys become stale and upload decrypt will fail; fetch a fresh attestation for a new session.
84
175
 
85
176
  ## React Native Wiring
@@ -101,9 +192,13 @@ Any conforming `SubtleCrypto` works. The package does not require `Buffer`.
101
192
 
102
193
  ```ts
103
194
  import {
195
+ createEncryptedBuyerTeeSessionMaterial,
104
196
  createEncryptedSellerCredentialUpload,
197
+ encryptBuyerTeeSessionMaterial,
105
198
  encryptSellerCredentialUpload,
106
199
  fetchAndVerifyAttestation,
200
+ uploadSellerCredential,
201
+ verifyBuyerTeePayment,
107
202
  } from "@zkp2p/zkp2p-attestation";
108
203
  ```
109
204
 
@@ -4470,6 +4470,9 @@ function requireArray(value, label) {
4470
4470
  fail("PAYLOAD_FIELD_MISSING", `Attestation payload field ${label} must be an array`);
4471
4471
  }
4472
4472
 
4473
+ // src/timeout.ts
4474
+ var DEFAULT_TIMEOUT_MS = 1e4;
4475
+
4473
4476
  // src/trust/pins.ts
4474
4477
  var STAGING_PCR8 = "5636e3bd96f847cf12cfd9de7faa8cad0e6fa00962ce16ba185f8e5ea57105abb3cc9cc34f1e1e4de3444ceabcca7485";
4475
4478
  var PRODUCTION_PCR8 = "41a4ae0b9b96752cab5addb7d22689b3070e564e29f90a54316fa33fa38ea51387a6e887ea4f5a4b0cc34f69cea3f40e";
@@ -4518,7 +4521,6 @@ function findHostPin(hostPins, hostname) {
4518
4521
  }
4519
4522
 
4520
4523
  // src/fetchAndVerifyAttestation.ts
4521
- var DEFAULT_TIMEOUT_MS = 1e4;
4522
4524
  var DEFAULT_FRESHNESS_WINDOW_MS = 5 * 60 * 1e3;
4523
4525
  async function fetchAndVerifyAttestation(params) {
4524
4526
  const fetcher = resolveFetch(params.fetch);