@interop/was-react 0.8.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +55 -44
  2. package/dist/auth/chapi.d.ts.map +1 -1
  3. package/dist/auth/chapi.js +16 -5
  4. package/dist/auth/chapi.js.map +1 -1
  5. package/dist/auth/loginFlow.d.ts.map +1 -1
  6. package/dist/auth/loginFlow.js +55 -49
  7. package/dist/auth/loginFlow.js.map +1 -1
  8. package/dist/auth/verifyResponse.d.ts.map +1 -1
  9. package/dist/auth/verifyResponse.js +27 -10
  10. package/dist/auth/verifyResponse.js.map +1 -1
  11. package/dist/auth/walletRequestTypes.d.ts +9 -90
  12. package/dist/auth/walletRequestTypes.d.ts.map +1 -1
  13. package/dist/config.d.ts +9 -9
  14. package/dist/config.js +0 -0
  15. package/dist/dev/provisionDevGrants.d.ts.map +1 -1
  16. package/dist/dev/provisionDevGrants.js +18 -19
  17. package/dist/dev/provisionDevGrants.js.map +1 -1
  18. package/dist/grants.d.ts +19 -9
  19. package/dist/grants.d.ts.map +1 -1
  20. package/dist/grants.js +17 -2
  21. package/dist/grants.js.map +1 -1
  22. package/dist/identity/agents.d.ts +1 -1
  23. package/dist/identity/agents.d.ts.map +1 -1
  24. package/dist/identity/agents.js +10 -25
  25. package/dist/identity/agents.js.map +1 -1
  26. package/dist/identity/appSession.d.ts +27 -0
  27. package/dist/identity/appSession.d.ts.map +1 -1
  28. package/dist/identity/appSession.js +51 -13
  29. package/dist/identity/appSession.js.map +1 -1
  30. package/dist/identity/seedCredential.d.ts +7 -0
  31. package/dist/identity/seedCredential.d.ts.map +1 -1
  32. package/dist/identity/seedCredential.js +11 -14
  33. package/dist/identity/seedCredential.js.map +1 -1
  34. package/dist/identity/seedStore.d.ts +19 -0
  35. package/dist/identity/seedStore.d.ts.map +1 -1
  36. package/dist/identity/seedStore.js +40 -13
  37. package/dist/identity/seedStore.js.map +1 -1
  38. package/dist/index.d.ts +4 -5
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +3 -4
  41. package/dist/index.js.map +1 -1
  42. package/dist/jsonLd.d.ts +19 -0
  43. package/dist/jsonLd.d.ts.map +1 -0
  44. package/dist/jsonLd.js +24 -0
  45. package/dist/jsonLd.js.map +1 -0
  46. package/dist/mui/AdoptDialog.d.ts.map +1 -1
  47. package/dist/mui/AdoptDialog.js +7 -3
  48. package/dist/mui/AdoptDialog.js.map +1 -1
  49. package/dist/mui/ClearDataDialog.d.ts.map +1 -1
  50. package/dist/mui/ClearDataDialog.js +12 -11
  51. package/dist/mui/ClearDataDialog.js.map +1 -1
  52. package/dist/mui/ConfirmDialog.d.ts +35 -0
  53. package/dist/mui/ConfirmDialog.d.ts.map +1 -0
  54. package/dist/mui/ConfirmDialog.js +18 -0
  55. package/dist/mui/ConfirmDialog.js.map +1 -0
  56. package/dist/mui/LogoutDialog.d.ts.map +1 -1
  57. package/dist/mui/LogoutDialog.js +7 -3
  58. package/dist/mui/LogoutDialog.js.map +1 -1
  59. package/dist/react/documentApp.d.ts +29 -0
  60. package/dist/react/documentApp.d.ts.map +1 -1
  61. package/dist/react/documentApp.js +9 -38
  62. package/dist/react/documentApp.js.map +1 -1
  63. package/dist/react/hooks.d.ts +13 -7
  64. package/dist/react/hooks.d.ts.map +1 -1
  65. package/dist/react/hooks.js +17 -11
  66. package/dist/react/hooks.js.map +1 -1
  67. package/dist/session/authStore.d.ts +9 -9
  68. package/dist/session/authStore.d.ts.map +1 -1
  69. package/dist/session/authStore.js +203 -112
  70. package/dist/session/authStore.js.map +1 -1
  71. package/dist/storage/adopt.d.ts +5 -1
  72. package/dist/storage/adopt.d.ts.map +1 -1
  73. package/dist/storage/adopt.js +8 -24
  74. package/dist/storage/adopt.js.map +1 -1
  75. package/dist/storage/entityStore.d.ts.map +1 -1
  76. package/dist/storage/entityStore.js +27 -20
  77. package/dist/storage/entityStore.js.map +1 -1
  78. package/dist/storage/localStore.d.ts +12 -6
  79. package/dist/storage/localStore.d.ts.map +1 -1
  80. package/dist/storage/localStore.js +146 -77
  81. package/dist/storage/localStore.js.map +1 -1
  82. package/dist/storage/rehydrate.d.ts.map +1 -1
  83. package/dist/storage/rehydrate.js +20 -4
  84. package/dist/storage/rehydrate.js.map +1 -1
  85. package/dist/storage/sharedCollectionReader.d.ts +1 -1
  86. package/dist/storage/sharedCollectionReader.d.ts.map +1 -1
  87. package/dist/storage/sharedCollectionReader.js +79 -64
  88. package/dist/storage/sharedCollectionReader.js.map +1 -1
  89. package/dist/storage/storageManager.d.ts +3 -1
  90. package/dist/storage/storageManager.d.ts.map +1 -1
  91. package/dist/storage/storageManager.js +20 -6
  92. package/dist/storage/storageManager.js.map +1 -1
  93. package/dist/storage/syncController.d.ts +1 -16
  94. package/dist/storage/syncController.d.ts.map +1 -1
  95. package/dist/storage/syncController.js +48 -37
  96. package/dist/storage/syncController.js.map +1 -1
  97. package/dist/storage/syncStatusStore.d.ts +8 -6
  98. package/dist/storage/syncStatusStore.d.ts.map +1 -1
  99. package/dist/storage/syncStatusStore.js +6 -6
  100. package/dist/storage/syncStatusStore.js.map +1 -1
  101. package/dist/storage/wasRemoteStore.d.ts +34 -2
  102. package/dist/storage/wasRemoteStore.d.ts.map +1 -1
  103. package/dist/storage/wasRemoteStore.js +45 -7
  104. package/dist/storage/wasRemoteStore.js.map +1 -1
  105. package/dist/storage/wasSync.d.ts.map +1 -1
  106. package/dist/storage/wasSync.js +47 -38
  107. package/dist/storage/wasSync.js.map +1 -1
  108. package/dist/sync/changesQuery.d.ts.map +1 -1
  109. package/dist/sync/changesQuery.js +2 -9
  110. package/dist/sync/changesQuery.js.map +1 -1
  111. package/dist/sync/docCipher.d.ts +23 -10
  112. package/dist/sync/docCipher.d.ts.map +1 -1
  113. package/dist/sync/docCipher.js +17 -11
  114. package/dist/sync/docCipher.js.map +1 -1
  115. package/dist/sync/feedMasterPort.d.ts +6 -0
  116. package/dist/sync/feedMasterPort.d.ts.map +1 -1
  117. package/dist/sync/feedMasterPort.js +82 -37
  118. package/dist/sync/feedMasterPort.js.map +1 -1
  119. package/dist/sync/index.d.ts +6 -5
  120. package/dist/sync/index.d.ts.map +1 -1
  121. package/dist/sync/index.js +6 -3
  122. package/dist/sync/index.js.map +1 -1
  123. package/dist/sync/lww.d.ts +27 -18
  124. package/dist/sync/lww.d.ts.map +1 -1
  125. package/dist/sync/lww.js +35 -8
  126. package/dist/sync/lww.js.map +1 -1
  127. package/dist/sync/lwwConflictHandler.d.ts +15 -14
  128. package/dist/sync/lwwConflictHandler.d.ts.map +1 -1
  129. package/dist/sync/lwwConflictHandler.js +37 -26
  130. package/dist/sync/lwwConflictHandler.js.map +1 -1
  131. package/dist/sync/pushWrites.d.ts +9 -9
  132. package/dist/sync/pushWrites.d.ts.map +1 -1
  133. package/dist/sync/pushWrites.js +102 -68
  134. package/dist/sync/pushWrites.js.map +1 -1
  135. package/dist/sync/syncedDocSchema.d.ts.map +1 -1
  136. package/dist/sync/syncedDocSchema.js +3 -0
  137. package/dist/sync/syncedDocSchema.js.map +1 -1
  138. package/dist/sync/types.d.ts +115 -15
  139. package/dist/sync/types.d.ts.map +1 -1
  140. package/dist/sync/types.js +36 -18
  141. package/dist/sync/types.js.map +1 -1
  142. package/dist/sync/wasSyncPort.d.ts +0 -11
  143. package/dist/sync/wasSyncPort.d.ts.map +1 -1
  144. package/dist/sync/wasSyncPort.js +20 -36
  145. package/dist/sync/wasSyncPort.js.map +1 -1
  146. package/package.json +6 -6
  147. package/dist/identity/initAppSession.d.ts +0 -27
  148. package/dist/identity/initAppSession.d.ts.map +0 -1
  149. package/dist/identity/initAppSession.js +0 -30
  150. package/dist/identity/initAppSession.js.map +0 -1
package/README.md CHANGED
@@ -64,6 +64,11 @@ pnpm add react zustand rxdb
64
64
  `@interop/was-react/mui` entry additionally needs `@mui/material`,
65
65
  `@mui/icons-material`, and `react-router`; the core entry never imports them.
66
66
 
67
+ No particular bundler is required: the library reads `import.meta.env.MODE` (a
68
+ Vite convention) only defensively, so webpack / Rspack / Parcel builds and Node
69
+ SSR imports work; without it, non-production-only affordances (the e2e CHAPI
70
+ bridge) simply stay off.
71
+
67
72
  ```
68
73
  pnpm add @mui/material @mui/icons-material @emotion/react @emotion/styled react-router
69
74
  ```
@@ -96,9 +101,9 @@ WAS collection `id` (a deliberately unprefixed, generic name shared across
96
101
  interoperable apps). `credential` names the self-issued seed credential the
97
102
  first-run flow mints; its `vocabBase` namespaces the app's own type term only,
98
103
  since every app key also carries the shared `AppKeyCredential` marker type and
99
- its `seed` / `origin` claims under `urn:was:` IRIs. All other fields
100
- (`mediatorBase`, `dbName`, `storageKeyPrefix`, `sync`, `expiry`) are optional
101
- with documented defaults.
104
+ its `seed` / `origin` claims under `https://w3id.org/byoe#` IRIs. All other
105
+ fields (`mediatorBase`, `dbName`, `storageKeyPrefix`, `sync`, `expiry`) are
106
+ optional with documented defaults.
102
107
 
103
108
  A collection may also declare `visibility: 'public'`
104
109
  (`{ key: 'posts', id: 'microblog-posts', visibility: 'public' }`); the default
@@ -119,11 +124,11 @@ carry the `updatedAt` / `clientId` LWW fields like any other collection --
119
124
  without them a concurrent multi-device edit falls back to server-wins.
120
125
 
121
126
  At login, a public collection is requested from the wallet with the distinct
122
- `urn:was:public-collection` descriptor type (private collections use
123
- `urn:was:collection`): the wallet provisions it plaintext with a public-read
124
- policy, shows a world-readable consent warning, and delegates the usual
125
- read/write capability (public covers only unauthenticated reads; writes stay
126
- capability-only). A wallet that predates the descriptor reports the request
127
+ `https://w3id.org/byoe#public-collection` descriptor type (private collections
128
+ use `https://w3id.org/byoe#collection`): the wallet provisions it plaintext with
129
+ a public-read policy, shows a world-readable consent warning, and delegates the
130
+ usual read/write capability (public covers only unauthenticated reads; writes
131
+ stay capability-only). A wallet that predates the descriptor reports the request
127
132
  unsatisfiable rather than silently provisioning a private collection, so the
128
133
  feature fails closed with older wallets. Publicness is granted at consent time
129
134
  by the wallet -- the app itself can never escalate an existing private
@@ -168,14 +173,14 @@ the same `key` or `id` in each is rejected at store open
168
173
  (`validateSharedCollections`).
169
174
 
170
175
  At login each shared collection is requested with the distinct
171
- `urn:was:shared-collection` descriptor type and the read-only action set
172
- `SHARED_ACTIONS` (`GET`/`HEAD`) -- an app never asks to write a wallet
173
- collection. As with `urn:was:public-collection`, a wallet that predates the type
174
- reports the request unsatisfiable and the feature fails closed, which is the
175
- point: a share fuses two axes -- the read zcap AND an entry in the collection's
176
- key-epoch roster -- and a wallet that granted only the zcap would hand the app
177
- ciphertext it cannot decrypt, surfacing as corrupt data rather than as a wallet
178
- that needs updating.
176
+ `https://w3id.org/byoe#shared-collection` descriptor type and the read-only
177
+ action set `SHARED_ACTIONS` (`GET`/`HEAD`) -- an app never asks to write a
178
+ wallet collection. As with `https://w3id.org/byoe#public-collection`, a wallet
179
+ that predates the type reports the request unsatisfiable and the feature fails
180
+ closed, which is the point: a share fuses two axes -- the read zcap AND an entry
181
+ in the collection's key-epoch roster -- and a wallet that granted only the zcap
182
+ would hand the app ciphertext it cannot decrypt, surfacing as corrupt data
183
+ rather than as a wallet that needs updating.
179
184
 
180
185
  Decryption uses the app's **identity** key-agreement key: the X25519 twin of its
181
186
  `did:key` controller (`IdentityAgents.keyAgreementKey`), which is exactly what
@@ -249,8 +254,7 @@ export function Root() {
249
254
  import { useLogin } from '@interop/was-react'
250
255
 
251
256
  export function LoginPage() {
252
- const { login, status, phase, error } = useLogin()
253
- const busy = status === 'authenticating'
257
+ const { login, authenticating: busy, phase, error } = useLogin()
254
258
 
255
259
  return (
256
260
  <div>
@@ -268,12 +272,13 @@ export function LoginPage() {
268
272
 
269
273
  ```tsx
270
274
  import { uuidv7 } from 'uuidv7'
271
- import { getClientId } from '@interop/was-react'
275
+ import { useSession } from '@interop/was-react'
272
276
  import { useNotes } from './stores.js'
273
277
 
274
278
  export function Notes() {
275
279
  const notes = useNotes(state => [...state.byId.values()])
276
280
  const insert = useNotes(state => state.insert)
281
+ const { clientId } = useSession()
277
282
 
278
283
  async function addNote() {
279
284
  const now = new Date().toISOString()
@@ -283,7 +288,7 @@ export function Notes() {
283
288
  body: '',
284
289
  createdAt: now,
285
290
  updatedAt: now,
286
- clientId: getClientId()
291
+ clientId
287
292
  })
288
293
  }
289
294
 
@@ -300,10 +305,12 @@ export function Notes() {
300
305
  }
301
306
  ```
302
307
 
303
- Entity payloads MUST carry `updatedAt` and `clientId` (from `getClientId()`),
304
- stamped on EVERY insert and update: they are the last-write-wins pair that
305
- settles concurrent multi-device edits of the same entity. A payload without them
306
- loses every sync conflict.
308
+ Entity payloads MUST carry `updatedAt` and `clientId`, stamped on EVERY insert
309
+ and update: they are the last-write-wins pair that settles concurrent
310
+ multi-device edits of the same entity. A payload without them loses every sync
311
+ conflict. Read the id from `useSession().clientId` (resolved once per session,
312
+ honoring `storageKeyPrefix`); outside React, call
313
+ `getClientId({ storageKeyPrefix })` with the same prefix your config declares.
307
314
 
308
315
  A public collection can additionally answer server-side equality queries.
309
316
  Declare the queryable content attributes in the collection config:
@@ -388,9 +395,9 @@ a progress line (`connecting` to `verifying`):
388
395
  2. **One popup.** A VPR carrying a `DIDAuthentication` query plus one
389
396
  `AppConnectQuery` -- the app's display name, `credentialType`, and
390
397
  `vocabBase`, a `capabilityQuery` entry per configured collection, and a
391
- `urn:was:shared-collection` entry per shared collection -- is sent via
392
- `navigator.credentials.get` (`buildAppConnectVpr`). A `null` response is a
393
- user cancel (`LoginCancelledError`), not an error.
398
+ `https://w3id.org/byoe#shared-collection` entry per shared collection -- is
399
+ sent via `navigator.credentials.get` (`buildAppConnectVpr`). A `null`
400
+ response is a user cancel (`LoginCancelledError`), not an error.
394
401
  3. **The wallet matches or mints.** On a first run the wallet generates the
395
402
  32-byte seed itself, self-issues the origin-bound app-key credential, and
396
403
  stores it in its own credential store under the same consent; on a returning
@@ -407,8 +414,7 @@ a progress line (`connecting` to `verifying`):
407
414
  and seed-to-DID bound, then recovers the seed.
408
415
  6. **Derive identity.** The stable `did:key` controller and its signer are
409
416
  derived deterministically from the seed via `CapabilityAgent.fromSeed`
410
- (`initAppSession` / `deriveIdentity`). The same seed yields the same identity
411
- on every device.
417
+ (`deriveIdentity`). The same seed yields the same identity on every device.
412
418
  7. **Check grants.** The delegated zcaps ride in the same presentation's
413
419
  top-level `zcap` array. `checkGrants` asserts every zcap is controlled by the
414
420
  app DID, shares one space on a single WAS host, covers each configured
@@ -424,10 +430,11 @@ a progress line (`connecting` to `verifying`):
424
430
  ## Session lifecycle
425
431
 
426
432
  The session is owned by a zustand auth store built once per app by the provider
427
- (`createAuthStore`). Its `status` is `idle` to `restoring` to `unauthenticated`
428
- / `authenticating` / `authenticated`, and it is the router gate: a protected
429
- route waits for the restore attempt to settle before choosing between the app
430
- and the login page.
433
+ (`createAuthStore`). Its `status` is `boot` to `local` / `connected` /
434
+ `reconnect`, and it is the router gate: a protected route waits for the restore
435
+ attempt to settle before choosing between the app and the login page. A login in
436
+ flight is NOT a status -- it is the `phase` field, which `useSession()` /
437
+ `useLogin()` also surface as the derived boolean `authenticating`.
431
438
 
432
439
  - **Restore (zero popups).** On mount, `restore()` reads the persisted session
433
440
  from IndexedDB and, if present and consistent, re-derives the identity, opens
@@ -436,7 +443,8 @@ and the login page.
436
443
  - **Login.** `useLogin().login()` runs the full [login flow](#login-flow).
437
444
  - **Reconnect.** Grants are expiry-only. The store watches the earliest grant
438
445
  expiry and, once within the warning window (`expiry.warningMs`, default 1h) or
439
- after a live 401/403, sets `accessExpired`. `useReconnect().reconnect()`
446
+ after a live 401/403, moves the status to `reconnect` (which `useReconnect()`
447
+ surfaces as the derived `accessExpired`). `useReconnect().reconnect()`
440
448
  re-requests grants with the existing seed (one wallet popup, same identity,
441
449
  same data) and restarts sync.
442
450
  - **Logout.** `useLogout()` stops sync, closes and forgets the local store,
@@ -447,15 +455,15 @@ and the login page.
447
455
 
448
456
  Hooks:
449
457
 
450
- | Hook | Returns |
451
- | ----------------- | --------------------------------------------------------------------------------------- |
452
- | `useSession()` | `status`, `phase`, `error`, `controllerDid`, `expires`, `accessExpired`, `reconnecting` |
453
- | `useLogin()` | `{ login, status, phase, error }` |
454
- | `useLogout()` | `() => Promise<void>` |
455
- | `useReconnect()` | `{ accessExpired, reconnecting, reconnect }` |
456
- | `useSyncStatus()` | `{ state, label, title }` (see below) |
457
- | `useAppReady()` | `{ ready, error }` -- the hydration gate |
458
- | `useAuthStore()` | the bound vanilla store (for `getState().restore()`, etc.) |
458
+ | Hook | Returns |
459
+ | ----------------- | --------------------------------------------------------------------------------------------------------- |
460
+ | `useSession()` | `status`, `phase`, `authenticating`, `error`, `controllerDid`, `expires`, `accessExpired`, `reconnecting` |
461
+ | `useLogin()` | `{ login, authenticating, status, phase, error }` |
462
+ | `useLogout()` | `() => Promise<void>` |
463
+ | `useReconnect()` | `{ accessExpired, reconnecting, reconnect }` |
464
+ | `useSyncStatus()` | `{ state, label, title }` (see below) |
465
+ | `useAppReady()` | `{ ready, error }` -- the hydration gate |
466
+ | `useAuthStore()` | the bound vanilla store (for `getState().restore()`, etc.) |
459
467
 
460
468
  ## Sync architecture
461
469
 
@@ -486,7 +494,10 @@ Hooks:
486
494
  with `sequence`+1 (a mutable-head model); deletes are soft-delete tombstones.
487
495
  - **Status.** `useSyncStatus()` rolls the per-collection replication states up
488
496
  to an aggregate: `offline` (no replication running / local-only), or
489
- `error > syncing > synced`. The `SyncStatusChip` MUI component renders it.
497
+ `error > syncing > synced`. The `SyncStatusChip` MUI component renders it. The
498
+ underlying `useSyncStatusStore().statuses` map is keyed by the registry's
499
+ logical collection `key`, like every other layer (two entries may share one
500
+ WAS collection `id`, so the id is not a unique status key).
490
501
 
491
502
  ## Entry points
492
503
 
@@ -1 +1 @@
1
- {"version":3,"file":"chapi.d.ts","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAE1D;;GAEG;AACH,eAAO,MAAM,qBAAqB,sCAAsC,CAAA;AAuDxE;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,EAC9B,YAAoC,EACrC,GAAE;IACD,YAAY,CAAC,EAAE,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,EAC7B,GAAG,EACH,YAAY,EACb,EAAE;IACD,GAAG,EAAE,WAAW,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAgB1C"}
1
+ {"version":3,"file":"chapi.d.ts","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAE1D;;GAEG;AACH,eAAO,MAAM,qBAAqB,sCAAsC,CAAA;AAgExE;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,EAC9B,YAAoC,EACrC,GAAE;IACD,YAAY,CAAC,EAAE,MAAM,CAAA;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAAC,EAC7B,GAAG,EACH,YAAY,EACb,EAAE;IACD,GAAG,EAAE,WAAW,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAgB1C"}
@@ -22,20 +22,31 @@ import { loadOnce } from 'credential-handler-polyfill';
22
22
  * The default CHAPI mediator base; the requesting origin is appended at load.
23
23
  */
24
24
  export const DEFAULT_MEDIATOR_BASE = 'https://authn.io/mediator?origin=';
25
+ /**
26
+ * The build mode, read defensively: `import.meta.env` exists only under Vite
27
+ * (a devDependency here, not a required consumer toolchain), so a webpack /
28
+ * Rspack / Parcel bundle -- or a Node SSR import -- has no `env` object at
29
+ * all. Treat that as a production build (the safe direction: the e2e bridge
30
+ * stays off).
31
+ */
32
+ function buildMode() {
33
+ return import.meta.env?.MODE ?? 'production';
34
+ }
25
35
  function e2eBridgeActive() {
26
- return (import.meta.env.MODE !== 'production' &&
36
+ return (buildMode() !== 'production' &&
27
37
  window.__WAS_REACT_E2E_CHAPI__ === true);
28
38
  }
29
39
  let e2eRequestId = 0;
30
40
  /**
31
- * Queues a request for the e2e harness and polls for its response.
41
+ * Queues a `get` request for the e2e harness and polls for its response (the
42
+ * one-popup flow rides `get` alone, so that is the only queued request type).
32
43
  */
33
- async function e2eRoundTrip(type, body) {
44
+ async function e2eRoundTrip(body) {
34
45
  const win = window;
35
46
  win.__WAS_REACT_E2E_CHAPI_REQUESTS__ ??= [];
36
47
  win.__WAS_REACT_E2E_CHAPI_RESPONSES__ ??= {};
37
48
  const id = ++e2eRequestId;
38
- win.__WAS_REACT_E2E_CHAPI_REQUESTS__.push({ id, type, body });
49
+ win.__WAS_REACT_E2E_CHAPI_REQUESTS__.push({ id, type: 'get', body });
39
50
  const deadline = Date.now() + 120_000;
40
51
  while (Date.now() < deadline) {
41
52
  if (id in win.__WAS_REACT_E2E_CHAPI_RESPONSES__) {
@@ -75,7 +86,7 @@ export async function loadChapi({ mediatorBase = DEFAULT_MEDIATOR_BASE } = {}) {
75
86
  export async function chapiGet({ vpr, mediatorBase }) {
76
87
  let wire;
77
88
  if (e2eBridgeActive()) {
78
- wire = await e2eRoundTrip('get', vpr);
89
+ wire = await e2eRoundTrip(vpr);
79
90
  }
80
91
  else {
81
92
  await loadChapi(mediatorBase !== undefined ? { mediatorBase } : {});
@@ -1 +1 @@
1
- {"version":3,"file":"chapi.js","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qCAAqC;AACrC;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AAItD;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,mCAAmC,CAAA;AAoBxE,SAAS,eAAe;IACtB,OAAO,CACL,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY;QACpC,MAA0B,CAAC,uBAAuB,KAAK,IAAI,CAC7D,CAAA;AACH,CAAC;AAED,IAAI,YAAY,GAAG,CAAC,CAAA;AAEpB;;GAEG;AACH,KAAK,UAAU,YAAY,CACzB,IAAqB,EACrB,IAAa;IAEb,MAAM,GAAG,GAAG,MAAyB,CAAA;IACrC,GAAG,CAAC,gCAAgC,KAAK,EAAE,CAAA;IAC3C,GAAG,CAAC,iCAAiC,KAAK,EAAE,CAAA;IAC5C,MAAM,EAAE,GAAG,EAAE,YAAY,CAAA;IACzB,GAAG,CAAC,gCAAgC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAA;IACrC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,EAAE,IAAI,GAAG,CAAC,iCAAiC,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,GAAG,CAAC,iCAAiC,CAAC,EAAE,CAAC,CAAA;YACvD,OAAO,GAAG,CAAC,iCAAiC,CAAC,EAAE,CAAC,CAAA;YAChD,OAAO,KAAK,IAAI,IAAI,CAAA;QACtB,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;IACxD,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;AACvE,CAAC;AAED,IAAI,cAAc,GAAG,KAAK,CAAA;AAE1B;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAC9B,YAAY,GAAG,qBAAqB,KAGlC,EAAE;IACJ,IAAI,cAAc,IAAI,eAAe,EAAE,EAAE,CAAC;QACxC,OAAM;IACR,CAAC;IACD,MAAM,QAAQ,CAAC,YAAY,GAAG,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;IACzE,cAAc,GAAG,IAAI,CAAA;AACvB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,EAC7B,GAAG,EACH,YAAY,EAIb;IACC,IAAI,IAA8B,CAAA;IAClC,IAAI,eAAe,EAAE,EAAE,CAAC;QACtB,IAAI,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACvC,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACnE,MAAM,MAAM,GAAG,CAAC,MAAM,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC;YAC9C,uEAAuE;YACvE,GAAG,EAAE,EAAE,sBAAsB,EAAE,GAAG,EAAE;SACT,CAAC,CAAwC,CAAA;QACtE,IAAI,GAAG,MAAM,CAAA;IACf,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC3D,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,IAAI,CAAC,IAA+B,CAAA;AAC7C,CAAC"}
1
+ {"version":3,"file":"chapi.js","sourceRoot":"","sources":["../../src/auth/chapi.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"loginFlow.d.ts","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAEV,KAAK,EACN,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,WAAW,EAAE,sBAAsB,EAAE,CAAA;IACrC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B;;OAEG;IACH,UAAU,EAAE,oBAAoB,CAAA;IAChC;;OAEG;IACH,cAAc,EAAE,cAAc,CAAA;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,WAAW,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,EAAE,YAAY,CAAA;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;;CAQhD;AAiED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,OAAO,EACR,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,aAAa,CAAC,CAqCzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,OAAO,EACR,EAAE;IACD,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,YAAY,CAAC,CAsExB"}
1
+ {"version":3,"file":"loginFlow.d.ts","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAEV,KAAK,EACN,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAE3D,OAAO,EAGL,KAAK,sBAAsB,EAC5B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;OAGG;IACH,WAAW,EAAE,sBAAsB,EAAE,CAAA;IACrC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B;;OAEG;IACH,UAAU,EAAE,oBAAoB,CAAA;IAChC;;OAEG;IACH,cAAc,EAAE,cAAc,CAAA;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,WAAW,CAAA;AAEnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,MAAM,EAAE,YAAY,CAAA;IACpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;;CAQhD;AA4HD;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,OAAO,EACR,EAAE;IACD,QAAQ,EAAE,cAAc,CAAA;IACxB,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,aAAa,CAAC,CAczB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,OAAO,EACR,EAAE;IACD,MAAM,EAAE,WAAW,CAAA;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CACtC,GAAG,OAAO,CAAC,YAAY,CAAC,CAkDxB"}
@@ -1,5 +1,5 @@
1
1
  import { findSeedCredential, parseSeedCredential } from '../identity/seedCredential.js';
2
- import { initAppSession } from '../identity/initAppSession.js';
2
+ import { NO_EXPIRY_MS } from '../identity/appSession.js';
3
3
  import { chapiGet } from './chapi.js';
4
4
  import { buildAppConnectVpr, newChallenge } from './loginRequest.js';
5
5
  import { checkGrants, grantsOf, verifyLoginPresentation } from './verifyResponse.js';
@@ -25,11 +25,6 @@ export class WalletUnsupportedError extends Error {
25
25
  this.name = 'WalletUnsupportedError';
26
26
  }
27
27
  }
28
- /**
29
- * A nominal far-future expiry (ms) used when an app requests no collections (so
30
- * there are no grants and thus no earliest-expiry to report).
31
- */
32
- const NO_GRANTS_EXPIRY_MS = 100 * 365 * 24 * 60 * 60 * 1000;
33
28
  /**
34
29
  * Reads the wallet-provided `presentation.appConnect.firstRun` boolean. Anything
35
30
  * other than boolean `true` (including an absent member -- a returning login) is
@@ -42,10 +37,14 @@ function appConnectFirstRun(presentation) {
42
37
  }
43
38
  /**
44
39
  * Structurally validates the grants embedded in the wallet response against the
45
- * requested collections. When the app requested NO collections at all (neither
46
- * app-owned nor shared) there is nothing to delegate: `checkGrants` (which
47
- * rejects an empty grant set) is skipped and an empty grant set with a
48
- * far-future expiry is returned instead.
40
+ * requested collections. When the app requested no APP-OWNED collections and
41
+ * the wallet returned no grants there is nothing to validate: `checkGrants`
42
+ * (which rejects an empty grant set) is skipped and an empty grant set with a
43
+ * far-future expiry is returned instead. That covers both the app that
44
+ * requests nothing at all and the shared-only app (`collections: []`, some
45
+ * `sharedCollections`) whose user declined every share -- a declined share is
46
+ * not a login failure, so such a login completes with no remote storage and
47
+ * the missing readers are warned about downstream.
49
48
  *
50
49
  * Only the app-owned collections are REQUIRED to be covered. A shared
51
50
  * collection the wallet declined to grant is not a login failure -- the reader
@@ -62,32 +61,39 @@ function appConnectFirstRun(presentation) {
62
61
  */
63
62
  function checkGrantsForCollections({ presentation, controllerDid, collections, sharedCollections = [] }) {
64
63
  const collectionIds = collections.map(collection => collection.id);
65
- if (collectionIds.length === 0 && sharedCollections.length === 0) {
64
+ const grants = grantsOf(presentation);
65
+ if (collectionIds.length === 0 && grants.length === 0) {
66
+ if (sharedCollections.length > 0) {
67
+ console.warn('The wallet returned no storage grants; the requested shared ' +
68
+ `collection(s) [${sharedCollections.join(', ')}] were declined, so ` +
69
+ 'no shared reader will be opened.');
70
+ }
66
71
  return {
67
72
  grants: [],
68
73
  parsed: { serverUrl: '', spaceId: '', byCollectionId: {} },
69
- expires: new Date(Date.now() + NO_GRANTS_EXPIRY_MS).toISOString()
74
+ expires: new Date(Date.now() + NO_EXPIRY_MS).toISOString()
70
75
  };
71
76
  }
72
77
  return checkGrants({
73
- grants: grantsOf(presentation),
78
+ grants,
74
79
  controllerDid,
75
80
  collections: collectionIds
76
81
  });
77
82
  }
78
83
  /**
79
- * Re-requests storage grants for `identity` over a fresh App Connect popup and
80
- * validates them. The expired-access reconnect path: the seed already exists, so
81
- * only the grants need renewing. The wallet matches the same app key and
82
- * re-delegates; the returned credential/`appConnect` marker are ignored here.
84
+ * Runs one App Connect round trip: builds the VPR, opens the single CHAPI `get`
85
+ * popup, and verifies the response presentation (cryptographically, plus the
86
+ * challenge/domain binds). Shared by the full login and the reconnect re-grant
87
+ * -- the same request either way; they differ only in what they take from the
88
+ * verified presentation, and in the step a user cancel names.
83
89
  *
84
90
  * @param options {object}
85
- * @param options.identity {IdentityAgents}
86
91
  * @param options.config {LoginConfig}
92
+ * @param options.cancelStep {string} the step a cancel is reported against
87
93
  * @param [options.onPhase] {Function}
88
- * @returns {Promise<CheckedGrants>}
94
+ * @returns {Promise<IVerifiablePresentation>}
89
95
  */
90
- export async function requestGrants({ identity, config, onPhase }) {
96
+ async function runAppConnect({ config, cancelStep, onPhase }) {
91
97
  onPhase?.('connecting');
92
98
  const challenge = newChallenge();
93
99
  const vpr = buildAppConnectVpr({
@@ -107,7 +113,7 @@ export async function requestGrants({ identity, config, onPhase }) {
107
113
  })
108
114
  });
109
115
  if (!presentation) {
110
- throw new LoginCancelledError('storage grants');
116
+ throw new LoginCancelledError(cancelStep);
111
117
  }
112
118
  onPhase?.('verifying');
113
119
  await verifyLoginPresentation({
@@ -116,6 +122,26 @@ export async function requestGrants({ identity, config, onPhase }) {
116
122
  domain: window.location.origin,
117
123
  documentLoader: config.documentLoader
118
124
  });
125
+ return presentation;
126
+ }
127
+ /**
128
+ * Re-requests storage grants for `identity` over a fresh App Connect popup and
129
+ * validates them. The expired-access reconnect path: the seed already exists, so
130
+ * only the grants need renewing. The wallet matches the same app key and
131
+ * re-delegates; the returned credential/`appConnect` marker are ignored here.
132
+ *
133
+ * @param options {object}
134
+ * @param options.identity {IdentityAgents}
135
+ * @param options.config {LoginConfig}
136
+ * @param [options.onPhase] {Function}
137
+ * @returns {Promise<CheckedGrants>}
138
+ */
139
+ export async function requestGrants({ identity, config, onPhase }) {
140
+ const presentation = await runAppConnect({
141
+ config,
142
+ cancelStep: 'storage grants',
143
+ ...(onPhase && { onPhase })
144
+ });
119
145
  return checkGrantsForCollections({
120
146
  presentation,
121
147
  controllerDid: identity.controllerDid,
@@ -140,33 +166,10 @@ export async function requestGrants({ identity, config, onPhase }) {
140
166
  * @returns {Promise<LoginOutcome>}
141
167
  */
142
168
  export async function loginWithWallet({ config, onPhase }) {
143
- onPhase?.('connecting');
144
- const challenge = newChallenge();
145
- const vpr = buildAppConnectVpr({
146
- challenge,
147
- domain: window.location.origin,
148
- appName: config.appName,
149
- credential: config.credential,
150
- collections: config.collections,
151
- ...(config.sharedCollections && {
152
- sharedCollections: config.sharedCollections
153
- })
154
- });
155
- const presentation = await chapiGet({
156
- vpr,
157
- ...(config.mediatorBase !== undefined && {
158
- mediatorBase: config.mediatorBase
159
- })
160
- });
161
- if (!presentation) {
162
- throw new LoginCancelledError('wallet login');
163
- }
164
- onPhase?.('verifying');
165
- await verifyLoginPresentation({
166
- presentation,
167
- challenge,
168
- domain: window.location.origin,
169
- documentLoader: config.documentLoader
169
+ const presentation = await runAppConnect({
170
+ config,
171
+ cancelStep: 'wallet login',
172
+ ...(onPhase && { onPhase })
170
173
  });
171
174
  // The wallet mints the app key on first run, so a response with no app-key
172
175
  // credential is not first run -- it is a wallet that could not satisfy
@@ -188,7 +191,10 @@ export async function loginWithWallet({ config, onPhase }) {
188
191
  });
189
192
  const seed = parsedCredential.seed;
190
193
  const firstRun = appConnectFirstRun(presentation);
191
- const identity = await initAppSession({ seed });
194
+ // The master identity comes off the parse, which already derived it from this
195
+ // seed to check the seed-to-DID binding (the same `deriveIdentity` call, and
196
+ // the same 32-byte seed rule, every other session path applies).
197
+ const identity = parsedCredential.identity;
192
198
  // Grants ride in the SAME response; validate them against the app-key subject
193
199
  // DID the wallet delegated to.
194
200
  const checked = checkGrantsForCollections({
@@ -1 +1 @@
1
- {"version":3,"file":"loginFlow.js","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loginFlow.js","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"verifyResponse.d.ts","sourceRoot":"","sources":["../../src/auth/verifyResponse.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EACV,uBAAuB,EACvB,KAAK,EACN,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAc7D;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,YAAY,EACZ,SAAS,EACT,MAAM,EACN,cAAc,EACf,EAAE;IACD,YAAY,EAAE,uBAAuB,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,cAAc,CAAA;CAC/B,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDhB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,YAAY,EAAE,uBAAuB,GAAG,KAAK,EAAE,CAMvE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;CAChB;AAUD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,aAAa,EACb,WAAW,EACX,eAA4B,EAC7B,EAAE;IACD,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B,GAAG,aAAa,CAyChB"}
1
+ {"version":3,"file":"verifyResponse.d.ts","sourceRoot":"","sources":["../../src/auth/verifyResponse.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EACV,uBAAuB,EACvB,KAAK,EACN,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AAK7D;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,YAAY,EACZ,SAAS,EACT,MAAM,EACN,cAAc,EACf,EAAE;IACD,YAAY,EAAE,uBAAuB,CAAA;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,cAAc,CAAA;CAC/B,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EhB;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,YAAY,EAAE,uBAAuB,GAAG,KAAK,EAAE,CAMvE;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;CAChB;AASD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,aAAa,EACb,WAAW,EACX,eAA4B,EAC7B,EAAE;IACD,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B,GAAG,aAAa,CAyChB"}
@@ -28,6 +28,7 @@
28
28
  import { verifyPresentation } from '@interop/verifier-core';
29
29
  import { parseGrants } from '../grants.js';
30
30
  import { earliestExpiry, isExpired } from '../identity/appSession.js';
31
+ import { asArray } from '../jsonLd.js';
31
32
  import { RW_ACTIONS } from './loginRequest.js';
32
33
  /**
33
34
  * Verifies a login response VP cryptographically and structurally (steps 1-2
@@ -69,17 +70,34 @@ export async function verifyLoginPresentation({ presentation, challenge, domain,
69
70
  .join(', ');
70
71
  throw new Error(`Wallet presentation failed verification (${summary || 'unknown check'}).`);
71
72
  }
72
- const rawProof = presentation.proof;
73
- const proofs = Array.isArray(rawProof) ? rawProof : rawProof ? [rawProof] : [];
74
- const authProof = proofs.find(proof => proof.proofPurpose === 'authentication');
75
- if (!authProof) {
73
+ // The presentation-level proofs (a VP may carry one object or several).
74
+ const proofs = asArray(presentation.proof);
75
+ if (proofs.length === 0) {
76
76
  throw new Error('Wallet presentation carries no authentication proof.');
77
77
  }
78
- if (authProof.challenge !== challenge) {
79
- throw new Error('Wallet presentation challenge does not match.');
78
+ // Belt-and-suspenders against a mixed proof set: the crypto layer selects ONE
79
+ // purpose for the whole set and skips non-matching proofs, so a proof under
80
+ // any OTHER purpose is one this verification may never have signature-checked
81
+ // -- and the challenge/domain checks below are only meaningful on a proof
82
+ // that provably verified. Requiring every presentation-level proof to be an
83
+ // authentication proof keeps this library failing closed even against an
84
+ // older `@interop/verifier-core` whose purpose selection reads `proof[0]`
85
+ // alone (a VP ordered `[assertionMethod, authentication]` would otherwise
86
+ // verify under AssertionProofPurpose with the authentication proof -- the
87
+ // only freshness bind -- never touched by a signature check).
88
+ if (proofs.some(proof => proof.proofPurpose !== 'authentication')) {
89
+ throw new Error('Wallet presentation carries a non-authentication proof; every ' +
90
+ 'presentation-level proof must be an authentication proof.');
80
91
  }
81
- if (authProof.domain !== domain) {
82
- throw new Error(`Wallet presentation domain "${authProof.domain ?? ''}" does not match "${domain}".`);
92
+ // Every proof in the set was verified under AuthenticationProofPurpose, so
93
+ // require the fresh challenge and this app's domain on each of them.
94
+ for (const proof of proofs) {
95
+ if (proof.challenge !== challenge) {
96
+ throw new Error('Wallet presentation challenge does not match.');
97
+ }
98
+ if (proof.domain !== domain) {
99
+ throw new Error(`Wallet presentation domain "${proof.domain ?? ''}" does not match "${domain}".`);
100
+ }
83
101
  }
84
102
  }
85
103
  /**
@@ -96,8 +114,7 @@ export function grantsOf(presentation) {
96
114
  * The actions a grant allows, normalized to an array.
97
115
  */
98
116
  function actionsOf(zcap) {
99
- const allowed = zcap.allowedAction;
100
- return Array.isArray(allowed) ? allowed : allowed ? [allowed] : [];
117
+ return asArray(zcap.allowedAction);
101
118
  }
102
119
  /**
103
120
  * Structural validation of the granted zcaps (step 3 above). Throws on any
@@ -1 +1 @@
1
- {"version":3,"file":"verifyResponse.js","sourceRoot":"","sources":["../../src/auth/verifyResponse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verifyResponse.js","sourceRoot":"","sources":["../../src/auth/verifyResponse.ts"],"names":[],"mappings":"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"}