matrix-doc/proposals/2214-join-upgraded-private-...

6.8 KiB

Joining upgraded private rooms

Although most rooms which require an upgrade will be public, there are already cases where private (invite-only) rooms are upgraded. There is also the lingering possibility of a bug being found in the various algorithms which run a room that require private rooms to be upgraded as well.

Currently when a room is upgraded all members need to rejoin manually. This is fine for public rooms because the users can click a button and it takes them over to the new room to join. For private rooms however, the members of the old room need to be manually invited.

This limitation in upgrades has caused some grief for those who have tried to upgrade private rooms already. While migrating membership transparently (auto-joining) would be ideal, this proposal is meant to fill the gap for private rooms while the harder problem of migrating membership is thought out more thoroughly. This proposal does not aim to solve transparent migration of membership.

This proposal is also an idea for how to solve this based largely on the author's work on MSC2213. It could be completely flawed.

Proposal

In a future room version, a new state event is introduced to track the previous membership events for a given room. This new state event acts like a "soft invite" where a user can be allowed into the room without getting hit with an explicit invite.

The new state event, m.room.previous_member, mirrors the existing m.room.member event. The state_key is the affected user and the content has the same definition as the m.room.member event.

When a room is upgraded to a version which supports this proposal, the server is expected to clone the state_key and content of the old room's m.room.member events into m.room.previous_member events. The sender of the old m.room.member event is specified as previous_sender under content, overwriting the key if it was present in the m.room.member event's content. Servers can skip membership events which won't result in the user being able to join the new room, such as kicks, bans, and plain leaves. It is instead recommended that the server copy bans over to the new room as regular m.room.member events.

m.room.previous_member carries its own set of auth rules for acceptance:

  1. If there is no state_key key, no membership in content, or no previous_sender in content, reject.
  2. If membership is not a valid m.room.member membership, reject.
  3. If the sender is not the room creator, reject.
  4. If the sender does not have permission to invite users, reject. This includes the room creator no longer being a member of the room themselves.
  5. If the sender and the state_key are the same, reject.

third_party_event in the content of m.room.previous_member is not validated and serves only audit purposes.

The redaction rules for m.room.member are copied for m.room.previous_member, with the addition of preserving previous_sender in content. Although the previous_sender does not serve a protocol purpose, it is metadata important for the audit trail of the room.

Servers for these previous membership events are not expected to receive them over federation until they actually join the room.

m.room.previous_member is only used in the auth rules when a user is attempting to join the room. For all other scenarios (such as sending messages), the auth rules must continue to look for an appropriate m.room.member event. The rules for handling joins in the new room are as follows:

  1. If the user has an m.room.member state event in the room, use that instead of the m.room.previous_member event. Stop processing these new rules and use the rules for handling a join with a m.room.member event instead.
  2. If the m.room.create event does not have a predecessor in its content, reject.
  3. If the m.room.previous_member membership is invite, process the join as though the user was invited (allow a m.room.member with membership of join).
  4. If the m.room.previous_member membership is join, process the join as though the user was already joined (allow a m.room.member event to take its place).
  5. If the m.room.previous_member membership is ban, process the join as though the user was banned (reject).
  6. If the m.room.previous_member membership is leave, process the join as though the user has left the room (for example, reject if the room is invite-only).

m.room.member events use their own auth rules even when they replace a m.room.previous_member event. For example, a user cannot introduce an m.room.member event with membership of ban unless the user has permission to ban users, even if the m.room.previous_member event had a membership of ban as well.

Security considerations

This effectively gives the room creator the power to invite users until the end of time. However, this is no different than any other user's ability to invite members to a room in the vast majority of rooms today. The only difference is that the room creator is able to lie about the previous membership of a user with no verification that it is accurate.

Clients should be skeptical of m.room.previous_member events and largely treat them as invites.

Servers could additionally forget (intentionally or otherwise) to include valid members. This is treated similar to the semantics of not inviting someone to your private room, and should have the same social consequences (forever being disappointed in the person who didn't invite you to the party).

Alternative solutions / known problems

There's many solutions to this kind of problem. For example, we could change the auth rules to allow a room creator to set membership of join on m.room.member events without the target user being involved. This results in very complicated auth rules however, as it would be possible for any room creator to craft a room which automatically joins users without them having been in a relevant previous room. This would be bad.

This solution is not meant to be the silver bullet to the problem of automatically transferring membership to the new room. It is just meant to alleviate a pain point in upgrades while a better solution can be created.

Another problem with this proposal is that users are not told they are invited to this new room. This is a designed feature of this proposal to prevent unnecessary notifications to target users (they already get one that a room was upgraded, so another that they are invited to a room would be confusing). Servers can of course ignore this proposal and just spam invites if they wanted to.

To further clarify: because these events are treated very similar to invites, it is possible to "kick" or ban a user from a room to prevent them from joining. This proposal does not revoke an admin/moderator's ability to stop someone from joining/accepting their invite.