|
| 1 | +# MSC3442: move the `prev_content` key to `unsigned` |
| 2 | + |
| 3 | +Background: the Client-Server API specification |
| 4 | +[documents](https://matrix.org/docs/spec/client_server/r0.6.1#state-event-fields) |
| 5 | +a `prev_content` property to be included on state events. It gives the |
| 6 | +`content` of the previous state event with the same `type` and `state_key`. |
| 7 | + |
| 8 | +This property does not form part of the "raw" event as sent to federating |
| 9 | +homeservers via the Server-Server API; it is added to events served over the |
| 10 | +Client-Server API as a service to those clients. |
| 11 | + |
| 12 | +Adding properties at the top level of the event in this way is confusing: it |
| 13 | +makes it difficult to understand which properties are part of the raw event, |
| 14 | +and which added retrospectively. |
| 15 | + |
| 16 | +It is also inconsistent with other properties which are added by the local |
| 17 | +homeserver such as `age`, `redacted_because` and `transaction_id`, which are |
| 18 | +returned under `unsigned`: see https://matrix.org/docs/spec/client_server/r0.6.1#room-event-fields. |
| 19 | + |
| 20 | +## Further background information |
| 21 | + |
| 22 | +1. The specification for the [`GET |
| 23 | + /_matrix/client/r0/notifications`](https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-notifications) |
| 24 | + API is unusual in that it requires `prev_content` to be returned under |
| 25 | + `unsigned`. |
| 26 | + |
| 27 | +2. In general, in addition to returning `prev_content` at the top level as |
| 28 | + specified, Synapse *also* returns it under `unsigned`, as proposed here. |
| 29 | + |
| 30 | + The exceptions to this are `GET /notifications` and `GET /sync`, where |
| 31 | + Synapse returns `prev_content` *only* under `unsigned`. As noted above, this |
| 32 | + is compliant with the spec for `/notifications`, but appears to be a spec |
| 33 | + violation for `/sync`. |
| 34 | + |
| 35 | +3. Dendrite returns `prev_content` *only* under `unsigned` (and is therefore |
| 36 | + theoretically in violation of the spec). |
| 37 | + |
| 38 | +## Proposal |
| 39 | + |
| 40 | +It is proposed that the specification be updated to move the `prev_content` |
| 41 | +property to the `unsigned` object, bringing it in line with `age`, |
| 42 | +`redacted_because` and `transaction_id`. |
| 43 | + |
| 44 | +This will affect: |
| 45 | + * Events returned by the Client-Server API. |
| 46 | + * Events sent to Application Services by the Application Services API. |
| 47 | + |
| 48 | +## Potential issues |
| 49 | + |
| 50 | +The proposed change may break compatibility with existing clients and |
| 51 | +Application Services. |
| 52 | + |
| 53 | +In practice, any client supporting Dendrite or `/sync` requests via Synapse |
| 54 | +must already support the new location, so this is not a breaking change for |
| 55 | +such clients. There may be Application Services which rely on `prev_content` at |
| 56 | +the top level; however these can be safely updated to use the new location, |
| 57 | +since Synapse populates both locations. |
| 58 | + |
| 59 | +The problem can be further mitigated by homeservers populating the key at |
| 60 | +*both* locations for as long as they support older versions of the |
| 61 | +specification, as Synapse does today. |
| 62 | + |
| 63 | +## Alternatives |
| 64 | + |
| 65 | +1. We could double-down on the existing situation and require that |
| 66 | + `prev_content` always be populated at the top level (possibly including |
| 67 | + `/notifications`). That is unattractive for the reasons set out in the |
| 68 | + introduction to this proposal. Furthermore, in practice it will introduce |
| 69 | + *more* compatibility problems, due to the implementations which currently do |
| 70 | + not comply with the spec. |
| 71 | + |
| 72 | +2. We could require that homeservers populate the property at *both* |
| 73 | + locations. However, setting aside the added complexity for homeserver |
| 74 | + implementations, it also increases the chances of a situation as follows: |
| 75 | + |
| 76 | + * Some clients use one property, some use another. |
| 77 | + * A homeserver developer tests against a subset of clients, all of which use |
| 78 | + one property. |
| 79 | + * In consequence, some clients are incompatible with some homeservers. |
| 80 | + |
| 81 | +## Security considerations |
| 82 | + |
| 83 | +When an event is sent over federation, the sending homeserver can freely add |
| 84 | +properties to the `unsigned` object, without them being covered by the |
| 85 | +hashes or signatures. Some homeserver implementations (including Synapse) |
| 86 | +will then pass any such properties on to clients and application services. |
| 87 | + |
| 88 | +In principle then, a malicious or buggy homeserver implementation could add an |
| 89 | +incorrect `prev_content` property under `unsigned`, and send it over |
| 90 | +federation. A receiving homeserver, implementing the *current* specification, |
| 91 | +might pass that property straight through to a client, and the receiving client |
| 92 | +would be unable to tell that it was actually incorrectly populated by the |
| 93 | +remote homeserver. |
| 94 | + |
| 95 | +This is a more general problem that exists today, and which requires a more |
| 96 | +general solution to `unsigned` objects - see |
| 97 | +https://github.com/matrix-org/synapse/issues/11080. This proposal does not |
| 98 | +materially affect the problem. |
| 99 | + |
| 100 | +## Unstable prefix |
| 101 | + |
| 102 | +No unstable prefix is required, since the behaviour proposed is already |
| 103 | +implemented by both Synapse and Dendrite. |
0 commit comments