matrix-doc/proposals/3192-batch-state.md

6.5 KiB

MSC3192: Batch state endpoint

It is desired to potentially dump a bunch of state into a room in one go. This is useful to:

  • Kick (or ban) many users at once.
  • Invite many users at once.
  • Add many rooms to a MSC1772 Space.
  • Bulk-insert MSC2313-style reputation data.

Proposal

A new endpoint is added to send multiple state events to a room in a single request.

This endpoint is authenticated and rate-limited.

PUT /_matrix/client/r0/rooms/{roomId}/batch_state/{txnId}

Example request:

[
  {
      "event_type": "m.room.membership",
      "state_key": "@alice:example.com",
      "content": {
          "membership": "join",
          "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF",
          "displayname": "Alice Margatroid"
      }
  }
]

Example response:

[
  "$YUwRidLecu:example.com"
]

This API extends the current ways to push state into a room by allowing for multiple events for differing state keys to be created with a single API call.

Path parameters:

  • room_id: Required. The room to set the state in
  • txnId: Required. The transaction ID for this state update. Clients should generate an ID unique across requests with the same access token; it will be used by the server to ensure idempotency of requests.

The body of the request should be an ordered array of objects with the following keys:

  • event_type: Required. A string. The type of event to send.
  • state_key: A string. The state_key for the state to send. Defaults to the empty string.
  • content: Required. The content object of the event; the fields in this object will vary depending on the type of event. See Room Events for the m. event specification.

At most 50 events can be included in the request body.1

The body of the response will contain an array of the created event IDs. If an event cannot be created then null will be returned in its place.

Error responses:

  • Status code 400: No events were successfully sent.
  • Status code 403: The sender doesn't have permission to send the event(s) into the room.

This also updates the previous definition to note that PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey} should be rate-limited.

Potential issues

Handling a partial batch of state updates could lead to unexpected behavior, but should not be worse than the current situation (where each state event must be sent individually).

Alternatives

Request body

A request body consisting of nested objects with event types and state keys as the keys pointed to their content was considered, but it seemed not in the style of other Matrix APIs. This alternative would look something like:

{
    "m.room.member": {
        "@alice:example.com": {
            "membership": "join",
            "avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF",
            "displayname": "Alice Margatroid"
        }
    }
}

Atomic requests

Handling the request atomically and returning an error if any of the state events cannot be created for some reason could be nicer. (See a similar discussion involving the federation API: /_matrix/federation/v1/send/{txnId}.)

Batch inserting state and messages

The MSC2716: Incrementally importing history into existing rooms has need to insert both state and messages at the same time. This is used to insert messages plus their auth state at the same time.

It is possible this API could be expanded to cover that use-case, but given the current specialization needed to handle MSC2716 there does not exist an example use-case for handling both state and messages at the same time.

Security considerations

The main risk of this endpoint is a denial of service attack (against a server directly or an amplification attack by using a server to spam over federation).

An example scenario would be:

  • An unprivileged user creates a public chatroom; has PL 100
  • Persuades loads of people into it (e.g. via spam or invite-spam, which should have other mitigations in place)
  • Starts looping creating m.space.* (or any other state) events en bulk
  • Causes loads of PDUs to be pushed over federation, as well as loads of state resolution due to the rapidly churning state of the room.

This is no more amplification than any other federation traffic, but it makes it easier for a single unsophisticated user to create a large amount of federation traffic, getting their local homeserver into trouble, without them having to run a malicious homeserver themselves.

However, other than consuming resources, there's no particular benefit in doing so, and there are other similar attacks (e.g. uploading lots of large files into a room and encouraging folks to click on them; or joining many large rooms in quick succession).

Note that, by default, you already have to be a room admin to set arbitrary state events in the first place, so the only risk here is of room admins going rogue. You could argue this is just one of many ways an admin could go rogue, and would need to be dealt with by the server admin on the server where they reside (by deactivation or puppetting them to self-demote).

The benefits of this API outweigh the risks. Server admins can always put some monitoring alerts in place to check if they have rogue admins who are bulk-spamming rooms with state events - and freeze users who do so. It is also recommended to have a low rate-limit on this endpoint.

There are some measures in the API design which attempt to mitigate some of the risk.

Limiting each call to a single event type and ensuring that each event type / state key pair only appears a single time should reduce state resolution churn to a degree.

Limiting the number of state events in a single API call to match what can be done by an abusive sever over federation should offer a level of security as well.

Unstable prefix

During development of this feature it will be available at an unstable endpoint:

/_matrix/client/unstable/org.matrix.mscxxxx/rooms/{roomId}/batch_state/{txnId}

Footnotes

[1]: This matches the maximum of 50 PDUs that can be in a federation transaction.