Sometimes, users may want to share an information or a story without inviting replies from outside their circles or from anyone at all. In particular, individuals may want to restrict who can reply to them in order to avoid “reply guys” or limit outright harassment, while instutions may want to disable replies on their posts to provide information without having to deal with a moderation burden.
This can be broken into an advisory part advertising what sets of actors are expected to be able to reply, and a collaborative verification process where third-parties check with the actor being replied to that the reply is indeed allowed.
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].
In the remaining of this FEP, “distribution authority” (or “authority” for short) refers to an actor that controls the distribution and audience of replies. The purpose of this wording is to make this FEP applicable both for models where replies are first-class posts, and for “post and comments” models where comments only exist in the context of a post and the post author decides who gets to see the comments. In the absence of extensions, the “authority” is the author of the post being replied to.
In order to advertise who is allowed to reply to an object, an author MAY set the canReply
(http://joinmastodon.org/ns#canReply
) property on their objects. If set, this property MUST be an empty array or one or more actors or collections.
To ease implementation, collections SHOULD be restricted to one of the following:
as:Public
, to indicate that anyone can replyIn addition, canReply
SHOULD contain every actor mentioned in the original object.
Whenever one of these collections is used, the receiving end can easily know whether they are expected to be able to reply.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"toot": "http://joinmastodon.org/ns#",
"canReply": "toot:canReply"
}
],
"attributedTo": "https://example.com/users/1",
"id": "https://example.com/users/1/statuses/1",
"type": "Note",
"content": "Hello world",
"canReply": "https://www.w3.org/ns/activitystreams#Public"
}
When an object with canReply
is set, it SHOULD be conveyed in human-readable form to the user if possible, for instance with something like “Only mentioned users can reply” or “Only people Authority follows and mentioned users can reply”.
The software SHOULD NOT offer the user to reply unless it is directly mentioned in the object’s tag
attribute or listed in canReply
(either directly or through a collection), or canReply
contains a collection for which the recipient cannot efficiently check the membership of the would-be replier.
After locally verifying that the replier should be allowed to reply, the replier’s end SHOULD POST
the Create
activity for the reply to the authority’s inbox only, and consider the reply to be pending approval.
When receiving a reply to an object with a canReply
property, the authority decides whether the reply is acceptable.
If the reply is considered acceptable, the authority MUST reply with an ApproveReply
(http://joinmastodon.org/ns#ApproveReply
) activity with the object
property set to the id
of the reply object, and its inReplyTo
property set to the object it is in reply to.
That ApproveReply
activity SHOULD be publicly dereferenceable and MUST be dereferenceable by all parties allowed to see the original post. It MUST NOT embed its object
nor its inReplyTo
as to avoid possible information leaks.
Additionally, the authority MAY forward an accepted reply according to its own rules.
If the reply is considered unacceptable, the authority SHOULD reply with a RejectReply
(http://joinmastodon.org/ns#RejectReply
) activity. This activity MAY be publicly accessible, but this is not a requirement.
The reason for using the new activity types ApproveReply
and RejectReply
is to be explicit about the purpose of the approval, as one could imagine other kinds of approvals, and remaining implicit may cause ambiguities with other potential extensions.
ApproveReply
activity{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"toot": "http://joinmastodon.org/ns#",
"ApproveReply": "toot:ApproveReply"
}
],
"actor": "https://example.com/users/1",
"id": "https://example.com/reply_approvals/1",
"type": "ApproveReply",
"object": "https://example.org/users/bob/statuses/3",
"inReplyTo": "https://example.com/users/1/statuses/1"
}
RejectReply
activity{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"toot": "http://joinmastodon.org/ns#",
"RejectReply": "toot:RejectReply"
}
],
"actor": "https://example.com/users/1",
"id": "https://example.com/reply_approvals/1",
"type": "RejectReply",
"object": "https://example.org/users/bob/statuses/3"
}
After sending the initial Create
, the replier SHOULD wait for an ApproveReply
activity such as described above.
Once the ApproveReply
has been received, the replier SHOULD add a replyApproval
(http://joinmastodon.org/ns#replyApproval
) property to their reply object pointing to the ApproveReply
activity they received, and then MAY send a Create
activity with the modified object to its intended audience.
If it instead receives a RejectReply
, the reply SHOULD be immediately deleted and the replier MAY be notified.
replyApproval
{
"@context": [
"https://www.w3.org/ns/activitystreams",
{
"toot": "http://joinmastodon.org/ns#",
"canReply": "toot:canReply",
"replyApproval": "toot:replyApproval"
}
],
"attributedTo": "https://example.com/users/1",
"id": "https://example.org/users/bob/statuses/3",
"type": "Note",
"content": "@alice hello!",
"inReplyTo": "https://example.com/users/1/statuses/1",
"canReply": "https://www.w3.org/ns/activitystreams#Public",
"replyApproval": "https://example.com/reply_approvals/1",
"tag": {
"type": "Mention",
"href": "https://example.com/users/1"
}
}
When processing a reply from a remote actor to a remote authority, a recipient SHOULD discard any reply that does not match any of the following conditions:
canReply
propertycanReply
containing the as:Public
collectionMention
object in the tag
property of the object it is in reply tocanReply
, and replyApproval
can be dereferenced and is a valid ApproveReply
activityTo be considered valid, the ApproveReply
activity referenced in replyApproval
MUST satisfy the following properties:
actor
property is the authorityobject
property is the reply under considerationinReplyTo
property matches that of the reply under considerationIn addition, if the reply is considered valid, but has no valid replyApproval
despite the object it is in reply to having a canReply
property, the recipient MAY hide the reply from certain views.
The authority may want to perform /a posteriori/ moderation of their replies.
To do this, the authority SHOULD send a RejectReply
activity to the sender and the reply’s audience, with the reply URI as the object
property. The object
property MUST NOT be embedded, as to avoid possible information leaks.
The URI at which the previously-offered ApproveReply
was available should return HTTP 404 or redirect to the newly-issued RejectReply
activity.
Upon receiving a RejectReply
activity for a previously-accepted reply, third-parties SHOULD check that the RejectReply
is valid and SHOULD delete or hide the revoked reply if it is.
To be considered valid, the RejectReply
activity MUST satisfy the following properties:
actor
property is the authorityobject
property is the reply under considerationBecause it is unrealistic to expect all implementations and deployments to implement this proposal at the same time, deployment SHOULD be gradual, with verification of third-party replies only performed once the other steps are widely implemented. To encourage adoption without breaking compatibility altogether, implementations MAY want to hide non-validated replies from certain views (e.g. requiring a click to see “hidden replies”, or not showing the reply to non-followers).
By not adding a hash or copy of the reply in the ApproveReply
activity, malicious actors could exploit this in a split horizon setting, sending different versions of the same activity to different actors. This is, however, already a concern in pretty much all contexts in ActivityPub, and enshrining that information in the ApproveReply
activity would have many drawbacks:
ApproveReply
activity is publicly dereferenceableNone so far.
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.