From e863cdd1d39d8f124aaa0dba091d1e409a4c7cc7 Mon Sep 17 00:00:00 2001 From: Oli Evans Date: Tue, 28 Nov 2023 20:02:21 +0000 Subject: [PATCH 1/3] fix: sync space names from proofs space names are stored as facts in proofs in the special `ucan:*` delegation from email to agent e.g. ```yaml iss: did:mailto:protocol.ai:oli att: - can: * with: ucan:* fct: - {"access/confirm":{"/":"bafyreidadrwbxueiuhtbph2tj2m7a6nizpx7sbtqotbfkkjsoytn3dg2t4"},"access/request":{"/":"bafyreigmlliovbpxka2borbdaw6zpsai4qzmzv5nv7syl7nagecxjcub6e"}} prf: - {"iss":"did:key:z6Mku56ywWspVnzkcVQbeSkw6egVRSNKVSYgS38HhKcUJRiN","aud":"did:mailto:protocol.ai:oli","v":"0.9.1","s":{"/":{"bytes":"7aEDQPgUVQFVOoLmijx8O7Li9zyc7iIHEDnCwiqr+LcV9CyHd/KzUg1Ige7Okh+ipVMOKy2EvG8dGjWfsdAAbUVPMwo"}},"exp":null,"att":[{"can":"*","with":"did:key:z6Mku56ywWspVnzkcVQbeSkw6egVRSNKVSYgS38HhKcUJRiN"}],"fct":[{"space":{"name":"fruits"}}],"prf":[],"/":"bafyreihhlz5yjci6h7vdrlgn5xnyc65e3unp3dx2yrspepwoftaxszxpxa"} ``` this will be fixed more robustly by the proposed re-imagining of the client as a stateless view over the stored ucans, but i'd like to land this fix asap, as it's currently you dont' get to see your existing space names when calling login in a new agent. fixes: https://github.com/web3-storage/w3up/issues/1176 License: MIT Signed-off-by: Oli Evans --- packages/access-client/src/agent.js | 46 +++++++++++++++++++---------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/access-client/src/agent.js b/packages/access-client/src/agent.js index d4d2d7c6d..09fafa1cb 100644 --- a/packages/access-client/src/agent.js +++ b/packages/access-client/src/agent.js @@ -7,7 +7,7 @@ import { attest } from '@web3-storage/capabilities/ucan' import * as Access from './access.js' import * as Space from './space.js' -import { invoke, delegate, DID, Delegation, Schema } from '@ucanto/core' +import { invoke, delegate, DID, Delegation, Schema, isDelegation } from '@ucanto/core' import { isExpired, isTooEarly, canDelegateCapability } from './delegations.js' import { AgentData, getSessionProofs } from './agent-data.js' import { UCAN } from '@web3-storage/capabilities' @@ -621,24 +621,40 @@ export async function addSpacesFromDelegations(agent, delegations) { }) } - for (const delegation of delegations) { - // We only consider delegations to this agent as those are only spaces that - // this agent will be able to interact with. - if (delegation.audience.did() === agent.did()) { - // TODO: we need a more robust way to determine which spaces a user has access to - // it may or may not involve look at delegations - const allows = ucanto.Delegation.allows(delegation) - - for (const [did, value] of Object.entries(allows)) { - // If we discovered a delegation to any DID, we add it to the spaces list. - if (did.startsWith('did:key') && Object.keys(value).length > 0) { - data.addSpace(/** @type {API.DID} */ (did), { - name: '', - }) + // spaces we find along the way. + const spaces = new Map() + // only consider ucans with this agent as the audience + const ours = delegations.filter(x => x.audience.did() === agent.did()) + // space names are stored as facts in proofs in the special `ucan:*` delegation from email to agent. + const ucanStars = ours.filter(x => x.capabilities[0].can === '*' && x.capabilities[0].with === 'ucan:*') + for (const delegation of ucanStars) { + for (const proof of delegation.proofs) { + if (!isDelegation(proof) || !proof.capabilities[0].with.startsWith('did:key')) { + continue + } + const space = Space.fromDelegation(proof) + spaces.set(space.did(), space.meta) + } + } + + // Find any other spaces the user may have access to + for (const delegation of ours) { + // TODO: we need a more robust way to determine which spaces a user has access to + // it may or may not involve look at delegations + const allows = ucanto.Delegation.allows(delegation) + for (const [resource, value] of Object.entries(allows)) { + // If we discovered a delegation to any DID, we add it to the spaces list. + if (resource.startsWith('did:key') && Object.keys(value).length > 0) { + if (!spaces.has(resource)) { + spaces.set(resource, {}) } } } } + + for (const [did, meta] of spaces) { + data.addSpace(did, meta) + } } /** From b03005769da81d10a100cb8976f7425bf5f442bb Mon Sep 17 00:00:00 2001 From: Oli Evans Date: Wed, 29 Nov 2023 11:09:57 +0000 Subject: [PATCH 2/3] fix: await addSpace License: MIT Signed-off-by: Oli Evans --- packages/access-client/src/agent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/access-client/src/agent.js b/packages/access-client/src/agent.js index 09fafa1cb..4cb24655c 100644 --- a/packages/access-client/src/agent.js +++ b/packages/access-client/src/agent.js @@ -653,7 +653,7 @@ export async function addSpacesFromDelegations(agent, delegations) { } for (const [did, meta] of spaces) { - data.addSpace(did, meta) + await data.addSpace(did, meta) } } From 877148e25c26f866397aa341dc9e7106adf6cf06 Mon Sep 17 00:00:00 2001 From: Oli Evans Date: Wed, 29 Nov 2023 11:18:43 +0000 Subject: [PATCH 3/3] chore: prettier i guess License: MIT Signed-off-by: Oli Evans --- packages/access-client/src/agent.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/access-client/src/agent.js b/packages/access-client/src/agent.js index 4cb24655c..793621ec6 100644 --- a/packages/access-client/src/agent.js +++ b/packages/access-client/src/agent.js @@ -7,7 +7,14 @@ import { attest } from '@web3-storage/capabilities/ucan' import * as Access from './access.js' import * as Space from './space.js' -import { invoke, delegate, DID, Delegation, Schema, isDelegation } from '@ucanto/core' +import { + invoke, + delegate, + DID, + Delegation, + Schema, + isDelegation, +} from '@ucanto/core' import { isExpired, isTooEarly, canDelegateCapability } from './delegations.js' import { AgentData, getSessionProofs } from './agent-data.js' import { UCAN } from '@web3-storage/capabilities' @@ -624,12 +631,17 @@ export async function addSpacesFromDelegations(agent, delegations) { // spaces we find along the way. const spaces = new Map() // only consider ucans with this agent as the audience - const ours = delegations.filter(x => x.audience.did() === agent.did()) + const ours = delegations.filter((x) => x.audience.did() === agent.did()) // space names are stored as facts in proofs in the special `ucan:*` delegation from email to agent. - const ucanStars = ours.filter(x => x.capabilities[0].can === '*' && x.capabilities[0].with === 'ucan:*') + const ucanStars = ours.filter( + (x) => x.capabilities[0].can === '*' && x.capabilities[0].with === 'ucan:*' + ) for (const delegation of ucanStars) { for (const proof of delegation.proofs) { - if (!isDelegation(proof) || !proof.capabilities[0].with.startsWith('did:key')) { + if ( + !isDelegation(proof) || + !proof.capabilities[0].with.startsWith('did:key') + ) { continue } const space = Space.fromDelegation(proof) @@ -651,7 +663,7 @@ export async function addSpacesFromDelegations(agent, delegations) { } } } - + for (const [did, meta] of spaces) { await data.addSpace(did, meta) }