Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authority API and URL & QR code device linking #572

Open
wants to merge 5 commits into
base: next
Choose a base branch
from

Conversation

icidasset
Copy link
Contributor

@icidasset icidasset commented Sep 20, 2023

Allows for authority transfer between multiple clients at the same time.

const volume = await program.account.volume()

// Provider
await program.authority.provide([
  odd.authority.account,
  odd.authority.fileSystem.rootAccess(volume.id)
])

program.authority.on("provide:query", event => {
  // Auto approve, alternatively you can show a UI for this.
  event.approve(event.queries)
})

// Requestor
await program.authority.request(
  odd.authority.account
)

await program.authority.request(
  odd.authority.fileSystem.rootAccess(volume.id)
)

program.authority.on("request:authorised", event => {
  console.log("Request authorised!", event)
})

Demo

Kapture.2023-09-01.at.17.03.09.mp4

⚠️ This was an older demo with the fission server that's still a work-in-progress. It also doesn't use the naming concept. I also had to refresh because of a bug with the websocket relay in the fission server.

How it works

  1. One or more clients call program.authority.provide() with authorisation queries. Queries are a way to select various UCANs and access keys. Above we have three queries: (1) query for the account capabilities (account component determines what these will be), (2 & 3) query for read & write access to the public & private roots of the file system
  2. You get a URL as the result from .provide(). This URL can be converted into a QR code.
  3. The URL is opened elsewhere.
  4. Whenever program.authority.request() is called, it checks for the query params associated with the authority component implementation. authority[challenge] and authority[publicKey] specifically.
  5. .request() detects the query params, establishes the channel via the channel component, making a websocket connection to the producer.
  6. The second part of the handshake is done, confirming various cryptographic values. Producer tells requestor that everything looks in order.
  7. Requestor sends over their query.
  8. Producer compares the query of the requestor with their own. The received query must be equal of contained by configured provision query (eg. if you share the path private/subdir/, the requestor cannot ask for acces to private/)
  9. Producer looks up the access keys and UCANs, then sends them over the channel encrypted.
  10. Requestor decrypts keys and UCANs.
  11. Authority transfer completed ✅

Names

File systems now have their own DID. I've added a names repo to manage the names for these DIDs. For example, when we do device linking, the new device doesn't know the DID of the file system they want request access to, instead we pass a name to the provider which then is resolved to a DID. It works like so:

  1. The new device requests account UCANs from the provider.
  2. The .volume() function which lives in the account implementation associates the name account_fs_did#${root_identifier_did} with the DID of the file system. This root identifier is the audience in the original file system UCAN and the FS DID is the issuer.
  3. Depending on the account UCANs in storage, the name returned from the volume function will be different. In other words, when we receive the account UCANs from the provider device, the name will be the same.
  4. We request file system capabilities with the name, not the DID.
  5. The provider resolves the name and provides the file system capabilities.
  6. Device = linked

This does introduce a new futile state for the volume and file system loading. This state represents the in-between state where we know the name of the file system, but we haven't resolved the name yet. This is the state after requesting the account UCANs and before requesting the file system UCANs.

Additional notes

  • This does not ping the producer until they're online. Because that concept doesn't make sense here seeing that every session will have unique key-pair and thus unique URL/QR-code. If you've opened a link and closed the producer, the session becomes useless. Instead you open the producer again and use the new URL/QR-code.
  • You can provide and request at the same time.

Other changes

  • Abstracted various UCAN delegations in order to support more ecosystems.
  • Adjusted Inventory to also work with access keys.
  • Added a channel implementation for local-first-web/relay
  • Fixes some file system issues (rs-wnfs has been updated too)
  • Made various identifier and agent method sync instead of async.
  • Moved all dependencies that are only used by components to peer dependencies (as to separate them from the sdk core)

Test plan

This was originally tested with a specific commit of the Fission server, before the UCAN changes were made. However, I've also now made the SDK compatible with the Web3Storage UCAN ecosystem, I'll make a repo for that soon on my Github profile.

@icidasset icidasset changed the title Authority Authority API and URL & QR code device linking Sep 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant