changed 3 years ago
Linked with GitHub

ActivityPub ZCAPs

aka activityCaps

What?

Prior Art

TODO

  • define activityCaps namespace and baseUri
  • add "@context" to all the Example JSONs

Simple: sending a direct message

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

"Simple"

Assumptions:

  • Ben is known by URI like https://bengo.is or did:web:bengo.is
  • We have defined new terms
    • activityCaps:act
      • This is relation from an actor to the capability to act as the actor
    • activityCaps:post
      • This is relation from a resource to the capability that posts (sends) a message to the resource
  • this scenario is for a service communicated with via HTTPS. Therefore, most URIs are https URIs. did URIs are only referenced via sameAs relationships, and should only need to be handled by did-aware clients.
    • TODO: sketch this for invocations over non-https transports

New Terms

activitypub-capabilities:act

This is relation from an actor to the capability to act as the actor

activitypub-capabilities:post

This is relation from a resource to the capability that posts (sends) a message to the resource

Posting the message to the actor's outbox

GET https://bengo.is

{ "id": "https://bengo.is", "sameAs": "did:web:bengo.is", "inbox": "/inbox", "outbox": { "id": "/outbox", "apcap:post": "/outbox?capability=post", }, "activityCaps:act": "?capability=act" }

GET https://bengo.is?capability=act

{ "content": "this capability represents being able to act as this actor, e.g. to 'post' things using activitypub tht are then attributedTo https://bengo.is. i.e. this may imply capability to write to this actor's outbox and to write to other activitypub servers' inboxes", "invoker": "https://bengo.is", }

GET https://bengo.is/outbox

The outbox has a post capability, which is referenced from the outbox using the activityCaps:post relation.

{ "http:status": 401, "content": "use POST or provide Authorization", "activityCaps:post": "?capability=post" }

GET https://bengo.is/outbox?capability=post

The outbox has a post capability. Who can invoke it? Well, the actor whose inbox it is.

{ "content": "invoke this capability to post a message to the outbox", "invoker": "https://bengo.is" }

POST https://bengo.is/outbox

sans authorization

Request

{ "type": "Note", "content": "gm" }

Response

{ "http:status": 401, "content": "Authorization is required. Try providing some." }
with authorization via zcap-ld

Request

.proof.creator is a key uri which has a 'capabilityInvocation' [verification relationship] expressed in the DID Document found by resolving the did did:web:bengo.is. Remember, resolving https://bengo.is as JSON-LD shows a owl:sameAs relationship to did:web:bengo.is. i.e. we can follow from

  • https://bengo.is ap:outbox ->
  • https://bengo.is/outbox activityCaps:post ->
  • https://bengo.is/outbox?capability=post zcap:invoker ->
  • https://bengo.is sameAs ->
  • did:web:bengo.is did:capabilityInvocation ->
  • did:key:bengo-keys:0 (which is the creator of the zcap:proof)

Questions

  • Perhaps it would be clearer if I wrap this Note object in a Create activity. But I think AP requires the server to do that at some point anyway.
{"@context": [ "https://example.org/zcap/v1", "https://www.w3.org/ns/activitystreams" ], "id": "urn:uuid:ad86eb2c-e9db-434a-beae-71b82120a8a4", "to": "https://dustycloud.org", "type": "Note", "content": "gm", "proof": { "type": "Ed25519Signature2018", "proofPurpose": "capabilityInvocation", "capability": "https://bengo.is?capability=act", "created": "2022-05-16T17:13:48Z", "creator": "did:key:bengo-keys:0", "signatureValue": "..."}}

Response

{ "http:status": 201, "location": "/urn:uuid:ad86eb2c-e9db-434a-beae-71b82120a8a4" }

GET /urn:uuid:ad86eb2c-e9db-434a-beae-71b82120a8a4

This is the posted 'Create Note' activity.

Response

{ "id": "urn:uuid:ad86eb2c-e9db-434a-beae-71b82120a8a4", "result": "/notes/89c9b8aa-bb17-4b5d-8583-ad88fc2de3f6" }

GET /notes/89c9b8aa-bb17-4b5d-8583-ad88fc2de3f6

{"@context": [ "https://example.org/zcap/v1", "https://www.w3.org/ns/activitystreams" ], "id": "urn:uuid:ad86eb2c-e9db-434a-beae-71b82120a8a4", "to": "https://dustycloud.org", "type": "Note", "content": "gm", "proof": { "type": "Ed25519Signature2018", "proofPurpose": "capabilityInvocation", "capability": "https://bengo.is?capability=act", "created": "2022-05-16T17:13:48Z", "creator": "did:key:bengo-keys:0", "signatureValue": "..."}}

Server-to-server Delivery

According to ActivityPub, Ben's server now wants to find a way of delivering this activity to dustycloud.org's server.

GET https://dustycloud.org

{"id": "https://dustycloud.org", "inbox": "/inbox"}

GET https://dustycloud.org/inbox

{"activityCaps:post": "?capabilities=post"}

GET https://dustycloud.org/inbox?capabilities=post

  • delegationPolicy is a relation I made up to describe the policy it will use to determine whether it will delegate to a potential invoker
{ "delegationPolicy": { "requireActorCapability": ["activityCaps:act"] } }

POST https://dustycloud.org/inbox

Noteworthy

  • we encourage activitypub inbox to allow POST via proof of capabilityInvocation of the capability that has the activityCaps:act relation from the actor

Request to https://dustycloud.org/inbox

{"@context": [ "https://example.org/zcap/v1", "https://www.w3.org/ns/activitystreams" ], "id": "urn:uuid:ad86eb2c-e9db-434a-beae-71b82120a8a4", "to": "https://dustycloud.org", "type": "Note", "content": "gm", "proof": { "type": "Ed25519Signature2018", "proofPurpose": "capabilityInvocation", "capability": "https://bengo.is?capability=act", "created": "2022-05-16T17:13:48Z", "creator": "did:key:bengo-keys:0", "signatureValue": "..."}}

Also considered:

  • ways for the sending server to request delegation of the 'post to inbox' capability from the receiving server, perhaps with a specific caveat of a specific message.
    • this is not preferred as it might end up being too different from TR ActivityPub server-to-server protocol. Maybe not that big a deal. Instead of POST fwded activity to /inbox, POST invocation to /inbox?capability=post

Curating a photo collection

Rights amplification for reply control

  • Question: What does this mean?

Controlling who can send you messages

  • do you really need to do this? Is it enough to only process messages in the inbox that have proof of invocation of activityCaps:act of actors that are in a set of actors controlled by 'you'?

Managing a mailing-list like Group

Creating an Identifier

POST /identifiers

Request

{ "controller": "did:method:identifiers:0:controllers:0" }

Response

  • HTTP
    • status: 201
    • location: /identifiers/did:key:identifiers:0
{ "url": "/identifiers/{uuid}" }

GET /identifiers/{uuid}

This is a did doc.

It's intended that did:web:{host}:identifiers:{uuid} resolves to this did doc. That may not be possible. The identifier may or may not support updates to its referent. If not, it may just be a did:key.

Response

{ "id": "/identifiers/{uuid}", "controller": "did:method:identifiers:0:controllers:0" }

Creating an Actor

POST /actors/

Request

{ "controller": "did:web:bengo.is", "parts": ["https://activitypub.com/parts/actor"] }

Response

  • HTTP
    • status: 201
{ "url": "/actors/did:key:actors:0" }

GET /actors/{did}

Response

  • HTTP
    • status: 200
{ "id": "/identifiers/{did}", "sameAs": "{did}", "inbox": "/actors/{did}/inbox", "activityCaps:act": "/actors/{did}/capabilities/act" }
Select a repo