Skip to content

Commit

Permalink
feat: use blob protocol capabilities (#92)
Browse files Browse the repository at this point in the history
Adjusts recommended capabilities to include blob protocol capabilities.

Note: I didn't update the HTTP bridge docs as it requires more work.
  • Loading branch information
Alan Shaw authored Jun 4, 2024
1 parent dce92da commit cf262fb
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/pages/docs/concepts/architecture-options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Your backend code can then re-delegate it's capabilities to your users. Your use

When your user is ready to upload, they should request a delegation from your backend to upload to your Space. They must send their Agent DID so that the delegation is restricted to be used by only them.

In your backend, you can call [`client.createDelegation(...)`](https://github.com/web3-storage/w3up/blob/main/packages/w3up-client/README.md#createdelegation) passing in the Agent object from `client.agent()` in your end user's instance, and passing params to limit the scope of the delegation (e.g., `store/add`, `upload/add`, expiration time)
In your backend, you can call [`client.createDelegation(...)`](https://github.com/web3-storage/w3up/blob/main/packages/w3up-client/README.md#createdelegation) passing in the Agent object from `client.agent()` in your end user's instance, and passing params to limit the scope of the delegation (e.g., `space/blob/add`, `upload/add`, expiration time)

You can serialize the delegation using `delegation.archive()` and send it to your user.

Expand Down Expand Up @@ -98,7 +98,7 @@ async function backend(did) {

// Create a delegation for a specific DID
const audience = DID.parse(did)
const abilities = ['store/add', 'upload/add']
const abilities = ['space/blob/add', 'space/index/add', 'filecoin/offer', 'upload/add']
const expiration = Math.floor(Date.now() / 1000) + (60 * 60 * 24) // 24 hours from now
const delegation = await client.createDelegation(audience, abilities, { expiration })

Expand Down
7 changes: 5 additions & 2 deletions src/pages/docs/concepts/ucan.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ async function delegationRequestHandler (request) {
// we're issuing the delegation to, as well as a list of
// "ability" strings.
// Here, we're passing in the abilities needed to upload to the space:
// 'space/info', 'store/add', and 'upload/add'.
// 'space/blob/add', 'space/index/add', 'filecoin/offer', and 'upload/add'.
//
// With these capabilities, the user will be able to upload to the space,
// but they won't be able to list existing uploads or perform any "management"
Expand All @@ -113,7 +113,10 @@ async function delegationRequestHandler (request) {
//
// See the capabilities spec for more about capabilities:
// https://github.com/web3-storage/w3protocol/blob/main/spec/capabilities.md
const delegation = await client.createDelegation(userDID, ['store/add', 'upload/add'])
const delegation = await client.createDelegation(
userDID,
['space/blob/add', 'space/index/add', 'filecoin/offer', 'upload/add']
)

// The delegation object is a binary "blob" that encodes the UCAN
// delegation into the CAR format.
Expand Down
8 changes: 4 additions & 4 deletions src/pages/docs/concepts/ucans-and-web3storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ UCAN-based APIs are centered around _capabilities_, which are comprised of an _a

When you upload data to w3up, your uploads are linked to a unique _Space_ that acts as a "namespace" for the data you upload. Each Space corresponds to a _DID_, or [Decentralized Identity Document](https://www.w3.org/TR/did-core/). In web3.storage's implementation of w3up, these Space DIDs generally use the key DID method, of the form did:key:publicKey with a corresponding private signing key.

When creating a Space, it generates this private key and did:key for you locally. To use web3.storage, you then register a Space by associating it with your email address. From there, when invoking storage capabilities with web3.storage, the Space did:key is the "resource" portion of the capability, while the ability is an action like store/add or store/remove. (A Space registered with web3.storage is imperfectly analogous to an "account" with web3.storage.)
When creating a Space, it generates this private key and did:key for you locally. To use web3.storage, you then register a Space by associating it with your email address. From there, when invoking storage capabilities with web3.storage, the Space did:key is the "resource" portion of the capability, while the ability is an action like space/blob/add or space/blob/remove. (A Space registered with web3.storage is imperfectly analogous to an "account" with web3.storage.)

Under the hood in the email registration process, your Space delegates the capabilities needed to use w3up to your email address, and this delegation is stored by web3.storage. If you need access to your Space in the future from any device, web3.storage allows you to reclaim those capabilities the same way you would reset a password in other services - using an email verification process. This means you don't need to store or manage Space private keys to use w3up - just create a new space, register it with w3up and use it from as many devices as you like. More on this "sign in" process is detailed in the next section on Agents.

### Agent

To invoke a capability like store/add on a Space using the client or CLI, the client must have an _Agent_. Like a Space, an Agent corresponds to a did:key whose private key is generated locally. An Agent is useful once the client or CLI has a UCAN delegation where a registered Space(s) delegates the Agent its capabilities. (An imperfect analogy is Agent to login session.)
To invoke a capability like space/blob/add on a Space using the client or CLI, the client must have an _Agent_. Like a Space, an Agent corresponds to a did:key whose private key is generated locally. An Agent is useful once the client or CLI has a UCAN delegation where a registered Space(s) delegates the Agent its capabilities. (An imperfect analogy is Agent to login session.)

The delegation from a Space to your Agent that w3up-client needs can be passed either by verifying the email address the Space is registered to and claiming the UCAN delegation (authorize(email) then capability.access.claim) or directly if you have the UCAN delegation available locally (addSpace(delegation)).

Expand Down Expand Up @@ -51,7 +51,7 @@ async function backend(did) {

// Create a delegation for a specific DID
const audience = DID.parse(did)
const abilities = ['store/add', 'upload/add']
const abilities = ['space/blob/add', 'space/index/add', 'filecoin/offer', 'upload/add']
const expiration = Math.floor(Date.now() / 1000) + (60 * 60 * 24) // 24 hours from now
const delegation = await client.createDelegation(audience, abilities, { expiration })

Expand All @@ -74,7 +74,7 @@ async function parseProof(data) {
When the `backend` function is called in the developer's backend:
- It's passed the DID of the user's Agent
- Backend client initializes with an Agent that has permission to the developer's Space
- It then generates a UCAN delegated to the user Agent DID passed in with only the `store/add` and `upload/add` abilities (to give the user ability to upload) and set to expire in 24 hours
- It then generates a UCAN delegated to the user Agent DID passed in with only the `space/blob/add`, `space/index/add`, `filecoin/offer` and `upload/add` abilities (to give the user ability to upload) and set to expire in 24 hours

**Frontend**

Expand Down
4 changes: 2 additions & 2 deletions src/pages/docs/concepts/upload-vs-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ Let's break it down. In the CLI example above where we called `w3 up file`, we s

The CLI and client first take the upload and converts it into an DAG (directed acyclic graph). This is what IPFS uses to generate the content CID - each node in the graph has its own CID, with the graph's leafs containing the upload's data, and the root node of the graph the content CID of the entire graph. However, to send the data to web3.storage, the content has to be in a different form. web3.storage achieves this by converting the graph into a set of CAR file shards.

Each CAR shard has a CID associated with the data itself (i.e., as it sits on disk serialized, with a header for instructions on how the blocks within the serialized data should be arranged, etc.). The CLI and client send each of these shards one-by-one to web3.storage by invoking the `store/add` UCAN capability under the hood (e.g., `w3 can store add`)!
Each CAR shard has a CID associated with the data itself (i.e., as it sits on disk serialized, with a header for instructions on how the blocks within the serialized data should be arranged, etc.). The CLI and client send each of these shards one-by-one to web3.storage by invoking the `space/blob/add` UCAN capability under the hood (e.g., `w3 can blob add`)!

However, from web3.storage's perspective, it doesn't necessarily know whether the set of CAR shards it was sent from the series of `store/add`s corresponds to a single content CID that the user cares about, multiple content CIDs, or none at all (e.g., the CAR files sent represent an incomplete graph). As a result, `upload/add` allows the user to explicitly register a content CID with a set of shard CIDs. This is primarily done for the user's sake - it makes it easier to track which content CIDs (what they're using to fetch data from the IPFS network) correspond to which shard CIDs (what is physically being stored with web3.storage).
However, from web3.storage's perspective, it doesn't necessarily know whether the set of CAR shards it was sent from the series of `space/blob/add`s corresponds to a single content CID that the user cares about, multiple content CIDs, or none at all (e.g., the CAR files sent represent an incomplete graph). As a result, `upload/add` allows the user to explicitly register a content CID with a set of shard CIDs. This is primarily done for the user's sake - it makes it easier to track which content CIDs (what they're using to fetch data from the IPFS network) correspond to which shard CIDs (what is physically being stored with web3.storage).

In cases where the user is uploading a whole file or directory like in the example above, it's safe to know that the series of CAR shards uploaded by the user correspond to the file's content CID that it cares about. That's why the higher-level `w3 up` method is appropriate to use, and should represent the vast majority of upload use cases by web3.storage users.

Expand Down
6 changes: 3 additions & 3 deletions src/pages/docs/how-to/ci.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ $ w3 key create --json > ci-key.json
$ AUDIENCE=$(jq -r .did ci-key.json)

# Create a signed proof that you delegate capabilties to that key.
$ w3 delegation create $AUDIENCE -c store/add -c upload/add --base64
$ w3 delegation create $AUDIENCE -c space/blob/add -c space/index/add -c filecoin/offer -c upload/add --base64
mAYIEAP8OEaJlcm9vdHOAZ3ZlcnNpb24BwwUBcRIg+oHTbzShh1WzBo9ISkonCW+KAcy/+zW8Zb...

# Pass the output to `w3 space add` in ci
Expand Down Expand Up @@ -90,15 +90,15 @@ The `did` from the command above is the public decentalised identifier for that

On your local machine, use [w3cli][] to delegate capabilties to upload to our space to the public DID for the signing key we created.

Our CI environment doesn't need to list our uploads or change our billing plan so we only delegate the `store/add` and `upload/add` capabilities to it.
Our CI environment doesn't need to list our uploads or change our billing plan so we only delegate the `space/blob/add`, `space/index/add`, `filecoin/offer` and `upload/add` capabilities to it.

Pass the `did` for the signing key as the audience parameter. We are delegating capabilities to that key.

```shell
$ AUDIENCE=did:key:z6Mk...

# Delegate capabilities to the `did` we created above.
$ w3 delegation create $AUDIENCE -c 'store/add' -c 'upload/add' --base64
$ w3 delegation create $AUDIENCE -c space/blob/add -c space/index/add -c filecoin/offer -c upload/add --base64
mAYIEAP8OEaJlcm9vdHOAZ3ZlcnNpb24BwwUBcRIg+oHTbzShh1WzBo9ISkonCW+KAcy/+zW8Zb...
```

Expand Down
6 changes: 3 additions & 3 deletions src/pages/docs/how-to/upload.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ w3 key create
# access to.
#
# If you want to limit permissions being passed to the Agent, you can specify
# permissions to give, e.g., `--can 'store/add' --can 'upload/add'` limits to
# just being able to upload.
# permissions to give, e.g., `--can space/blob/add --can space/index/add --can
# filecoin/offer --can upload/add` limits to just being able to upload.
w3 delegation create <did_from_ucan-key_command_above> | base64

# ❗️ Store the output in environment variable PROOF
Expand Down Expand Up @@ -246,7 +246,7 @@ async function backend(did) {

// Create a delegation for a specific DID
const audience = DID.parse(did)
const abilities = ['store/add', 'upload/add']
const abilities = ['space/blob/add', 'space/index/add', 'filecoin/offer', 'upload/add']
const expiration = Math.floor(Date.now() / 1000) + (60 * 60 * 24) // 24 hours from now
const delegation = await client.createDelegation(audience, abilities, { expiration })

Expand Down

0 comments on commit cf262fb

Please sign in to comment.