From e783c9069311221d160c3ff368a79a5c3b2399e9 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Mon, 26 Jun 2023 08:27:14 +1000 Subject: [PATCH 1/3] add FEDERATION info --- FEDERATION.md | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 FEDERATION.md diff --git a/FEDERATION.md b/FEDERATION.md new file mode 100644 index 000000000..fcd3d5ce9 --- /dev/null +++ b/FEDERATION.md @@ -0,0 +1,223 @@ +# Federation + +TODO: extension object and activity examples +TODO: show how things are translated into `Notes` or `Articles` + +BookWyrm uses the [ActivityPub](http://activitypub.rocks/) protocol to send and receive user activity between other BookWyrm instances and other services that implement ActivityPub. To handle book data, BookWyrm has a handful of extended Activity types which are not part of the standard, but are legible to other BookWyrm instances. + +## Activities and Objects + +### Users and relationships +User relationship interactions follow the standard ActivityPub spec. + +- `Follow`: request to receive statuses from a user, and view their statuses that have followers-only privacy +- `Accept`: approves a `Follow` and finalizes the relationship +- `Reject`: denies a `Follow` +- `Block`: prevent users from seeing one another's statuses, and prevents the blocked user from viewing the actor's profile +- `Update`: updates a user's profile and settings +- `Delete`: deactivates a user +- `Undo`: reverses a `Follow` or `Block` + +### Statuses + +BookWyrm is focused on book reading activities - it is not a general-purpose messaging application. For this reason, BookWyrm only accepts status `Create` activities if they are: + +- Direct messages (i.e., `Note`s with the privacy level `direct`, which mention a local user), +- Related to a book (of a custom status type that includes the field `inReplyToBook`), +- Replies to existing statuses saved in the database + +All other statuses will be received by the instance inbox, but **will not be delivered to user inboxes or displayed to users**. + +#### Non-standard Object types + +With the exception of `Note`, the following object types are used in Bookwyrm but are not currently provided with a JSON-LD `@context` extension IRI. This is likely to change in future to make them true deserialisable JSON-LD objects. + +##### Note + +Within BookWyrm a `Note` is constructed according to [the ActivityStreams vocabulary](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note), however `Note`s can only be created as direct messages or as replies to other statuses. As mentioned above, this also applies to incoming `Note`s. + +##### Review + +A `Review` is a status in response to a book (indicated by the `inReplyToBook` field), which has a title, body, and numerical rating between 0 (not rated) and 5. + +##### Comment + +A `Comment` on a book mentions a book and has a message body. + +##### Quotation + +A quotation (aka "quote") has a message body, an excerpt from a book, and mentions a book. + +Example: + +```json +{ + "id": "https://example.com/user/mouse/quotation/13", + "url": "https://example.com/user/mouse/quotation/13", + "inReplyTo": null, + "published": "2020-05-10T02:38:31.150343+00:00", + "attributedTo": "https://example.com/user/mouse", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://example.com/user/mouse/followers" + ], + "sensitive": false, + "content": "commentary", + "type": "Quotation", + "replies": { + "id": "https://example.com/user/mouse/quotation/13/replies", + "type": "Collection", + "first": { + "type": "CollectionPage", + "next": "https://example.com/user/mouse/quotation/13/replies?only_other_accounts=true&page=true", + "partOf": "https://example.com/user/mouse/quotation/13/replies", + "items": [] + } + }, + "inReplyToBook": "https://example.com/book/1", + "quote": "quote body" +} +``` + +##### Work +A particular book, a "work" in the [FRBR](https://en.wikipedia.org/wiki/Functional_Requirements_for_Bibliographic_Records) sense. + +Example: + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://bookwyrm.social/book/5988", + "type": "Work", + "authors": [ + "https://bookwyrm.social/author/417" + ], + "first_published_date": null, + "published_date": null, + "title": "Piranesi", + "sort_title": null, + "subtitle": null, + "description": "**From the *New York Times* bestselling author of *Jonathan Strange & Mr. Norrell*, an intoxicating, hypnotic new novel set in a dreamlike alternative reality.", + "languages": [], + "series": null, + "series_number": null, + "subjects": [ + "English literature" + ], + "subject_places": [], + "openlibrary_key": "OL20893680W", + "librarything_key": null, + "goodreads_key": null, + "attachment": [ + { + "url": "https://bookwyrm.social/images/covers/10226290-M.jpg", + "type": "Image" + } + ], + "lccn": null, + "editions": [ + "https://bookwyrm.social/book/5989" + ] +} +``` + +##### Edition +A particular _manifestation_ of a Work, in the [FRBR](https://en.wikipedia.org/wiki/Functional_Requirements_for_Bibliographic_Records) sense. + +Example: + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://bookwyrm.social/book/5989", + "lastEditedBy": "https://example.com/users/rat", + "type": "Edition", + "authors": [ + "https://bookwyrm.social/author/417" + ], + "first_published_date": null, + "published_date": "2020-09-15T00:00:00+00:00", + "title": "Piranesi", + "sort_title": null, + "subtitle": null, + "description": "Piranesi's house is no ordinary building; its rooms are infinite, its corridors endless, its walls are lined with thousands upon thousands of statues, each one different from all the others.", + "languages": [ + "English" + ], + "series": null, + "series_number": null, + "subjects": [], + "subject_places": [], + "openlibrary_key": "OL29486417M", + "librarything_key": null, + "goodreads_key": null, + "isfdb": null, + "attachment": [ + { + "url": "https://bookwyrm.social/images/covers/50202953._SX318_.jpg", + "type": "Image" + } + ], + "isbn_10": "1526622424", + "isbn_13": "9781526622426", + "oclc_number": null, + "asin": null, + "pages": 272, + "physical_format": null, + "publishers": [ + "Bloomsbury Publishing Plc" + ], + "work": "https://bookwyrm.social/book/5988" +} +``` + +#### Activities +- `Create/Status`: saves a new status in the database. +- `Delete/Status`: Removes a status +- `Like/Status`: Creates a favorite on the status +- `Announce/Status`: Boosts the status into the actor's timeline +- `Undo/*`,: Reverses a `Like` or `Announce` + +### Collections +User's books and lists are represented by [`OrderedCollection`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) + +#### Custom Objects + +- `Shelf`: A user's book collection. By default, every user has a `to-read`, `reading`, and `read` shelf which are used to track reading progress. Users may create an unlimited number of additional shelves with their own ids. +- `List`: A collection of books that may have items contributed by users other than the one who created the list. + +#### Activities + +- `Create`: Adds a shelf or list to the database. +- `Delete`: Removes a shelf or list. +- `Add`: Adds a book to a shelf or list. +- `Remove`: Removes a book from a shelf or list. + +## Alternative Serialization +Because BookWyrm uses custom object types (`Review`, `Comment`, `Quotation`) that aren't listed in [the standard ActivityStreams Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary), statuses are transformed into standard types when sent to or viewed by non-BookWyrm services. `Review`s are converted into `Article`s, and `Comment`s and `Quotation`s are converted into `Note`s, with a link to the book and the cover image attached. + +In future this may be done with [JSON-LD type arrays](https://www.w3.org/TR/json-ld/#specifying-the-type) instead. + +## Other extensions + +### Webfinger + +Bookwyrm uses the [Webfinger](https://datatracker.ietf.org/doc/html/rfc7033) standard to identify and disambiguate fediverse actors. The [Webfinger documentation on the Mastodon project](https://docs.joinmastodon.org/spec/webfinger/) provides a good overview of how Webfinger is used. + +### HTTP Signatures + +Bookwyrm uses and requires HTTP signatures for all `POST` requests. `GET` requests are not signed by default, but if Bookwyrm receives a `403` response to a `GET` it will re-send the request, signed by the default server user. This usually will have a user id of `https://example.net/user/bookwyrm.instance.actor` + +#### publicKey id + +In older versions of Bookwyrm the `publicKey.id` was incorrectly listed in request headers as `https://example.net/user/username#main-key`. As of v0.6.3 the id is now listed correctly, as `https://example.net/user/username/#main-key`. In most ActivityPub implementations this will make no difference as the URL will usually resolve to the same place. + +### NodeInfo + +Bookwyrm uses the [NodeInfo](http://nodeinfo.diaspora.software/) standard to provide statistics and version information for each instance. + +## Further Documentation + +See [docs.joinbookwyrm.com/](https://docs.joinbookwyrm.com/) for more documentation. \ No newline at end of file From c875b18e34cc66b8204093baedc1a937941072a2 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Sat, 1 Jul 2023 14:23:02 +1000 Subject: [PATCH 2/3] complete FEDERATION.md initial file --- FEDERATION.md | 169 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 141 insertions(+), 28 deletions(-) diff --git a/FEDERATION.md b/FEDERATION.md index fcd3d5ce9..ecd91273b 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -18,6 +18,16 @@ User relationship interactions follow the standard ActivityPub spec. - `Delete`: deactivates a user - `Undo`: reverses a `Follow` or `Block` +### Activities +- `Create/Status`: saves a new status in the database. +- `Delete/Status`: Removes a status +- `Like/Status`: Creates a favorite on the status +- `Announce/Status`: Boosts the status into the actor's timeline +- `Undo/*`,: Reverses a `Like` or `Announce` + +### Collections +User's books and lists are represented by [`OrderedCollection`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) + ### Statuses BookWyrm is focused on book reading activities - it is not a general-purpose messaging application. For this reason, BookWyrm only accepts status `Create` activities if they are: @@ -26,9 +36,9 @@ BookWyrm is focused on book reading activities - it is not a general-purpose mes - Related to a book (of a custom status type that includes the field `inReplyToBook`), - Replies to existing statuses saved in the database -All other statuses will be received by the instance inbox, but **will not be delivered to user inboxes or displayed to users**. +All other statuses will be received by the instance inbox, but by design **will not be delivered to user inboxes or displayed to users**. -#### Non-standard Object types +### Custom Object types With the exception of `Note`, the following object types are used in Bookwyrm but are not currently provided with a JSON-LD `@context` extension IRI. This is likely to change in future to make them true deserialisable JSON-LD objects. @@ -40,10 +50,71 @@ Within BookWyrm a `Note` is constructed according to [the ActivityStreams vocabu A `Review` is a status in response to a book (indicated by the `inReplyToBook` field), which has a title, body, and numerical rating between 0 (not rated) and 5. +Example: + +```json +{ + "id": "https://example.net/user/library_lurker/review/2", + "type": "Review", + "published": "2023-06-30T21:43:46.013132+00:00", + "attributedTo": "https://example.net/user/library_lurker", + "content": "

This is an enjoyable book with great characters.

", + "to": ["https://example.net/user/library_lurker/followers"], + "cc": [], + "replies": { + "id": "https://example.net/user/library_lurker/review/2/replies", + "type": "OrderedCollection", + "totalItems": 0, + "first": "https://example.net/user/library_lurker/review/2/replies?page=1", + "last": "https://example.net/user/library_lurker/review/2/replies?page=1", + "@context": "https://www.w3.org/ns/activitystreams" + }, + "summary": "Spoilers ahead!", + "tag": [], + "attachment": [], + "sensitive": true, + "inReplyToBook": "https://example.net/book/1", + "name": "What a cracking read", + "rating": 4.5, + "@context": "https://www.w3.org/ns/activitystreams" +} +``` + ##### Comment A `Comment` on a book mentions a book and has a message body. +Example: + +```json +{ + "id": "https://example.net/user/library_lurker/comment/9", + "type": "Comment", + "published": "2023-06-30T21:43:46.013132+00:00", + "attributedTo": "https://example.net/user/library_lurker", + "content": "

This is a very enjoyable book so far.

", + "to": ["https://example.net/user/library_lurker/followers"], + "cc": [], + "replies": { + "id": "https://example.net/user/library_lurker/comment/9/replies", + "type": "OrderedCollection", + "totalItems": 0, + "first": "https://example.net/user/library_lurker/comment/9/replies?page=1", + "last": "https://example.net/user/library_lurker/comment/9/replies?page=1", + "@context": "https://www.w3.org/ns/activitystreams" + }, + "summary": "Spoilers ahead!", + "tag": [], + "attachment": [], + "sensitive": true, + "inReplyToBook": "https://example.net/book/1", + "readingStatus": "reading", + "progress": 25, + "progressMode": "PG", + "@context": "https://www.w3.org/ns/activitystreams" +} +``` + ##### Quotation A quotation (aka "quote") has a message body, an excerpt from a book, and mentions a book. @@ -52,35 +123,40 @@ Example: ```json { - "id": "https://example.com/user/mouse/quotation/13", - "url": "https://example.com/user/mouse/quotation/13", + "id": "https://example.net/user/mouse/quotation/13", + "url": "https://example.net/user/mouse/quotation/13", "inReplyTo": null, "published": "2020-05-10T02:38:31.150343+00:00", - "attributedTo": "https://example.com/user/mouse", + "attributedTo": "https://example.net/user/mouse", "to": [ "https://www.w3.org/ns/activitystreams#Public" ], "cc": [ - "https://example.com/user/mouse/followers" + "https://example.net/user/mouse/followers" ], "sensitive": false, - "content": "commentary", + "content": "I really like this quote", "type": "Quotation", "replies": { - "id": "https://example.com/user/mouse/quotation/13/replies", + "id": "https://example.net/user/mouse/quotation/13/replies", "type": "Collection", "first": { "type": "CollectionPage", - "next": "https://example.com/user/mouse/quotation/13/replies?only_other_accounts=true&page=true", - "partOf": "https://example.com/user/mouse/quotation/13/replies", + "next": "https://example.net/user/mouse/quotation/13/replies?only_other_accounts=true&page=true", + "partOf": "https://example.net/user/mouse/quotation/13/replies", "items": [] } }, - "inReplyToBook": "https://example.com/book/1", - "quote": "quote body" + "inReplyToBook": "https://example.net/book/1", + "quote": "To be or not to be, that is the question.", + "position": 50, + "positionMode": "PCT", + "@context": "https://www.w3.org/ns/activitystreams" } ``` +### Custom Objects + ##### Work A particular book, a "work" in the [FRBR](https://en.wikipedia.org/wiki/Functional_Requirements_for_Bibliographic_Records) sense. @@ -88,7 +164,6 @@ Example: ```json { - "@context": "https://www.w3.org/ns/activitystreams", "id": "https://bookwyrm.social/book/5988", "type": "Work", "authors": [ @@ -119,7 +194,8 @@ Example: "lccn": null, "editions": [ "https://bookwyrm.social/book/5989" - ] + ], + "@context": "https://www.w3.org/ns/activitystreams" } ``` @@ -130,9 +206,8 @@ Example: ```json { - "@context": "https://www.w3.org/ns/activitystreams", "id": "https://bookwyrm.social/book/5989", - "lastEditedBy": "https://example.com/users/rat", + "lastEditedBy": "https://example.net/users/rat", "type": "Edition", "authors": [ "https://bookwyrm.social/author/417" @@ -169,24 +244,62 @@ Example: "publishers": [ "Bloomsbury Publishing Plc" ], - "work": "https://bookwyrm.social/book/5988" + "work": "https://bookwyrm.social/book/5988", + "@context": "https://www.w3.org/ns/activitystreams" } ``` -#### Activities -- `Create/Status`: saves a new status in the database. -- `Delete/Status`: Removes a status -- `Like/Status`: Creates a favorite on the status -- `Announce/Status`: Boosts the status into the actor's timeline -- `Undo/*`,: Reverses a `Like` or `Announce` +#### Shelf -### Collections -User's books and lists are represented by [`OrderedCollection`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) +A user's book collection. By default, every user has a `to-read`, `reading`, and `read` shelf which are used to track reading progress. Users may create an unlimited number of additional shelves with their own ids. -#### Custom Objects +Example -- `Shelf`: A user's book collection. By default, every user has a `to-read`, `reading`, and `read` shelf which are used to track reading progress. Users may create an unlimited number of additional shelves with their own ids. -- `List`: A collection of books that may have items contributed by users other than the one who created the list. +```json +{ + "id": "https://example.net/user/avid_reader/books/extraspecialbooks-5", + "type": "Shelf", + "totalItems": 0, + "first": "https://example.net/user/avid_reader/books/extraspecialbooks-5?page=1", + "last": "https://example.net/user/avid_reader/books/extraspecialbooks-5?page=1", + "name": "Extra special books", + "owner": "https://example.net/user/avid_reader", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://example.net/user/avid_reader/followers" + ], + "@context": "https://www.w3.org/ns/activitystreams" +} +``` + +#### List + +A collection of books that may have items contributed by users other than the one who created the list. + +Example: + +```json +{ + "id": "https://example.net/list/1", + "type": "BookList", + "totalItems": 0, + "first": "https://example.net/list/1?page=1", + "last": "https://example.net/list/1?page=1", + "name": "My cool list", + "owner": "https://example.net/user/avid_reader", + "to": [ + "https://www.w3.org/ns/activitystreams#Public" + ], + "cc": [ + "https://example.net/user/avid_reader/followers" + ], + "summary": "A list of books I like.", + "curation": "curated", + "@context": "https://www.w3.org/ns/activitystreams" +} +``` #### Activities From fad1eb8952b1c976d3b751a3e0d3dd3be4e3f705 Mon Sep 17 00:00:00 2001 From: Hugh Rundle Date: Mon, 3 Jul 2023 08:38:53 +1000 Subject: [PATCH 3/3] clean up and add stopped-reading shelf type --- FEDERATION.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/FEDERATION.md b/FEDERATION.md index ecd91273b..dd0c917e2 100644 --- a/FEDERATION.md +++ b/FEDERATION.md @@ -1,8 +1,5 @@ # Federation -TODO: extension object and activity examples -TODO: show how things are translated into `Notes` or `Articles` - BookWyrm uses the [ActivityPub](http://activitypub.rocks/) protocol to send and receive user activity between other BookWyrm instances and other services that implement ActivityPub. To handle book data, BookWyrm has a handful of extended Activity types which are not part of the standard, but are legible to other BookWyrm instances. ## Activities and Objects @@ -40,7 +37,7 @@ All other statuses will be received by the instance inbox, but by design **will ### Custom Object types -With the exception of `Note`, the following object types are used in Bookwyrm but are not currently provided with a JSON-LD `@context` extension IRI. This is likely to change in future to make them true deserialisable JSON-LD objects. +With the exception of `Note`, the following object types are used in Bookwyrm but are not currently provided with a custom JSON-LD `@context` extension IRI. This is likely to change in future to make them true deserialisable JSON-LD objects. ##### Note @@ -82,7 +79,7 @@ Example: ##### Comment -A `Comment` on a book mentions a book and has a message body. +A `Comment` on a book mentions a book and has a message body, reading status, and progress indicator. Example: @@ -117,7 +114,7 @@ Example: ##### Quotation -A quotation (aka "quote") has a message body, an excerpt from a book, and mentions a book. +A quotation (aka "quote") has a message body, an excerpt from a book including position as a page number or percentage indicator, and mentions a book. Example: @@ -251,7 +248,7 @@ Example: #### Shelf -A user's book collection. By default, every user has a `to-read`, `reading`, and `read` shelf which are used to track reading progress. Users may create an unlimited number of additional shelves with their own ids. +A user's book collection. By default, every user has a `to-read`, `reading`, `read`, and `stopped-reading` shelf which are used to track reading progress. Users may create an unlimited number of additional shelves with their own ids. Example @@ -309,7 +306,7 @@ Example: - `Remove`: Removes a book from a shelf or list. ## Alternative Serialization -Because BookWyrm uses custom object types (`Review`, `Comment`, `Quotation`) that aren't listed in [the standard ActivityStreams Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary), statuses are transformed into standard types when sent to or viewed by non-BookWyrm services. `Review`s are converted into `Article`s, and `Comment`s and `Quotation`s are converted into `Note`s, with a link to the book and the cover image attached. +Because BookWyrm uses custom object types that aren't listed in [the standard ActivityStreams Vocabulary](https://www.w3.org/TR/activitystreams-vocabulary), some statuses are transformed into standard types when sent to or viewed by non-BookWyrm services. `Review`s are converted into `Article`s, and `Comment`s and `Quotation`s are converted into `Note`s, with a link to the book and the cover image attached. In future this may be done with [JSON-LD type arrays](https://www.w3.org/TR/json-ld/#specifying-the-type) instead.