← Tiny Subversions

A small ActivityPub debugging server on Glitch

by Darius Kazemi, Dec 10, 2019

When I'm developing for ActivityPub it can be helpful to have a way to send an arbitrary JSON payload from a remote server. I wrote an application in Glitch that:

My actual use case is: I'm trying to make my software compatible with some new-to-me federated software. I do a curl request to get the JSON for a message from their software, and then copy/paste it into the compose box in this tool, sometimes editing it lightly. I hit send, and the object is now sent to my subscribed user.

This way I don't need to create accounts on other tools in order to send test messages to my instance. It's great for debugging ActivityPub bugs too, you can very quickly iterate on how an Object should be composed in order to get what you want.

Get started

Click here to remix this project on Glitch (aka clone it).

Set everything up

Click "Show" in the upper left and open in a new window. After a brief "wake-up" period, you should see a simple web form and if you look at the URL bar there will be an automatically generated subdomain at the glitch.me domain. Take note of this, and go back to the editor and select the .env file from the file list on the left. You'll see this:

USER=
PASS=
DOMAIN=

Put a username and a password in there. For the domain, enter the full subdomain and domain but without the protocol portion. It should look something like this now:

USER=admin
PASS=MyAmazingPassword
DOMAIN=funny-name.glitch.me

The content of the .env file is kept secret even from people who remix your project, so this is where we store our admin password. The SQLite database that contains all of the information for this little server lives in a special directory called .data/, which is likewise kept secret from prying eyes. If you need to access the database directly, click on "Tools" at the bottom of the file tree, then "Full Page Console", and then cd .data and sqlite3 bot-node.db.

Create an account

Next, create a test account by entering a username under "Create Account" and then giving it your admin user/pass when prompted. You should now have an ActivityPub actor that can be found at either https://YOUR_SUBDOMAIN.glitch.me/u/YOUR_USERNAME or by searching most AP-compatible software for @YOUR_USERNAME@YOUR_SUBDOMAIN.glitch.me.

Write down the API key that it gives you, along with the username. You'll need this to send future messages. (I did it this way so that if you wanted to give a secondary user an account to play around with but not your admin password, you can just give them a username and API key that you create for them.)

Follow the account from somewhere

Search for the account from your ActivityPub software of choice and send a follow request. This server should acknowledge and Accept the follow.

Send a message

The moment of truth! Put the username and the API key in the "Send Message To Followers" field. Then drop in some valid JSON for the object you're going to send. A good test message is:

{
  "@context": ["https://www.w3.org/ns/activitystreams"],
  "type": "Note",
  "content": "Hello world."
}

(The above object will be given a to field plus some other necessities. See below for more.)

There is also a link right in the form to a gist that I maintain of various object formats seen in the wild.

What this actually sends

When you send a raw JSON payload, it sends one Create Activity for each follower. This is what it sends as the Create Event wrapper:

{
  "@context":"https://www.w3.org/ns/activitystreams",
  "id":"https://YOUR_DOMAIN/m/SOME_GUID",
  "type":"Create",
  "actor":"https://YOUR_DOMAIN/u/USER_NAME",
  "to":["https://SOME_FOLLOWER"],
  "object": { YOUR_RAW_JSON }
}

Note that nothing is sent to https://www.w3.org/ns/activitystreams#Public by default because this is a debugging tool and this stuff probably shouldn't show up in the public timelines of instances that have them.

No matter what JSON you send, the tool will overwrite or create couple of fields.

Of course if you need to make any adjustments, you have the code! The stuff you care about is in routes/api.js and specifically the rawMessage() function is what creates the message and its wrapper.

License

Copyright (c) 2019 Darius Kazemi. Licensed under the MIT license.