Kegan DougalandClaude Fable 5.1 b1228f6d9b C2: Create, join, send and leave in MSC4430 member key rooms
With `msc4430_enabled` on, the member key room version is registered and a
user can create such a room, join it, send events, change their own
membership, invite another user of this server and leave, all by user ID as
today, while every event in the room names member keys and is signed by
them. One homeserver only; members of other servers, moderation (kick, ban,
power levels), restricted joins and what clients are served back (`/sync`,
`/event`, `/members`) are outside this change.

Where a user ID becomes a key. Clients speak in user IDs, so the translation
happens once, in `EventCreationHandler.create_event`, before the event is
built: `MemberKeyHandler.translate_event_dict` replaces the `sender`, the
`state_key` of an `m.room.member` event and the `additional_creators` of a
create event with the users' member keys in the room, creating a key for a
user who has none (a key never changes, so a user who leaves and re-joins
keeps theirs). A membership event about one of our users gets our linkage
information (`content.localpart` and `content.domain`); whatever the client
put there is dropped first, since linkage information is a server's
assertion, and an erased user gets no `localpart`, so their name is not
published again. A user ID of another server, as sender, target or
additional creator, is refused (403 or 400) rather than quietly sent as a
user ID the room cannot hold, and so is a member key the client chose itself
as a target or additional creator: a key nobody vouches for would be a seat
in the room for whoever holds its private half (the membership servlets
still parse user IDs, so a key as a target is refused there too). A room
with a remote invitee is refused before anything is created, not by the
invite after the room exists, and a room cannot be upgraded into this
version (the clone names user IDs in power levels, bans and invites). The
handler is also where the rest of the server asks what an identity means:
`local_user_id_for_identity` (ours, by user ID or by a key we hold in that
room), `user_id_for_identity` (also the verified link of another server's
key), `domain_for_identity` (routing only: our name for our keys, the
claimed domain of a linked key) and `room_identity_for_user` (how to look a
user of ours up in a room's state: their key where they have one, their user
ID otherwise, which the state then does not contain, as it should not).
Three other places compared the sender with a user ID and now resolve it: a
suspended user redacting their own event, the admin-redaction rate limit,
and room participation.

The create event. In these room versions the room ID is derived from the
create event, and the create event names and is signed by the creator's key,
so the key has to exist before the room ID does. `translate_event_dict`
generates such keys as "pending" (an expiring in-memory cache), they sign the
create event from there, and once the event is built `create_event` stores
them under the new room ID; if building fails they are dropped at once. A
pending key is ours only for the create event itself (no room yet): in any
existing room it is nobody's, so a key minted for one room cannot act in
another while it waits. A user named twice by one create event (as creator
and additional creator) gets one key; a create event sent into an existing
room is refused before any key is made; and the room ID collision retry
starts each attempt from the content the client sent, not the translated
one. Room creation then looks the creator's membership up by their key in
the state map it batches the rest of the initial state against, and refuses
the version when the flag is off even though the registry (process wide) may
know it, which is also why the tests can run flag-off cases.
`default_room_version` cannot name this version: the server config validates
it before the experimental config registers it, so rooms are created with an
explicit `room_version`.

Signatures. `EventBuilder.build` asks `MemberKeyHandler.get_signers_for_event_dict`
who signs and `create_local_event_from_event_dict` signs with exactly those:
the sender's member key under the entity `sender`, if we hold it; our server
signing key on an `m.room.member` event whose target is a key we hold and
whose linkage information is exactly what we vouch for about that user (our
domain, their localpart unless they are erased, in which case none), which
is what lets other servers verify the member's link; and the authorising
member's key on a restricted join that names one of ours. An event whose
sender is not a key we hold gets no signature at all (it is only hashed), so
the server never signs as a key it does not own; the co-signature is decided
from the store, never from the dict, so no caller can have us vouch for a
name that is not the user's; and the signing helper refuses any signer the
event may not carry, so a wrong choice here could not produce one either. A
third-party rules module that replaces an event is as untrusted as a client:
its dict is translated again, and it may not change who authorised a join.
The builder's validation accepts canonical member keys as sender and
membership target in these rooms, and nothing else.

Membership handling. `update_membership_locked` looks the target and the
requester up in the room's state under their room identity (their key once
they have one), so re-joins, duplicate events and the ban checks see the
right membership; the previous membership of a new event is read under the
event's own state key; whether this server is in the room is answered from
the members that map to our users rather than by domain; a pending invite is
read by user ID (that table is keyed by user) and the inviter's server is
found through `domain_for_identity`, so a join via a remote inviter would
still route; the join notification maps the joining key to its user; and an
invite in such a room is refused with 400 unless the invitee is a key we
hold.

Hosts in a room. Registering the version makes the "which servers are in
this room" paths reachable for the first time, and they are what the
federation sender consults for every event. They took the domain of every
member; a member key has none, and on Postgres the SQL that extracts domains
from state keys returned a `None` host for such a room.
`get_hosts_for_identities` on the member keys store now gives the server
behind each identity (a user ID's domain, our own name for keys we hold, the
claimed domain of a key we have a link for, nothing for the rest), and
`_get_joined_hosts`, `get_current_hosts_in_room` and
`get_current_hosts_in_room_ordered` use it for member key rooms (the ordered
form is unordered there: nothing in the state keys to sort by). The sender
itself decided whether an event was ours by the sender's domain, which for a
key said "not ours" and dropped every event of such a room before reaching
any of this; it now asks the identity map, and finds the server of a
rescinded invite's target the same way rather than by parsing the key, which
would have raised outside the guard that protects the sending loop. A member
key room holds only our own members, so its hosts are this server and
nothing is sent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-15 09:22:39 +02:00
2026-09-29 11:15:31 -05:00
2026-09-18 12:00:45 +01:00
2026-09-29 11:15:31 -05:00
2024-11-20 15:01:56 +00:00
2023-12-13 16:15:22 +00:00
2023-12-13 16:15:22 +00:00

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
.. image:: https://github.com/element-hq/synapse/raw/develop/docs/element_logo_white_bg.svg
   :height: 60px

**Element Synapse - Matrix homeserver implementation**

|support| |development| |documentation| |license| |pypi| |python|

Synapse is an open source `Matrix <https://matrix.org>`__ homeserver
implementation, written and maintained by `Element <https://element.io>`_.
`Matrix <https://github.com/matrix-org>`__ is the open standard for secure and
interoperable real-time communications. You can directly run and manage the
source code in this repository, available under an AGPL license (or
alternatively under a commercial license from Element).

There is no support provided by Element unless you have a subscription from
Element.

🚀 Getting started
==================

This component is developed and maintained by `Element <https://element.io>`_.
It gets shipped as part of the **Element Server Suite (ESS)** which provides the
official means of deployment.

ESS is a Matrix distribution from Element with focus on quality and ease of use.
It ships a full Matrix stack tailored to the respective use case.

There are three editions of ESS:

- `ESS Community <https://github.com/element-hq/ess-helm>`_ - the free Matrix
  distribution from Element tailored to small-/mid-scale, non-commercial
  community use cases
- `ESS Pro <https://element.io/server-suite>`_ - the commercial Matrix
  distribution from Element for professional use
- `ESS TI-M <https://element.io/server-suite/ti-messenger>`_ - a special version
  of ESS Pro focused on the requirements of TI-Messenger Pro and ePA as
  specified by the German National Digital Health Agency Gematik


🛠️ Standalone installation and configuration
============================================

The Synapse documentation describes `options for installing Synapse standalone
<https://element-hq.github.io/synapse/latest/setup/installation.html>`_. See
below for more useful documentation links.

- `Synapse configuration options <https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html>`_
- `Synapse configuration for federation <https://element-hq.github.io/synapse/latest/federate.html>`_
- `Using a reverse proxy with Synapse <https://element-hq.github.io/synapse/latest/reverse_proxy.html>`_
- `Upgrading Synapse <https://element-hq.github.io/synapse/develop/upgrade.html>`_


🎯 Troubleshooting and support
==============================

🚀 Professional support
-----------------------

Enterprise quality support for Synapse including SLAs is available as part of an
`Element Server Suite (ESS) <https://element.io/pricing>`_ subscription.

If you are an existing ESS subscriber then you can raise a `support request <https://customer.element.io/support>`_
and access the `Element product documentation <https://docs.element.io>`_.

🤝 Community support
--------------------

The `Admin FAQ <https://element-hq.github.io/synapse/latest/usage/administration/admin_faq.html>`_
includes tips on dealing with some common problems. For more details, see
`Synapse's wider documentation <https://element-hq.github.io/synapse/latest/>`_.

For additional support installing or managing Synapse, please ask in the community
support room |room|_ (from a matrix.org account if necessary). We do not use GitHub
issues for support requests, only for bug reports and feature requests.

.. |room| replace:: ``#synapse:matrix.org``
.. _room: https://matrix.to/#/#synapse:matrix.org

.. |docs| replace:: ``docs``
.. _docs: docs


🛠️ Development
==============

We welcome contributions to Synapse from the community!
The best place to get started is our
`guide for contributors <https://element-hq.github.io/synapse/latest/development/contributing_guide.html>`_.
This is part of our broader `documentation <https://element-hq.github.io/synapse/latest>`_, which includes
information for Synapse developers as well as Synapse administrators.

Developers might be particularly interested in:

* `Synapse's database schema <https://element-hq.github.io/synapse/latest/development/database_schema.html>`_,
* `notes on Synapse's implementation details <https://element-hq.github.io/synapse/latest/development/internal_documentation/index.html>`_, and
* `how we use git <https://element-hq.github.io/synapse/latest/development/git.html>`_.

Alongside all that, join our developer community on Matrix:
`#synapse-dev:matrix.org <https://matrix.to/#/#synapse-dev:matrix.org>`_, featuring real humans!

Copyright and Licensing
=======================

  | Copyright 2014–2017 OpenMarket Ltd
  | Copyright 2017 Vector Creations Ltd
  | Copyright 2017–2025 New Vector Ltd
  | Copyright 2025 Element Creations Ltd

This software is dual-licensed by Element Creations Ltd (Element). It can be
used either:

(1) for free under the terms of the GNU Affero General Public License (as
    published by the Free Software Foundation, either version 3 of the License,
    or (at your option) any later version); OR

(2) under the terms of a paid-for Element Commercial License agreement between
    you and Element (the terms of which may vary depending on what you and
    Element have agreed to).

Unless required by applicable law or agreed to in writing, software distributed
under the Licenses is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the Licenses for the
specific language governing permissions and limitations under the Licenses.

Please contact `licensing@element.io <mailto:licensing@element.io>`_ to purchase
an Element commercial license for this software.


.. |support| image:: https://img.shields.io/badge/matrix-community%20support-success
  :alt: (get community support in #synapse:matrix.org)
  :target: https://matrix.to/#/#synapse:matrix.org

.. |development| image:: https://img.shields.io/matrix/synapse-dev:matrix.org?label=development&logo=matrix
  :alt: (discuss development on #synapse-dev:matrix.org)
  :target: https://matrix.to/#/#synapse-dev:matrix.org

.. |documentation| image:: https://img.shields.io/badge/documentation-%E2%9C%93-success
  :alt: (Rendered documentation on GitHub Pages)
  :target: https://element-hq.github.io/synapse/latest/

.. |license| image:: https://img.shields.io/github/license/element-hq/synapse
  :alt: (check license in LICENSE file)
  :target: LICENSE

.. |pypi| image:: https://img.shields.io/pypi/v/matrix-synapse
  :alt: (latest version released on PyPi)
  :target: https://pypi.org/project/matrix-synapse

.. |python| image:: https://img.shields.io/pypi/pyversions/matrix-synapse
  :alt: (supported python versions)
  :target: https://pypi.org/project/matrix-synapse
S
Description
No description provided
Readme
640 MiB
0 Stars 1 Watchers 0 Forks
Languages
Python 95.2%
Rust 3.5%
HTML 0.4%
Shell 0.3%
Go 0.2%
Other 0.1%