mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-12 01:17:40 +00:00
In a room whose members are MSC4430 member keys, the `sender` of every event and the `state_key` of every membership event is a per-room Ed25519 key, and the event is signed by that key rather than by the sender's server. This change teaches the two places every received event must pass, signature verification and the auth rules, to work on keys. The member key room version is not registered, so none of it is reachable; it is the acceptance boundary every server has to agree on, so it depends on nothing but the event. Signatures (`_check_sigs_on_pdu`): in a member key room the event must carry a valid signature under the entity `sender` by the key decoded from its `sender`, with key ID `ed25519:1`, over the redacted event as for server signatures; a restricted join must additionally carry a valid signature by the member key named in `join_authorised_via_users_server`, under that member key string. No server signature is required and no key is fetched, so every server reaches the same verdict. The sender and the authoriser are parsed strictly: a non-canonical base64 encoding of a key is not that key (otherwise one public key would have two identities), and a user ID is rejected. A server co-signature on a membership event's linkage information is not checked here, on purpose: the MSC makes it decide whether the member's link is verified, not whether the event is accepted, and some membership events legitimately carry no linkage information at all. Hash checking, redaction on a hash mismatch, the policy server and the spam checker are unchanged. Auth rules (`event_auth`): `validate_event_for_room_version` checks that the sender is a canonical member key and has signed the event, that a membership event's `state_key` is a canonical member key, and that a restricted join names a canonical member key as authoriser and carries its signature. The `m.federate` domain comparison is skipped in member key rooms, in both the general and the membership rule: keys have no domain, so it cannot be evaluated, and in such rooms `m.federate: false` means no federation at all. Power level `users` and `additional_creators` must be member keys; `check_valid_additional_creators` therefore takes the room version, and the room upgrade servlet passes the new one. Third-party invites need no rule change: the rule compares `signed.mxid` with the `state_key` and verifies `signed` with the key published in the inviter's `m.room.third_party_invite` event, so an identity server that signs the member key produces an acceptable invite; how it learns the key is unspecified. Everything else in the rules already works on opaque identities: membership lookups, power levels, creator power and the restricted-join authoriser are all compared as strings. A membership event with no `membership` in its content is handled without raising on both new paths (the legacy paths have the same latent `KeyError`). Redactions: in room versions since v3 a redaction by a sender without redact power is applied only if both senders are from the same server, a check deferred until the redacted event is known and made in three places (the event cache, the read path, and persistence of an existing redaction). Those three now share `redaction_sender_matches`, which keeps the server comparison for every other room version and, in member key rooms where senders have no server, applies only when the two senders are the very same key. That is stricter than before (a server's other users can no longer redact a member's events without power), and the only rule that needs no network. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>