@zkp2p/zkp2p-attestation 3.0.1 → 4.0.0-rc.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,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.0-rc.0
4
+
5
+ - Add X Money seller credential uploads and receipt-gated `register_xmoney` seller identity types. Mailbox credentials support Google OAuth, Microsoft OAuth, and iCloud Mail; standalone X Money identity requests remain unavailable.
6
+
7
+ - BREAKING: Monobank buyer TEE now uses entrepreneur business portal `gatewayState`/`browserId` credentials and `CLIENT_ID`/`TRANSACTION_ID` params. Retire the buyer Open API token shape; enforce settled UAH transfers and a service-owned 14-day timestamp buffer.
8
+
9
+ - Add typed X Money Buyer TEE requests with encrypted captured `url` and headers, and no public params. Replay the captured GraphQL operation ID and derive the transaction ID from the URL instead of accepting duplicate input.
10
+
11
+ - BREAKING: remove the retired HDFC Gmail buyer proof types and action. Amazon
12
+ Pay is the supported UPI buyer and seller verification path.
13
+
14
+ ## 3.1.0
15
+
16
+ - Remove the retired preproduction hostname and PCR8 from bundled trust pins.
17
+ - Add typed Venmo and PayPal dispute helpers for attested session encryption, `POST /dispute/verify`, and local `DisputeAttestation` verification. The helpers use the `ZKP2P DisputeVerifier` EIP-712 domain and `DisputeDetails` wire fields while keeping all extracted identifiers out of public params.
18
+
3
19
  ## 3.0.1
4
20
 
5
21
  - Restore the generic Buyer TEE compact JWE for standalone identity capture while retaining the Alipay types added in 3.0.0. `callerAddress` remains required on `POST /identity` and in the signed typed data, but is no longer required by identity encryption helpers or nested inside encrypted session material.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zkp2p/zkp2p-attestation
2
2
 
3
- Client-side verifier and encryptor for ZKP2P Nitro identity attestations, seller credential uploads, and buyer TEE session-material requests.
3
+ Client-side verifier and encryptor for ZKP2P Nitro payment, dispute, identity, and seller-credential flows.
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
 
@@ -33,7 +33,7 @@ Environment defaults:
33
33
  | `staging` | `https://attestation-service-staging.zkp2p.xyz` | bundled staging pin |
34
34
  | `production` | `https://attestation-service.zkp2p.xyz` | bundled production pin |
35
35
 
36
- Callers can still pass `attestationServiceUrl` and `trust.expectedPcr8Hex` directly. Explicit trust pins always win. The preprod hostname is pinned to the isolated preprod enclave; it is not a production alias.
36
+ Callers can still pass `attestationServiceUrl` and `trust.expectedPcr8Hex` directly. Explicit trust pins always win. Bundled trust is limited to the canonical staging and production hostnames.
37
37
 
38
38
  ## Fast Path
39
39
 
@@ -86,15 +86,17 @@ const encryptedUpload = await nitro.createEncryptedSellerCredentialUpload({
86
86
  });
87
87
  ```
88
88
 
89
+ Venmo Gmail OAuth uploads use the same encryption helper with numeric Venmo account id as `payeeId` and `sessionMaterial: { credentialSource: "google_oauth", authorizationCode, redirectUri, oauthClient? }`. The service binds a DKIM-verified receipt recipient to that account through Venmo's public profile API. The optional partner app secret and refresh token remain inside the encrypted seller bundle. Existing Venmo session-cookie uploads remain an independently supported credential type.
90
+
89
91
  PayPal Gmail OAuth seller uploads use the same app-selection model. Pass the seller PayPal email as `payeeId` and use `sessionMaterial: { credentialSource: "google_oauth", authorizationCode, redirectUri }`; the service validates Gmail access against paypal.com DKIM-signed payment receipts. To onboard through a partner-owned Google OAuth app, include `oauthClient: { clientId, clientSecret }` inside the encrypted `sessionMaterial`. The PayPal partner client secret is handled as seller credential material: it rides only in the compact JWE upload plaintext, is sealed with the Gmail refresh token in the KMS-envelope seller credential bundle, and is reused only to refresh that seller's Gmail access token.
90
92
 
91
93
  Buyer TEE requests use the same attested upload key and compact JWE envelope. The typed helper encrypts the captured
92
94
  session material, posts `{ encryptedSessionMaterial, params, chainId, intent }` to
93
95
  `POST /buyer/verify/:platform/:actionType`, unwraps the service envelope, and returns a typed `AttestationOutput`.
94
- The service does not enforce capture-age or one-use replay limits for buyer TEE session material; verification depends
95
- on the upstream session still being active. A leaked encrypted JWE is therefore valid for the upstream session
96
- lifetime — treat any accidental disclosure as equivalent to leaking the underlying upstream credential (cookies, PAT,
97
- etc.) and rotate the upstream session.
96
+ The service does not enforce capture-age or one-use replay limits for reusable
97
+ buyer TEE session material; verification depends on the upstream session still
98
+ being active. Treat any accidental JWE disclosure as equivalent to leaking its
99
+ underlying private evidence.
98
100
 
99
101
  ```ts
100
102
  const attestation = await nitro.verifyBuyerTeePayment({
@@ -153,19 +155,76 @@ Buyer TEE platform matrix:
153
155
  | `zelle` | `transfer_zelle_chase` | `Cookie`, `x-jpmc-channel`, `x-jpmc-csrf-token`, `Referer`, `Origin` | `index` |
154
156
  | `zelle` | `transfer_zelle_citi` | `Cookie` | `index` |
155
157
  | `paypal` | `transfer_paypal` | `Cookie` | `PAYMENT_ID` |
158
+ | `monobank` | `transfer_monobank` | `gatewayState`, `browserId` | `CLIENT_ID`, `TRANSACTION_ID` |
156
159
  | `alipay` | `transfer_alipay` | `Cookie` | `TRADE_NO` |
160
+ | `upi` | `transfer_upi_amazonpay` | `Cookie`, `User-Agent`, `body` | `TRANSACTION_URL` |
161
+ | `xmoney` | `transfer_xmoney` | `url`, `Cookie` and other captured session headers | `{}` |
162
+
163
+ Monobank buyer verification uses the entrepreneur business portal session. Capture
164
+ `localStorage.gateway` as `gatewayState`, and encode the raw P-256 public key from
165
+ `localStorage.browserId.publicKey` as unpadded base64url `browserId`. Encrypt both
166
+ inside the normal buyer JWE. `CLIENT_ID` selects the business profile and
167
+ `TRANSACTION_ID` selects its payment detail. The attestor constructs and encrypts
168
+ the bank request itself; caller-supplied payment JSON or encrypted request bodies
169
+ are rejected. It accepts settled outgoing UAH transfers (bank currency code 980),
170
+ hashes the recipient IBAN and bank payment ID, and signs a service-owned 14-day
171
+ buffer. The previous buyer Open API token shape is no longer accepted.
172
+
173
+ X Money replays the captured `url`, including X's current GraphQL operation ID,
174
+ just as Chime replays its captured `body`. Both stay inside encrypted session
175
+ material. The attestor owns endpoint and operation validation; X Money remains
176
+ GET-only on `https://x.com`, derives the transaction ID from the captured URL,
177
+ and requires the response ID to match. Ship the X Money extension capture and attestor changes
178
+ together; captures without `url` are rejected. Chime's contract is unchanged.
157
179
 
158
180
  Zelle buyer verification uses only `platform: "zelle"` with bank-specific action types. Every Zelle action attests
159
181
  `intent.paymentMethod = hashUtf8("zelle")`; direct bank-specific platforms are unsupported.
160
182
 
183
+ Amazon Pay uses `platform: "upi"` and `actionType: "transfer_upi_amazonpay"`.
184
+ Capture the `getTransactionHistory` GraphQL request after signing into Amazon
185
+ Pay and applying a transaction-history filter. Send its headers and exact request
186
+ body as encrypted session material, with only the selected history row's
187
+ `transactionDetailPageURL` as `params.TRANSACTION_URL`. The service rebuilds the
188
+ history query, confirms the selected outgoing payment, and fetches its receipt;
189
+ receipt URL labels alone do not establish payment direction. Both UPI actions use
190
+ the same `upi:<UPI reference>` payment-id preimage. Amazon session cookies remain
191
+ subject to server-side expiry or revocation; the package does not refresh them.
192
+
161
193
  Per-platform session-material types require these headers using the canonical names shown above while still allowing
162
194
  additional captured headers. Captured request bodies are session material because they can contain sensitive data and
163
195
  are encrypted before being sent to the service.
164
196
 
165
- Identity requests use the same generic attested upload envelope as buyer TEE. The typed request helper encrypts the
166
- captured session material, normalizes the outer `callerAddress`, posts
167
- `{ platform, actionType, callerAddress, encryptedSessionMaterial, params }` to the public `POST /identity` endpoint,
168
- unwraps the service response, and returns an `IdentityAttestationOutput`. `verifyIdentityAttestation` checks the EIP-712 signature, trusted signer,
197
+ Dispute verification uses the same attested key and compact JWE shape. The complete raw email stays encrypted, and all
198
+ payment, dispute, and amount fields come from its authenticated contents rather than public params.
199
+
200
+ ```ts
201
+ const dispute = await nitro.verifyDispute({
202
+ platform: "venmo",
203
+ actionType: "dispute_venmo",
204
+ sessionMaterial: { rawEmail: completeRfc5322Email },
205
+ params: {},
206
+ chainId,
207
+ intentHash,
208
+ });
209
+
210
+ const verifiedDispute = verifyDisputeAttestation(dispute, {
211
+ trustedSigners,
212
+ expectedPlatform: "venmo",
213
+ expectedActionType: "dispute_venmo",
214
+ expectedDomain: { chainId, verifyingContract: disputeVerifier },
215
+ expectedIntentHash: intentHash,
216
+ });
217
+ ```
218
+
219
+ Venmo uses `dispute_venmo`; PayPal uses `dispute_paypal`. Both accept only `{ rawEmail }` encrypted session material
220
+ and `{}` public params. `verifyDisputeAttestation` checks the DisputeVerifier EIP-712 domain, the same trusted
221
+ attestation-service witnesses used by payment and identity, the request intent, the signed data hash, and exact parity
222
+ between `disputeDetails` and `encodedDisputeDetails`.
223
+
224
+ Identity requests use the same attested upload key and compact JWE plaintext shape as buyer TEE, but with a narrower
225
+ platform/action matrix. The typed helper encrypts captured session material, posts
226
+ `{ platform, actionType, callerAddress, encryptedSessionMaterial, params }` to `POST /identity`, unwraps the service response, and
227
+ returns an `IdentityAttestationOutput`. `verifyIdentityAttestation` checks the EIP-712 signature, trusted signer,
169
228
  platform/action binding, expected caller address, expected payee hash, canonical identity `dataHash`, and `validUntil`,
170
229
  then returns normalized identity details.
171
230
 
@@ -215,7 +274,9 @@ For Cash App identity, pass the replayable Cash App session cookie as `sessionMa
215
274
 
216
275
  For Alipay identity, pass a replayable `Cookie` header. The service fetches the authenticated account page and signs
217
276
  the historical transfer-recipient preimage: normalized recipient name concatenated directly with the redacted,
218
- lowercased email. The full normalized email is returned as `identity.username` for Curator binding.
277
+ lowercased email. CJK names use their final CJK character to match Alipay's masked transfer detail; non-CJK names keep
278
+ the existing token normalization. The normalized full email remains `identity.username`; the authenticated account's
279
+ 16-digit PID is returned as `identity.metadata.alipayPid` for payment routing.
219
280
 
220
281
  Buyer TEE and identity expose discriminated unions keyed by `platform` and `actionType`, including per-platform
221
282
  `params`, so invalid pairings fail during TypeScript compilation. Seller credential upload keeps its existing
@@ -268,6 +329,17 @@ Identity helpers emit `{ platform, actionType, sessionMaterial, boundPubKeySha25
268
329
  like buyer TEE capture. The outer `callerAddress` is required by `POST /identity` and included in the signed typed data,
269
330
  but is not encrypted into or authenticated by the session envelope.
270
331
 
332
+ For dispute flows with a cached attestation:
333
+
334
+ ```ts
335
+ const encryptedSessionMaterial = await nitro.encryptDisputeSessionMaterial({
336
+ key: verified.attestedSellerUploadKey,
337
+ platform: "paypal",
338
+ actionType: "dispute_paypal",
339
+ sessionMaterial: { rawEmail: completeRfc5322Email },
340
+ });
341
+ ```
342
+
271
343
  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.
272
344
 
273
345
  ## React Native Wiring
@@ -290,18 +362,23 @@ Any conforming `SubtleCrypto` works. The package does not require `Buffer`.
290
362
  ```ts
291
363
  import {
292
364
  createEncryptedBuyerTeeSessionMaterial,
365
+ createEncryptedDisputeSessionMaterial,
293
366
  createEncryptedIdentitySessionMaterial,
294
367
  createEncryptedSellerCredentialUpload,
295
368
  encryptBuyerTeeSessionMaterial,
369
+ encryptDisputeSessionMaterial,
296
370
  encryptIdentitySessionMaterial,
297
371
  encryptSellerCredentialUpload,
298
372
  fetchAndVerifyAttestation,
299
373
  getUnifiedPaymentVerifierDomainSeparator,
374
+ getDisputeVerifierDomainSeparator,
300
375
  hashUtf8,
301
376
  requestIdentityAttestation,
302
377
  uploadSellerCredential,
303
378
  verifyBuyerTeePaymentAttestation,
304
379
  verifyBuyerTeePayment,
380
+ verifyDispute,
381
+ verifyDisputeAttestation,
305
382
  verifyIdentityAttestation,
306
383
  verifySellerCredentialBundle,
307
384
  } from "@zkp2p/zkp2p-attestation";
@@ -4510,10 +4510,8 @@ var DEFAULT_TIMEOUT_MS = 1e4;
4510
4510
  // src/trust/pins.ts
4511
4511
  var STAGING_PCR8 = "5636e3bd96f847cf12cfd9de7faa8cad0e6fa00962ce16ba185f8e5ea57105abb3cc9cc34f1e1e4de3444ceabcca7485";
4512
4512
  var PRODUCTION_PCR8 = "41a4ae0b9b96752cab5addb7d22689b3070e564e29f90a54316fa33fa38ea51387a6e887ea4f5a4b0cc34f69cea3f40e";
4513
- var PREPROD_PCR8 = "5453c5bfb7d040285be5ba9af142f4fbdd9685d082f244b66c62bf7b22d8d02a638fa2e02b9a6fe8877953a9429209e0";
4514
4513
  var DEFAULT_EXPECTED_PCR8_BY_HOST = {
4515
4514
  "attestation-service-staging.zkp2p.xyz": normalizePcr8Pin(STAGING_PCR8, "bundled staging PCR8"),
4516
- "attestation-service-preprod.zkp2p.xyz": normalizePcr8Pin(PREPROD_PCR8, "bundled preprod PCR8"),
4517
4515
  "attestation-service.zkp2p.xyz": normalizePcr8Pin(PRODUCTION_PCR8, "bundled production PCR8")
4518
4516
  };
4519
4517