diff --git a/proposals/2346-bridge-info-state-event.md b/proposals/2346-bridge-info-state-event.md new file mode 100644 index 00000000000..f017e8138c7 --- /dev/null +++ b/proposals/2346-bridge-info-state-event.md @@ -0,0 +1,241 @@ +# MSC 2346: Bridge information state event + +Many rooms across the Matrix network are currently bridged into third party networks, using bridges. +However the spec does not contain a cross-federated method to determine which networks are +bridged into a given room. + +There exists a way to do this in a local setting, by using the +[/thirdparty/location](https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-thirdparty-protocol-protocol) +API but this creates a splitbrain view across the federation and is an unnacceptable situation. + +Many users have taken to peeking at the list of aliases for a giveaway alias like `#freenode_` or +looking for bridge bots or users with a `@_discord_` prefix. This is an unacceptable situation, +as it assumes prior knowledge of these networks and an understanding of how bridges operate. + +## Proposal + +This proposal attempts to address this problem by providing a single state event for each bridge in a room +to announce which channels have been bridged into a room. + +It should be noted that this MSC is intended to provide the baseline needed to display information about +a bridge, and nothing more. See the "Future MSCs" section for more information. + +This proposal is heavily based upon my previous attempt [#1410](https://github.com/matrix-org/matrix-doc/issues/1410) +albeit with a notably reduced set of features. The aim of this proposal is to offer information about the +bridged network and nothing more. + +### `m.bridge` + +```js +{ + "state_key": "org.matrix.appservice-irc://{protocol.id}/{network.id}/{channel.id}", + "type": "m.bridge", + "content": { + "bridgebot": "@appservice-irc:matrix.org", + "creator": "@alice:matrix.org", // Optional + "protocol": { + "id": "irc", + "displayname": "IRC", // Optional + "avatar_url": "mxc://foo/bar", // Optional + "external_url": "https://example.com" // Optional + }, + "network": { // Optional + "id": "freenode", + "displayname": "Freenode", // Optional + "avatar_url": "mxc://foo/bar", // Optional + "external_url": "irc://chat.freenode.net" // Optional + }, + "channel": { + "id": "#friends", + "displayname": "Friends", // Optional + "avatar_url": "mxc://foo/bar", // Optional + "external_url": "irc://chat.freenode.net/#friends" // Optional + } + }, + "sender": "@appservice-irc:matrix.org" +} +``` + +The `state_key` must be comprised of the bridge's prefix, followed by the `protocol.id`, followed by the `network.id`, +followed by the `channel.id`. Any `/`s must be escaped into `%2F`. The bridge prefix can be anything, but should uniquely +identify the bridge software. E.g. The matrix.org IRC bridge `matrix-org/matrix-appservice-irc` +becomes `org.matrix.appservice-irc`. This is to help distinguish two bridges on different softwares which may conflict. + +The `bridgebot` should be the MXID of the bridge bot. It is important to note that `sender` should not be presumed to be +the bridge bot. This is because room upgrades, other bridges or admins could also set the state in the room on behalf of +the bridge bot. + +The `creator` field is the name of the *user* which provisioned the bridge. In the case of alias based bridges, where the +creator is not known -- it should be omitted. + +The `protocol` field describes the protocol that is being bridged. For example, it may be "IRC", "Slack", or "Discord". This +field does not describe the low level protocol the bridge is using to access the network, but a common user recongnisable +name. + +The `network` field should be information about the specific network the bridge is connected to. +It's important to make the distinction here that this does *NOT* describe the protocol name, but the specific network +the user is on. For protocols that do not have the concept of a network, this field may be omitted. + +The `channel` field should be information about the specific channel the room is connected to. + +The `id` field is case-insensitive and should be lowercase. Uppercase characters should be escaped (e.g. using QP encoding +or similar).The purpose of the id field is not to be human readable but just for comparing within the same bridge type, +hence no encoding standard will be enforced in this proposal. + +The `network`, `channel` and `protocol` fields can contain `displayname` and `avatar` keys. The `displayname` is meant to +be a human readable identifier for the item in question, whereas the ID should be a unique identifer relevant to the protocol. +The `id` should be used in place of a `displayname`, if not given. The `avatar` key is a MXC URI which refers to an image +file, similar to a user or room avatar. + +The `external_url` key is a optional link to a connected channel, network or protocol that works in much the same way as +`external_url` works for bridged messages in the AS spec. + +In terms of hierachy, the protocol can contain many networks, which can contain many channels. + +### Removing a bridge + +When removing a bridge, you simply need to send a new state event with the same `state_key` with a `content` of `{}`. This +is because matrix does not yet have a mechanism to remove a state event in it's entireity. + +### Example Content + +#### XMPP + +An example of a straight forward messaging bridge, such as the XMPP (bifrost) bridge: + +```js +{ + "state_key": "org.matrix.matrix-bifrost://xmpp/muc.xmpp.org/xsf@muc.xmpp.org", + "type": "m.bridge", + "content": { + "creator": "@alice:matrix.org", + "bridgebot": "@xmpp:matrix.org", + "protocol": { + "id": "xmpp", + "displayname": "XMPP" + }, + "network": { + "id": "muc.xmpp.org", + "displayname": "XSF", + "external_url": "xmpp:muc.xmpp.org" + }, + "channel": { + "id": "xsf@muc.xmpp.org", + "displayname": "XSF Discussion", + "external_url": "xmpp:xsf@muc.xmpp.org" + } + }, + "sender": "@xmpp:matrix.org" +} +``` + +#### GitHub + +An example of a non-messaging bridge, such as the GitHub bridge: + +```js +{ + "state_key": "uk.half-shot.matrix-github://github/matrix-org%2Fmatrix-doc/2346", + "type": "m.bridge", + "content": { + "creator": "@alice:matrix.org", + "bridgebot": "@github:matrix.org", + "protocol": { + "id": "github", + "displayname": "GitHub" + }, + "network": { + "id": "matrix-org/matrix-doc", + "external_url": "https://github.com/matrix-org/matrix-doc" + }, + "channel": { + "id": "2346", + "displayname": "MSC2346: Bridge information state event", + "external_url": "https://github.com/matrix-org/matrix-doc/pull/2346" + }, + "uk.half-shot.matrix-github.merged": false, + "uk.half-shot.matrix-github.opened_by": "Half-Shot", + }, + "sender": "@github:matrix.org" +} +``` + +#### Mastodon feed + +An example of a feed oriented bridge. + +```js +{ + "state_key": "org.matrix-org.matrix-mastodon://mastodon/mastodon.matrix.org/@matrix", + "type": "m.bridge", + "content": { + "creator": "@alice:matrix.org", + "bridgebot": "@mastodon:matrix.org", + "protocol": { + "id": "mastodon", + "displayname": "Mastodon" + }, + "network": { + "id": "mastodon.matrix.org", + "external_url": "https://mastodon.matrix.org" + }, + "channel": { + "id": "@matrix", + "displayname": "Matrix.org", + "external_url": "https://mastodon.matrix.org/@matrix" + }, + "org.matrix-org.matrix-mastodon.bio": "An open standard for decentralised persistent communication. Toots by @matthew, @Amandine & co.", + "org.matrix-org.matrix-mastodon.joined": "May 2017", + }, + "sender": "@mastodon:matrix.org" +} +``` + +Note the `@` in this case helps distinguish the type of channel. Here the protocol used is "Mastodon" rather than "ActivityPub". +While the underlying protocol might indeed be ActivityPub, the choice of name should be recognisable to users. + +## Potential issues + +### We do not specify a "bridge type". + +The proposal intentionally sidesteps the 'bridge type' problem: Codifing what a portal, plumbed and gatewayed bridge look +like in Matrix. For the time being, the event will not contain information about the type of bridge in a room but merely +information about what is is connected to. + +### Anyone* can send this event into the room. + +This kinda goes for *any* event in Matrix, there is no way to determine a bridge across federation. The difference here +is that we at least require the user for the ability to send state events into the room. If you are allowed to send +arbitrary state events into the room, it's assumed you are somewhat trusted. + +## Alternatives + +Some thoughts have been thought on using the third party bridge routes in the AS api to get bridge info, +by calling a specalised endpoint. There are many issues with this, such as the routes not working presently +over federation, as well as requring the bridge to be online. Using a state event ensures the data is scoped +per room, and can be synchronised and updated over federation. + +## Future MSCs + +(This section is for the beneift of readers to understand why this MSC doesn't contain X feature) + +This proposal forms the basis for bridges to become more interactive with clients as first class citizens rather +than relying upon users having prior knowledge about which users are bridged users, or where a room is bridged to. + +Future MSCs could expand the /publicRooms response format to show what network a room is bridged to before the +user attempts to join it. Another potential MSC could allow users to see which bridges they are connected to +via an accounts settings page, rather than relying on PMs to the bridge bot. + +## Security considerations + +Anybody with the correct PLs to post state events will be able to manipulate a room by sending a bridge +event into a room, even if the bridge is not present or does not exist. It goes without saying that if +you let people modify your room state, you need to trust them not to mess around. A future MSC may allow +users to "trust" some mxids as bridges, rather than relying on just PLs to convey trustworthiness. + + +## Implementation notes + +This proposal is partially implemented by [Riot](https://github.com/vector-im/riot-web) and the +[IRC Bridge](https://github.com/matrix-org/matrix-appservice-irc) using the `uk.half-shot.*` namespace +until this becomes stable. Therefore `m.bridge` becomes `uk.half-shot.bridge`.