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

FEP-fffd: New draft using url and Link, plus merging instructions (#99)

This is an extensive update to FEP-fffd:

- Proxy links are now `Link`s in `url` with `"rel": "alternate"` or `"rel": "canonical"`. The new `@context` entries have been removed entirely.
- Protocols are determined by URI scheme and/or `mediaType`, not an explicit `protocol` URI.
- Added ATProto, DID, Secure Scuttlebutt, RSS, Atom, and ActivityPub to the list of well-known protocols.
- Specified that only bare NIP-19 identifiers can be used in Nostr URIs.
- Added a section to explain the merging "algorithm", mostly the situations in which merging breaks down and should be skipped.
- Removed references to Zot, since no bridging is needed for Zot.
- More clarity about which sections are normative.
- Added a reference to proxies for moved ActivityPub posts, which seems like an ideal use case not considered before.

Co-authored-by: Adam R. Nelson <adam@nels.onl>
Reviewed-on: https://codeberg.org/fediverse/fep/pulls/99
Co-authored-by: Adam Nelson <arnelson@noreply.codeberg.org>
Co-committed-by: Adam Nelson <arnelson@noreply.codeberg.org>
This commit is contained in:
Adam Nelson
2023-05-17 15:39:50 +00:00
committed by David Sterry
parent 565a08889b
commit cf880fd7a6
+110 -66
View File
@@ -3,23 +3,29 @@ authors: Adam R. Nelson <adam@nels.onl>
status: DRAFT
dateReceived: 2023-04-29
---
# FEP-fffd: Proxy Objects
## Summary
A *proxy object* is an \[ActivityPub] object that is semantically identical to an entity on another, non-ActivityPub protocol. For example, an ActivityPub-to-Nostr bridge creates Actors and Notes that are proxies for Nostr users and notes.
A *proxy object* is an \[ActivityPub] object that is semantically identical to another entity, which may exist on another, non-ActivityPub protocol. For example, an ActivityPub-to-Nostr bridge creates Actors and Notes that are proxies for Nostr users and notes.
This document describes a data format to identify proxy objects and to describe the non-ActivityPub entities that they are equivalent to, with the intention that multi-protocol clients will automatically merge objects with their proxies, hiding the implementation details of bridges and cross-protocol publishing from users.
This document describes a data format to identify proxy objects and to specify the ActivityPub and non-ActivityPub entities they are equivalent to, with the intention that multi-protocol clients will automatically merge objects with their proxies, hiding the implementation details of bridges and cross-protocol publishing from users.
## Requirements
## 1. Requirements
The key words "MUST", "SHOULD", and "MAY" are to be interpreted as described in \[RFC2119].
## Rationale
## 2. Rationale
Many Fediverse servers speak multiple protocols besides ActivityPub, such as Zot or Diaspora, and simultaneously publish posts across multiple protocols. Additionally, bridge servers exist to relay posts between ActivityPub and other protocols such as Nostr.
> This section is non-normative.
There is currently no standard way to communicate that an ActivityPub activity is a copy (or *proxy*) of a post on another protocol.
Many Fediverse servers speak multiple protocols besides ActivityPub, such as Nostr or Diaspora, and simultaneously publish posts across multiple protocols. Additionally, bridge servers exist to relay posts between ActivityPub and other protocols such as Nostr.
A use case also exists for creating a duplicate of an ActivityPub object: moving an account to a new instance. Posts copied to a user's new account should be marked as duplicates of the originals, in a way that preserves the original posts' likes and replies.
Despite these use cases, there is currently no standard way to communicate that an ActivityPub activity is a copy (or *proxy*) of a post on another protocol.
Consider this scenario:
@@ -30,69 +36,75 @@ Consider this scenario:
Proxy objects provide a potential solution to this problem.
## Format
## 3. Format
FEP-fffd uses the `w3id.org/fep` namespace as defined in \[FEP-9606]. Conforming ActivityPub JSON-LD messages MUST include a context that maps the terms `proxyOf`, `protocol`, `proxied`, and `authoritative` to the same IRIs and types as in this context:
FEP-fffd does not define any new vocabulary or `@context` entries. Instead, it further defines the meaning of Links in the `url` property of an Object when they have a `rel` property of `"alternate"` or `"canonical"`.
```json
{
"@context": {
"xsd": "http://www.w3.org/2001/XMLSchema#",
"fep": "https://w3id.org/fep/",
"proxyOf": {
"@id": "fep:fffd/proxyOf",
"@type": "@id",
"@container": "@set"
},
"protocol": {
"@id": "fep:fffd/protocol",
"@type": "@id"
},
"proxied": {
"@id": "fep:fffd/proxied",
"@type": "xsd:string"
},
"authoritative": {
"@id": "fep:fffd/authoritative",
"@type": "xsd:boolean"
}
}
}
```
Each Link in `url` with `"rel": "alternate"` or `"rel": "canonical"` is called a *proxy link*. Any Object with one or more proxy links is called a *proxy object*. The referent of a proxy link is called a *proxied object*, and SHOULD be considered semantically identical to the parent proxy object, modulo the limitations described in section 4.
The property `proxyOf` may be included in any ActivityPub Object, such as an Actor or a Note. If `proxyOf` is present, its value MUST be an array of objects, and each object in this array MUST include the properties `protocol` and `proxied`, and additionally MAY include the property `authoritative`. An object with a nonempty `proxyOf` property is called a *proxy object*.
A proxied object is not necessarily an ActivityPub object, or even an object accessible via a network request; its meaning is determined based on its protocol. The protocol and format of the proxied object are determined by the proxy link's URI scheme and `mediaType`; well-known protocols and defaults are defined in section 5. An application SHOULD ignore proxied objects in protocols or formats that the application does not understand.
Each entry in `proxyOf` names a non-ActivityPub entity, called a *proxied object*, which should be considered semantically identical to the parent proxy object. `protocol` is an IRI that identifies the non-ActivityPub protocol being used, and `proxied` is a freeform string (usually, but not necessarily, a URL) that identifies an entity in whatever format the protocol in question uses.
If a proxy link has `"rel": "canonical"`, it indicates that its proxied object is the *canonical* (original, authoritative) version of the proxy object. A proxy object MUST NOT have more than one proxy link with `"rel": "canonical"`. This property SHOULD be used by bridges that relay posts made by third parties, to indicate that the bridged post is not the original. It SHOULD NOT be used by servers that publish to multiple protocols at once; in this case no one version of an object is more authoritative than another.
If `authoritative` is present and its value is `true`, it indicates that the proxied object is the original, authoritative version of the proxy object. The `proxyOf` array MUST NOT contain more than one object with `authoritative: true`. This property SHOULD be used by bridges that relay posts made by third parties, to indicate that the bridged post is not the original. It SHOULD NOT be used by servers that publish to multiple protocols at once; in this case no one version of an object is more authoritative than another.
## 4. Merging
## Protocols
When a conforming application encounters a proxy object, it may merge it with its proxy objects under certain circumstances.
This document defines two protocol names, but more may be included in either future FEPs or future revisions of this document.
To *merge* a proxy object and its proxied object(s) means to display all of these objects as a single entity (such as a user or a post), while combining all collections and metadata belonging to these objects:
### Nostr
- The followers, following, liked, and outbox collections of an actor, if present, SHOULD be combined with those of a proxy when merging.
- The replies, likes, and shares of a non-actor object, if present, SHOULD be combined with those of a proxy object when merging.
- If one of the merged objects is canonical, its properties SHOULD override any conflicting properties in any other merged object.
- If none of the merged objects are canonical, conflicting properties MAY be resolved in any way the application chooses, including but not limited to: choosing the representation from the protocol with the most features, displaying a detailed description of the conflict, or refusing to merge objects with conflicting properties.
`protocol`: `"https://nostr.com"`
In some circumstances, an application may encounter malformed or malicious proxy links that could misrepresent objects not owned by the links' author, or it may encounter proxy links whose referents are malformed or missing. These situations sometimes prevent merging.
`proxied` format: A \[NIP-19] string identifying a pubkey or note.
- If a proxy link's referent has been deleted (as indicated by an HTTP 410 Gone status, a Delete activity, or another protocol's equivalent), then:
- If the proxied object is canonical, the proxy object SHOULD be deleted
- If the proxied object is not canonical, the proxy object MAY be deleted; if it is not, all collection entries originally from the deleted object's protocol (if it is not ActivityPub) SHOULD be removed from the proxy object's collections, and their proxy objects, if any, SHOULD be deleted.
- If a proxy link is broken, but has not been explicitly deleted, then the proxy object MAY continue to exist, and the application MAY still display cached data or proxy objects for the proxied object's collection entries.
- If a proxied object is canonical, and that proxied object itself has a link to a different canonical representation (whether through FEP-fffd or another protocol's equivalent), then:
- The application SHOULD follow the chain of canonical links up to a fixed, application-defined maximum number of links.
- If this number of links is exceeded (possibly indicating a cycle), or if any link in the chain has more than one canonical link, the application SHOULD NOT merge any of the objects in the chain.
- If a proxied object is not canonical, the application SHOULD verify that the proxied object also considers itself a proxy for the proxy object. If the proxied object is an ActivityPub object, then the application SHOULD NOT merge it with the proxy object if it does not meet at least one of these criteria:
- It has a proxy link pointing to the proxy object (that is, both objects are proxies for each other)
- Both objects are actors, and both are `alsoKnownAs` each other.
- Both object are owned by the same actor, or by actors that are `alsoKnownAs` each other.
- If a proxy link points to localhost or any loopback address, the application SHOULD NOT follow the link or attempt to merge the proxied object it represents.
### Diaspora
## 5. Protocols
`protocol`: `"https://joindiaspora.com/protocol"`
Several protocols are named in this document, but interaction with these protocols is left intentionally underspecified, as the behavior of non-ActivityPub protocols is outside the scope of this FEP. If a proxy link's URI scheme and/or `mediaType` match a protocol named in this section, a conforming application SHOULD either use the matching protocol to access the proxied object or ignore the proxy link entirely, but it MUST NOT interpret the link as a proxy link for a different protocol or format.
`proxied` format: A URI with the \[`diaspora://` URI scheme].
### 5.1. Well-known Alternate Protocols
### Freeform Prefix IRIs
- Nostr: Identified by the `nostr:` URI scheme, as defined in \[NIP-21]. The identifiers used in these URIs MUST be "bare" NIP-19 identifiers starting with `npub1` or `note1`. The `npub1` identifier type MUST be used only in proxy links for Actors.
- Diaspora: Identified by the `diaspora:` URI scheme, following the format defined in \[`diaspora://` URI scheme].
- DID: Identified by the `did:` URI scheme, as defined in \[DID URL Syntax], and MUST be used only in proxy links for Actors.
- ATProto: Identified by the `at` URI scheme, as defined in \[AT URI Scheme]. AT Repositories, Collections, and Records MUST be used only in proxy links for ActivityPub Actors, Collections, and Objects, respectively. Repository URIs starting with `at://did:` SHOULD be considered identical to the `did:` URIs they contain; including both a `did:` link and an `at://did:` link for the same DID is redundant.
- Secure Scuttlebutt: Identified by the `ssb:` URI scheme.
In addition to the above specified protocol IRIs, `protocol` MAY be any other IRI if `proxied` is also an IRI and `protocol` is a prefix of `proxied`.
### 5.2. Well-known Media Types
This allows an ActivityPub object to proxy any non-federated Web content; for example, a Twitter-to-ActivityPub bridge may use a `protocol` of `"https://twitter.com"` and a `proxied` value that is a Twitter URL, to identify a Note as a proxy object for a Twitter post.
- RSS: `application/rss+xml`; the `href` should be the URL of the feed, followed by a URL fragment whose content is the `<guid>` value of an entry in the feed.
- Atom: `application/atom+xml`; the `href` should be the URL of the feed, followed by a URL fragment whose content is the `<id>` value of an entry in the feed.
- ActivityPub: `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` or `application/activity+json`; the `href` should point to an ActivityPub Object.
## Examples
If an application supports general-purpose transport protocols other than HTTP(S), such as Gemini or IPFS, it MAY interpret proxy links to these protocols in the same manner as it would interpret HTTP(S) proxy links, including applying these well-known media types.
(This section is non-normative. The JSON-LD `@context` property is omitted for brevity.)
### 5.3. Non-federated Web Content
A post relayed by a third-party Twitter-to-ActivityPub bridge:
By default, if a proxy link uses the `http` or `https` protocol, and either does not have a `mediaType` or has a `mediaType` of `text/html`, it is considered a link to some unspecified, application-defined non-federated Web content. An application MAY interpret this link as any kind of content or protocol other than one of the well-known protocols or formats defined in this section. Notably, this kind of proxy object MUST NOT be interpreted as an ActivityPub resource, even if the link responds with valid ActivityStreams data.
This default allows an ActivityPub object to proxy any non-federated Web content; for example, a Twitter-to-ActivityPub bridge may use a proxy link to a Twitter URL to identify a Note as a proxy object for a Twitter post.
## 6. Examples
> This section is non-normative. The JSON-LD `@context` property is omitted for brevity.
---
A post relayed by a third-party Twitter-to-ActivityPub bridge. Because the `canonical` proxy link is also the only `url` entry, it should also be used as a clickable link to the original post.
```json
{
@@ -100,15 +112,17 @@ A post relayed by a third-party Twitter-to-ActivityPub bridge:
"type": "Note",
"actor": "http://twitter-bridge.example/@jack",
"content": "just setting up my twttr",
"proxyOf": [{
"protocol": "https://twitter.com",
"proxied": "https://twitter.com/jack/status/20",
"authoritative": true
}]
"url": {
"type": "Link",
"rel": "canonical",
"href": "https://twitter.com/jack/status/20"
}
}
```
A post published to ActivityPub, Diaspora, and Nostr simultaneously:
---
A post published to ActivityPub, Diaspora, and Nostr simultaneously. Because there is one non-proxy `Link` in `url` with an `https` protocol, this non-proxy link should be used as a clickable link to the original post.
```json
{
@@ -116,23 +130,53 @@ A post published to ActivityPub, Diaspora, and Nostr simultaneously:
"type": "Note",
"actor": "http://fediverse.example/@alice",
"content": "Hello, world!",
"proxyOf": [{
"protocol": "https://joindiaspora.com/protocol",
"proxied": "diaspora://alice@fediverse.example/post/deadbeefdeadbeefdeadbeefdeadbeef"
"url": [{
"type": "Link",
"href": "https://fediverse.example/@alice/1234"
}, {
"protocol": "https://nostr.com",
"proxied": "note1gwdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
"type": "Link",
"rel": "alternate",
"href": "diaspora://alice@fediverse.example/post/deadbeefdeadbeefdeadbeefdeadbeef"
}, {
"type": "Link",
"rel": "alternate",
"href": "nostr:note1gwdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
}]
}
```
---
An ActivityPub Note copied from a user's old instance to a new instance when moving to a new account.
```json
{
"id": "http://newinstance.example/status/1234",
"type": "Note",
"actor": "http://newinstance.example/@alice",
"content": "Hello, world!",
"url": [{
"type": "Link",
"href": "https://newinstance.example/@alice/1234"
}, {
"type": "Link",
"rel": "canonical",
"mediaType": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
"href": "https://oldinstance.example/status/5678"
}]
}
```
---
## References
* [RFC-2119] S. Bradner, [Key words for use in RFCs to Indicate Requirement Levels](https://tools.ietf.org/html/rfc2119.html)
* [ActivityPub] Christine Lemmer Webber, Jessica Tallon, [ActivityPub](https://www.w3.org/TR/activitypub/), 2018
* [FEP-9606] a, [FEP-9606 : Using `w3id.org/fep` as a namespace for extension terms and for FEP documents](https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-9606.md), 2023
* [NIP-19] jb55, fianjaf, Semisol, [NIP-19: bech32-encoded entities](https://github.com/nostr-protocol/nips/blob/master/19.md), 2023
* [`diaspora://` URI scheme] Benjamin Neff, [diaspora* federation protocol](https://diaspora.github.io/diaspora_federation/index.html), 2017
- [ActivityPub] Christine Lemmer Webber, Jessica Tallon, [ActivityPub](https://www.w3.org/TR/activitypub/), 2018
- [RFC-2119] S. Bradner, [Key words for use in RFCs to Indicate Requirement Levels](https://tools.ietf.org/html/rfc2119.html), 1997
- [NIP-21] fiatjaf, martindsq, mplorentz, [NIP-21: `nostr:` URI scheme](https://github.com/nostr-protocol/nips/blob/master/21.md), 2023
- [`diaspora://` URI scheme] Benjamin Neff, [diaspora* federation protocol](https://diaspora.github.io/diaspora_federation/index.html), 2017
- [DID URL Syntax] Manu Sporny, Markus Sabadello, Drummond Reed, Orie Steele, Christopher Allen, [Decentralized Identifiers (DIDs) v1.0](https://www.w3.org/TR/did-core/#did-url-syntax), 2022
- [AT URI Scheme] Bluesky, [ATProto Documentation](https://atproto.com/specs/at-uri-scheme), 2023
## Copyright