prefetcher's inane ramblings

my thoughts on anything that wouldn't fit as a fedi post

if you were ever curious about (or god forbid, tried to implement) ActivityPub, chances are you've stumbled upon this cutesy looking image

ActivityPub diagram [image courtesy of https://activitypub.rocks/]

it all looks fine... but what is “/outbox”? why do we have an actor reading from the “/inbox”? isn't inbox only for sending messages from one server to another? what's going on???

overview

what you see here is how ActivityPub was envisioned to be used. you had a server that interacted with other servers to exchange messages, which was supposed to actually be quite dumb. it sends stuff, it stores stuff, that's it.

and then, you had the client, who was actually quite smart! it read posts sent to it through the “/inbox” endpoint, it sent activities to the server to the “/outbox”, which the server then federated... all of this basically resulting in the client doing the majority of the work for the server.

and this idea was cool, at least in my opinion...

the good about C2S (as i see it)

the client-to-server protocol is kind of vague in points, but as i see it, it would've solved a lot of the issues i have with AP thus far.

1. up to date information

you've probably already stumbled upon this. you see a post that has 15 likes on your instance, but it has 3 likes on cats.social and 400 likes on timsweeney.zone which is the parent instance of the author of the post.

this is all due to the very quirky way likes get propagated across fedi, which in part is mastodon's fault.

a diagram showing how the like counter behaves on mastodon [image courtesy of https://seb.jambor.dev/posts/understanding-activitypub-part-3-the-state-of-mastodon/]

mastodon only sends the like activity to the author of the post, and due to “performance reasons” mastodon doesn't forward the like to the instances of its followers, resulting in the like count varying from instance to instance.

(to my knowledge the pleroma family does do that, but still, there's a better solution...)

considering that ActivityPub is supposed to be a series of interconnected documents, with a C2S client and a conformant ActivityPub implementation, the client would directly query the parent server for the post's ActivityStreams representation, and check its likes collection.

so, if a C2S client wanted to fetch this post a screenshot of my post reading "she Activity on my Pub til i toot" [https://miku.place/notice/AfPB01gN5xEJ8VzB8S]

it would: 1. fetch the https://miku.place/objects/391f3893-009c-4b76-a39f-eded2e8941f6 object. 2. fetch its likes collection (if the server supported it) to get the amount of likes this post has 3. fetch its shares collection (if the server supported it) to get the amount of shares this post has 4. fetch the actor responsible for the note, to then get their name, avatar, etc.. 5. finally be able to display it, with all the up to date information!

same goes for user information, and other variable things.

this of course could be implemented in mastoapi clients (and as far as i know, a some implementations do that), but in C2S as far as i can tell it's the de-facto way of fetching any information.

2. any conformant implementation should be able to speak it

considering it's part of the spec, any conformant ActivityPub implementation would be able to speak at least a minimal subset of it (as described above).

meaning that your client would be able to connect to Mastodon, Pleroma, Misskey (but also WriteFreely, Bookwyrm, Funkwhale, etc...)

it all would depend on the client supporting all the different types of Activity Vocabulary objects.

the bad

C2S isn't without its quirks of course.

1. timelines don't exist

you only get what you receive in your inbox. period. no timelines, no anything.

of course, you can extend C2S with your own implementation, but then it's not conformant and you have to hope other clients support that too and yadda yadda...

2. too much implementation-defined behavior

so, C2S specifies how you're supposed to interface with the server... but it doesn't specify how you are supposed to even securely tell the server that you're @ishmael@mephistophel.es and not someone completely different.

as defined in the ActivityPub spec:

Unfortunately at the time of standardization, there are no strongly agreed upon mechanisms for authentication. Some possible directions for authentication are laid out in the Social Web Community Group Authentication and Authorization best practices report.

if you follow the Social Web Authentication best practices report, you'll learn that:

Client to Server

ActivityPub clients authenticate against a server using OAuth 2.0 bearer tokens.

Bearer tokens may be acquired out of band. They may also be acquired using OAuth 2.0 authorization. To discover the correct endpoint for authorization, clients should use OAuth-Server-Metadata on the host part from the actor's ID URI.

which sounds good, but of course is only a recommendation that no server has to follow.

3. the base is kind of limited

you get as much as ActivityPub defines. the rest is implementation-defined and not standard. simple as.

4. and of course, the elephant in the room

there's genuinely one semi-complete C2S implementation. and its only for android. i'm talking of course about AndStatus

so we have no C2S clients, what does that result in? ah right. no C2S servers, lol. supposedly Pleroma (and by extension Akkoma) support it, but reading up on it it's kinda half-baked and not always works properly.

this kind of results in a chicken-and-egg problem, that in order to develop a C2S client, you need a conformant C2S server to test against... for which you then need a conformant C2S client to validate that it works properly. ouch.

so what went wrong?

mastodon.

mastodon is by far the biggest implementation of ActivityPub and the most popular fediverse software to date. and it omitted C2S in favor of the mastodon api (or thereafter referred to as mastoapi).

if you wanted to interface with a mastodon server, you had to talk with it via the mastoapi, as there was no other way. so of course, when new AP implementations came to be, they also had to implement mastoapi if they wanted user apps to be able to talk with them without waiting for them to implement their custom API. (notably, Misskey still doesn't implement mastoapi)

all of this resulted in mastoapi being the de facto standard for client to server communication, completely sunsetting C2S.

closing thoughts

i like C2S, i want it to be a viable replacement for mastoapi.

i've been thinking about writing a library/client for C2S to implement it in Toki, but it's still a far ahead thought... but who knows?

as of recent, i've took upon myself the horrible and daring task of developing a, god forbid, ActivityPub server. i've done a lot of research into it, reading upon a lot of blog posts detailing what you have to implement and whatnot...

every single blogpost tells you that .well-known only hosts webfinger, but what if i've told you that there's more than just that?

.well-known/nodeinfo

this one is actually a spec originally made for diaspora*, that one social networking platform that sorta exists and absolutely refuses to do anything with ActivityPub.

nodeinfo is a “standardized” way of querying information about an instance, such as its user count, blocked instances, software it's running, etc... etc...

it's the way, for example, how Akkoma or Misskey queries an instance about what instance its running, to display it on the frontend.

when queried, it returns a json JRD document describing every version of the nodeinfo protocol that the server supports:

{
    "links":
    [
        {
            "rel": "http://nodeinfo.diaspora.software/ns/schema/2.0",
            "href": "https://miku.place/nodeinfo/2.0.json"
        },
        {
            "rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
            "href": "https://miku.place/nodeinfo/2.1.json"
        }
    ]
}

from which you can select the version you want to query and fetch the information from it.

while it's absolutely safe to skip, a lot of instances actually fetch and make use of the information from it, which makes it worth implementing. (like come on, even snac has it, fucking snac)

for a more detailed look on it, i recommend checking https://github.com/jhass/nodeinfo

.well-known/host-meta

this one i have to admit i don't understand THAT well, but from what i've understood, it acts as a way for other instances to discover where the webfinger endpoint of your instance is.

so, given a scenario like this:

someone queries @person@example.com, but when looking up the actor your instance sees that https://example.com/.well-known/webfinger doesn't exist, so it looks up the host-meta, and finds out that, oh, your instance and the webfinger endpoint is actually at https://fedi.example.com/.well-known/webfinger instead.

and believe me, a lot of servers actually reside on a different address than they report... (looking at you layer02.net)

also as a side note, for some reason, this is the only endpoint that all instances implement that when queried, returns an XML response instead of JSON(-LD)???

<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
   <Link type="application/xrd+xml" template="https://miku.place/.well-known/webfinger?resource={uri}" rel="lrdd" />
</XRD>

addendum, or wtf is going on with webfinger

this is more of a curiosity, but a lot of instances seem to expose an extra link with each webfinger query that looks akin to this

{
    "rel": "http://ostatus.org/schema/1.0/subscribe",
    "template": "https://miku.place/ostatus_subscribe?acct={uri}"
}

from what i've understood, it's used for remote following (or at least brings to a remote follow page for both Akkoma and Sharkey)

i've never seen anyone make use of it though, and the rel link has died long ago, and now redirects to some scam sports betting page lmao