4293 Commits
Author SHA1 Message Date
e5ac865661 Fix largest rooms Admin API failing when pg_stats has no common room IDs (#20390)
Fixes #19561

`GET /_synapse/admin/v1/statistics/database/rooms` returns a 500 when
`pg_stats` has no common `room_id` values for one of the tables it
checks. This happens in two cases:

- The table is empty or not yet analyzed, so `pg_stats` has no row for
it.
- No value is more common than the others, so `most_common_vals` is
`NULL`. `event_edges.room_id` hits this on servers where all rows were
written after schema 72 stopped filling the column.

The change skips the table in both cases, since it adds nothing to the
estimate.

Thanks to @christianarielli for finding the cause and suggesting the
fix. They're credited as co-author on the commit.

The new test runs only on Postgres, as the endpoint doesn't support
SQLite. It creates a room, runs `ANALYZE` while `event_push_actions` is
empty and `event_edges.room_id` is all `NULL`, and checks for a 200 with
the room listed. I ran it against Postgres 17.

`event_edges.room_id` isn't written any more, so dropping that table
from the list might make sense. I left that out to keep this PR small.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Christian Arielli <903609+christianarielli@users.noreply.github.com>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-11-13 13:57:50 +01:00
Erik Johnston 323a619544 Make trial unit tests use less memory (#20513)
This is something that came up during the Rust spike, where running lots
of unit tests in parallel used lots of memory.

This is primarily due to a) `HomeServer` object having circular
references during tests, and b) us not doing full GC all the time.

The fix is to ensure that we drop references to the `HomeServer` at the
end of each test (or only keep weakrefs around), so that the GC-0
collection we run at the end of each test correctly cleans it up.

Requires https://github.com/element-hq/synapse/pull/20512 to fully clean
everything up.
2026-11-13 10:09:38 +00:00
Erik Johnston 3bbbbf5d04 Run homeserver shutdown handlers at the end of each test (#20509)
This fixes the test `ThreadedMemoryReactorClock` to support
`removeSystemEventTrigger`, which in turn allows the shutdown triggers
to run when `HomeServer.shutdown()` is called in the tests. Previously,
`ThreadedMemoryReactorClock.removeSystemEventTrigger` raised a
`NotImplementedError`,

`cleanup_test_reactor_system_event_triggers` cleared the triggers by
hand so that a homeserver could be garbage collected. `shutdown()` now
removes them itself, so the helper goes.

We can also remove all the `tearDown` implementations that tried to
manually trigger the shutdown as its not longer necessary to do so
manually. They also didn't work, as they indexed `reactor.triggers` as
`[eventType][phase]` when the keys are `[phase][eventType]`
2026-11-13 10:09:16 +00:00
Kegan Dougal ce98985f9f Add check_room_id to more store functions which get events (#20436)
Use it when retrieving missing events in state DAG mode.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))
2026-11-11 08:19:03 +00:00
Ankit Jha 0744b28c6a Fix federated media downloads failing when a multipart response is split across chunks (#20282)
Fixes #20035

`_MultipartParserProtocol` assigned each `on_header_field` /
`on_header_value` / `on_part_data` value instead of accumulating it.
python-multipart calls these once per `dataReceived` chunk, so any
header name, header value or JSON part split across two chunks kept only
its last piece. A long `Location` in a federated media redirect was the
visible case: the truncated URL had no host and `get_file` failed with
`TypeError`.

The protocol now buffers header names, header values and the JSON part
in `bytearray`s and acts on them in `on_header_end` / `on_part_end`,
with a part counter replacing the `in_json` / `json_done` / `in_*`
flags. The file part still streams straight to the output stream, and
the existing `max_length` check still bounds everything that gets
buffered.

The new tests parse a file response and a redirect response split at
every byte offset, and byte by byte, and check the result matches the
unsplit parse. Before the fix, 100 and 115 split offsets respectively
produced a wrong result.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Signed-off-by: Ankit Jha <ankit.jha@tradomate.one>
Signed-off-by: Ankit Jha <jhaankit373@gmail.com>
2026-11-10 16:42:13 +00:00
Ayesha Waseem 9d8354419c Report a user in device_lists.changed when they join after being invited (#20487)
`DeviceHandler.get_user_ids_changed`, which the sliding sync e2ee
extension and `GET /keys/changes` use, adds a member to
`newly_joined_or_invited_or_knocked_users` only when the previous
membership was none of join, invite or knock. A user going from invite
to join is skipped, so other members are never told to refresh the
devices of a user whose device list changed while they were only
invited. Classic sync does report them.

A change to join from any membership other than join is now counted.
join -> join (a profile change) is still ignored.
`test_extension_e2ee.py` covers invite -> join, invite -> join -> leave
in one window and a profile change, `test_keys.py` covers invite -> join
through `/keys/changes`. Not covered: device list changes made while a
user is only invited (#3504), which are still not announced until the
user joins.

Fixes #20486
2026-11-10 14:11:31 +00:00
Erik Johnston 4e43a3f710 Fix sync lazy-loaded membership cache to correctly handle concurrent requests (#20435)
Follows on from #20289 and #20433. Properly fixes handling of concurrent
requests (on single workers).

This tries to fix two cases:
1. We are *computing* responses for multiple syncs at the same time,
which currently causes the cache to get cross-contaminated.
2. Two syncs concurrent syncs on the wire (but don't overlap during
processing). When the second request is processed we correctly forget
any entries from the first request, however we currently still update
the cache with members returned on the second request. However, there is
no guarantee that the second request is what the client actually reads.

We use three rules to handle concurrent requests:
1. A response only uses cached members recorded at or before the
request's `since`. Members recorded after it cannot be from an ancestor
sync response.
2. Once a response has been built, we forget all already cached members
recorded after its `since`. This handles the client reusing an older
`since` token. Doing it at the end of the build rather than the start
also forgets members recorded by responses built at the same time.
3. We track the highest position seen for the device (`_newest`), from
the `since` of each request and the `next_batch` of each built response.
A response only records its members if its `next_batch` is after that
position. This handles responses that end at the same position, or that
finish out of order.

With these rules, when concurrent requests happen we throw away all
existing cached members and don't record any further members until one
sync has advanced sufficiently such that there are no longer any
concurrent sync requests.


Note that ideally we'd have some sort of per-connection identity so that
we can track this properly (like in sliding sync). However, that is a
bigger change. Instead, we note that we just need to detect concurrent
requests, and not update the cache in those cases.

Also note, can only detect concurrent requests that go to the same
worker.
2026-11-10 13:15:03 +00:00
Junker der Provinz 217e4c0f48 Fix RemoteHandler no longer sending logs after connecting (#20389)
Fixes #17480

Once `RemoteHandler` is connected, `whenConnected` returns a Deferred
that has already fired, so `writer` runs synchronously inside
`addCallbacks` and clears `_connection_waiter`. The next line then set
the waiter to that fired Deferred, so every later `_connect` call
returned early and logs stopped after the first line or two.

This sets the waiter before adding the callbacks, so a callback that
runs right away can still clear it. The new test logs a few more lines
over an existing connection and checks that they all arrive.

The bug came in with #9591, hence v1.30.0 in the changelog.

Thanks to @haarp for tracking this down and for the detailed
reproduction steps.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))
2026-11-09 18:43:57 +00:00
Quentin Gliech a7a665047e Rebuild the server TLS context in place on certificate reload (#20491)
`refresh_certificate` used to build a new `ServerContextFactory` on
every SIGHUP and then replace the factory on each listening port with a
fresh `TLSMemoryBIOFactory` wrapping the new one, reaching into the
port's `factory` attribute to do so.

Twisted asks the context factory for a context on every new connection,
so rebuilding the `SSL.Context` inside the existing factory is enough
for new connections to pick up the new certificate. `start()` now builds
the factory once, and `refresh_certificate` is only the SIGHUP handler.

This is spawning of #20452: Twisted 26.10 annotates `tcp.Port.factory`
as `Factory | None`, and mypy does not accept a `TLSMemoryBIOFactory`
there because its protocol type parameter does not match, so the old
assignment no longer type-checks. The change removes the assignment
rather than suppressing the error.

Verified with trial against Twisted 23.8.0 (our minimum declared dep),
26.4.0 (the current version in the lockfile) and 26.10.0 (the next
version), and with mypy against 26.4.0 and 26.10.0.
2026-11-09 18:37:09 +01:00
Ayesha Waseem 4a8532b259 Fix logging breaking after a SIGHUP reload when stdio is redirected to the logs (#20402)
Reloading the log config on SIGHUP writes every record back into
Twisted's logging. `redirect_stdio_to_logs()` replaces `sys.stderr` with
a `LoggingFile` after startup, and `_load_logging_config` then rebuilds
`StreamHandler`s on it, so records hit the `logging during logging`
guard in `one_time_logging_setup` and JSON lines get wrapped a second
time.

`dictConfig` now runs with `sys.__stdout__` and `sys.__stderr__` swapped
in, and the redirected streams are put back afterwards, including when
the config is invalid. `tests/config/test_logger.py` covers both. Not
covered: Windows and configs that use a `FileHandler`.

Fixes #20091

### Pull Request Checklist

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (ruff check, ruff format and mypy run on the changed files)
2026-11-09 11:31:56 +00:00
Erik Johnston 20d925bb33 Add a metric for CPU time per thread type (#20405)
Adds a `synapse_thread_cpu_seconds_total{thread_type, mode}` metric,
grouping threads into:
1. the `main` thread
2. each registered threadpool (`threadpool_*`)
3. `tokio`
4. `other`

The kernel only reports CPU time for live threads, so the collector sums
per-thread deltas between scrapes. A thread that exits loses the CPU it
used since the last scrape.

This is primarily useful for seeing how busy the main thread is vs other
ones.
2026-11-09 10:30:04 +00:00
Matt Van HornandMatt Van Horn 4787b424e9 Accept notary queries without minimum validity timestamps (#20477)
### Pull Request Checklist

A notary key query that leaves out minimum_valid_until_ts is rejected
with errcode M_MISSING_PARAM and an error naming that field as required.
Callers that follow the server-server API, where the timestamp is
optional and the server is supposed to use the current time, cannot
complete the query. The criteria model typed minimum_valid_until_ts as
an integer or null but gave it no default, so validation treated the
field as required and failed before the query ran.

An explicit null was already a separate accepted value, used for
half-lifetime cache behaviour, and was not the same as omitting the
field.

The field now defaults to null, so an omitted timestamp validates. After
parsing, each key whose criteria did not include the field is replaced
with a copy that sets minimum_valid_until_ts to the current time in
milliseconds. Explicit null is left unchanged, and an empty key-id map
is left unchanged so a request for every cached key still ignores
validity. Tests cover the omitted timestamp against cache lifetime,
mixed criteria including zero and null, non-integer timestamps, and a
body without server_keys, and a bugfix newsfragment records the default.

Ran `python3 -m pytest -q tests/rest/key/v2/test_remote_key_resource.py`
in a Linux container (`python:3.12`) for the synapse RemoteKey change; 7
tests passed.
The tests in `tests/rest/key/v2/test_remote_key_resource.py` fail
without the fix in the synapse RemoteKey change (checked by reverting
the source changes).

Fixes #20466

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-11-05 23:11:57 +00:00
Will Hunt 72a27d71db Allow MSC4155 to work if m.invite_permission_config was previously set (#20476)
Allow MSC4155 to work if m.invite_permission_config was previously set

Fixes #20474
2026-11-05 15:11:10 +00:00
Hugh Nimmo-Smith 8e1e7dc0af Rate limiting, configurable TTL and correct auth responses for MSC4388 (sign-in with QR code) (#20404)
This PR should be reviewable on a commit-by-commit basis. If you would
prefer that it is broken down into multiple PRs then I can do so.

Fixes to match latest MSC4388:

- Return `200` with `create_available=false` for `GET` when configured
in `authenticated` mode and no access token presented
- Return `401` for a `GET` where an invalid/expired token is presented
- Return `404` for `DELETE` where session has expired but not yet
evicted

Features:

- Rate limiting which is configurable via
`experimental_features.msc4388_rc_create` (for `POST` and is per
requester for authenticated requests or per client IP for
unauthenticated requests) and
`experimental_features.msc4388_rc_requests` (for `GET`/`PUT`/`DELETE`).
- Allow the session TTL to be configured via the
`experimental_features.msc4388_session_ttl`. As per spec this is between
2 and 5 minutes.
- Concurrent sessions are unlimited for authenticated requesters
(subject to the rate limits).
- Unauthenticated requesters have a maximum concurrent sessions limit
(default 1,000) which is configurable by
`experimental_features.msc4388_max_unauthenticated_sessions`.

Misc:

- Code and comment cleanup

The experimental feature is tracked by
https://github.com/element-hq/synapse/issues/19433 and I will update it
with the new config options when this PR merges.
2026-11-05 15:00:12 +00:00
Sid Karunaratne 86c96382b2 Fix store_into_file leaving empty files behind when media downloads fail (#20429)
Fix a bug introduced in Synapse v1.146.0 where failed remote media
downloads and URL previews would leave behind empty files in the media
store.

Regressed in #19204 which restructured
`MediaStorage.store_into_file(...)` to support running without a local
media store. As part of that, the `yield` (where the caller writes into
the file) was moved outside of the `try`/`except` that cleans up the
file on failure. Since `store_into_file(...)` is an
`asynccontextmanager`, an exception raised by the caller is thrown back
in at the `yield`, so it now bypasses the cleanup entirely.

This means any failed remote media download leaves a zero-byte file in
`remote_content/` (and similarly `url_cache/` for URL previews) without
a corresponding database row. Most of these fail before a single byte is
written, for example `NotRetryingDestination` while a remote server is
backed off, which fails instantly without any network request. Media
retention works from the database so it never cleans these up, and
because each attempt uses a fresh `filesystem_id`, clients repeatedly
requesting media (e.g. avatars of members on dead servers) keep
accumulating new ones. On a small homeserver, this added up to ~6000
orphaned files (and ~36000 directories) since upgrading to v1.146.0.

This PR moves the `yield` back inside the `try` (as it was before
#19204) so the file is removed again on failure. This applies to both
the local media store and the temporary file used when
`enable_local_media_storage` is disabled.


### Dev notes

To find orphaned files on an affected homeserver (zero-byte files with
no matching `remote_media_cache` row):

```shell
find /path/to/media_store/remote_content /path/to/media_store/url_cache -type f -size 0
```

Any of these without a matching row in `remote_media_cache` (or
`local_media_repository` for `url_cache/`) are orphans and safe to
delete, along with any empty directories left behind.
2026-11-05 11:06:23 +00:00
Ayesha Waseem 44757a4917 Prefer the stored server key valid for longest when several notaries answered (#20406)
`KeyStore.get_server_keys_json` orders the `server_keys_json` rows of a
key by `ts_added_ms` and each row overwrites the previous one, so the
last notary to answer wins even when its `ts_valid_until_ms` is lower
than an earlier answer's. When that answer is stale, `StoreKeyFetcher`
returns a key below `minimum_valid_until_ts` and event signature
verification fails although a long enough key is stored.

The query now orders by `ts_valid_until_ms, ts_added_ms`, so the
longest-valid entry wins and the most recent one still wins a tie.
`tests/crypto/test_keyring.py` stores two notary responses for one key,
the longer-lived one first, and checks that the lookup and
`verify_json_for_server` use it. Not covered:
`get_server_keys_json_for_remote` and
`get_all_server_keys_json_for_remote`, which still prefer the most
recently added row.

Fixes #20358

### Pull Request Checklist

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (ruff check, ruff format and mypy run on the changed files)
2026-11-04 19:36:40 +00:00
45175f2247 [Server Announcements] Admin API to send announcements and list the rooms (#20467)
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 18:33:10 +00:00
2e81f0785a Handle read receipts in Server Announcement rooms (#20427)
Co-authored-by: Quentin Gliech <quenting@element.io>
Co-authored-by: Andrew Morgan <andrew@amorgan.xyz>
2026-11-04 18:32:44 +00:00
Paul ChobertandQuentin Gliech 7593add0c5 Server Announcement Room Tags (#20448)
> [!NOTE]
> **Epic**: [Efficient Server
Announcements](https://github.com/element-hq/synapse/issues/20240)

In the previous PR, @anoadragon453 noted that we should sync account
data, see
https://github.com/element-hq/synapse/pull/20412#discussion_r4404823625.
Unfortunately, tagging required another change in the authorization
check.

This PR:
- [x] Allows synthetic members to set tags (eg: `m.favorite`)
- [x] Return tags of announcement rooms in Sync
  - [x] Legacy Sync
  - [ ] Sliding Sync
_Should merge the branch `barodeur/srv-announcements-sync-sliding` &
change the PR base branch_.
- [x] Always returns the tag `m.server_notice`
- [x] Prevent from removing the tag `m.server_notice`

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [ ] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Quentin Gliech <quenting@element.io>
2026-11-04 15:44:33 +01:00
Andrew Morgan 749a21a0bf [Server Announcements] Set the management user profile info to that of the room (#20468) 2026-11-04 13:38:08 +00:00
Andrew Morgan e2661d692b Correctly invalidate announcement room ID mapping in unit tests (#20469) 2026-11-04 12:39:53 +00:00
Quentin GliechandAndrew Morgan 4902d34f93 [Server Announcements] Don't deliver announcement rooms to excluded users in legacy sync (#20465)
Follow-up to https://github.com/element-hq/synapse/pull/20407, which
added the `excluded_user_ids` option without enforcing it. This makes
legacy `/sync` respect it: users listed in a room's `excluded_user_ids`
no longer get that room through the synthetic join. They can still read
it, as it is world-readable.

The cached lookup now maps room ID to config ID, so the per-user filter
runs in memory and adds no database query to `/sync`.
`get_server_announcement_room_ids()` is kept as a wrapper, so the
stacked PRs are unaffected.

Known limitation, documented in the config docs: changing the list does
not update rooms that clients already have. A newly excluded user keeps
the room, which stops updating. A user removed from the list gets new
events without the room's state until their next initial sync. I think
that's an okay limitation for now, as we don't really expect this list
to be used for real users

---------

Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2026-11-04 11:55:07 +01:00
bf9a68b017 Allow reading Server Announcement history outside of sync (#20423)
> [!NOTE]
> Epic: [Efficient Server
Announcements](https://github.com/element-hq/synapse/issues/20240)
> Follows: https://github.com/element-hq/synapse/pull/20372

This PR first tests that every user can read the server announcements
through the "history" endpoints like

- [x] `GET /rooms/{roomId}/messages`
- [x] `GET /rooms/{roomId}/context/{eventId}`
- [x] `GET /rooms/{roomId}/event/{eventId}`
- [x] `GET /rooms/{roomId}/relations/{eventId}`
- [x] `GET /rooms/{roomId}/threads`
- [x] `GET /rooms/{roomId}/initialSync`

This already works for users who have never been in the room, because
announcement rooms are world-readable.

It doesn't for a sender who was removed from the room's config: Synapse
still uses their `leave` membership and shows them the room as it was
when they left.
This PR then treats a user who left a configured announcement room like
a user who has never been in it.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
Co-authored-by: Quentin Gliech <quenting@element.io>
2026-11-03 19:04:28 +01:00
Andrew MorganandQuentin Gliech 6860a7cbb7 [Server Announcements] Implement excluded_user_ids option (#20407)
Follow-up to https://github.com/element-hq/synapse/pull/20372, and
re-uses the changelog.

Adds a new config option to exclude a given list of users from being
proactively pushed events from a given announcement room.

Requested by the ESS team at
https://github.com/element-hq/synapse/issues/20344#issuecomment-6217038992

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Quentin Gliech <quenting@element.io>
2026-11-03 17:50:36 +01:00
JimKnoxxandClaude Opus 5.5 dec679de1c Do not read media from disk when answering a HEAD request (#20368)
Fixes #20367

HEAD requests are routed to the GET handlers, so the media download
endpoints read the whole file and stream it to Twisted, which then
discards the body. Stop after writing the headers instead.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 15:06:03 +00:00
Paul ChobertandQuentin Gliech ab8f060746 Deliver Server Announcement over Legacy Sync (#20412)
> [!NOTE]
> **Epic**: [Efficient Server
Announcements](https://github.com/element-hq/synapse/issues/20240)
> Follows: https://github.com/element-hq/synapse/pull/20372

When a new announcement is sent in the announcement room, this PR will
ensure that the announcement and the room state are shared with the
client over Legacy Sync.

If you reviewed the PoC before, please note that there are several
differences:
- We intentionally don't wake all sync
- We don't want typing and receipts
- We don't need device lists

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Quentin Gliech <quenting@element.io>
2026-11-03 13:14:08 +01:00
Andrew Ferrazzutti 241dc05caa MSC4140 + MSC4354: Update sticky delayed event arg (#20378)
- For the dedicated delayed event scheduling endpoint, drop support for
setting the sticky duration in a query parameter, as MSC4354 is slated
to use only a body parameter for that
- Restrict the sticky duration for delayed events to being strictly
positive, analogously to #20350
2026-11-02 21:46:57 +00:00
Eric Eastwood 33aa953879 Merge branch 'master' into develop 2026-11-02 10:21:32 -06:00
Quentin Gliech e3e847083e [v1.164] Restore the unstable MSC2965 /auth_metadata endpoint (#20460)
This is a partial revert of
https://github.com/element-hq/synapse/pull/20143 to restore the unstable
`/auth_metadata` C-S API endpoint.

The details on why are in #20459 

Since this is affecting live clients (Rust SDK-based clients including
Element X iOS and Android), this PR is against the 1.164 release branch
as we plan to release 1.164.2 with this fix.

The CI failures are unrelated and were already fixed on `develop` in
https://github.com/element-hq/synapse/pull/20386. Please look at
`develop` counterpart of this PR
https://github.com/element-hq/synapse/pull/20461 for the green CI
2026-11-02 16:55:22 +01:00
Olivier 'reivilibre 0a88b4287e Fix MSC4354 Sticky Events that expired during sync processing being returned as expired events in the sticky section of the sync response. (#20349)
Part of: MSC4354 (Experimental Feature tracking issue #19409)

This is a bit of an edge case, but nonetheless good to handle.

The included regression tests failed before the fix.

- Fix sticky events that expired during sync processing being returned

  See discussion:

https://github.com/matrix-org/matrix-spec-proposals/pull/4354#discussion_r4209309068

  See MSC cautionary note:

https://github.com/matrix-org/matrix-spec-proposals/commit/9915d50437ac494efdd91244451f46fd1934168c

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-30 17:29:14 +00:00
Johannes Marbach 25492acda3 Stabilise MSC4143 (#20425)
This stabilizes the implementation of
https://github.com/matrix-org/matrix-spec-proposals/pull/4143 which
includes the following:

- Stable `/rtc/transports` as per
https://github.com/matrix-org/matrix-spec-proposals/pull/4143 and
https://github.com/matrix-org/matrix-spec-proposals/pull/4195. The
unstable endpoint is retained for backwards compatibility.
- Adding `m.rtc.slot` events to the state events retained during room
upgrades.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))
2026-10-30 15:47:01 +00:00
Raphael Fakhri 56acc229a5 Return identity server errors from third-party invites instead of a 500 (#20401)
Fixes #19257.

When an identity server returns a non-2xx response to
`/_matrix/identity/v2/store-invite` during a third-party invite,
`ask_id_server_for_third_party_invite` lets the `HttpResponseException`
escape. The client receives a 500 `M_UNKNOWN` error and the real cause
(for example, `M_THREEPID_IN_USE`) is lost.

This change catches `HttpResponseException` and converts it with
`to_synapse_error()`, which matches how the other identity server calls
in `IdentityHandler` (bind, `requestToken`) already handle error
responses.

A new test in `ThreepidInviteTestCase` makes the identity server return
a 400 `M_THREEPID_IN_USE` error and checks that the client receives the
same code and errcode. The test fails on `develop` with `500 != 400` and
passes with this change.
2026-10-29 18:43:27 +00:00
Erik Johnston eca9a4acd3 Fix regression with lazy membership and concurrenet syncs (#20433)
Broke by #20289. Hopefully fixes element-hq/element-web#35567.

One subtle change in #20289 was that we started to filter rooms with
`full_state` set through the cache. This *should* be safe since none of
the membership events should have been previously sent down the sync.

However, there is a bug with the lazy-loaded member cache when two
concurrent syncs for the same device happens. The updates to the cache
from the handling of one request are immediately seen by the other
request, polluting the cache.

This is a relatively common scenario in Element Web when a user reloads
the page. The sync from before the reload is still being processed when
Synapse receives the initial sync from after the reload.

The full fix to correctly handle overlapping requests is a separate PR,
but this is a stop-gap measure that should help Element Web.
2026-10-29 16:06:13 +00:00
Jason Robinson 2ff51d3c7f Partially revert "Reject setting null profile field values" (#20422)
As per https://github.com/element-hq/synapse/issues/20419 this change
broke Element Web clearing user status, which basically means the client
is stuck with any status, and users cannot set a new one.

EW should move to use DELETE to clear user status, but until then we
should ensure the feature is not broken on existing clients in the wild.

Should we set a clear deprecation time for rejecting nulls? There might
be other clients using profile fields and doing PUT to clear the field.


Discussed in
[`#element-backend-internal:matrix.org`](https://matrix.to/#/!SGNQGPGUwtcPBUotTL:matrix.org/$b7zid3lLGdFDC8pwy1IvSPv3zl9y1fXEpnnBte9vcQU?via=jki.re&via=element.io&via=matrix.org)
[[1]](https://matrix.to/#/!SGNQGPGUwtcPBUotTL:matrix.org/$jTEcHlDBIvKRAKtV-ESXabkPkLia9B7C4JQVkoOxzj0?via=jki.re&via=element.io&via=matrix.org)

Reverts a part of https://github.com/element-hq/synapse/pull/20153 by
only rejecting null fields when the profile update stream is configured
(ie user status requirement).

Future work to unrevert tracked by
https://github.com/element-hq/synapse/issues/20424
2026-10-28 12:56:29 -05:00
Jason Robinson ee3fc37345 Partially revert "Reject setting null profile field values" (#20422)
As per https://github.com/element-hq/synapse/issues/20419 this change
broke Element Web clearing user status, which basically means the client
is stuck with any status, and users cannot set a new one.

EW should move to use DELETE to clear user status, but until then we
should ensure the feature is not broken on existing clients in the wild.

Should we set a clear deprecation time for rejecting nulls? There might
be other clients using profile fields and doing PUT to clear the field.


Discussed in
[`#element-backend-internal:matrix.org`](https://matrix.to/#/!SGNQGPGUwtcPBUotTL:matrix.org/$b7zid3lLGdFDC8pwy1IvSPv3zl9y1fXEpnnBte9vcQU?via=jki.re&via=element.io&via=matrix.org)
[[1]](https://matrix.to/#/!SGNQGPGUwtcPBUotTL:matrix.org/$jTEcHlDBIvKRAKtV-ESXabkPkLia9B7C4JQVkoOxzj0?via=jki.re&via=element.io&via=matrix.org)

Reverts a part of https://github.com/element-hq/synapse/pull/20153 by
only rejecting null fields when the profile update stream is configured
(ie user status requirement).

Future work to unrevert tracked by
https://github.com/element-hq/synapse/issues/20424
2026-10-28 11:34:02 -05:00
dependabot[bot]andDevon Hudson b20ae98cc5 Bump authlib from 1.6.12 to 1.9.1 (#20415)
Bumps [authlib](https://github.com/authlib/authlib) from 1.6.12 to
1.9.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/authlib/authlib/releases">authlib's
releases</a>.</em></p>
<blockquote>
<h2>v1.9.1</h2>
<p>Changelog: <a
href="https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-1">https://docs.authlib.org/en/stable/upgrades/changelog.html#changelog-1-9-1</a></p>
<h2>What's Changed</h2>
<ul>
<li>Use scriv to handle the changelog by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/954">authlib/authlib#954</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.9.0...v1.9.1">https://github.com/authlib/authlib/compare/v1.9.0...v1.9.1</a></p>
<h2>v1.9.0</h2>
<h2>What's Changed</h2>
<ul>
<li>feat: add Identity Assertion JWT Authorization Grant (ID-JAG) by <a
href="https://github.com/BinoyOza-okta"><code>@​BinoyOza-okta</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/898">authlib/authlib#898</a></li>
<li>Fix empty signatures validation in JWS JSON deserialization by <a
href="https://github.com/loporto"><code>@​loporto</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/938">authlib/authlib#938</a></li>
<li>fix(jose): reject boolean values for NumericDate claims by <a
href="https://github.com/cpruijsen"><code>@​cpruijsen</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/942">authlib/authlib#942</a></li>
<li>fix(client): avoid duplicated OAuth 1.0 parameters in signed
requests by <a
href="https://github.com/cpruijsen"><code>@​cpruijsen</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/943">authlib/authlib#943</a></li>
<li>OAuth2 token fetch crashes with JSONDecodeError instead of a
catchable error on rate-limit responses by <a
href="https://github.com/juneja-varun"><code>@​juneja-varun</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/929">authlib/authlib#929</a></li>
<li>docs: add i18n wrappers in conf.py and templates by <a
href="https://github.com/hwhsu1231"><code>@​hwhsu1231</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/901">authlib/authlib#901</a></li>
<li>fix(oauth): enforce JOSE key, scope, and audience validation by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/945">authlib/authlib#945</a></li>
<li>AsyncOpenIDMixin.parse_id_token: return None when id_token is
absent, matching the sync client by <a
href="https://github.com/ckarnell"><code>@​ckarnell</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/924">authlib/authlib#924</a></li>
<li>fix(oauth): enforce nonce and JAR request validation by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/949">authlib/authlib#949</a></li>
<li>fix(oauth): require client authentication for ID-JAG grants by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/955">authlib/authlib#955</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/BinoyOza-okta"><code>@​BinoyOza-okta</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/898">authlib/authlib#898</a></li>
<li><a href="https://github.com/loporto"><code>@​loporto</code></a> made
their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/938">authlib/authlib#938</a></li>
<li><a href="https://github.com/cpruijsen"><code>@​cpruijsen</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/942">authlib/authlib#942</a></li>
<li><a
href="https://github.com/juneja-varun"><code>@​juneja-varun</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/929">authlib/authlib#929</a></li>
<li><a href="https://github.com/hwhsu1231"><code>@​hwhsu1231</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/901">authlib/authlib#901</a></li>
<li><a href="https://github.com/ckarnell"><code>@​ckarnell</code></a>
made their first contribution in <a
href="https://redirect.github.com/authlib/authlib/pull/924">authlib/authlib#924</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/authlib/authlib/compare/v1.8.0...v1.9.0">https://github.com/authlib/authlib/compare/v1.8.0...v1.9.0</a></p>
<h2>v1.8.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Prefer <code>id_token_signed_response_alg</code> client metadata to
guess algs by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/888">authlib/authlib#888</a></li>
<li>fix: Catch InvalidKeyIdError in RFC 9068 JWTBearerTokenValidator by
<a
href="https://github.com/liudonggalaxy"><code>@​liudonggalaxy</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/891">authlib/authlib#891</a></li>
<li>fix: make leeway configurable in JWTBearerTokenValidator by <a
href="https://github.com/mondi04"><code>@​mondi04</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/903">authlib/authlib#903</a></li>
<li>feat: add default jti claim to sign_jwt_bearer_assertion by <a
href="https://github.com/liudonggalaxy"><code>@​liudonggalaxy</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/897">authlib/authlib#897</a></li>
<li>fix(oauth): cast sub claim to string in JWTBearerTokenGenerator by
<a href="https://github.com/levinKaus"><code>@​levinKaus</code></a> in
<a
href="https://redirect.github.com/authlib/authlib/pull/911">authlib/authlib#911</a></li>
<li>Declare lower bounds for dependencies by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/912">authlib/authlib#912</a></li>
<li>feat(client): use httpx2 instead of httpx by <a
href="https://github.com/levinKaus"><code>@​levinKaus</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/909">authlib/authlib#909</a></li>
<li>Fix RFC7523 malformed claims handling by <a
href="https://github.com/azmeuk"><code>@​azmeuk</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/916">authlib/authlib#916</a></li>
<li>Fix httpx oauth1 binary form data by <a
href="https://github.com/shc261392"><code>@​shc261392</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/779">authlib/authlib#779</a></li>
<li>fix(starlette_client): remove default= keyword from config.get calls
by <a
href="https://github.com/aliaksei-protchanka"><code>@​aliaksei-protchanka</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/770">authlib/authlib#770</a></li>
<li>Added client_id parameter to AssertionClient by <a
href="https://github.com/vilmar-hillow"><code>@​vilmar-hillow</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/476">authlib/authlib#476</a></li>
<li>fix(oauth): save device credential with authenticated client id by
<a
href="https://github.com/arpitjain099"><code>@​arpitjain099</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/908">authlib/authlib#908</a></li>
<li>fix(oauth1): correct protocol name in InsecureTransportError
description by <a
href="https://github.com/RavSinghChandan"><code>@​RavSinghChandan</code></a>
in <a
href="https://redirect.github.com/authlib/authlib/pull/919">authlib/authlib#919</a></li>
<li>fix(client): client can be flexible with jwt's header by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/922">authlib/authlib#922</a></li>
<li>fix(oidc): omit claims when the value is None by <a
href="https://github.com/lepture"><code>@​lepture</code></a> in <a
href="https://redirect.github.com/authlib/authlib/pull/923">authlib/authlib#923</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/authlib/authlib/commit/46b94870d915ee77430da8fa2a358378d90b3a45"><code>46b9487</code></a>
chore: release 1.9.1</li>
<li><a
href="https://github.com/authlib/authlib/commit/abb3f49dd97b086ade807942957ffdf4949d9f30"><code>abb3f49</code></a>
docs: use the issuer identifier as ID-JAG audience and fix broken
links</li>
<li><a
href="https://github.com/authlib/authlib/commit/1bd2a313492ce0a4d0571c150730907aa3fc91ff"><code>1bd2a31</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/authlib/authlib/commit/311da11e41ae44fac570ac5224a45e0fec993939"><code>311da11</code></a>
docs: more detailed PKCE instructions</li>
<li><a
href="https://github.com/authlib/authlib/commit/873f72c0345a6fc9b303b2e686bab29cab90f4ac"><code>873f72c</code></a>
docs: rpinitiated instructions</li>
<li><a
href="https://github.com/authlib/authlib/commit/4ff30db442c70e29486e1982cb0ad37c037f5f4b"><code>4ff30db</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/authlib/authlib/commit/9a86ff3e54e3c87d419d425c105f03fd84f3fe39"><code>9a86ff3</code></a>
docs: rpinitiated sequence chart</li>
<li><a
href="https://github.com/authlib/authlib/commit/1c357571408cad6c9a3cc08ea6df96df5e4edaf7"><code>1c35757</code></a>
docs: RFC 9101 sequence chart</li>
<li><a
href="https://github.com/authlib/authlib/commit/a755e2869f07710a5077784d04807bbe9bfd8026"><code>a755e28</code></a>
docs: add a sequence diagram to the token introspection page</li>
<li><a
href="https://github.com/authlib/authlib/commit/1996c567ed325c5e328f3c00dc7452ff79a89bd2"><code>1996c56</code></a>
docs: PKCE flow chart illustration</li>
<li>Additional commits viewable in <a
href="https://github.com/authlib/authlib/compare/v1.6.12...v1.9.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=authlib&package-manager=pip&previous-version=1.6.12&new-version=1.9.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/element-hq/synapse/network/alerts).

</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Devon Hudson <devonhudson@librem.one>
2026-10-27 21:58:13 +00:00
Eric Eastwood 4cece59c30 Drop support for Python 3.10 (#20359)
Fix https://github.com/element-hq/synapse/issues/20041

Keywords:

 - `3.10`
 - `py310`
 - `cp310`
2026-10-26 16:26:19 -05:00
Andrew MorganandPaul Chobert b27615282d [Server Announcements] [Create/Configure Rooms] Configure announcement rooms and reconcile them on startup (#20372)
Co-authored-by: Paul Chobert <paul@chobert.fr>
2026-10-26 17:20:04 +00:00
Johannes MarbachandOlivier 'reivilibre 0d28e93a7a Move the sticky events sliding sync extension to the global pos and MSC4508 scoping (#20363)
This includes the following:
    
- Implements ['Implicit Forward
Pagination'](https://github.com/matrix-org/matrix-spec/issues/2378).
Remove the extension's `since` and `next_batch` fields. The position is
now tracked via the global `pos`, with per-room connection state
recording how far each room has been sent so that `limit` paginates
without holding `pos` back and lost responses are re-delivered.
- Discussed in
https://github.com/matrix-org/matrix-spec-proposals/pull/4480#discussion_r4165887827
- Honour the `lists` and `rooms` fields.
- Send all unexpired sticky events when a room enters scope for the
first time or is newly joined, and catch up on events sent while a room
was out of scope when it re-enters.
- Enabling the extension partway through a connection returns all
unexpired sticky events for in-scope rooms, and re-enabling it after
disabling it returns the unexpired sticky events sent in the meantime.

I tried to split this up into standalone commits though the bulk of the
change is in the third commit.

---------

Co-authored-by: Olivier 'reivilibre <git.oo@emunest.net>
2026-10-26 14:02:22 +00:00
Hugh Nimmo-Smith d99e5fe783 Implement transaction IDs for MSC4388 and other updates (sign-in with QR code) (#19906) 2026-10-26 11:56:06 +00:00
7d44c81d5c Fix new state saved with the last local user's leave missing from state_after (#20314)
> [!NOTE]
> This PR will be rebased on `develop` once
https://github.com/element-hq/synapse/pull/20081 is merged

This PR is a follow up to
https://github.com/element-hq/synapse/pull/20081 and is based on its
code.
The scope of that original PR is limited to recovering the leave event
missing from `state_after`.

I noticed that state events from the leave event batch would only be
recovered if they were previously defined.

That made me add a pre-condition to the test: the topic had to be set
first.


https://github.com/element-hq/synapse/blob/bccf1679aed0a5d86de87165c548f8c459758055/tests/handlers/test_sync.py#L1096-L1099

This PR attempts to recover new state events that only appeared first in
the leave batch.

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Fefaine <fefaine@gmail.com>
Co-authored-by: Quentin Gliech <quenting@element.io>
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-10-19 09:25:23 +00:00
Paul Chobert 26a92c7111 MSC4140: Reject scheduling a delayed event that the sender could not send at that time (#20266)
## What the MSC says

From MSC4140's [Auth rule
evaluation](https://github.com/matrix-org/matrix-spec-proposals/blob/b7cb09664fed684388ba656459d08cfaf786c1d1/proposals/4140-delayed-events-futures.md#auth-rule-evaluation):

> The server SHOULD also check the event could be sent when it is
scheduled and reject the request if not. In particular, servers SHOULD
check the sender is in the room (or otherwise authorized to send the
event) to avoid storing events for rooms the user is not in.

## This PR

- Checks the event against the room's auth rules as if it were sent now,
and returns the same 403 `M_FORBIDDEN` that `/send` and `/state` would.
- Changes to the sender's own membership are exempt: a join or knock can
be sent from outside the room, which is how this PR reads the MSC's "or
otherwise authorized". They are checked by the auth rules when they are
sent.

Here are a few examples:

| Delayed event | Before | After |
| ----------------------------------------------------------------- |
--------------------------------------- |
---------------------------------------- |
| `m.room.message` from outside the room | 200 `delay_id`, fails at send
time | 403 `M_FORBIDDEN` |
| Kick of another member from outside the room | 200 `delay_id`, fails
at send time | 403 `M_FORBIDDEN` |
| `m.room.name` from a member whose power level is too low | 200
`delay_id`, fails at send time | 403 `M_FORBIDDEN` |
| **Exception**: join of a public room from outside it | 200 `delay_id`,
joins at send time | unchanged |
| Join from outside the room, then a message due after it | both
accepted, message sent once joined | join accepted, message 403
`M_FORBIDDEN` |
2026-10-16 14:38:12 +01:00
Olivier 'reivilibre 4785f06e0e In legacy sync, lazy-load the memberships of the senders of MSC4354 Sticky Events. (#20362)
Part of: MSC4354 (Sticky Events, Experimental Feature tracking issue
#19409)

When a user is the sender of a sticky event that comes down sync, that
user is now in scope for having their lazy-loaded membership sent down
in sync.

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-15 20:26:51 +01:00
Andrew Morgan 98735bc6db Remove remaining references to lxml python dependency, which is no longer required (#20356) 2026-10-15 12:54:54 +00:00
542554c093 MSC4242: State DAGs (inbound joins) (#20194)
Process inbound requests to join a state DAG room.

Split out from https://github.com/element-hq/synapse/pull/19425

Part of a series of 5x PRs to land the federation part of MSC4242
(https://github.com/element-hq/synapse/pull/19718,
https://github.com/element-hq/synapse/pull/20127,
https://github.com/element-hq/synapse/pull/20133, inbound-joins (this
PR), inbound-pulls).

Has some Complement tests:
```
PASS TestMSC4242JoinLeaveRejoinPublicRoom 9.19s
PASS TestMSC4242JoinPublicRoomWithRejectedStateDAGEvents 0.88s
```

### Pull Request Checklist

<!-- Please read
https://element-hq.github.io/synapse/latest/development/contributing_guide.html
before submitting your pull request -->

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
  - Use markdown where necessary, mostly for `code blocks`.
  - End with either a period (.) or an exclamation mark (!).
  - Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-10-15 13:17:08 +01:00
Olivier 'reivilibre b9b74e8892 Catch up historical MSC4354 Sticky Events to remote homeservers that are newly joining the room. (#20337)
Part of: MSC4354 (Experimental Feature tracking issue #19409)

Follows: #20165 (Sticky Event federation backlog + catch-up
transactions)


The MSC says that we need to tell a newly-joining server about all of
our sticky events (yes, even the ones before the server joined the
room).
This PR introduces the mechanism, building on the 'Sticky Event backlog'
mechanism introduced in #20165, to make that happen.

Most of the logic is taken from the original Sticky Events PR #18968,
but the Sticky Event backlog system did not exist back then.
(The benefit of having the persistent Sticky Event backlog is that we
don't need to rely on the federation senders not crashing to make sure
we get around to sending the Sticky Events out.)

- Add NEW_SERVER_JOINED replication command. (This is a cross-worker
'wake-up call' to check for a sticky event backlog)
We send it when persisting a state change that causes a new server to be
in the room.
We handle it by waking up federation senders for the destination,
including checking the sticky event backlog tables.

- When a server newly joins a room, we insert a sticky event backlog row
for that server, if there are any Sticky Events needing to be sent.

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-15 09:53:02 +01:00
Olivier 'reivilibreandAndrew Morgan 1423a29f93 Reject null profile field values (following an optional clause in the specification), in order to avoid clients accidentally harming interoperability. (#20153)
Depends on: https://github.com/matrix-org/complement/pull/914

`displayname` and `avatar_url` already did not permit nulls, seemingly
from #8223.

The specification at v1.15 does not permit `null` for those fields
either, so this seems consistent with historical specification.

This only changes behaviour for 'custom' fields.

---------

Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2026-10-15 09:52:28 +01:00
Olivier 'reivilibre e86eb378af Require a strictly positive stickiness duration for MSC4354 Sticky Events. (#20350)
Part of: MSC4354 (Sticky Events, Experimental Feature tracking issue
#19409)

Since a zero value would be meaningless, don't accept it.

Spawns from
https://github.com/matrix-org/matrix-spec-proposals/pull/4354#discussion_r4211703962

- MSC4354 Sticky Events: only strictly positive durations are valid

  MSC clarified in

https://github.com/matrix-org/matrix-spec-proposals/commit/2d1c3d646aae3738680f8a9a0ccb38b2d941a45f
  to require strict positivity!

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-15 09:51:56 +01:00
Olivier 'reivilibre 64689d45f4 Fix Sliding Sync considering a displayname/avatar change to mean the room was newly-joined (#20339)
Follows: #18375

This bugfix is a prerequisite for MSC4354 (Sticky Events, Experimental
Feature tracking issue #19409) changes.

- Add a failing test for join->join being newly_joined

- Fix the join->join transition being treated as a new join

  (when prev_events didn't coincidentally mask the problem)

  Rationale:

  `event_edges` / `prev_events` does NOT link a membership event
  to its previous state.
  (It could even be someone else's membership!)
In most real-world cases, this would generate a `prev_membership` of
NULL
  for every normal membership change.

  It appears as though the author intended some kind of 'previous state'
  relationship, but if you fix the first branch of the `UNION` query
  to use `current_state_delta_stream` for this (which is the source of
  state transitions), then it looks very redundant with the second
  branch.

It looks like the real reason we want to use the snapshots table is for
  out-of-band memberships (outlier memberships).
  So we continue using that for those, but ONLY for those.

  The `SUSPICIOUS` if block is removed because it appears to have been
papering over this issue by deduplicating the spurious `NULL` ->
non-null transitions,
but when you remove those duplicates at the source, it causes more
trouble
  because it doesn't know that what it's 'deduplicating' is actually the
  same membership transition.
This means if you join, then out-of-band leave (e.g. last member on the
server
to leave), that room would appear in `newly_joined` on a new initial
sync.
  (Tests did in fact catch this, too.)

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-15 09:48:51 +01:00
Paul Chobert d773067277 MSC4140: authenticate the delayed event management endpoints and allow guests (#20257) 2026-10-13 16:24:30 +00:00