diff --git a/fep/5711/fep-5711.json b/fep/5711/fep-5711.json new file mode 100644 index 0000000..2bfdd48 --- /dev/null +++ b/fep/5711/fep-5711.json @@ -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" + } + } +} \ No newline at end of file diff --git a/fep/5711/fep-5711.md b/fep/5711/fep-5711.md new file mode 100644 index 0000000..ee9803e --- /dev/null +++ b/fep/5711/fep-5711.md @@ -0,0 +1,306 @@ +--- +slug: "5711" +authors: Evan Prodromou +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.