Federated forge server

[[ 🗃 ^rjQ3E vervis ]] :: [📥 Inbox] [📤 Outbox] [🐤 Followers] [🤝 Collaborators] [🛠 Commits]

Clone

HTTPS: git clone https://vervis.peers.community/repos/rjQ3E

SSH: git clone USERNAME@vervis.peers.community:rjQ3E

Branches

Tags

main ::

API.md

This document describes the Client-to-Server API of Vervis. If you’re developing a frontend application, or a forge search engine, or anything else that wants to interact with Vervis instances, and wondering what language Vervis speaks, this is the document for you.

I suppose in the future it should sit on a Docusaurus website or something like that. For now it’s here.

Public Browsing

The /browse page lists the public actors and resource hosted on the server. However there’s currently no AP version of that page.

Server Information

NodeInfo isn’t implemented yet.

Registration and Authorization

Creating an account on a Vervis instance allows to:

  1. Create and manipulate resources (such as projects, repositories, teams)
  2. View non-public information

Register the application

Register client

Send a POST request to the /oauth/apps endpoint:

curl -X POST \
    -F 'client_name=Anvil' \
    -F 'redirect_uris=urn:ietf:wg:oauth:2.0:oob' \
    -F 'scopes=read' \
    -F 'website=https://anvil.forgefed.org' \
    -F 'repository=https://codeberg.org/Anvil/Anvil' \
    https://vervis.example/oauth/apps

The response, upon success, is a JSON object with 2 text fields:

Keep these stored for future use.

Obtain an Application Access Token

Send a POST request to the /oauth/token endpoint:

curl -X POST \
    -F 'client_id=your_client_id_here' \
    -F 'client_secret=your_client_secret_here' \
    -F 'redirect_uri=urn:ietf:wg:oauth:2.0:oob' \
    -F 'grant_type=client_credentials' \
    https://vervis.example/oauth/token

The response is a JSON object with:

Verify the Application Access Token

You can verify the token works by sending a GET request to the /oauth/verify_credentials endpoint:

curl \
    -H 'Authorization: Bearer our_access_token_here' \
    https://vervis.example/oauth/verify_credentials

Register an Account

This section isn’t implemented yet. I’m about to implement it. Putting the API here for review while I’m coding.

Check if registration is enabled

Send a GET request to the /register/enabled endpoint. A 2xx response indicates it’s enabled, otherwise it’s disabled.

Check username availability

Send a GET request to the /register/available endpoint:

curl -X GET \
    -H 'Authorization: Bearer our_application_access_token_here' \
    -F 'username=alice' \
    https://vervis.example/register/available

A 2xx response indicates the username is available.

Create a new account

Send a POST request to the /register endpoint:

curl -X POST \
    -H 'Authorization: Bearer our_application_access_token_here' \
    -F 'username=alice' \
    -F 'passphrase=R6GQJ9HqLtRQ58' \
    -F 'email=alice@email.example' \
    https://vervis.example/register

A 2xx response indicates the account has been created. A JSON object is returned, with a boolean email_sent field. If true, a verification email has been sent to the specified email address. If false, it means email verification is disabled on this server, and the account is ready to be used.

Verify account

The email contains a token, which you can send via a POST request to the /register/verify endpoint, in order to verify and enable the account:

curl -X POST \
    -H 'Authorization: Bearer our_application_access_token_here' \
    -F 'username=alice' \
    -F 'token=pRiW8ayeuN7UBW4qAKg9qRBE0DUVCIof' \
    https://vervis.example/register/verify

A 2xx response indicates successful verification.

Log in as Existing User

Obtain authorization code

In a browser, send a GET request to the /oauth/authorize endpoint:

https://vervis.example/oauth/authorize
?client_id=CLIENT_ID
&scope=read
&redirect_uri=urn:ietf:wg:oauth:2.0:oob
&response_type=code

redirect_uri?code=qDFUEaYrRK5c-HNmTCJbAzazwLRInJ7VHFat0wcMgCU

Obtain a User Access Token

Now that we have the code, send a POST request to the /oauth/token endpoint (which we previously used when registering the application):

curl -X POST \
    -F 'client_id=your_client_id_here' \
    -F 'client_secret=your_client_secret_here' \
    -F 'redirect_uri=urn:ietf:wg:oauth:2.0:oob' \
    -F 'grant_type=authorization_code' \
    -F 'code=user_authzcode_here' \
    -F 'scope=read' \
    https://vervis.example/oauth/token

The response is a JSON object with:

Verify the User Access Token & Obtain Actor Object

You can verify the token works by sending a GET request to the /oauth/verify_credentials endpoint:

curl \
    -H 'Authorization: Bearer our_access_token_here' \
    https://vervis.example/oauth/verify_credentials

The response is a JSON object that has a url field, whose value is the HTTPS URI of the user’s Person ActivityPub JSON object.

Perform Authorized Requests

You can now use the access token via the Authorization header, as in the curl example above.

Getting ActivityPub objects

You can obtain an ActivityPub object by sending GET request to its id URI, with Content-Type being application/ld+json; profile="https://www.w3.org/ns/activitystreams. Unless you’ve been given such a URI, the starting points for discovering objects are:

The Person Object

{
    "id": "https://fig.fr33domlover.site/people/vDxKn",
    "type": "Person",
    "preferredUsername": "perelev",
    "summary": "Cool person who makes cool stuff",
    "inbox": "https://fig.fr33domlover.site/people/vDxKn/inbox",
    "outbox": "https://fig.fr33domlover.site/people/vDxKn/outbox",
    "followers": "https://fig.fr33domlover.site/people/vDxKn/followers",
    "following": "https://fig.fr33domlover.site/people/vDxKn/following",
    "sshKey": [
        "https://fig.fr33domlover.site/people/vDxKn/ssh-keys/Pn9Yn"
    ]
}

Receiving Messages

Requests and event notifications are received as ActivityPub Activity objects in the Person’s inbox collection. Currently push notifications aren’t implemented, so client applications need to periodically GET the collection and detect whether new items have appeared at the top. The inbox is a (typically paged) reverse-chronologically OrderedCollection of Activity objects, as described in the ActivityPub specification.

The ForgeFed specification has a relevant detailed section:

https://forgefed.org/spec/#s2s

Common properties

These would appear in every activity:

These would appear in some activities:

{
    "id": "https://fig.fr33domlover.site/decks/W058b/outbox/nV34D",
    "type": "Accept",
    "actor": "https://fig.fr33domlover.site/decks/W058b",
    "fulfills": [
        "https://grape.fr33domlover.site/people/WZpnG/outbox/GQvnR"
    ],
    "object": "https://grape.fr33domlover.site/people/WZpnG/outbox/GQvnR"
}

Accept

The actor has accepted/approved some activity.

Always:

Sometimes:

Add

The actor has requested to add some actor to an authorization-related collection. The cases are everything except adding direct collaborators (which use an Invite activity instead):

Always:

To determine the case, grab the target collection’s owning actor, pointed via the collection’s context field. Now you can example the target and object actor types, as well as which field of the target actor specifies the collection:

The Add activity is usually just the first step in a sequence of activities that create the desired authorization link. The activity sequences are described in detail in the specification, e.g. in these sections:

Apply

Create

An actor has published a new object/resource, specified in the object field:

Follow

The actor has requested to follow the actor/object specified by the object field.

Grant

See https://forgefed.org/spec/#managing-access.

Invite

https://forgefed.org/spec/#Invite

Except target specifies the collection, not the resource itself. For a Team, that would be the URI of its members collection. For other actor types, it would be the URI of the collaborators collection.

Join

https://forgefed.org/spec/#Join

Except object specifies the collection, not the resource itself. For a Team, that would be the URI of its members collection. For other actor types, it would be the URI of the collaborators collection.

Offer

Push

https://forgefed.org/spec/#pushing

Reject

Remove

Resolve

Revoke

Undo

Publishing and Manipulating Objects

All object manipulation in Vervis is done using the ActivityPub C2S API, i.e. by POSTing Activity objects to the user’s outbox.

To determine the outbox URI, you can HTTP GET the Person object as mentioned above, and grab the URI specified by its outbox field.

Common properties

There are properties you’d often specify in the Activity object, that aren’t specific to any activity type.

Accept

Add

Create

Follow

Invite

Join

Offer

Remove

Resolve

Undo

S2S Sequences to Move to the Spec

Using a Factory

Documented in my Vikunja task board)

Issue tracker migration

This involves 2 pieces that happen independently, one can happen without the other:

For signalling:

For anonymous copying:

For authenticated copying:

From all this, I’m now implementing only authenticated copying:

[See repo JSON]