diff --git a/scripts/css/nature.css b/scripts/css/nature.css index 5fd4fae5e..771e40b22 100644 --- a/scripts/css/nature.css +++ b/scripts/css/nature.css @@ -285,3 +285,8 @@ div.admonition-rationale { border: 1px solid #ccc; } +div.admonition-example { + background-color: #eef; + border: 1px solid #ccc; +} + diff --git a/specification/server_server_api.rst b/specification/server_server_api.rst index 7ed7e5d60..b8eaf715e 100644 --- a/specification/server_server_api.rst +++ b/specification/server_server_api.rst @@ -570,6 +570,123 @@ transaction request to be responded to with an error response. result in the user being considered joined. +Soft failure +++++++++++++ + +.. admonition:: Rationale + + It is important that we prevent users from evading bans (or other power + restrictions) by creating events which reference old parts of the DAG. For + example, a banned user could continue to send messages to a room by having + their server send events which reference the event before they were banned. + Note that such events are entirely valid, and we cannot simply reject them, as + it is impossible to distinguish such an event from a legitimate one which has + been delayed. We must therefore accept such events and let them participate in + state resolution and the federation protocol as normal. However, servers may + choose not to send such events on to their clients, so that end users won't + actually see the events. + + When this happens it is often fairly obvious to servers, as they can see that + the new event doesn't actually pass auth based on the "current state" (i.e. + the resolved state across all forward extremities). While the event is + technically valid, the server can choose to not notify clients about the new + event. + + This discourages servers from sending events that evade bans etc. in this way, + as end users won't actually see the events. + + +When the homeserver receives a new event over federation it should also check +whether the event passes auth checks based on the current state of the room (as +well as based on the state at the event). If the event does not pass the auth +checks based on the *current state* of the room (but does pass the auth checks +based on the state at that event) it should be "soft failed". + +When an event is "soft failed" it should not be relayed to the client nor be +referenced by new events created by the homeserver (i.e. they should not be +added to the server's list of forward extremities of the room). Soft failed +events are otherwise handled as usual. + + +.. NOTE:: + + Soft failed events participate in state resolution as normal if further events + are received which reference it. It is the job of the state resolution + algorithm to ensure that malicious events cannot be injected into the room + state via this mechanism. + + +.. NOTE:: + + Because soft failed state events participate in state resolution as normal, it + is possible for such events to appear in the current state of the room. In + that case the client should be told about the soft failed event in the usual + way (e.g. by sending it down in the ``state`` section of a sync response). + + +.. NOTE:: + + A soft failed event should be returned in response to federation requests + where appropriate (e.g. in ``/event/``). Note that soft failed + events are returned in ``/backfill`` and ``/get_missing_events`` responses + only if the requests include events referencing the soft failed events. + + +.. admonition:: Example + + As an example consider the event graph:: + + A + / + B + + where ``B`` is a ban of a user ``X``. If the user ``X`` tries to set the topic + by sending an event ``C`` while evading the ban:: + + A + / \ + B C + + servers that receive ``C`` after ``B`` should soft fail event ``C``, and so + will neither relay ``C`` to its clients nor send any events referencing ``C``. + + If later another server sends an event ``D`` that references both ``B`` and + ``C`` (this can happen if it received ``C`` before ``B``):: + + A + / \ + B C + \ / + D + + then servers will handle ``D`` as normal. ``D`` is sent to the servers' + clients (assuming ``D`` passes auth checks). The state at ``D`` may resolve to + a state that includes ``C``, in which case clients should also to be told that + the state has changed to include ``C``. (*Note*: This depends on the exact + state resolution algorithm used. In the original version of the algorithm + ``C`` would be in the resolved state, whereas in latter versions the algorithm + tries to prioritise the ban over the topic change.) + + Note that this is essentially equivalent to the situation where one server + doesn't receive ``C`` at all, and so asks another server for the state of the + ``C`` branch. + + Let's go back to the graph before ``D`` was sent:: + + A + / \ + B C + + If all the servers in the room saw ``B`` before ``C`` and so soft fail ``C``, + then any new event ``D'`` will not reference ``C``:: + + A + / \ + B C + | + D + + Retrieving event authorization information ++++++++++++++++++++++++++++++++++++++++++