1
0
mirror of https://codeberg.org/fediverse/fep.git synced 2026-08-06 04:05:53 +00:00

feat: FEP-5711: Inverse Properties for Collections (#537)

This FEP introduces inverse properties for the most important collection properties in ActivityPub. These provide two main benefits: first, navigating from a collection to the object it is a property of; second, two-way verification of the relationship between the object and the collection.

Reviewed-on: https://codeberg.org/fediverse/fep/pulls/537
Co-authored-by: Evan Prodromou <codeberg@evanprodromou.name>
Co-committed-by: Evan Prodromou <codeberg@evanprodromou.name>
This commit is contained in:
Evan Prodromou
2025-03-24 21:10:17 +00:00
committed by silverpill
parent 340120ac4d
commit 86fcfeae82
2 changed files with 343 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
{
"@context": {
"inv": "https://w3id.org/fep/5711#",
"likesOf": {
"@id": "inv:likesOf",
"@type": "@id"
},
"sharesOf": {
"@id": "inv:sharesOf",
"@type": "@id"
},
"repliesOf": {
"@id": "inv:repliesOf",
"@type": "@id"
},
"inboxOf": {
"@id": "inv:inboxOf",
"@type": "@id"
},
"outboxOf": {
"@id": "inv:outboxOf",
"@type": "@id"
},
"followersOf": {
"@id": "inv:followersOf",
"@type": "@id"
},
"followingOf": {
"@id": "inv:followingOf",
"@type": "@id"
},
"likedOf": {
"@id": "inv:likedOf",
"@type": "@id"
}
}
}
+306
View File
@@ -0,0 +1,306 @@
---
slug: "5711"
authors: Evan Prodromou <evan@socialwebfoundation.org>
status: DRAFT
dateReceived: 1970-01-01
discussionsTo: https://codeberg.org/evanp/fep/issues
---
# FEP-5711: Inverse Properties for Collections
## Summary
This FEP defines inverse properties for collections that are important in ActivityPub.
## Motivation
The [Activity Vocabulary][ActivityVocab] defines a number of important collection properties for organizing reactions to an object. [ActivityPub][ActivityPub] augments these with additional properties that specify the activity streams and social graph for actors.
Out of context, though, it can be hard to determine if a collection has a defined relationship to an object or actor. This can be important for clients that give users the ability to manipulate collections with the `Add`, `Remove`, `Update` and `Delete` activities, since the special collections defined in ActivityPub are usually maintained with different flows.
Other methods exist to identify collections that are the value of properties of actors. It's possible to use the `attributedTo` property to identify the actor, and then compare against all of the collection properties of the actor (`inbox`, `outbox`, and so on). This is a good fallback mechanism, but the inverse properties defined in this document are a more direct way to determine the relationship. There is no method for determining if a collection is the property of an object, however.
Additionally, one form of spoofing that a server could use is referring to collections as properties of objects that in fact are related to other objects. For example, a server could include a collection of likes as a property of an object that is not the object that the likes are for. This could be used to inflate the apparent popularity of an object. Inverse properties can help prevent this kind of spoofing by providing a two-way verification mechanism.
These inverse properties are most useful when the collections are represented separately from the object or actor they are related to. For example, this representation can help identify the object that the collection contains the `likes` of:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/b25kr36ief",
"likesOf": "https://example.com/image/7pqs5i7c1e"
}
```
This representation, on the other hand, is redundant, since the collection is represented as the property of the object:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Image",
"id": "https://example.com/image/7pqs5i7c1e",
"likes": {
"type": "Collection",
"id": "https://example.com/collection/b25kr36ief",
"likesOf": "https://example.com/image/7pqs5i7c1e"
}
}
```
### User stories
- As an ActivityPub user, I want to confirm that a collection referred to in the property of an object is actually intended for use with that property, to prevent spoofing.
- As an ActivityPub developer, I want to know that a collection is intended for a particular use, so that I can use it correctly in my application.
## Specification
The following terms are defined in this vocabulary extension.
The examples in the following sections refer to the following example object:
```json
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Image",
"id": "https://example.com/image/7pqs5i7c1e",
"name": "A beautiful image",
"url": "https://files.example.com/image/29m2p4kdq15.jpg",
"likes": "https://example.com/collection/b25kr36ief",
"shares": "https://example.com/collection/hvjgqhpv3e",
"replies": "https://example.com/collection/u9hwmfih7r"
}
```
...and/or the following actor:
```json
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Person",
"id": "https://example.com/person/bup9a8eqm",
"name": "Alice",
"inbox": "https://example.com/collection/tgiqwh6p3b",
"outbox": "https://example.com/collection/hvf8crcd6r",
"followers": "https://example.com/collection/x48dtnhlt9",
"following": "https://example.com/collection/r9w7krxua",
"liked": "https://example.com/collection/jzc50wc28l"
}
```
### likesOf
- URI: `https://w3id.org/fep/5711#likesOf`
- Domain: `as:Collection`
- Range: `as:Object`
- Functional: True
Defines an object for which the collection is the value of the `likes` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/b25kr36ief",
"likesOf": "https://example.com/image/7pqs5i7c1e"
}
```
### sharesOf
- URI: `https://w3id.org/fep/5711#sharesOf`
- Domain: `as:Collection`
- Range: `as:Object`
- Functional: True
Defines an object for which the collection is the value of the `shares` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/hvjgqhpv3e",
"sharesOf": "https://example.com/image/7pqs5i7c1e"
}
```
### repliesOf
- URI: `https://w3id.org/fep/5711#repliesOf`
- Domain: `as:Collection`
- Range: `as:Object`
- Functional: True
Defines an object for which the collection is the value of the `replies` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "OrderedCollection",
"id": "https://example.com/collection/u9hwmfih7r",
"repliesOf": "https://example.com/image/7pqs5i7c1e"
}
```
### inboxOf
- URI: `https://w3id.org/fep/5711#inboxOf`
- Domain: `as:Collection`
- Range: `as:Object` (an ActivityPub actor)
- Functional: True
Defines an actor for which the collection is the value of the `inbox` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/tgiqwh6p3b",
"inboxOf": "https://example.com/person/bup9a8eqm"
}
```
### outboxOf
- URI: `https://w3id.org/fep/5711#outboxOf`
- Domain: `as:Collection`
- Range: `as:Object` (an ActivityPub actor)
- Functional: True
Defines an actor for which the collection is the value of the `outbox` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/hvf8crcd6r",
"outboxOf": "https://example.com/person/bup9a8eqm"
}
```
### followersOf
- URI: `https://w3id.org/fep/5711#followersOf`
- Domain: `as:Collection`
- Range: `as:Object` (an ActivityPub actor)
- Functional: True
Defines an actor for which the collection is the value of the `followers` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/x48dtnhlt9",
"followersOf": "https://example.com/person/bup9a8eqm"
}
```
### followingOf
- URI: `https://w3id.org/fep/5711#followingOf`
- Domain: `as:Collection`
- Range: `as:Object` (an ActivityPub actor)
- Functional: True
Defines an actor for which the collection is the value of the `following` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/r9w7krxua",
"followingOf": "https://example.com/person/bup9a8eqm"
}
```
### likedOf
- URI: `https://w3id.org/fep/5711#likedOf`
- Domain: `as:Collection`
- Range: `as:Object` (an ActivityPub actor)
- Functional: True
Defines an actor for which the collection is the value of the `liked` property.
Example:
```json
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/5711"
],
"type": "Collection",
"id": "https://example.com/collection/jzc50wc28l",
"likedOf": "https://example.com/person/bup9a8eqm"
}
```
## Implementation notes
There should be only one inverse relationship property for a collection. There are conceivable structures where the `replies` collection of an object is also the `liked` collection of an actor, but these are rare.
All of these properties are functional, meaning that there is only one value for each collection.
## Security considerations
Claims made by these properties should be verified by retrieving the referenced object or actor and checking the appropriate property. For example, if a server claims that a collection is the `shares` property of an object using the `sharesOf` property, the consumer should retrieve the referenced object and check that the `shares` property references the same collection.
Use of these inverse properties can help prevent spoofing of collections, but they do not provide verification of the contents of the collection. For example, a collection that uses the
`likesOf` property to claim that it is the `likes` collection of a video, and which is in turn referenced by the video, may still contain `Like` activities that are not actually likes of the video.
## References
- James Snell, Evan Prodromou, [Activity Vocabulary][ActivityVocab], 2018
- Christine Lemmer Webber, Jessica Tallon, [ActivityPub][ActivityPub], 2018
[ActivityPub]: https://www.w3.org/TR/activitypub/
[ActivityVocab]: https://www.w3.org/TR/activitystreams-vocabulary/
## Copyright
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.