@interop/was-react 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.md +20 -0
- package/README.md +410 -0
- package/dist/auth/chapi.d.ts +43 -0
- package/dist/auth/chapi.d.ts.map +1 -0
- package/dist/auth/chapi.js +107 -0
- package/dist/auth/chapi.js.map +1 -0
- package/dist/auth/loginFlow.d.ts +93 -0
- package/dist/auth/loginFlow.d.ts.map +1 -0
- package/dist/auth/loginFlow.js +149 -0
- package/dist/auth/loginFlow.js.map +1 -0
- package/dist/auth/loginRequest.d.ts +66 -0
- package/dist/auth/loginRequest.d.ts.map +1 -0
- package/dist/auth/loginRequest.js +83 -0
- package/dist/auth/loginRequest.js.map +1 -0
- package/dist/auth/verifyResponse.d.ts +52 -0
- package/dist/auth/verifyResponse.d.ts.map +1 -0
- package/dist/auth/verifyResponse.js +138 -0
- package/dist/auth/verifyResponse.js.map +1 -0
- package/dist/auth/verifyResponse.test.d.ts +2 -0
- package/dist/auth/verifyResponse.test.d.ts.map +1 -0
- package/dist/auth/verifyResponse.test.js +282 -0
- package/dist/auth/verifyResponse.test.js.map +1 -0
- package/dist/auth/walletRequestTypes.d.ts +143 -0
- package/dist/auth/walletRequestTypes.d.ts.map +1 -0
- package/dist/auth/walletRequestTypes.js +2 -0
- package/dist/auth/walletRequestTypes.js.map +1 -0
- package/dist/config.d.ts +150 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +27 -0
- package/dist/config.js.map +1 -0
- package/dist/dev/cli.d.ts +16 -0
- package/dist/dev/cli.d.ts.map +1 -0
- package/dist/dev/cli.js +122 -0
- package/dist/dev/cli.js.map +1 -0
- package/dist/dev/cli.test.d.ts +2 -0
- package/dist/dev/cli.test.d.ts.map +1 -0
- package/dist/dev/cli.test.js +39 -0
- package/dist/dev/cli.test.js.map +1 -0
- package/dist/dev/index.d.ts +10 -0
- package/dist/dev/index.d.ts.map +1 -0
- package/dist/dev/index.js +10 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/provisionDevGrants.d.ts +73 -0
- package/dist/dev/provisionDevGrants.d.ts.map +1 -0
- package/dist/dev/provisionDevGrants.js +176 -0
- package/dist/dev/provisionDevGrants.js.map +1 -0
- package/dist/grants.d.ts +59 -0
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +82 -0
- package/dist/grants.js.map +1 -0
- package/dist/grants.test.d.ts +2 -0
- package/dist/grants.test.d.ts.map +1 -0
- package/dist/grants.test.js +79 -0
- package/dist/grants.test.js.map +1 -0
- package/dist/identity/agents.d.ts +99 -0
- package/dist/identity/agents.d.ts.map +1 -0
- package/dist/identity/agents.js +132 -0
- package/dist/identity/agents.js.map +1 -0
- package/dist/identity/appSession.d.ts +78 -0
- package/dist/identity/appSession.d.ts.map +1 -0
- package/dist/identity/appSession.js +93 -0
- package/dist/identity/appSession.js.map +1 -0
- package/dist/identity/documentLoader.d.ts +20 -0
- package/dist/identity/documentLoader.d.ts.map +1 -0
- package/dist/identity/documentLoader.js +99 -0
- package/dist/identity/documentLoader.js.map +1 -0
- package/dist/identity/initAppSession.d.ts +27 -0
- package/dist/identity/initAppSession.d.ts.map +1 -0
- package/dist/identity/initAppSession.js +30 -0
- package/dist/identity/initAppSession.js.map +1 -0
- package/dist/identity/seedCredential.d.ts +74 -0
- package/dist/identity/seedCredential.d.ts.map +1 -0
- package/dist/identity/seedCredential.js +165 -0
- package/dist/identity/seedCredential.js.map +1 -0
- package/dist/identity/seedCredential.test.d.ts +2 -0
- package/dist/identity/seedCredential.test.d.ts.map +1 -0
- package/dist/identity/seedCredential.test.js +205 -0
- package/dist/identity/seedCredential.test.js.map +1 -0
- package/dist/identity/seedStore.d.ts +27 -0
- package/dist/identity/seedStore.d.ts.map +1 -0
- package/dist/identity/seedStore.js +74 -0
- package/dist/identity/seedStore.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/mui/ProtectedRoute.d.ts +10 -0
- package/dist/mui/ProtectedRoute.d.ts.map +1 -0
- package/dist/mui/ProtectedRoute.js +54 -0
- package/dist/mui/ProtectedRoute.js.map +1 -0
- package/dist/mui/ReconnectBanner.d.ts +2 -0
- package/dist/mui/ReconnectBanner.d.ts.map +1 -0
- package/dist/mui/ReconnectBanner.js +20 -0
- package/dist/mui/ReconnectBanner.js.map +1 -0
- package/dist/mui/SyncStatusChip.d.ts +2 -0
- package/dist/mui/SyncStatusChip.d.ts.map +1 -0
- package/dist/mui/SyncStatusChip.js +27 -0
- package/dist/mui/SyncStatusChip.js.map +1 -0
- package/dist/mui/index.d.ts +12 -0
- package/dist/mui/index.d.ts.map +1 -0
- package/dist/mui/index.js +12 -0
- package/dist/mui/index.js.map +1 -0
- package/dist/react/WasSessionProvider.d.ts +36 -0
- package/dist/react/WasSessionProvider.d.ts.map +1 -0
- package/dist/react/WasSessionProvider.js +35 -0
- package/dist/react/WasSessionProvider.js.map +1 -0
- package/dist/react/hooks.d.ts +66 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/hooks.js +121 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react/index.d.ts +11 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +11 -0
- package/dist/react/index.js.map +1 -0
- package/dist/session/appReadyStore.d.ts +10 -0
- package/dist/session/appReadyStore.d.ts.map +1 -0
- package/dist/session/appReadyStore.js +22 -0
- package/dist/session/appReadyStore.js.map +1 -0
- package/dist/session/authStore.d.ts +71 -0
- package/dist/session/authStore.d.ts.map +1 -0
- package/dist/session/authStore.js +347 -0
- package/dist/session/authStore.js.map +1 -0
- package/dist/session/index.d.ts +10 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +10 -0
- package/dist/session/index.js.map +1 -0
- package/dist/storage/entityStore.d.ts +51 -0
- package/dist/storage/entityStore.d.ts.map +1 -0
- package/dist/storage/entityStore.js +78 -0
- package/dist/storage/entityStore.js.map +1 -0
- package/dist/storage/localStore.d.ts +144 -0
- package/dist/storage/localStore.d.ts.map +1 -0
- package/dist/storage/localStore.js +289 -0
- package/dist/storage/localStore.js.map +1 -0
- package/dist/storage/rehydrate.d.ts +56 -0
- package/dist/storage/rehydrate.d.ts.map +1 -0
- package/dist/storage/rehydrate.js +87 -0
- package/dist/storage/rehydrate.js.map +1 -0
- package/dist/storage/rehydrate.test.d.ts +2 -0
- package/dist/storage/rehydrate.test.d.ts.map +1 -0
- package/dist/storage/rehydrate.test.js +172 -0
- package/dist/storage/rehydrate.test.js.map +1 -0
- package/dist/storage/storageManager.d.ts +39 -0
- package/dist/storage/storageManager.d.ts.map +1 -0
- package/dist/storage/storageManager.js +68 -0
- package/dist/storage/storageManager.js.map +1 -0
- package/dist/storage/syncController.d.ts +79 -0
- package/dist/storage/syncController.d.ts.map +1 -0
- package/dist/storage/syncController.js +189 -0
- package/dist/storage/syncController.js.map +1 -0
- package/dist/storage/syncStatusStore.d.ts +17 -0
- package/dist/storage/syncStatusStore.d.ts.map +1 -0
- package/dist/storage/syncStatusStore.js +19 -0
- package/dist/storage/syncStatusStore.js.map +1 -0
- package/dist/storage/wasRemoteStore.d.ts +73 -0
- package/dist/storage/wasRemoteStore.d.ts.map +1 -0
- package/dist/storage/wasRemoteStore.js +76 -0
- package/dist/storage/wasRemoteStore.js.map +1 -0
- package/dist/storage/wasSync.d.ts +42 -0
- package/dist/storage/wasSync.d.ts.map +1 -0
- package/dist/storage/wasSync.js +34 -0
- package/dist/storage/wasSync.js.map +1 -0
- package/dist/sync/changesQuery.d.ts +44 -0
- package/dist/sync/changesQuery.d.ts.map +1 -0
- package/dist/sync/changesQuery.js +61 -0
- package/dist/sync/changesQuery.js.map +1 -0
- package/dist/sync/changesQuery.test.d.ts +2 -0
- package/dist/sync/changesQuery.test.d.ts.map +1 -0
- package/dist/sync/changesQuery.test.js +145 -0
- package/dist/sync/changesQuery.test.js.map +1 -0
- package/dist/sync/docCipher.d.ts +68 -0
- package/dist/sync/docCipher.d.ts.map +1 -0
- package/dist/sync/docCipher.js +89 -0
- package/dist/sync/docCipher.js.map +1 -0
- package/dist/sync/feedMasterPort.d.ts +30 -0
- package/dist/sync/feedMasterPort.d.ts.map +1 -0
- package/dist/sync/feedMasterPort.js +58 -0
- package/dist/sync/feedMasterPort.js.map +1 -0
- package/dist/sync/index.d.ts +21 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +21 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/lww.d.ts +29 -0
- package/dist/sync/lww.d.ts.map +1 -0
- package/dist/sync/lww.js +28 -0
- package/dist/sync/lww.js.map +1 -0
- package/dist/sync/lww.test.d.ts +2 -0
- package/dist/sync/lww.test.d.ts.map +1 -0
- package/dist/sync/lww.test.js +28 -0
- package/dist/sync/lww.test.js.map +1 -0
- package/dist/sync/lwwConflictHandler.d.ts +49 -0
- package/dist/sync/lwwConflictHandler.d.ts.map +1 -0
- package/dist/sync/lwwConflictHandler.js +65 -0
- package/dist/sync/lwwConflictHandler.js.map +1 -0
- package/dist/sync/lwwConflictHandler.test.d.ts +2 -0
- package/dist/sync/lwwConflictHandler.test.d.ts.map +1 -0
- package/dist/sync/lwwConflictHandler.test.js +78 -0
- package/dist/sync/lwwConflictHandler.test.js.map +1 -0
- package/dist/sync/pushWrites.d.ts +57 -0
- package/dist/sync/pushWrites.d.ts.map +1 -0
- package/dist/sync/pushWrites.js +159 -0
- package/dist/sync/pushWrites.js.map +1 -0
- package/dist/sync/pushWrites.test.d.ts +2 -0
- package/dist/sync/pushWrites.test.d.ts.map +1 -0
- package/dist/sync/pushWrites.test.js +287 -0
- package/dist/sync/pushWrites.test.js.map +1 -0
- package/dist/sync/syncedDocSchema.d.ts +22 -0
- package/dist/sync/syncedDocSchema.d.ts.map +1 -0
- package/dist/sync/syncedDocSchema.js +26 -0
- package/dist/sync/syncedDocSchema.js.map +1 -0
- package/dist/sync/types.d.ts +194 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +36 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/sync/wasReplication.d.ts +47 -0
- package/dist/sync/wasReplication.d.ts.map +1 -0
- package/dist/sync/wasReplication.js +55 -0
- package/dist/sync/wasReplication.js.map +1 -0
- package/dist/sync/wasSyncPort.d.ts +45 -0
- package/dist/sync/wasSyncPort.d.ts.map +1 -0
- package/dist/sync/wasSyncPort.js +170 -0
- package/dist/sync/wasSyncPort.js.map +1 -0
- package/package.json +142 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loginFlow.d.ts","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,EAKL,KAAK,oBAAoB,EAC1B,MAAM,+BAA+B,CAAA;AAEtC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAO3D,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,4DAA4D;IAC5D,UAAU,EAAE,oBAAoB,CAAA;IAChC,gEAAgE;IAChE,cAAc,EAAE,cAAc,CAAA;IAC9B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,sEAAsE;AACtE,MAAM,MAAM,UAAU,GACpB,SAAS,GAAG,aAAa,GAAG,mBAAmB,GAAG,WAAW,CAAA;AAE/D,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,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,6DAA6D;AAC7D,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,IAAI,EAAE,MAAM;CAIzB;AAED;;;;;;;;;GASG;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,CAkCzB;AAED;;;;;;;;;GASG;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,CAiFxB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { findSeedCredential, issueSeedCredential, parseSeedCredential, wrapCredentialForStore } from '../identity/seedCredential.js';
|
|
2
|
+
import { initAppSession } from '../identity/initAppSession.js';
|
|
3
|
+
import { chapiGet, chapiStore } from './chapi.js';
|
|
4
|
+
import { buildGrantsVpr, buildSeedProbeVpr, newChallenge } from './loginRequest.js';
|
|
5
|
+
import { checkGrants, grantsOf, verifyLoginPresentation } from './verifyResponse.js';
|
|
6
|
+
/** Thrown when the user cancels/dismisses a wallet popup. */
|
|
7
|
+
export class LoginCancelledError extends Error {
|
|
8
|
+
constructor(step) {
|
|
9
|
+
super(`The wallet request was cancelled (${step}).`);
|
|
10
|
+
this.name = 'LoginCancelledError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Requests storage grants for `identity` and validates them. Shared by the
|
|
15
|
+
* login flow and the expired-access reconnect path.
|
|
16
|
+
*
|
|
17
|
+
* @param options {object}
|
|
18
|
+
* @param options.identity {IdentityAgents}
|
|
19
|
+
* @param options.config {LoginConfig}
|
|
20
|
+
* @param [options.onPhase] {Function}
|
|
21
|
+
* @returns {Promise<CheckedGrants>}
|
|
22
|
+
*/
|
|
23
|
+
export async function requestGrants({ identity, config, onPhase }) {
|
|
24
|
+
onPhase?.('requesting-grants');
|
|
25
|
+
const challenge = newChallenge();
|
|
26
|
+
const vpr = buildGrantsVpr({
|
|
27
|
+
challenge,
|
|
28
|
+
domain: window.location.origin,
|
|
29
|
+
controllerDid: identity.controllerDid,
|
|
30
|
+
collections: config.collections,
|
|
31
|
+
appName: config.appName
|
|
32
|
+
});
|
|
33
|
+
const presentation = await chapiGet({
|
|
34
|
+
vpr,
|
|
35
|
+
...(config.mediatorBase !== undefined && {
|
|
36
|
+
mediatorBase: config.mediatorBase
|
|
37
|
+
})
|
|
38
|
+
});
|
|
39
|
+
if (!presentation) {
|
|
40
|
+
throw new LoginCancelledError('storage grants');
|
|
41
|
+
}
|
|
42
|
+
onPhase?.('verifying');
|
|
43
|
+
await verifyLoginPresentation({
|
|
44
|
+
presentation,
|
|
45
|
+
challenge,
|
|
46
|
+
domain: window.location.origin,
|
|
47
|
+
documentLoader: config.documentLoader
|
|
48
|
+
});
|
|
49
|
+
return checkGrants({
|
|
50
|
+
grants: grantsOf(presentation),
|
|
51
|
+
controllerDid: identity.controllerDid,
|
|
52
|
+
collections: config.collections,
|
|
53
|
+
...(config.wasServerUrl !== undefined && {
|
|
54
|
+
expectedServerUrl: config.wasServerUrl
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Runs the full Login-With-Wallet flow (first-run or returning, decided by
|
|
60
|
+
* the seed probe). Throws `LoginCancelledError` on dismissal and `Error` on
|
|
61
|
+
* verification failures; nothing is persisted here (the caller persists).
|
|
62
|
+
*
|
|
63
|
+
* @param options {object}
|
|
64
|
+
* @param options.config {LoginConfig}
|
|
65
|
+
* @param [options.onPhase] {Function}
|
|
66
|
+
* @returns {Promise<LoginOutcome>}
|
|
67
|
+
*/
|
|
68
|
+
export async function loginWithWallet({ config, onPhase }) {
|
|
69
|
+
// Popup #1: probe the wallet for an existing app key.
|
|
70
|
+
onPhase?.('probing');
|
|
71
|
+
const probeChallenge = newChallenge();
|
|
72
|
+
const probeVpr = buildSeedProbeVpr({
|
|
73
|
+
challenge: probeChallenge,
|
|
74
|
+
domain: window.location.origin,
|
|
75
|
+
credentialType: config.credential.credentialType,
|
|
76
|
+
appName: config.appName
|
|
77
|
+
});
|
|
78
|
+
const probeVp = await chapiGet({
|
|
79
|
+
vpr: probeVpr,
|
|
80
|
+
...(config.mediatorBase !== undefined && {
|
|
81
|
+
mediatorBase: config.mediatorBase
|
|
82
|
+
})
|
|
83
|
+
});
|
|
84
|
+
if (!probeVp) {
|
|
85
|
+
throw new LoginCancelledError('wallet login');
|
|
86
|
+
}
|
|
87
|
+
await verifyLoginPresentation({
|
|
88
|
+
presentation: probeVp,
|
|
89
|
+
challenge: probeChallenge,
|
|
90
|
+
domain: window.location.origin,
|
|
91
|
+
documentLoader: config.documentLoader
|
|
92
|
+
});
|
|
93
|
+
let seed;
|
|
94
|
+
let firstRun;
|
|
95
|
+
const credential = findSeedCredential({
|
|
96
|
+
presentation: probeVp,
|
|
97
|
+
credentialType: config.credential.credentialType
|
|
98
|
+
});
|
|
99
|
+
if (credential) {
|
|
100
|
+
// Returning login: recover the seed, enforce self-issue + origin + the
|
|
101
|
+
// seed-to-DID binding.
|
|
102
|
+
const parsed = await parseSeedCredential({
|
|
103
|
+
credential,
|
|
104
|
+
origin: config.appOrigin,
|
|
105
|
+
config: config.credential
|
|
106
|
+
});
|
|
107
|
+
seed = parsed.seed;
|
|
108
|
+
firstRun = false;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// First run: mint a fresh master seed and store its credential in the
|
|
112
|
+
// wallet. Block until the store succeeds -- without it, cross-device
|
|
113
|
+
// recovery is silently broken.
|
|
114
|
+
seed = crypto.getRandomValues(new Uint8Array(32));
|
|
115
|
+
firstRun = true;
|
|
116
|
+
onPhase?.('storing-key');
|
|
117
|
+
const issued = await issueSeedCredential({
|
|
118
|
+
seed,
|
|
119
|
+
origin: config.appOrigin,
|
|
120
|
+
config: config.credential,
|
|
121
|
+
documentLoader: config.documentLoader
|
|
122
|
+
});
|
|
123
|
+
const stored = await chapiStore({
|
|
124
|
+
presentation: wrapCredentialForStore(issued),
|
|
125
|
+
...(config.mediatorBase !== undefined && {
|
|
126
|
+
mediatorBase: config.mediatorBase
|
|
127
|
+
})
|
|
128
|
+
});
|
|
129
|
+
if (!stored) {
|
|
130
|
+
throw new LoginCancelledError('saving your app key to the wallet');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const identity = await initAppSession({ seed });
|
|
134
|
+
// Popup #2: request the storage grants for the stable controller DID.
|
|
135
|
+
const checked = await requestGrants({
|
|
136
|
+
identity,
|
|
137
|
+
config,
|
|
138
|
+
...(onPhase && { onPhase })
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
seed,
|
|
142
|
+
identity,
|
|
143
|
+
grants: checked.grants,
|
|
144
|
+
parsed: checked.parsed,
|
|
145
|
+
expires: checked.expires,
|
|
146
|
+
firstRun
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=loginFlow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loginFlow.js","sourceRoot":"","sources":["../../src/auth/loginFlow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* RP-side VPR construction for Login With Wallet. Two requests:
|
|
6
|
+
*
|
|
7
|
+
* 1. The seed probe: DIDAuthentication + QueryByExample for the app-key
|
|
8
|
+
* credential. An empty result is the first-run signal; a hit recovers the
|
|
9
|
+
* master seed on a new device.
|
|
10
|
+
* 2. The grants request: DIDAuthentication + AuthorizationCapabilityQuery with
|
|
11
|
+
* one capabilityQuery per collection (descriptor-object targets, which the
|
|
12
|
+
* wallet resolves against the user's one Space and auto-provisions) plus a
|
|
13
|
+
* read-only whole-space grant. The wallet force-caps whole-space grants to
|
|
14
|
+
* GET/HEAD, so read-only is all that is ever requested there.
|
|
15
|
+
*
|
|
16
|
+
* `domain` must host-match the CHAPI requesting origin or the wallet refuses
|
|
17
|
+
* to sign; `challenge` must be fresh per request (echoed into the DIDAuth
|
|
18
|
+
* proof and checked in verifyResponse).
|
|
19
|
+
*/
|
|
20
|
+
import type { IVPRDetails } from './walletRequestTypes.js';
|
|
21
|
+
/** Default read/write actions requested on each app collection. */
|
|
22
|
+
export declare const RW_ACTIONS: string[];
|
|
23
|
+
/** The referenceId of the read-only whole-space grant. */
|
|
24
|
+
export declare const SPACE_READ_REFERENCE_ID = "space-read";
|
|
25
|
+
/** A fresh nonce for a VPR challenge. */
|
|
26
|
+
export declare function newChallenge(): string;
|
|
27
|
+
/**
|
|
28
|
+
* VPR #1: DIDAuthentication + QueryByExample for the app-key credential.
|
|
29
|
+
*
|
|
30
|
+
* @param options {object}
|
|
31
|
+
* @param options.challenge {string}
|
|
32
|
+
* @param options.domain {string}
|
|
33
|
+
* @param options.credentialType {string} the app's seed-credential type name
|
|
34
|
+
* @param options.appName {string} human-readable app name for the reason line
|
|
35
|
+
* @returns {IVPRDetails}
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildSeedProbeVpr({ challenge, domain, credentialType, appName }: {
|
|
38
|
+
challenge: string;
|
|
39
|
+
domain: string;
|
|
40
|
+
credentialType: string;
|
|
41
|
+
appName: string;
|
|
42
|
+
}): IVPRDetails;
|
|
43
|
+
/**
|
|
44
|
+
* VPR #2: DIDAuthentication + AuthorizationCapabilityQuery -- one read/write
|
|
45
|
+
* capabilityQuery per app collection (delegated to `controllerDid`), plus a
|
|
46
|
+
* read-only whole-space grant.
|
|
47
|
+
*
|
|
48
|
+
* @param options {object}
|
|
49
|
+
* @param options.challenge {string}
|
|
50
|
+
* @param options.domain {string}
|
|
51
|
+
* @param options.controllerDid {string}
|
|
52
|
+
* @param options.collections {string[]} the WAS collection ids to request
|
|
53
|
+
* @param options.appName {string} human-readable app name for the reason line
|
|
54
|
+
* @param [options.actions] {string[]} the RW action set (defaults to
|
|
55
|
+
* `RW_ACTIONS`)
|
|
56
|
+
* @returns {IVPRDetails}
|
|
57
|
+
*/
|
|
58
|
+
export declare function buildGrantsVpr({ challenge, domain, controllerDid, collections, appName, actions }: {
|
|
59
|
+
challenge: string;
|
|
60
|
+
domain: string;
|
|
61
|
+
controllerDid: string;
|
|
62
|
+
collections: string[];
|
|
63
|
+
appName: string;
|
|
64
|
+
actions?: string[];
|
|
65
|
+
}): IVPRDetails;
|
|
66
|
+
//# sourceMappingURL=loginRequest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loginRequest.d.ts","sourceRoot":"","sources":["../../src/auth/loginRequest.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAEV,WAAW,EACZ,MAAM,yBAAyB,CAAA;AAEhC,mEAAmE;AACnE,eAAO,MAAM,UAAU,UAA2C,CAAA;AAElE,0DAA0D;AAC1D,eAAO,MAAM,uBAAuB,eAAe,CAAA;AAEnD,yCAAyC;AACzC,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,MAAM,EACN,cAAc,EACd,OAAO,EACR,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,WAAW,CAkBd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,MAAM,EACN,aAAa,EACb,WAAW,EACX,OAAO,EACP,OAAoB,EACrB,EAAE;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CACnB,GAAG,WAAW,CA6Bd"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** Default read/write actions requested on each app collection. */
|
|
2
|
+
export const RW_ACTIONS = ['GET', 'HEAD', 'PUT', 'POST', 'DELETE'];
|
|
3
|
+
/** The referenceId of the read-only whole-space grant. */
|
|
4
|
+
export const SPACE_READ_REFERENCE_ID = 'space-read';
|
|
5
|
+
/** A fresh nonce for a VPR challenge. */
|
|
6
|
+
export function newChallenge() {
|
|
7
|
+
return crypto.randomUUID();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* VPR #1: DIDAuthentication + QueryByExample for the app-key credential.
|
|
11
|
+
*
|
|
12
|
+
* @param options {object}
|
|
13
|
+
* @param options.challenge {string}
|
|
14
|
+
* @param options.domain {string}
|
|
15
|
+
* @param options.credentialType {string} the app's seed-credential type name
|
|
16
|
+
* @param options.appName {string} human-readable app name for the reason line
|
|
17
|
+
* @returns {IVPRDetails}
|
|
18
|
+
*/
|
|
19
|
+
export function buildSeedProbeVpr({ challenge, domain, credentialType, appName }) {
|
|
20
|
+
return {
|
|
21
|
+
query: [
|
|
22
|
+
{
|
|
23
|
+
type: 'DIDAuthentication',
|
|
24
|
+
acceptedMethods: [{ method: 'key' }]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'QueryByExample',
|
|
28
|
+
credentialQuery: {
|
|
29
|
+
reason: `Recover the ${appName} app key stored in your wallet.`,
|
|
30
|
+
example: { type: credentialType }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
challenge,
|
|
35
|
+
domain
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* VPR #2: DIDAuthentication + AuthorizationCapabilityQuery -- one read/write
|
|
40
|
+
* capabilityQuery per app collection (delegated to `controllerDid`), plus a
|
|
41
|
+
* read-only whole-space grant.
|
|
42
|
+
*
|
|
43
|
+
* @param options {object}
|
|
44
|
+
* @param options.challenge {string}
|
|
45
|
+
* @param options.domain {string}
|
|
46
|
+
* @param options.controllerDid {string}
|
|
47
|
+
* @param options.collections {string[]} the WAS collection ids to request
|
|
48
|
+
* @param options.appName {string} human-readable app name for the reason line
|
|
49
|
+
* @param [options.actions] {string[]} the RW action set (defaults to
|
|
50
|
+
* `RW_ACTIONS`)
|
|
51
|
+
* @returns {IVPRDetails}
|
|
52
|
+
*/
|
|
53
|
+
export function buildGrantsVpr({ challenge, domain, controllerDid, collections, appName, actions = RW_ACTIONS }) {
|
|
54
|
+
const capabilityQuery = collections.map(id => ({
|
|
55
|
+
referenceId: id,
|
|
56
|
+
reason: `Store your ${appName} data in the "${id}" collection.`,
|
|
57
|
+
controller: controllerDid,
|
|
58
|
+
allowedAction: actions,
|
|
59
|
+
invocationTarget: { type: 'urn:was:collection', name: id }
|
|
60
|
+
}));
|
|
61
|
+
capabilityQuery.push({
|
|
62
|
+
referenceId: SPACE_READ_REFERENCE_ID,
|
|
63
|
+
reason: 'Read your storage space description.',
|
|
64
|
+
controller: controllerDid,
|
|
65
|
+
allowedAction: ['GET', 'HEAD'],
|
|
66
|
+
invocationTarget: { type: 'urn:was:space' }
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
query: [
|
|
70
|
+
{
|
|
71
|
+
type: 'DIDAuthentication',
|
|
72
|
+
acceptedMethods: [{ method: 'key' }]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
type: 'AuthorizationCapabilityQuery',
|
|
76
|
+
capabilityQuery
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
challenge,
|
|
80
|
+
domain
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=loginRequest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loginRequest.js","sourceRoot":"","sources":["../../src/auth/loginRequest.ts"],"names":[],"mappings":"AAwBA,mEAAmE;AACnE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;AAElE,0DAA0D;AAC1D,MAAM,CAAC,MAAM,uBAAuB,GAAG,YAAY,CAAA;AAEnD,yCAAyC;AACzC,MAAM,UAAU,YAAY;IAC1B,OAAO,MAAM,CAAC,UAAU,EAAE,CAAA;AAC5B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,SAAS,EACT,MAAM,EACN,cAAc,EACd,OAAO,EAMR;IACC,OAAO;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,mBAAmB;gBACzB,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;aACrC;YACD;gBACE,IAAI,EAAE,gBAAgB;gBACtB,eAAe,EAAE;oBACf,MAAM,EAAE,eAAe,OAAO,iCAAiC;oBAC/D,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;iBAClC;aACF;SACF;QACD,SAAS;QACT,MAAM;KACP,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,SAAS,EACT,MAAM,EACN,aAAa,EACb,WAAW,EACX,OAAO,EACP,OAAO,GAAG,UAAU,EAQrB;IACC,MAAM,eAAe,GAA6B,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACvE,WAAW,EAAE,EAAE;QACf,MAAM,EAAE,cAAc,OAAO,iBAAiB,EAAE,eAAe;QAC/D,UAAU,EAAE,aAAa;QACzB,aAAa,EAAE,OAAO;QACtB,gBAAgB,EAAE,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,EAAE,EAAE;KAC3D,CAAC,CAAC,CAAA;IACH,eAAe,CAAC,IAAI,CAAC;QACnB,WAAW,EAAE,uBAAuB;QACpC,MAAM,EAAE,sCAAsC;QAC9C,UAAU,EAAE,aAAa;QACzB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;QAC9B,gBAAgB,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE;KAC5C,CAAC,CAAA;IACF,OAAO;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,mBAAmB;gBACzB,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;aACrC;YACD;gBACE,IAAI,EAAE,8BAA8B;gBACpC,eAAe;aAChB;SACF;QACD,SAAS;QACT,MAAM;KACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { IVerifiablePresentation, IZcap } from '@interop/data-integrity-core';
|
|
2
|
+
import type { DocumentLoader } from '../identity/documentLoader.js';
|
|
3
|
+
import { type ParsedGrants } from '../grants.js';
|
|
4
|
+
/**
|
|
5
|
+
* Verifies a login response VP cryptographically and structurally (steps 1-2
|
|
6
|
+
* above). Throws on any failure.
|
|
7
|
+
*
|
|
8
|
+
* @param options {object}
|
|
9
|
+
* @param options.presentation {IVerifiablePresentation}
|
|
10
|
+
* @param options.challenge {string} the fresh nonce this app sent
|
|
11
|
+
* @param options.domain {string} the domain this app sent (its origin)
|
|
12
|
+
* @param options.documentLoader {DocumentLoader}
|
|
13
|
+
* @returns {Promise<void>}
|
|
14
|
+
*/
|
|
15
|
+
export declare function verifyLoginPresentation({ presentation, challenge, domain, documentLoader }: {
|
|
16
|
+
presentation: IVerifiablePresentation;
|
|
17
|
+
challenge: string;
|
|
18
|
+
domain: string;
|
|
19
|
+
documentLoader: DocumentLoader;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
/** Extracts the delegated zcaps from a wallet response VP (`zcap` array). */
|
|
22
|
+
export declare function grantsOf(presentation: IVerifiablePresentation): IZcap[];
|
|
23
|
+
/** A validated grant set: parsed topology plus the earliest expiry. */
|
|
24
|
+
export interface CheckedGrants {
|
|
25
|
+
parsed: ParsedGrants;
|
|
26
|
+
grants: IZcap[];
|
|
27
|
+
/** ISO timestamp: the earliest expiry across the grants. */
|
|
28
|
+
expires: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Structural validation of the granted zcaps (step 3 above). Throws on any
|
|
32
|
+
* failure; returns the parsed topology and the earliest expiry on success.
|
|
33
|
+
*
|
|
34
|
+
* @param options {object}
|
|
35
|
+
* @param options.grants {IZcap[]}
|
|
36
|
+
* @param options.controllerDid {string} this app's seed-derived DID
|
|
37
|
+
* @param options.collections {string[]} the WAS collection ids that must be
|
|
38
|
+
* covered
|
|
39
|
+
* @param [options.requiredActions] {string[]} the actions each collection
|
|
40
|
+
* grant must allow (defaults to `RW_ACTIONS`)
|
|
41
|
+
* @param [options.expectedServerUrl] {string} the configured WAS host; when
|
|
42
|
+
* set, every grant must target it
|
|
43
|
+
* @returns {CheckedGrants}
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkGrants({ grants, controllerDid, collections, requiredActions, expectedServerUrl }: {
|
|
46
|
+
grants: IZcap[];
|
|
47
|
+
controllerDid: string;
|
|
48
|
+
collections: string[];
|
|
49
|
+
requiredActions?: string[];
|
|
50
|
+
expectedServerUrl?: string;
|
|
51
|
+
}): CheckedGrants;
|
|
52
|
+
//# sourceMappingURL=verifyResponse.d.ts.map
|
|
@@ -0,0 +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;AAY7D;;;;;;;;;;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,CAmChB;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,YAAY,EAAE,uBAAuB,GAAG,KAAK,EAAE,CAMvE;AAED,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,EAAE,KAAK,EAAE,CAAA;IACf,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAA;CAChB;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,aAAa,EACb,WAAW,EACX,eAA4B,EAC5B,iBAAiB,EAClB,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;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B,GAAG,aAAa,CAgDhB"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* RP-side verification of a wallet's Login-With-Wallet response VP.
|
|
6
|
+
*
|
|
7
|
+
* Layered checks:
|
|
8
|
+
* 1. Cryptographic: `@interop/verifier-core` `verifyPresentation` (the VP's
|
|
9
|
+
* DIDAuth proof plus every embedded VC proof; the default crypto service
|
|
10
|
+
* covers Ed25519Signature2020 and eddsa-rdfc-2022, the two suites the
|
|
11
|
+
* wallet mints). `registries: []` disables issuer-registry lookup (the
|
|
12
|
+
* app-key credential is self-issued by design).
|
|
13
|
+
* 2. Manual proof checks verifier-core does not make: `proofPurpose` is
|
|
14
|
+
* `authentication`, `domain` equals what this app sent (its origin), and
|
|
15
|
+
* the `challenge` echoes this request's fresh nonce.
|
|
16
|
+
* 3. Grant structure: every zcap is controlled by OUR seed-derived DID,
|
|
17
|
+
* targets a single space on the expected WAS host, is unexpired, and the
|
|
18
|
+
* collection set is fully covered with sufficient actions. (Delegation-
|
|
19
|
+
* chain proofs are enforced server-side at invocation; the RP checks
|
|
20
|
+
* structure.)
|
|
21
|
+
*
|
|
22
|
+
* Note on holder binding: the wallet signs the VP as ITS holder DID (did:web
|
|
23
|
+
* or the wallet's did:key) -- not as this app's controller DID, which never
|
|
24
|
+
* leaves this app. The seed-to-identity binding is enforced instead by
|
|
25
|
+
* `parseSeedCredential` (issuer === subject === DID derived from the embedded
|
|
26
|
+
* seed) and by every grant's `controller` being the requested controller DID.
|
|
27
|
+
*/
|
|
28
|
+
import { verifyPresentation } from '@interop/verifier-core';
|
|
29
|
+
import { parseGrants } from '../grants.js';
|
|
30
|
+
import { earliestExpiry, isExpired } from '../identity/appSession.js';
|
|
31
|
+
import { RW_ACTIONS } from './loginRequest.js';
|
|
32
|
+
/**
|
|
33
|
+
* Verifies a login response VP cryptographically and structurally (steps 1-2
|
|
34
|
+
* above). Throws on any failure.
|
|
35
|
+
*
|
|
36
|
+
* @param options {object}
|
|
37
|
+
* @param options.presentation {IVerifiablePresentation}
|
|
38
|
+
* @param options.challenge {string} the fresh nonce this app sent
|
|
39
|
+
* @param options.domain {string} the domain this app sent (its origin)
|
|
40
|
+
* @param options.documentLoader {DocumentLoader}
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
export async function verifyLoginPresentation({ presentation, challenge, domain, documentLoader }) {
|
|
44
|
+
const result = await verifyPresentation({
|
|
45
|
+
presentation,
|
|
46
|
+
challenge,
|
|
47
|
+
registries: [],
|
|
48
|
+
documentLoader
|
|
49
|
+
});
|
|
50
|
+
if (!result.verified) {
|
|
51
|
+
const failures = [
|
|
52
|
+
...result.presentationResults,
|
|
53
|
+
...result.credentialResults.flatMap(c => c.results)
|
|
54
|
+
]
|
|
55
|
+
.filter(check => check.outcome.status === 'failure')
|
|
56
|
+
.map(check => check.check);
|
|
57
|
+
throw new Error(`Wallet presentation failed verification (${failures.join(', ') || 'unknown check'}).`);
|
|
58
|
+
}
|
|
59
|
+
const rawProof = presentation.proof;
|
|
60
|
+
const proofs = Array.isArray(rawProof) ? rawProof : rawProof ? [rawProof] : [];
|
|
61
|
+
const authProof = proofs.find(proof => proof.proofPurpose === 'authentication');
|
|
62
|
+
if (!authProof) {
|
|
63
|
+
throw new Error('Wallet presentation carries no authentication proof.');
|
|
64
|
+
}
|
|
65
|
+
if (authProof.challenge !== challenge) {
|
|
66
|
+
throw new Error('Wallet presentation challenge does not match.');
|
|
67
|
+
}
|
|
68
|
+
if (authProof.domain !== domain) {
|
|
69
|
+
throw new Error(`Wallet presentation domain "${authProof.domain ?? ''}" does not match "${domain}".`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Extracts the delegated zcaps from a wallet response VP (`zcap` array). */
|
|
73
|
+
export function grantsOf(presentation) {
|
|
74
|
+
const zcap = presentation.zcap;
|
|
75
|
+
if (!Array.isArray(zcap)) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
return zcap;
|
|
79
|
+
}
|
|
80
|
+
/** The actions a grant allows, normalized to an array. */
|
|
81
|
+
function actionsOf(zcap) {
|
|
82
|
+
const allowed = zcap.allowedAction;
|
|
83
|
+
return Array.isArray(allowed) ? allowed : allowed ? [allowed] : [];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Structural validation of the granted zcaps (step 3 above). Throws on any
|
|
87
|
+
* failure; returns the parsed topology and the earliest expiry on success.
|
|
88
|
+
*
|
|
89
|
+
* @param options {object}
|
|
90
|
+
* @param options.grants {IZcap[]}
|
|
91
|
+
* @param options.controllerDid {string} this app's seed-derived DID
|
|
92
|
+
* @param options.collections {string[]} the WAS collection ids that must be
|
|
93
|
+
* covered
|
|
94
|
+
* @param [options.requiredActions] {string[]} the actions each collection
|
|
95
|
+
* grant must allow (defaults to `RW_ACTIONS`)
|
|
96
|
+
* @param [options.expectedServerUrl] {string} the configured WAS host; when
|
|
97
|
+
* set, every grant must target it
|
|
98
|
+
* @returns {CheckedGrants}
|
|
99
|
+
*/
|
|
100
|
+
export function checkGrants({ grants, controllerDid, collections, requiredActions = RW_ACTIONS, expectedServerUrl }) {
|
|
101
|
+
if (grants.length === 0) {
|
|
102
|
+
throw new Error('The wallet returned no storage grants.');
|
|
103
|
+
}
|
|
104
|
+
for (const grant of grants) {
|
|
105
|
+
const controller = grant.controller;
|
|
106
|
+
if (controller !== controllerDid) {
|
|
107
|
+
throw new Error(`A grant is controlled by "${String(controller)}", not this app's DID.`);
|
|
108
|
+
}
|
|
109
|
+
const expires = grant.expires;
|
|
110
|
+
if (typeof expires !== 'string' || isExpired(expires)) {
|
|
111
|
+
throw new Error('A grant is missing an expiry or is already expired.');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Asserts a single server origin + single space across all grants and
|
|
115
|
+
// builds the per-collection routing table.
|
|
116
|
+
const parsed = parseGrants(grants);
|
|
117
|
+
if (expectedServerUrl !== undefined &&
|
|
118
|
+
parsed.serverUrl !== expectedServerUrl) {
|
|
119
|
+
throw new Error(`Grants target "${parsed.serverUrl}", expected "${expectedServerUrl}".`);
|
|
120
|
+
}
|
|
121
|
+
for (const id of collections) {
|
|
122
|
+
const grant = parsed.byCollectionId[id];
|
|
123
|
+
if (!grant) {
|
|
124
|
+
throw new Error(`No grant covers the "${id}" collection.`);
|
|
125
|
+
}
|
|
126
|
+
const actions = actionsOf(grant);
|
|
127
|
+
const missing = requiredActions.filter(action => !actions.includes(action));
|
|
128
|
+
if (missing.length > 0) {
|
|
129
|
+
throw new Error(`The "${id}" grant lacks required actions: ${missing.join(', ')}.`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const expires = earliestExpiry(grants);
|
|
133
|
+
if (!expires) {
|
|
134
|
+
throw new Error('No grant carries a parseable expiry.');
|
|
135
|
+
}
|
|
136
|
+
return { parsed, grants, expires };
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=verifyResponse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyResponse.js","sourceRoot":"","sources":["../../src/auth/verifyResponse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyResponse.test.d.ts","sourceRoot":"","sources":["../../src/auth/verifyResponse.test.ts"],"names":[],"mappings":""}
|