/social.distributed.press

A Social Inbox for Decentralized Publishing and ActivityPub.

Primary LanguageTypeScriptGNU Affero General Public License v3.0AGPL-3.0

social.distributed.press

A Social Inbox for Decentralized Publishing and ActivityPub

How it works

This server runs a minimal implementation of an ActivityPub Inbox and Outbox.

Here's how to use it:

  1. Publish a static site that contains your ActivityPub Actor, Outbox, and Posts. You can fork our staticpub example or use this Jekyll Plugin. Make sure you set up the webfinger endpoint!
  2. Generate a keypair using either OpenSSL or npm run generate-keypair in this repo
  3. Add the public key to your ActivityPub Actor
  4. Set up the social inbox server somewhere like httpa://social.example.com
  5. Note the WebMention compatible format of your account like @username@social.example.com which will be used as the username in parameters
  6. Register your ActorInfo by doing a Signed HTTP POST to /v1/:username/ with JSON that looks like {actorURL, publicKeyId, keypair: {publicKeyPEM,privateKeyPem}} to initialize your inbox. The server will use your keypair to sign HTTP requests for activities you send to your outbox. You can also use the client.setInfo() API.
  7. Set your Actor's inbox property to point at https://yourserver/v1/:username/inbox
  8. Send any Activities you want to notify your followers with by doing a Signed HTTP POST to /v1/:username/outbox

Check out the available API endpoints either in the swagger docs at the https://yourserver/v1/docs/ or in the JS client API in /src/client/index.js.

Development

This project requires Node.js Version 19.x and NPM. The code is written using TypeScript in the src folder which gets compiled into the dist folder.

  • Run server right from the source: npm run dev
  • Lint the code to catch common mistakes and maintain code style: npm run lint
  • Build JS files to dist: npm run build
  • Build and run server: npm run start

Testing out the API

You can use the Swagger UI (http://localhost:8080/v1/docs/static/index.html) to test out API endpoints.

Testing out internal authenticated endpoints

To test out internal authenticated endpoints, you can just comment out the authentication check on the endpoint's code (usually around a call to apsystem.hasPermissionActorRequest().)

Keep in mind that the actor you want to impersonate must actually exist; that is, it has to be able to respond to webfinger. Also, you should register it first locally to be able to use other endpoints by calling POST /v1/{actor} (you will need to bypass authentication in src/server/api/creation.ts like mentioned previously.) You need to pass vaild keys when creating the actor, which you can generate by running npm run generate-identity.

Testing out ActivityPub server-to-server endpoints

To test out external (ActivityPub server-to-server) endpoints, you can short-circuit APSystem.verifySignedRequest and return the actor you want to impersonate.

Keep in mind that the actor you want to impersonate must actually exist; that is, it has to be able to respond to webfinger.

For example, to impersonate @sutty@sutty.nl, you can add return '@sutty@sutty.nl' at the beginning of verifySignedRequest and send activites with the actor:

Example POST to /v1/{actor}/inbox

POST /v1/{actor}/inbox

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "@language": "es",
      "sensitive": "as:sensitive"
    }
  ],
  "actor": "https://sutty.nl/about.jsonld",
  "type": "Note",
  "id": "https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty.jsonld",
  "url": [
    {
      "type": "Link",
      "mediaType": "text/html",
      "href": "https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty/",
      "rel": "canonical"
    },
    {
      "type": "Link",
      "mediaType": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
      "href": "https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty.jsonld",
      "rel": "alternate"
    },
    {
      "type": "Link",
      "mediaType": "application/activity+json",
      "href": "https://sutty.nl/lanzamiento-de-publicaciones-distribuidas-en-el-fediverso-a-trav%C3%A9s-de-sutty.jsonld",
      "rel": "alternate"
    }
  ],
  "summary": "Lanzamiento de publicaciones distribuidas en el Fediverso a través de Sutty",
  "published": "2023-12-04T21:53:05+00:00",
  "updated": "2023-12-05T20:41:34+00:00",
  "attributedTo": "https://sutty.nl/about.jsonld",
  "to": ["https://www.w3.org/ns/activitystreams#Public"],
  "cc": ["https://social.distributed.press/v1/@sutty@sutty.nl/followers"],
  "inReplyTo": "https://hypha.coop/dripline/announcing-dp-social-inbox/",
  "sensitive": false,
  "content": "content"
}

(activity derived from the real one)

Project structure

  • /scripts: Scripts for doing tasks like importing blocklists/admins or generating keypairs
  • /src/ Main folder for source code
  • /src/server/ Source code for the inbox server
  • /src/server/api/ HTTP routes
  • /src/client/ Implementation of a JS client to talk to the inbox via fetch