Desired changes for a future revision of ActivityPub and ActivityStreams

The idea is that we’re sending messages around that claim to be from some actor. The recipient of those messages needs to be able to verify that claim.

Excellent questions for the protocol to answer. AP is a sort of everything protocol, so who knows, right now. What’s the difference between a reply and quote post? What’s the difference between commenting on a blog and writing a blog post as a response to a blog? AP has no good answer, and that’s a problem.

2 Likes

How would the protocol stop a malicious intermediary server from automatically forwarding messages? I don’t really see how unless messages are end-to-end-encrypted (which is a valuable goal, although quite complicated). Or is E2EE exactly what you want to solve this?

This sounds like it would be kind of conflicting with the “no self-authenticating messages” part. I’m honestly not entirely clear on what a self-authenticating messages is versus a “regular” authenticating message. I mean even when you don’t have the signature as part of the message, as AP currently does with HTTP Signatures, you could just forward the entire HTTP request with the HTTP signature header and all, and it would be verifiable. Or is that not self-authenticating because you need to fetch the public key from the instance and then you might need authentication? That would make sense.

Or rather AP only has one mechanism which is usually interpreted as more akin to commenting on a blog (the replies collection) and not so much writing a response blog as its own post. On a philosophical level I can see that they are different, even if the technical difference is very subtle. Those are good things to consider.

UUIDs aren’t human readable.

{
  "actor": "https://alice.example",
  "type": "Create",
  "object": "https://alice.example/some-object"
}
{
  "1a7894b3-4b45-4847-8b67-c6b7fa83e0b2": "https://alice.example",
  "8afd3d3f-57c3-43dd-99d7-9b5a49b5fa04": "fb454051-8c25-4c4e-a00b-4164a71a883b",
  "ab389f13-fe41-4d9f-b09e-6c39794cdcf3": "https://alice.example/some-object"
}

HTTP(S) URIs can look ugly, but they at least generally provide some human meaning, and they have a chance at returning some useful information if you try to fetch them. They also have an authority component built-in, so for example only the W3C can rightfully assign identifiers on www.w3.org.

{
  "https://www.w3.org/ns/activitystreams#actor": "https://alice.example",
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": "https://www.w3.org/ns/activitystreams#Create",
  "https://www.w3.org/ns/activitystreams#object": "https://alice.example/some-object"
}

Prefixes look a little better, but require everyone to agree on consistent prefixes. In this case, I’m using as for ActivityStreams, and I’m using rdf for RDF Syntax. This is a workable option if you’re willing to accept the requirement of ahead-of-time communication with the entire known universe, present and future.

{
  "as:actor": "https://alice.example",
  "rdf:type": "as:Create",
  "as:object": "https://alice.example/some-object"
}

You can combine prefixing and reverse FQDN, also. ATProto’s Lexicon does pretty much this.

{
  "org.w3.www.activitystreams.actor": "https://alice.example",
  "org.w3.www.rdf.type": "org.w3.www.activitystreams.Create",
  "org.w3.www.activitystreams.object": "https://alice.example/some-object"
}

You cannot forward the entire signed http message. It won’t validate. Unless you’re talking about delivering the whole thing as text in some preplanned exfiltration scheme? In which case, this is such extraordinary bad faith that it’s not even a protocol concern anymore.

Anyway, I’ve exceeded the amount of energy I have for this thought experiment.

As I said previously, I don’t think human readability is very important at all honestly. Converting to readable names for debugging would be trivial and you would already do this as part of deserialization in some programming languages at least.

URIs are also just prefixes, they are just long. If you make the prefixes long, you don’t need to coordinate with anyone. Yes, you may not own the domain but that doesn’t stop you from using the URI prefix.

Edit: Alternatively, use a UUID prefix. Random as UUID and no collisions, but still readable.

Can anyone else confirm this? As far as I know, a forwarded HTTP request with the signature header and all will validate but maybe I’m misunderstanding something.

As another topic, I’m surprised nobody has mentioned nomadic identities or even instance-agnostic identities.

Nomadic identities seems like a good thing to have built into the protocol from the start. However I’d be curious to hear what people think about instance-agnostic identities. I might be wrong but ActivityPub as it is right now doesn’t explicitly disallow instance-agnostic identities but in practice I don’t know of any implementation that supports it.

I’m personally a little worried that instance-agnostic identities would be hard to moderate. I think the ability to defederate and in effect block an entire instance’s users is a useful tool.

They also seem more complicated than an identity tied to an instance. It seems like the user would need to hold on to a private key in order to authenticate and that is not something most users can or should do I think.

Wow, too much text here, I’m out.
I’ll continue with RDF :wink:

2 Likes

Yes, for sure. This whole thread is TL;DR for anyone that didn’t participate thus far. Anyway, I heard voices say things that boil down to:

  • What is the use of the discussion if there isn’t a custodian group able and willing to bring these changes? Aren’t we talking wishful thinking and wasting our time?

I’d cc @codenamedmitri on that one.


Other than that I would like to reference a wishlist of changes from the fedi, by @hrefna, whom has spent much time before looking deeply into various aspects of AS/AP and discussed them at length (also on fedi). I fully agree to these points myself…

Is someone willing to create a bullet list summarizing desired changes that are discussed above?

Then we can post that in a separate topic, turn it into a wiki post, and cross-link to discussion points in this overly long thread.

1 Like

A post was merged into an existing topic: Summary: Desired changes for a future revision of ActivityPub and ActivityStreams

@SorteKanin this is great. Can I turn your post into that wiki I mentioned? Just Like if you consent.

Update: Thank you @SorteKanin :green_heart:

1 Like

Fediverse developers read activities all the time, so human readability is very important.

I guess the forwarded HTTP request won’t validate because the Host header will be different, but I don’t think that can stop anyone. If the message is private, forwarding can be prevented with encryption. If the message is public… It’s public.

What is the difference between “nomadic” and “instance agnostic”? FEP-ef61 identities are not tied to a server or a domain name, are they “instance agnostic”? This FEP is implemented by two projects.

In FEP-ef61, for example, nomadic identities are connected to non-nomadic fediverse via gateways, so domain name blocking still works.

Key management can be delegated to a trusted service.

For development, yes, but it’s not important for anything else. And you could also just use a UUID prefix, then it is both unique and readable.

I mean, then you aren’t forwarding the request unchanged.

The way I understand these terms is this: A nomadic identity is one that can move from one instance to another but it is still tied to an instance at any one time. An instance-agnostic identity is one that is not tied to any instance/domain at all.

How exactly would this work? Would it be user friendly enough that normal users could do that?

Where I pointed to @hrefna’s toots before, I should also point to @trwnh writing a long comparison of the two approaches to the AS/AP protocol, let’s say open-world vs. closed-world perspective, that is interesting to mention here:

Does throwing away JSON-LD necessarily mean we have to accept the “closed-world assumption”? I personally don’t think so. We can have open-world with plain JSON, I think. I feel like the thread sets up a dichotomy that forces us to keep JSON-LD, but I don’t think that dichotomy actually exists.

While this is interesting, I’m not sure it’s what the fediverse needs going forward. I mean, they almost say it directly:

consider S2S. why are there zero compliant impls in fedi? because AP as specified doesn’t address the needs of fedi.

Maybe that’s taken out of context, not sure. But I think there is some truth to that. Whatever @trwnh is talking about in that thread is interesting, but I’m not sure it’s useful for the fediverse. At least, I’d like to see a practical, real-world, actually-used-by-normal-people implementation that demonstrates the benefits and use cases of… whatever it is (and no, browser.pub does not qualify, at least not in its current state).

Until something actually concrete exists that demonstrates the benefits, I have a very hard time being convinced by this vision.

Fediverse historians seem to believe that nomadic identity was instance-agnostic from the beginning:

Macgirvin decided that the only way to secure people’s online identity was for it to exist on multiple independent servers. Thus, the idea of nomadic identity was born.

A client can call key management service every time it needs to sign an activity. FEP-ef61 supports did:web identities that enable delegated signing, but doesn’t specify the exact mechanism (the current work is mostly focused on did:key identities).

I think delegated signing can be implemented with “sign-in with google” level of user-friendliness.

To me that doesn’t sound like instance-agnostic (bound to 0 instances) but more like multi-instance identity or something (i.e. bound to more than 1 instance at once but certainly at least 1). Which is also cool I guess? Certainly a good way to have a backup in case an instance goes down, since you can’t move a nomadic identity on that instance once that happens I would think.

Just to be clear, in this scenario you have an instance and then also a third party holding the key? Isn’t that just as bad as the instance holding the key? I mean what happens if the key holder goes down, are you stuck then? Or you can’t even sign anything I guess? I’m not sure how this third party key holder solves anything. But I’d love to see an implementation demonstrating this.

if you throw away jsonld then you need something else that can serve as an explicit definition of what any given term means. if your answer to this is “just read the documentation” then this is not explicit and does not enable someone to extend freely without some level of coordination with the entire world. that’s what “open-world” and “closed-world” really comes down to – can you communicate with someone you’ve never encountered before, or are you bound by your existing awareness?

json-ld is just one approach to mapping terms to iris, and rdf then maps iris to concepts. an alternative solution needs to consider how to map terms to concepts. otherwise you won’t be able to tell that two symbols mean the same thing or refer to the same concept. you also won’t be able to tell when two people are using the same symbol in different ways.

this is why i bring the example of impls that declare some context but then can’t even understand their own context. as a baseline you are saying

  • i understand that when you say discoverable you are referring to mastodon’s definition of the term as represented by http://joinmastodon.org/ns#discoverable
  • i do not understand what you mean by http://joinmastodon.org/ns#discoverable i only understand the literal string discoverable

because that’s what jsonld does. it purely maps discoverable to http://joinmastodon.org/ns#discoverable whether you are aware of it or not. if you as an implementer only support discoverable then you are relying on “implicit context” and only have “partial support for extensions”. you are saying that discoverable ALWAYS means http://joinmastodon.org/ns#discoverable and are therefore unequipped to handle any other case where discoverable means something else. in effect, you are implicitly expecting the document to be compacted against the following context (undeclared):

{
  "@context": {
    "discoverable": "http://joinmastodon.org/ns#discoverable"
  }
}

this is happening implicitly, without you ever declaring or being aware of it, by the way that you hardcode your software in a context-unaware manner. just as discoverable is being mapped to http://joinmastodon.org/ns#discoverable without your awareness, you are neglecting to map http://joinmastodon.org/ns#discoverable to your internal understanding of what discoverable means.

if you find this all “not useful for the fediverse” then okay, you don’t have to use json-ld, but you still have to deal with the concept of context whether you like it or not. at the very least you need to be able to agree what any given term means, you need to have a shared understanding. if you find something you don’t know what it means, you drop it as AS2 says you MUST do. but it could be that you find something that means something you already know, you just don’t recognize it as something you already know. that’s the kind of fragility and lack of robustness that fedi is doing by refusing to support iri expansion. (just as they indiscriminately flood the rest of fedi with Deletes because they don’t understand http caching, just as they fail to update their records when encountering an http 301, just as many other consequences of failing to comply with or even understand the specs and ecosystems that they are implementing)

Nomadic identity system with 3rd party key holder is better because it facilitates data migrations. Yes, you still can lose everything if identity server goes down, but now you can migrate all your data if you’re not happy with installed software or moderation policies.
Also, identity server is very lightweight compared to an average fediverse server. It’s cheaper and the probability of catastrophic failure is lower, so that’s another reason why people may choose such setup.

1 Like

Why not? You ridiculed my UUID suggestion in the Mastodon thread, but to me it seems that if I wanted to extend freely, then I could do that with a UUID key (with a readable prefix, if you want readability) since I would know for sure that there are no collisions with that key. So if I wanted to introduce a new term as an extension, I would just generate a new UUID and use it. I don’t need to talk to anyone or coordinate with anyone.

I admit it is not “explicit”, if your requirement of explicit is that it can be fetched as a URI to get documentation. But I don’t think that’s very useful anyway. But by all means, use a URI with a UUID in the path or whatever, to ensure that it is completely unique. Then you have a unique key.

I fail to see where any of this requires JSON-LD, but I said the same a lot of messages up. You then said “you’ve just reinvented JSON-LD expanded form”. Well great, let’s then use this reinvention because all it requires is JSON and evidently achieves the same thing as JSON-LD, so we can forget about JSON-LD. Where is the problem? Why can’t we just do that? I’m rehashing stuff here so this is starting to feel cyclical.

You can tell that two UUIDs (or prefixed UUIDs, or UUIDs in URI if you prefer) are equal when they are… equal. JSON-LD needlessly complicates this by allowing a shorthand. We just need to not do that. There is no mapping of discoverable to http://joinmastodon.org/ns#discoverable, there is only the latter, unambiguous key (with or without UUID, I don’t care, just as long as it is collision-free with no coordination).

That will never happen if you used UUID keys, unless you deliberately made an extension and used a UUID that you found that was already used by another extension. But why in the world would you do that? And that can happen in JSON-LD land as well anyway (i.e. using the same URI term for a different concept).

This could also not happen when you use unambiguous keys that do not have multiple representations or mappings. No JSON-LD required.