ActivityPub

Last modified by Vincent Massol on 2024/02/26 17:53

 XWiki
 Implementation
 Active
 
 

https://forum.xwiki.org/t/new-application-activitypub

 

https://www.w3.org/TR/activitypub
https://github.com/xwiki-contrib/application-activitypub

Description

    1. Design choices
      1. JSON library
      2. HTTP Answers
      3. Persistency
      4. Follow Activity
      5. URLs
    2. WebFinger

This page is to follow implementation of the ActivityPub protocol inside XWiki and to document the different design decisions.

Design choices

JSON library

The protocol is using JSON-LD to define the various requests body. However JSON-LD is fully compliant with JSON libraries, and we don't need here to use the specifity of JSON-LD. So for now we decided to use Jackson to serialize/parse the requests. 

HTTP Answers

The protocol doesn't define precisely what should be the answers of the POST request made. So we decided to use the following rule when everything's fine:

  • answer a 202 Accepted, in case of request that needs to be processed later on by the user (e.g. a follow request) with the activity in the body (useful to get the produced ID)
  • answer a 201 Created, in case of request that leads to a Create activity (e.g. posting a Note) or posted directly with the Create activity, with the activity in the body
  • answer a 200 OK, in other cases with the activity in the body

Persistency

All JSON produced by an instance of AP are immediately stored in a DB: the ID is generated after the storing since IDs are URI that must serve the resource they identify.

We chose to also store the information that are needed by AP but coming from other servers in AP 1.2 for two reasons:

  1. it avoids using too many HTTP requests since the info are immediately available in the DB

  2. it allows to be able to resolve information if an instance is not available right now, which can avoid errors

Follow Activity

It is not explicitely explained in the protocol if a follow activity should be public or not.
The only information we have is that each actor contains a list of followers/following and

 The following [or follower] collection [...] MAY be filtered on privileges of an authenticated user or as appropriate when no authentication is given. 

I consider for now that only the logged user can see her/his followings/followers. Any anonymous user will get an empty list.

Now according to the documentation every actor has an outbox which

 contains activities the user has published, subject to the ability of the requestor to retrieve the activity (that is, the contents of the outbox are filtered by the permissions of the person reading it).

So I consider that the follow activity is immediately published (even if it has not been accepted yet), but only the logged user can retrieve it.

URLs

ActivityPub and more globally ActivityStreams specify that each object is defined by an ID which is also an URI. Moreover, most of the attributes in the JSON answers can be the actual objects or a link (the ID) towards those objects.
Now ActivityPub protocol entirely relies on performing GET/POST on Actors' Inbox/Outbox, which are some specific kind of ActivityStreams object.

I hesitated to use a dedicated URL scheme for actions to perform on Inbox/Outbox, but I finally decided to only use a single URL scheme for all entities manipulated by AP:
xwiki-server/entity/id

where entity can be: an activity (e.g. Follow) or an object (e.g. a Note or even an Inbox).
The ID can be different given the kind of entity: in case of an Inbox, it would be the User reference of that Inbox for example.
In case of another type of object it might an UUID provided by the persistency API.

WebFinger

We provide an implementation of WebFinger resolution to help using AP in XWiki.

The idea of WebFinger is to be able to use "simple" identifier that will be resolved automatically, so for example using foo@domain.com
will automatically trigger a request to domain.com to find the user foo.
That being said, we now have several usecases that we need to be able to handle for XWiki, and we want to be able to handle them with WebFinger:

  1. find an XWiki user from the main wiki
      2. find an XWiki user from a subwiki
      3. find a Wiki (main or sub) from the main wiki
      4. find a Wiki (main or sub) from a subwiki

The usecase 4 might look strange, but we can imagine that domain.com actually points to a subwiki and not the main wiki. And we might want to be able to follow a sibling subwiki, or its main wiki.
I ordered the usecases by what I consider is their priority and how likely they will happen.

Before providing a scheme to solve those usecases, let's sum up some rules regarding XWiki and WebFinger names:
  - WebFinger resolution name must be a valid URI so xwiki:Foo@domain.com is not supported
  - XWiki User name currently does not accept symbol other than underscore, so dots . and @ are not supported
  - XWiki Wiki name currently cannot be xwiki since it's the default main wiki name
  - XWiki User name might be xwiki

We propose the following resolution name scheme:
resolutionName = identifier '@' host
identifier = username
         || username '.' subwiki
         || wikiname '.xwiki'

Examples: 

Example 1

resolutionName: foo@domain.com

Assumption: domain.com points to the main wiki

Resolution:
  - the XWiki User named foo is looked in the main wiki.
  - if the user is not found a 404 is answered.

Example 2

resolutionName: foo.bar@domain.com

Assumption: domain.com points to the main wiki

Resolution:
  - A subwiki bar is looked for, if not found a 404 is answered
  - if the subwiki is found, the user foo is looked for, by following the user policy of the subwiki
  - if the user is not found a 404 is answered.

Example 3

resolutionName: foo@domain.com

Assumption: domain.com points to the sub wiki bar

Resolution:
  - the user foo is looked for, by following the user policy of the subwiki
  - if the user is not found a 404 is answered.

Example 4

resolutionName: foo.bar@domain.com

Assumption: domain.com points to the sub wiki bar

Resolution:
  - the user foo is looked for, by following the user policy of the subwiki
  - if the user is not found a 404 is answered.

Example 5

resolutionName: foo.buz@domain.com

Assumption: domain.com points to the sub wiki bar

Resolution:
  - A subwiki buz is looked for, if not found a 404 is answered
  - the user foo is looked for, by following the user policy of the subwiki
  - if the user is not found a 404 is answered.

Example 6

resolutionName: xwiki@domain.com

Assumption: domain.com points to the main wiki

Resolution:
  - the XWiki User named xwiki is looked in the main wiki.
  - if the user is not found a 404 is answered.

Example 7

resolutionName: bar.xwiki@domain.com

Assumption: domain.com points to the main wiki

Resolution:
  - a subwiki named bar is looked for, if not found a 404 is answered
  - the actor corresponding of the sub wiki is returned if found

Example 8

resolutionName: xwiki.xwiki@domain.com

Assumption: domain.com points to the main wiki

Resolution:
  - the actor corresponding of the main wiki is directly returned

Example 9

resolutionName: foo.xwiki@domain.com

Assumption: domain.com points to the sub wiki bar

Resolution:
  - a subwiki named foo is looked for, if not found a 404 is answered
  - the actor corresponding of the sub wiki is returned if found

Example 10

resolutionName: xwiki.xwiki@domain.com

Assumption: domain.com points to the sub wiki bar

Resolution:
  - the actor corresponding of the main wiki on top of this subwiki is directly returned

Example 11

resolutionName: bar.xwiki@domain.com

Assumption: domain.com points to the sub wiki bar

Resolution:
  - the actor corresponding of this subwiki is directly returned


 

Get Connected