In social media, it’s a frequent pattern when there’s a collection owned by someone that other people can contribute to. Examples include:
Currently, there is no generic way to signify that an object was created as part of a collection and should only be considered in its context.
This proposal describes how ActivityPub servers and clients could specify collections to which objects created by their actors belong.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this specification are to be interpreted as described in [RFC-2119].
A publicly-appendable collection is any collection where it is expected that someone other than its owner could add items but over which its owner retains complete authority. For example, a wall is a collection to which other people could add posts (Note
s), but from which its owner could delete any posts as well as restrict who can add them.
A publicly-appendable collection SHOULD have a valid and globally-unique id
that SHOULD point to either a Collection
or an OrderedCollection
object that contains the links to all its objects.
If an actor has publicly-appendable collections, its server MAY include them as additional fields in its ActivityPub representation. For example, user actors may specify the link to their walls, or groups may specify the link to the collection of their photo albums.
Implementations MAY use the presence or absence of specific collection to determine whether the actor’s server supports features that depend on that collection and alter their UIs accordingly.
target
in objectsIf an ActivityPub object is being created as part of a collection, the object SHOULD include the target
field that contains an abbreviated collection object, which SHOULD contain at least the following fields:
type
— either Collection
or OrderedCollection
.id
— the id
of the collection.attributedTo
— the id
of the owner of the collection. This is necessary to simplify the database design on the receiving side.While [Activity Vocabulary] specifies target
as a field with similar semantics in activities, it’s important to include it in objects themselves so any software that only sees the object without its enclosing Create
activity, e.g. when following a link form another object or retrieving the object from a user-provided URI, unambiguously knows that it should only be considered in the context of its collection.
When an ActivityPub server receives in its inbox a correctly signed Create
activity with an object that has the target
field, it does the following:
attributedTo
or id
fields of the abbreviated collection object.
attributedTo
doesn’t match the actual owner of the collection specified by id
, or if the collection owner is not a local actor, the server SHOULD abort processing and MAY return 400 Bad Request
.403 Unauthorized
or respond with 200 OK
and later send a Reject{Create}
activity to the originating server.id
in its local storage as belonging to the specified collection.Add
activity to any parties that might be concerned with it. The target
field in the activity SHOULD only be the collection id
, and the object
field SHOULD be the id
of the object being added. It is RECOMMENDED that this activity is sent to all the collection owner’s followers for the sake of data consistency, and it SHOULD be sent to the actor that created the object being added.Add
activityWhen an ActivityPub server receives in its inbox a correctly signed Add
activity, it SHOULD do the following:
actor
either from local storage or from the network.object
.target
is the ID of a collection owned by actor
. If it is not, abort processing and return 400 Bad Request
.target
in the activity matches target.id
in the object and that target.attributedTo
in the object matches the actor ID. If it does not, abort processing and return 400 Bad Request
.id
in its local storage as belonging to the specified collection.Add
activity{
"@context":"https://www.w3.org/ns/activitystreams",
"actor":"https://example.com/users/1",
"id":"https://example.com/posts/41864/activityAdd",
"to":[
"https://www.w3.org/ns/activitystreams#Public",
"https://example.com/users/1/followers",
"https://example.com/users/6946"
],
"type":"Add",
"object":"https://example.com/posts/41864",
"target":"https://example.com/users/1/wall"
}
Since the collection owner has complete authority over the contents of the collection, they can delete any objects from it. When an object is deleted from a collection by its owner, their server SHOULD send a Delete
activity to at least the server of the actor that created the object; it’s also RECOMMENDED that this activity is sent to all the servers that Add
was sent to. Those servers then SHOULD delete the object as if the deletion was initiated by its creator.
In some use cases, it might make sense to allow objects to be moved between collections, for example, a group moderator might want to move a photo between photo albums in a group, or a forum moderator might want to split some messages into a separate thread. It’s only possible to move objects between collections that are owned by the same actor.
When moving an object between collections, the collection owner SHOULD send a Move
activity to at least the server of the object creator, specifying the target collection and the id
of the object; it’s also RECOMMENDED that this activity is sent to all the servers that Add
was sent to. Those servers then SHOULD update the target
field in their stored copies of the object.
The requirement of an Add
activity sent by a collection owner largely prevents a bad actor from effectively adding something to a collection against the collection owner’s will while also helping data consistency across servers. However, there’s still one case when this is possible. When a server fetches an object that has a target
field directly, for example when a user has entered its URL into a search box or when it is referenced by a field such as inReplyTo
, there’s presently no reliable way to verify whether the object actually belongs to the collection.
This proposal is implemented in Smithereen for both user and group walls since the following commit: https://github.com/grishka/Smithereen/commit/de013593dde06a3091ecfbd32960a694d79c146e
CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
To the extent possible under law, the authors of this Fediverse Enhancement Proposal have waived all copyright and related or neighboring rights to this work.