FEP-400e: Publicly-appendable ActivityPub collections

Okay the security aspect makes sense, I think you should mention that in the FEP.

Dont know what you’re trying to say with this.

I guess simplifying database design is not one of our goals. And we dont use in-memory cache either. In our case there is exactly one collection per actor, so its already pretty simple in that regard.

It simplifies the logic a lot if you can simply check the target field to determine if an actor is allowed to post in the community (it might have been banned). Otherwise you would have to resolve the object first, or even resolve it recursively (eg in case of Undo/Like/Note).

That maybe I meant “MUST” there.

In your case yes. But in my case there will be photo albums, and discussion boards, and who knows what else, in addition to walls. And if I’m to copy VK in this regard, a group could be configured so anyone could create a photo album in it. And each photo album could be configured so anyone could upload new photos to it.

But you’ll have to anyway, sooner or later? To check if it exists, if there’s already a like from that user on it, and so on.

IIRC I only support Undo{Like{Note}} if the inner Like is an object, not a link.

1 Like

Well if your goal for this FEP is to describe Smithereen behaviour, then it is probably okay in the current form. But for Lemmy it doesnt really make sense to implement things in that specific way.

Not if the actor is blocked in the community, and cant post there. Or in case its a private community. Of course if the user is allowed to post, i will have to dereference everything and verify that the target community matches the object.

This “authority” of the “origin” server sounds out of place in a decentralized context. It seems to me that it’s another case of “please delete” and non-compliant servers will simply ignore this. Can you please expand on what security reasons you see here?

There are two issues I’m trying to solve:

  • The group needs to be able to moderate its content.
  • The user needs to be sure that they are not impersonated and the content they contribute to the group isn’t tampered with.

What I’m proposing (and what is already implemented in Smithereen) is essentially two-way linking, which is ubiquitous on the web when you want to somehow link two services together or prove the ownership of something. The group links to the post from its wall collection, and the post links to the collection from its target field. If any one side removes its link, the entire relationship is invalidated. So no, it’s not “please delete”.

  • If the group deletes the post but the user does not honor this request, the link to the post is no longer in the group’s collection anyway (and it sends a Delete{Note} activity to all followers). Other servers will notice that and consider that post invalid.
  • If the user is blocked in the group but tries posting in it anyway, the group won’t accept that activity and won’t add the link to that post to its collection in the first place.
  • If the user deletes the post but the group keeps the link, this link is no longer valid because it won’t resolve any more.

But if you make groups return objects themselves instead of links, that would break the user’s ability to delete or edit the posts, and it would also enable the group to impersonate the user because the post isn’t signed by that user’s key and doesn’t come from their server. Even disregarding that (though you really shouldn’t be disregarding that), if the user’s and group’s servers run different software, they might mangle each other’s objects because to my knowledge no one ever stores the original JSON.

So this leaves us with this model of authority:

  • The group is authoritative for the inclusion of an object in its collection.
  • The user is authoritative for the object itself.

We already have this in the microblogging model most everyone implements. For an activity or object to be considered authoritative, it either needs to be signed with the key of its creator upon receipt, or come from their server when fetching via id. I’m just building on top of that by adding the ability to split this authority across two servers.

1 Like

I’ve requested the finalization of this FEP and I ask for any final comments before that happens.


Hi @grishka, thank you for this FEP. I’ve been working on FEP-8485 that proposes a modelling of an “unbound actor” and uses this to achieve it.

If I understood your FEP correctly, it is aimed at public collections only. That isn’t always the case of the collection described in FEP-8485, and thus I suggested handling the case in which it is public as you describe, and the case in which it isn’t by using the type Offer instead of Create. Can you have a look at it and share your thoughts?

It’s not necessarily public (though I don’t really believe in true privacy in federated systems). The existence of the collection must be public, but its owning server is free to control access to it however it sees fit. For example, requiring that it must be fetched with a GET request signed by a pre-approved actor. The objects themselves could use bearcaps (a bear: URI that includes an access token and the actual URL of the object, @dansup uses these in pixelfed for stories iirc), or maybe just some kind of random URLs that are infeasible to enumerate.

I’ll read your FEP later.

Yeah I don’t see any issues with private collections here

However, I still disagree with the idea that such a collection has any authority over the objects themselves, and will not be implementing it as described

That’s how walls commonly work — it’s part of your profile and thus you can delete anything and everything anyone has posted on there. I just replicated this pattern in a federated manner.

Well. It’s specifically designed to work in case one side doesn’t cooperate as two-way linking is required for an object to belong to a collection. If the object doesn’t link to the collection, it’s considered to be standalone (i.e. posted to the timeline/profile). If the collection doesn’t link to the object, it’s considered to be invalid because the collection owner didn’t approve its inclusion into the collection.

The way I interpret this is that having target set without inclusion in the collection is an expected case, since that’s the way it will be before the collection owner accepts the object. Removing the object from the collection would therefore simply return it to this “unapproved” state

I used the term public wrongly. I meant to say that anyone could add things to collections. But you have just explained that it’s possible to have pre-approved actors. The usage I suggested in FEP-8485 was: when it is subject to approval, then Offer the object to the collection, so the owner of the collection answers either with an Accept or Reject. Otherwise, if the collection is “open”, as in anyone can add objects to it, (this is why I wrote “public” earlier), then use Create.

Having the target property in the object is a spec violation (because of the domain of the target property). It is a property of Activity and not of Object. But I understand the usefulness of knowing that “an object was created to be part of a collection and should only be considered in its context”. Therefore, maybe for objects use the context property instead and keep using target only in activities?

For example:

  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://example.org/activity/123",
  "summary": "Sally posted a note to John's wall.",
  "type": "Create",
  "actor": "acct:sally@example.org",
  "object": {
    "id": "http://example.org/notes/123",
    "type": "Note",
    "content": "hello, world.",
    "context": {
      "target": "http://example.org/john/wall"
  "target": "http://example.org/john/wall"

On another note, how would we use this to add activities to a collection? That would make the use of target problematic since it has another meaning there

I’m not sure what the current uses of context are and whether that would create conflicts (pleroma seems to be setting it), maybe it would be better to add a new field

You wouldn’t add activities to a collection. This is specifically for objects. I treat activities as more or less transient things. Some of mine (like Create{Note}) do have persistent URLs and I’m able to recreate them, but many do not.

Activity is a subtype of Object, so they should be able to do anything other objects can. Specifically Question is often treated like a Note


As this FEP was just finalized, it becomes the second and really the first non-meta FEP. Congratulations @grishka!