Commit Graph
4259 Commits
Author SHA1 Message Date
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
Paul Chobert 766f057305 Stop forwarding non compliant user ids (#20338)
Closes #20116

> [!NOTE]
> This PR Follows #20115 which already implemented this for
`m.device_list_update`

> User IDs with localparts containing characters outside the range
U+0021 to U+007E, or with
> an empty localpart, are considered non-compliant. For current room
versions, servers must
> still accept events using such user IDs over federation; however they
SHOULD NOT forward
> such user IDs to clients when referenced outside the context of an
event. For example,
> device list updates from non-compliant user IDs would be dropped by
the receiving server.
>
> — [Spec
1.19](https://spec.matrix.org/v1.19/appendices/#historical-user-ids)

This PR prevents from forwarding non compliant user ids for the
following events:

- `m.signing_key_update` 8c3c35e95d
- `m.presence` 26a8dfe862
- `m.typing` 1110cf2d73
- `m.receipt` 9e2da8b0a6
- `m.direct_to_device` 9541232a30
2026-10-13 11:10:48 +01:00
Richard van der Hoff 52f053abef Remove support for unstable MSC2965 (#20143)
These things are not needed now that MSC2965 has stabilised. In any
case, they
should never have been exposed without a config flag in the first place.
2026-10-12 16:43:38 +00:00
Will Hunt c52121d4b4 Add m.preview_url capability (Stabilise MSC4452) (#20298)
For https://github.com/element-hq/synapse/issues/19719

MSC4452 is now merged, so the stable capability can be made visible.
I've kept in the unstable flag in order to transition away at a later
date.

### Pull Request Checklist

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

* [ ] 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.
* [ ] [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-12 14:40:44 +01:00
Will Hunt 91020a9518 Short-circuit push rule evaluation when only one user is in a room (#20315)
This speeds up the /createRoom calls a tiny bit by not checking the
senders push rules.

This helps speed up a lot of test runs in Element Web which 
runs a lot of tests in one-person rooms (and creates a heck of a lot of rooms)
2026-10-12 11:56:27 +01:00
40acb97022 MSC4140: drop delayed state interference (#19495)
No longer cancel a user's delayed state events by a more recent state
event sent from a different user. This behaviour has been delegated to
an "alternative" in the delayed event MSC for some time now, and is not
known to be used by any module other than experimental iterations of
MatrixRTC.

See also: https://github.com/matrix-org/complement/pull/845

Opens: https://github.com/element-hq/synapse/issues/20311

---------

Co-authored-by: Olivier 'reivilibre' <olivier@librepush.net>
Co-authored-by: Paul Chobert <paul@chobert.fr>
2026-10-12 10:33:13 +01:00
MANI K 5e78aad7d7 Default request token errors to privacy-preserving responses (#20243)
## Summary

- default `request_token_inhibit_3pid_errors` to `true` to prevent
account enumeration
- document the new default and the explicit opt-out
- add an upgrade note and regression coverage for the default

Fixes #18415.
2026-10-09 13:26:31 +01:00
Olivier 'reivilibre 93368c7eb8 Prevent MSC4354 Sticky Events being sticky when they were redacted in the same persistence batch. (#20322)
Part of: MSC4354
Part of: #19641
Follows: #20232 (which applies already-persisted redactions to Sticky
Events being persisted)


In some cases we batch events together during persistence.

If one of the events in the batch is a redaction of another event, we
should apply it, which provides the same benefit as #20232 (namely: we
avoid potentially dodgy event content being persisted & the event
naturally loses its stickiness
so is not written to `sticky_events`)

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-09 12:30:58 +01:00
Olivier 'reivilibre 36f3e1df4b Apply the MSC4354 Sticky Events history visibility exemptions on all client-server endpoints. (#20295)
Part of: MSC4354 (Experimental Feature tracking issue:
https://github.com/element-hq/synapse/issues/19409)

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-09 11:15:36 +01:00
kruthikiran2007 07ecd8b497 Condense Pydantic validation error messages in client API responses (#20321)
Fixes #20309.

For endpoints that validate the request body with Pydantic, a validation
failure put Pydantic's raw verbose error text into the `error` field of
the standard error response, e.g.:

```json
{
  "errcode": "M_MISSING_PARAM",
  "error": "1 validation error for PutBody\\nroom_id\\n  Field required [type=missing, input_value={}, input_type=dict]\\n    For further information visit https://errors.pydantic.dev/2.12/v/missing"
}
```

This leaks internal details clients cannot act upon (model class names,
raw input values, pydantic.dev URLs). This PR adds a
`_format_pydantic_error` helper in `synapse/http/servlet.py` that builds
a short client-friendly message from the structured
`ValidationError.errors()` data instead of `str(e)`:

- `{}` against a model requiring `room_id` -> `Missing required field
'room_id'.`
- `{"room_id": 123}` -> `'room_id': Input should be a valid string.`
- nested models use dotted paths, e.g. `Missing required field
'put.room_id'.`
- multiple errors are joined: `Missing required field 'name'; Missing
required field 'put'.`

The `errcode` selection logic (`M_MISSING_PARAM` / `M_INVALID_PARAM` /
`M_BAD_JSON`) is unchanged.
2026-10-09 09:40:32 +01:00
Paul ChobertandEric Eastwood 3c46a10955 Stabilise MSC4222: support the stable use_state_after identifiers on /sync (#20170)
Part of #19414 (Support Matrix 1.16).

⚠️ Before merging, wait for the following PRs to be merged first:
- https://github.com/element-hq/synapse/pull/20081
- https://github.com/element-hq/synapse/pull/20169
- https://github.com/element-hq/synapse/pull/20171

---

Since Matrix 1.16, the
[spec](https://spec.matrix.org/v1.19/client-server-api/#get_matrixclientv3sync)
defines the stable identifiers for
[MSC4222](https://github.com/matrix-org/matrix-spec-proposals/pull/4222):
the `use_state_after` query parameter on `GET /_matrix/client/v3/sync`,
and the `state_after` room response field:

> **`use_state_after`** — `boolean` — Controls whether to receive state
changes between the previous sync and the start of the timeline, or
between the previous sync and the end of the timeline. If this is set to
`true`, servers MUST respond with the state between the previous sync
and the end of the timeline in `state_after` and MUST omit `state`. […]
>
> **`state_after`** — […] Required if `use_state_after` was set to true
in the request, even if it is empty. Added in `v1.16`
>
> — [Matrix
Spec](https://spec.matrix.org/v1.19/client-server-api/#get_matrixclientv3sync)

Synapse so far only implemented the unstable identifiers
(`org.matrix.msc4222.use_state_after` /
`org.matrix.msc4222.state_after`), gated behind the `msc4222_enabled`
experimental flag and the per-user experimental features admin API.

This PR:

- accepts the stable `use_state_after` query parameter, unconditionally,
and responds with the stable `state_after` field. The unstable query
parameter is kept for a transition period; clients opting in with it get
the unstable response field name back, so unstable-era clients see an
unchanged wire format. If both parameters are set, the stable one wins.
- removes the `msc4222_enabled` experimental flag and the `msc4222`
per-user feature from the experimental features admin API, since the
behaviour is no longer gated.

### 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>
2026-10-08 15:14:23 +02:00
694ad6bfa7 Fix leave event missing from state_after on incremental sync (#18793) (#20081)
Fixes https://github.com/element-hq/synapse/issues/18793


When the last local user leaves a room, Synapse clears
`current_state_events` and writes `null` `event_id` entries into the
`current_state_delta_stream`. The incremental sync code for MSC4222's
state_after skipped those `null` deltas entirely, and
`get_current_state_ids` also returned nothing (table already cleared).
Result: clients using `state_after` never learned about the leave.

Fix by falling back to state groups (which are preserved) to look up the
actual state at `end_token` for any cleared state keys.

### 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).
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: Paul Chobert <paul@chobert.fr>
Co-authored-by: Quentin Gliech <quenting@element.io>
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
2026-10-08 15:11:22 +02:00
Jason RobinsonandEric Eastwood e36ce7df9b Filter out MSC4426 User Status profile fields for remote users (#20328)
Several clients, including Element Web/Desktop and Element X, have
already implemented
[MSC4426](https://github.com/matrix-org/matrix-spec-proposals/pull/4426)
User Status profile fields. However, we have only implemented sending
profile fields down sync for local users
([MSC4429](https://github.com/matrix-org/matrix-spec-proposals/pull/4429)/[MSC4262](https://github.com/matrix-org/matrix-spec-proposals/pull/4262)),
since federation support for pushing profile field updates from server
to server has not yet been implemented
([MSC4259](https://github.com/matrix-org/matrix-spec-proposals/pull/4259)).

This has created user confusion. The before mentioned clients use the
profile and/or profile field fetch endpoints to fetch missing profile
information, regardless of the user being local or remote. Since the
sync response isn't delivering these profiles, the client does a
fallback fetch, causing a one time update of the profile information
over federation.

This causes stale data to be cached in the client for the remote user,
which in the case of EW for example is never cleared.

This filtering should be temporary until MSC4259 is implemented and the
remote profile data also syncs via the profile update stream to clients.

I suggest making this not configurable so we don't have to maintain a
configuration property, as hopefully this would only be a case for a few
months at most.

### 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>
2026-10-08 10:29:33 +00:00
Olivier 'reivilibre 815d2e0c7d Remove the stickiness of MSC4354 Sticky Events when they are redacted after persistence. (#20323)
Part of: MSC4354
Part of: #19641
Follows: #20232 (redacted before persistence), #20322 (redacted during
persistence)

Original commit schedule, with full messages:

- Add tests for redaction of Sticky Events

- Add `delete_sticky_events_txn`

- Remove stickiness from validly redacted events at persistence


### Dev notes

Overview:

- [`#20232`](https://github.com/element-hq/synapse/pull/20232) (redacted
before persistence)
- [`#20322`](https://github.com/element-hq/synapse/pull/20322) (redacted
during persistence)
- [`#20323`](https://github.com/element-hq/synapse/pull/20323) (redacted
after persistence)

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-08 10:04:08 +01:00
Paul Chobert 42ddc70ea7 Remove the legacy mention push rules by default (#20220)
Part of #19415 (Support Matrix 1.17).

Companion test PRs:
- Complement: https://github.com/matrix-org/complement/pull/920
- Sytest: https://github.com/matrix-org/sytest/pull/1430

**What this does:** `experimental_features.msc4210_enabled` default
value changed `true`
([MSC4210](https://github.com/matrix-org/matrix-spec-proposals/pull/4210)).
The rest of the changes is fixing the tests, making sure test relying en
mentions sends the proper `m.mentions` attribute.

## Migration plan

Element Web has been writing both rule sets together since September
2023
([matrix-react-sdk#11667](https://github.com/matrix-org/matrix-react-sdk/pull/11667),
[element-web@0d367a7c7e](https://github.com/element-hq/element-web/commit/0d367a7c7e)),
so for its users `.m.rule.is_user_mention` and `.m.rule.is_room_mention`
already carry the same customisations as the legacy rules.

<strike>For everyone else, #20215 adds a background update that migrates
the overrides on the legacy rules to the intentional ones.</strike>

## Opt-out

```yaml
experimental_features:
  msc4210_enabled: false
```

---

### 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-08 11:03:30 +02:00
Paul Chobert 46ff03f93a Reject modifying server-default push rules that are not served (#20202)
TLDR: `PUT` on a server-default push rule now applies the same existence
check that `GET` already does. A rule that is not served cannot be
modified.

Synapse ships some server-default push rules behind experimental feature
flags, so the set of server-default rules a user has depends on the
server's configuration. Most flags add rules that only exist while the
flag is on.
[MSC4210](https://github.com/matrix-org/matrix-spec-proposals/pull/4210)
works the other way: it removes the three legacy mention rules while its
flag is on. The flags that change the set are:

- `msc1767_enabled`:
[MSC1767](https://github.com/matrix-org/matrix-spec-proposals/pull/1767)
extensible events rules
- `msc3381_polls_enabled`:
[MSC3381](https://github.com/matrix-org/matrix-spec-proposals/pull/3381)
poll rules
- `msc3664_enabled`:
[MSC3664](https://github.com/matrix-org/matrix-spec-proposals/pull/3664)
reply rule
- `msc4028_push_encrypted_events`:
[MSC4028](https://github.com/matrix-org/matrix-spec-proposals/pull/4028)
encrypted event rule
- `msc4306_enabled`:
[MSC4306](https://github.com/matrix-org/matrix-spec-proposals/pull/4306)
thread subscription rules
- `msc4210_enabled`: removes `.m.rule.contains_display_name`,
`.m.rule.contains_user_name` and `.m.rule.roomnotif`

`GET /pushrules/` only lists the rules that exist for that
configuration. `GET` on a single rule that is not in the set returns
`404 M_NOT_FOUND`. The same set is used to evaluate notifications, and
to build the `m.push_rules` account data in `/sync`.

`PUT .../enabled` and `PUT .../actions` did not use that set. They
accepted any rule ID that Synapse knows about, whether or not the server
currently serves it. Clients could modify a rule the server had just
said did not exist. The request returned `200`, the change was stored,
and it was then ignored. Both endpoints now return `404 M_NOT_FOUND` for
such a rule, as [the spec
requires](https://spec.matrix.org/v1.19/client-server-api/#put_matrixclientv3pushrulesglobalkindruleidenabled)
for a rule that does not exist.

Before (`msc4210_enabled: true`):

```
GET /_matrix/client/v3/pushrules/global/override/.m.rule.roomnotif
  404 {"errcode": "M_NOT_FOUND", "error": "..."}

PUT /_matrix/client/v3/pushrules/global/override/.m.rule.roomnotif/enabled
  {"enabled": false}
  200 {}
```

After:

```
GET /_matrix/client/v3/pushrules/global/override/.m.rule.roomnotif
  404 {"errcode": "M_NOT_FOUND", "error": "..."}

PUT /_matrix/client/v3/pushrules/global/override/.m.rule.roomnotif/enabled
  {"enabled": false}
  404 {"errcode": "M_NOT_FOUND", "error": "Unknown rule"}
```

This is a no-op for default configurations. All of these flags are off
by default, and rules that are served are still modifiable as before.
2026-10-08 08:57:58 +01:00
Paul Chobert a93175ccb5 Skip application services with url: null when notifying them of events (#20273)
ESS deployments of MatrixRTC are going to run `lk-jwt-service` as an
application service so that it can manage delayed events. However,
setting up an application service is particularly inefficient, as
Synapse iterates through all the events of the rooms it covers since
their creation.

When an application service is configured with `url: null`, there is no
need to traverse all the events for it, so we can set up such
application services much faster without having to decide what to do for
other application services. Discussions about those are still open:
element-hq/synapse#11629 (see also matrix-org/synapse#1834).


### 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-08 07:35:37 +00:00
dc1291aa65 MSC4140: add dedicated endpoint for delayed events (#19354)
Use a new, dedicated endpoint for scheduling delayed events. This should
deprecate the `delay` query parameter on the `/send` and `/state`
endpoints.

Co-authored-by: Paul Chobert <paul@chobert.fr>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-10-08 05:02:12 +00:00
Will Hunt 63bade4325 Skip running delayed event background job if the room event stream has not advanced. (#20316)
In a similar vein to #20315, this attempts to speed up Synapse when
delayed events aren't in use. Here we skip doing any work if the room
event stream has not advanced.
2026-10-07 14:57:56 +01:00
Hugh Nimmo-SmithandAndrew Morgan 52835fc397 Don't store file on disk after media upload limit failure (#20006)
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2026-10-07 12:05:01 +00:00
Erik Johnston 7ae1d987ef Add a per-homeserver clock to the Rust side (#20294)
This is a prerequisite to being able to add caching on the Rust side.
2026-10-07 11:11:08 +01:00
Olivier 'reivilibre 31ca874890 Add received_ts to the in-memory event internal metadata struct. (#20312)
Motivated by work on MSC4354, because the sticky events MSC specs that
`received_ts` is used to calculate the
start of an event's stickiness. (It would therefore be convenient to
have it available as part of event metadata, so an event can expose a
cheap helper method to check if it is sticky.)

This commit adds `received_ts` into the `event.internal_metadata` struct,
alongside `stream_ordering`.

I conceptually treat it as a sibling to `stream_ordering` and populate
it in all the same places where `stream_ordering` is populated.

Because this needs `received_ts` to be added to the HTTP replication
response for event persistence,
I also add a temporary compatibility measure that keeps rolling worker
upgrades working during this
transition.
I intend to remove the compatibility code in the next release.


I have manually tested that
```
SYNAPSE_POSTGRES=1 SYNAPSE_POSTGRES_USER=postgres SYNAPSE_POSTGRES_HOST=localhost SYNAPSE_POSTGRES_PASSWORD=postgres poetry run trial -j 6 tests.replication.test_sharded_event_persister
```
fails only when both the compatibility code is removed and the
`"received_ts"` key is commented out in the response (to omit it).
The compatibility code causes the test to pass even when `"received_ts"`
is commented out.

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2026-10-06 19:27:46 +01:00
Olivier 'reivilibreandEric Eastwood 7773f05596 Use sharded tokens in MSC4354: Sticky Events sync and sliding sync, preventing events appearing in multiple sync responses. (#20186)
Fixes: #19661
Part of: MSC4354

First introduced some helpers for querying a sharded stream, which were moved to
https://github.com/element-hq/synapse/pull/20108.

- SQL builder for 'give me rows between two sharded tokens'
- a function to return the 'new' from_token after a limited read


Then make the sticky events portions of both oldschool and sliding sync use
sharded tokens.

This prevents a 'torn sync' problem where, because the events and sticky
events streams are both sharded with the same writers:

1. persisting a sticky event leads to an event row and a `sticky_events`
row being created for event `e` (on writer `W`).
2. Suppose another writer is still persisting, so the position of the
stream for writer W advances, but the global
['linear'](https://element-hq.github.io/synapse/latest/development/synapse_architecture/streams.html?highlight=%E2%80%9Clinear%E2%80%9D#current-stream-id)
(I have been calling this 'baseline') position does not advance yet.
3. sync is sharding-aware for the regular events stream, so `e` appears
as a real-time timeline event, thus coming down sync
4. since sticky events were not sharding-aware, `e` is not detected as a
sticky event in this sync response. The sticky event position doesn't
advance in the sync token, either.
5. (assume the position advances because other writers have finished
writing and so the 'linear' position advances for the sticky events
stream)
6. the client then syncs again, using the new sync token. This time, `e`
appears in the sticky event section.

If we make sticky events sharding-aware in sync, then `e` would appear
for consideration in both the timeline section **and** the sticky event
section in the first sync.
It then gets deduplicated out of the sticky section since it is
appearing in the timeline section in the same sync.

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-10-05 12:40:55 +01:00
Olivier 'reivilibreandEric Eastwood 9f0168aace Catch up MSC4354 Sticky Events to remote homeservers that have missed them. (#20165)
Part of: MSC4354 (Sticky Events)

Our locally-sent Sticky Events need to be reliably (within bounds of
possibility) sent to remote homeservers.

This adds the mechanism to make this happen.

Notably omits catching up historical sticky events to homeservers that only just
joined the room.

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-10-05 10:52:46 +01:00
4f5524043c Use beautifulsoup4 instead of lxml for URL previews (#19301)
Use `beautifulsoup4` instead of `lxml` for URL previews. This offers
some nicer APIs when parsing HTML and avoids using `libxml`, [which is
unmaintained](https://gitlab.gnome.org/GNOME/libxml2/-/commit/9c80a89af2fdf4f853892f84e46580f4902658ba).

I haven’t done a full regression against commonly previewed sites, but I
expect this will give similar (or better) results.

beautiulsoup also handles decoding the charset for us, which is less
custom code.

---------

Co-authored-by: Andrew Morgan <andrew@amorgan.xyz>
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2026-10-02 15:46:34 +01:00
Erik Johnston 5a8c4b3990 Fix bug where /sync would not return membership changes due to lazy-loaded membership cache (#20289)
In `/sync` there is a mode called lazy loaded (LL) members. In this mode
`/sync` does not return all memberships in the room, instead it only
returns a) membership changes, and b) the memberships of senders of
events in the timeline (if not previously sent).

Synapse implements a lazy-loaded member cache to avoid repeatedly
sending down the same memberships when a single user sends multiple
events. It does this by storing for each user/device the memberships it
has previously returned in an LRU cache. Note that it is fine for the
server to return the same membership, clients handle that fine, but it
is a waste of bandwidth.

The current lazy-loaded membership cache has three intertwined flaws:
1. It does not handle retries or clients re-using old tokens.
2. It incorrectly applies the membership cache to membership changes,
not just memberships added by lazy-loading.
3. It does not correctly handle multiple "sync streams" from the same
device.

In this PR we explicitly fix the first two issues in two commits, and
the third issue is mitigated:

1. Alongside each membership in the LL cache we store the `next_batch`
position of the response that carried it. A client that processed a
response syncs from its `next_batch` next. When a request arrives with a
`since` token, we delete every membership recorded after that token, as
they were sent in responses the client never processed. Memberships
recorded at or before `since` are kept.
2. We always return memberships that have changed, even if they appear
in the LL member cache.

These changes also half mitigate the issue of running multiple `/sync`
loops per-device (though we do not see this in the wild), as we'd at
least always return the changed membership states.

Fixes #19978 and #20278, supersedes #20279
2026-10-02 09:48:14 +01:00
Andrew Morgan b3c67110a5 Bump Twisted in poetry.lock from 25.5.0 to 26.4.0 (#20259) 2026-09-29 17:50:55 +00:00
Andrew Morgan c9b61fc2a3 Stop real threadpool for test DB pool before replacing it with threadless test implementation (#20272) 2026-09-29 16:25:32 +00:00
Olivier 'reivilibreandEric Eastwood d1874cdc37 Prevent MSC4354 Sticky Events being sticky when they were redacted prior to persistence. (#20232)
Part of: MSC4354, 
Part of: https://github.com/element-hq/synapse/issues/19641

This PR persists events in redacted form when they already have valid
redactions. That's not directly a sticky events-specific change (and I
feel it makes sense to redact immediately before persistence when we
already have the redaction).

This causes a nice effect which is that the event's stickiness is lost
immediately before persistence, because the `msc4354_sticky` field is
redacted by the redaction algorithm.

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-09-29 15:22:34 +01:00
Paul ChobertandOlivier 'reivilibre db618e276d Fix appservice ephemeral read receipts being permanently skipped on large receipt bursts (#20108)
Fixes https://github.com/element-hq/synapse/issues/20096.

Part of https://github.com/element-hq/synapse/issues/18118

The spec requires read receipts to be delivered to interested
application services ([Pushing ephemeral
data](https://spec.matrix.org/v1.19/application-service-api/#pushing-ephemeral-data)):

> If the `receive_ephemeral` settings is enabled in the registration
file, homeservers MUST send ephemeral data that is relevant to the
application service via the transaction API, using the `ephemeral`
property of the request's body.
>
> `m.receipt`: MUST be sent to the application service under the same
rules as regular events, meaning that the application service must have
registered interest in the room itself, or in a user that is in the
room.

Ephemeral data delivery to application services was added in Matrix
v1.13 from
[MSC2409](https://github.com/matrix-org/matrix-spec-proposals/pull/2409)
(see the [v1.13
changelog](https://spec.matrix.org/v1.19/changelog/v1.13/#application-service-api)).

## Problem

When more than 100 read receipts are covered by a single receipt stream
update, only the last 100 are sent to appservices. The rest is
permanently skipped.


## Proposed Fix

- Looping over the receipts in batches of 100 items and updating the
cursor on every iteration
- Keep the fast-forward behavior for new appservices as intended in
https://github.com/matrix-org/synapse/pull/8744

---------

Co-authored-by: Olivier 'reivilibre <oliverw@element.io>
2026-09-29 12:06:15 +01:00
Ankit Jha 18c10b8075 Fix 500 error when user-interactive auth requests send a null or non-object auth (#20274)
Fixes #15871

### What was broken

Sending `{"auth": null}` to any endpoint that requires user-interactive
auth (for example `POST /keys/device_signing/upload`, `DELETE
/devices/{deviceId}` or `POST /register`) returned a 500 instead of the
usual 401 with the available flows. A non-object `auth` on endpoints
that do not validate the body with a model (such as `/register`) could
also 500, e.g. `{"auth": ["session"]}`.

### Root cause

`AuthHandler.check_ui_auth` did `clientdict.pop("auth", {})`, so the
`{}` default only applies when the key is missing. An explicit `null`
came through as `None` and the following `"session" in authdict` raised
`TypeError`. `get_session_id` had the same assumption that `auth` is a
dict.

### 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 (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>
2026-09-28 18:36:39 +00:00
Ankit Jha 929e3524d1 fix: reject user creation via the admin API when delegating to MAS (#20241)
Signed-off-by: Ankit Jha <jhaankit373@gmail.com>
Signed-off-by: Ankit Jha <ankit.jha@tradomate.one>
2026-09-28 10:17:37 +00:00
Erik Johnston 7630492e90 Add metrics for wait_for_stream_token timeouts per lagging stream (#20095)
Add a metric for the number of times we see a stall due to being given a
future token.

This would have caught
https://github.com/element-hq/synapse/issues/20080, where lots of sync
streams got stuck due to a stream not getting replicated correctly.
2026-09-25 12:09:38 +01:00
Johannes MarbachandAndrew Morgan b8bd6f93a1 Add push rules for MSC4075: MatrixRTC invites and notifications (#20227)
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2026-09-25 10:40:24 +00:00
e863ce7fab Fire deferreds from Rust futures without taking the GIL (#20252)
Tokio tasks currently complete by taking the GIL and calling
`reactor.callFromThread`. Taking the GIL may block for a period of time,
and we do not want that to happen on the tokio reactor threads (as that
can block other work from happening).

To avoid this, we instead add a work queue that we can add to from Rust
without taking the GIL, which is drained by the reactor. We signal to
the Twisted reactor that it should wake up by using a unix socket pair,
which is exactly how `reactor.callFromThread` works.

---

The self-pipe trick is basically where you create a pair of unix sockets
connected to each other. One end is added to the reactor so the reactor
is woken up when there are bytes to read, and when another thread needs
to wake up the reactor it just needs to write a byte into the other unix
socket.

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2026-09-25 09:49:14 +01:00