From 39f80296c5683bfa2c06a7ade56d4c95f0e30b2a Mon Sep 17 00:00:00 2001 From: Devon Hudson Date: Tue, 6 Jan 2026 09:38:44 -0700 Subject: [PATCH 1/6] 1.145.0rc1 --- CHANGES.md | 57 +++++++++++++++++++++++++++++++ changelog.d/18402.misc | 1 - changelog.d/19187.misc | 1 - changelog.d/19206.bugfix | 1 - changelog.d/19212.misc | 1 - changelog.d/19231.bugfix | 1 - changelog.d/19232.misc | 1 - changelog.d/19234.misc | 1 - changelog.d/19253.misc | 1 - changelog.d/19254.removal | 1 - changelog.d/19258.misc | 1 - changelog.d/19260.feature | 1 - changelog.d/19262.misc | 1 - changelog.d/19267.bugfix | 1 - changelog.d/19268.feature | 1 - changelog.d/19270.doc | 1 - changelog.d/19274.bugfix | 1 - changelog.d/19275.feature | 1 - changelog.d/19278.misc | 1 - changelog.d/19279.feature | 1 - changelog.d/19281.feature | 1 - changelog.d/19289.misc | 1 - changelog.d/19291.misc | 1 - changelog.d/19297.misc | 1 - changelog.d/19300.feature | 1 - changelog.d/19302.misc | 1 - changelog.d/19323.misc | 1 - changelog.d/19324.docker | 1 - changelog.d/19326.misc | 1 - changelog.d/19327.misc | 1 - changelog.d/19340.bugfix | 1 - debian/changelog | 6 ++++ pyproject.toml | 2 +- schema/synapse-config.schema.yaml | 2 +- 34 files changed, 65 insertions(+), 32 deletions(-) delete mode 100644 changelog.d/18402.misc delete mode 100644 changelog.d/19187.misc delete mode 100644 changelog.d/19206.bugfix delete mode 100644 changelog.d/19212.misc delete mode 100644 changelog.d/19231.bugfix delete mode 100644 changelog.d/19232.misc delete mode 100644 changelog.d/19234.misc delete mode 100644 changelog.d/19253.misc delete mode 100644 changelog.d/19254.removal delete mode 100644 changelog.d/19258.misc delete mode 100644 changelog.d/19260.feature delete mode 100644 changelog.d/19262.misc delete mode 100644 changelog.d/19267.bugfix delete mode 100644 changelog.d/19268.feature delete mode 100644 changelog.d/19270.doc delete mode 100644 changelog.d/19274.bugfix delete mode 100644 changelog.d/19275.feature delete mode 100644 changelog.d/19278.misc delete mode 100644 changelog.d/19279.feature delete mode 100644 changelog.d/19281.feature delete mode 100644 changelog.d/19289.misc delete mode 100644 changelog.d/19291.misc delete mode 100644 changelog.d/19297.misc delete mode 100644 changelog.d/19300.feature delete mode 100644 changelog.d/19302.misc delete mode 100644 changelog.d/19323.misc delete mode 100644 changelog.d/19324.docker delete mode 100644 changelog.d/19326.misc delete mode 100644 changelog.d/19327.misc delete mode 100644 changelog.d/19340.bugfix diff --git a/CHANGES.md b/CHANGES.md index 83ab1849e6..1f6ed01c20 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,60 @@ +# Synapse 1.145.0rc1 (2026-01-06) + +- Ubuntu 25.04 (Plucky Puffin) will be end of life on Jan 17, 2026. Synapse will stop building packages for Ubuntu 25.04 shortly thereafter. +- Remove the "Updates to locked dependencies" section from the changelog due to lack of use and the maintenance burden. ([\#19254](https://github.com/element-hq/synapse/issues/19254)) + +## Features + +- Add `memberships` endpoint to the admin API. This is useful for forensics and T&S purpose. ([\#19260](https://github.com/element-hq/synapse/issues/19260)) +- Add an admin API for retrieving a paginated list of quarantined media. ([\#19268](https://github.com/element-hq/synapse/issues/19268)) +- Server admins can bypass the quarantine media check when downloading media by setting the `admin_unsafely_bypass_quarantine` query parameter to `true` on Client-Server API media download requests. ([\#19275](https://github.com/element-hq/synapse/issues/19275)) +- Implemented pagination for the [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666) mutual rooms endpoint. Contributed by @tulir @ Beeper. ([\#19279](https://github.com/element-hq/synapse/issues/19279)) +- Admin API: add worker support to `GET /_synapse/admin/v2/users/`. ([\#19281](https://github.com/element-hq/synapse/issues/19281)) +- Improve proxy support for the `federation_client.py` dev script. Contributed by Denis Kasak (@dkasak). ([\#19300](https://github.com/element-hq/synapse/issues/19300)) + +## Bugfixes + +- Fix sliding sync performance slow down for long lived connections. ([\#19206](https://github.com/element-hq/synapse/issues/19206)) +- Fix a bug where Mastodon posts (and possibly other embeds) have the wrong description for URL previews. ([\#19231](https://github.com/element-hq/synapse/issues/19231)) +- Fix bug where `Duration` was logged incorrectly. ([\#19267](https://github.com/element-hq/synapse/issues/19267)) +- Fix bug introduced in 1.143.0 that broke support for versions of `zope-interface` older than 6.2. ([\#19274](https://github.com/element-hq/synapse/issues/19274)) +- Transform events with client metadata before serialising in /event response. ([\#19340](https://github.com/element-hq/synapse/issues/19340)) + +## Updates to the Docker image + +- Add a way to expose metrics from the Docker image (`SYNAPSE_ENABLE_METRICS`). ([\#19324](https://github.com/element-hq/synapse/issues/19324)) + +## Improved Documentation + +- Document the importance of `public_baseurl` when configuring OpenID Connect authentication. ([\#19270](https://github.com/element-hq/synapse/issues/19270)) + +## Deprecations and Removals + +- Ubuntu 25.04 (Plucky Puffin) will be end of life on Jan 17, 2026. Synapse will stop building packages for Ubuntu 25.04 shortly thereafter. +- Remove the "Updates to locked dependencies" section from the changelog due to lack of use and the maintenance burden. ([\#19254](https://github.com/element-hq/synapse/issues/19254)) + +## Internal Changes + +- Group together dependabot update PRs to reduce the review load. ([\#18402](https://github.com/element-hq/synapse/issues/18402)) +- Fix `HomeServer.shutdown()` failing if the homeserver hasn't been setup yet. ([\#19187](https://github.com/element-hq/synapse/issues/19187)) +- Respond with useful error codes with `Content-Length` header/s are invalid. ([\#19212](https://github.com/element-hq/synapse/issues/19212)) +- Fix `HomeServer.shutdown()` failing if the homeserver failed to `start`. ([\#19232](https://github.com/element-hq/synapse/issues/19232)) +- Switch the build backend from `poetry-core` to `maturin`. ([\#19234](https://github.com/element-hq/synapse/issues/19234)) +- Raise the limit for concurrently-open non-security @dependabot PRs from 5 to 10. ([\#19253](https://github.com/element-hq/synapse/issues/19253)) +- Require 14 days to pass before pulling in general dependency updates to help mitigate upstream supply chain attacks. ([\#19258](https://github.com/element-hq/synapse/issues/19258)) +- Drop the broken netlify documentation workflow until a new one is implemented. ([\#19262](https://github.com/element-hq/synapse/issues/19262)) +- Don't include debug logs in `Clock` unless explicitly enabled. ([\#19278](https://github.com/element-hq/synapse/issues/19278)) +- Use `uv` to test olddeps to ensure all transitive dependencies use minimum versions. ([\#19289](https://github.com/element-hq/synapse/issues/19289)) +- Add a config to be able to rate limit search in the user directory. ([\#19291](https://github.com/element-hq/synapse/issues/19291)) +- Log the original bind exception when encountering `Failed to listen on 0.0.0.0, continuing because listening on [::]`. ([\#19297](https://github.com/element-hq/synapse/issues/19297)) +- Unpin the version of Rust we use to build Synapse wheels (was 1.82.0) now that MacOS support has been dropped. ([\#19302](https://github.com/element-hq/synapse/issues/19302)) +- Make it more clear how `shared_extra_conf` is combined in our Docker configuration scripts. ([\#19323](https://github.com/element-hq/synapse/issues/19323)) +- Update CI to stream Complement progress and format logs in a separate step after all tests are done. ([\#19326](https://github.com/element-hq/synapse/issues/19326)) +- Format `.github/workflows/tests.yml`. ([\#19327](https://github.com/element-hq/synapse/issues/19327)) + + + + # Synapse 1.144.0 (2025-12-09) ## Deprecation of MacOS Python wheels diff --git a/changelog.d/18402.misc b/changelog.d/18402.misc deleted file mode 100644 index 4b13652845..0000000000 --- a/changelog.d/18402.misc +++ /dev/null @@ -1 +0,0 @@ -Group together dependabot update PRs to reduce the review load. \ No newline at end of file diff --git a/changelog.d/19187.misc b/changelog.d/19187.misc deleted file mode 100644 index d831de38c8..0000000000 --- a/changelog.d/19187.misc +++ /dev/null @@ -1 +0,0 @@ -Fix `HomeServer.shutdown()` failing if the homeserver hasn't been setup yet. diff --git a/changelog.d/19206.bugfix b/changelog.d/19206.bugfix deleted file mode 100644 index 9cdfaa2571..0000000000 --- a/changelog.d/19206.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix sliding sync performance slow down for long lived connections. diff --git a/changelog.d/19212.misc b/changelog.d/19212.misc deleted file mode 100644 index 83158ce2d9..0000000000 --- a/changelog.d/19212.misc +++ /dev/null @@ -1 +0,0 @@ -Respond with useful error codes with `Content-Length` header/s are invalid. diff --git a/changelog.d/19231.bugfix b/changelog.d/19231.bugfix deleted file mode 100644 index 580b642bb2..0000000000 --- a/changelog.d/19231.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix a bug where Mastodon posts (and possibly other embeds) have the wrong description for URL previews. diff --git a/changelog.d/19232.misc b/changelog.d/19232.misc deleted file mode 100644 index 6e3e2ff649..0000000000 --- a/changelog.d/19232.misc +++ /dev/null @@ -1 +0,0 @@ -Fix `HomeServer.shutdown()` failing if the homeserver failed to `start`. diff --git a/changelog.d/19234.misc b/changelog.d/19234.misc deleted file mode 100644 index d79bc0b19f..0000000000 --- a/changelog.d/19234.misc +++ /dev/null @@ -1 +0,0 @@ -Switch the build backend from `poetry-core` to `maturin`. \ No newline at end of file diff --git a/changelog.d/19253.misc b/changelog.d/19253.misc deleted file mode 100644 index 1d45f936f6..0000000000 --- a/changelog.d/19253.misc +++ /dev/null @@ -1 +0,0 @@ -Raise the limit for concurrently-open non-security @dependabot PRs from 5 to 10. \ No newline at end of file diff --git a/changelog.d/19254.removal b/changelog.d/19254.removal deleted file mode 100644 index ee527cef99..0000000000 --- a/changelog.d/19254.removal +++ /dev/null @@ -1 +0,0 @@ -Remove the "Updates to locked dependencies" section from the changelog due to lack of use and the maintenance burden. \ No newline at end of file diff --git a/changelog.d/19258.misc b/changelog.d/19258.misc deleted file mode 100644 index 9155f9d20f..0000000000 --- a/changelog.d/19258.misc +++ /dev/null @@ -1 +0,0 @@ -Require 14 days to pass before pulling in general dependency updates to help mitigate upstream supply chain attacks. \ No newline at end of file diff --git a/changelog.d/19260.feature b/changelog.d/19260.feature deleted file mode 100644 index 19b192a009..0000000000 --- a/changelog.d/19260.feature +++ /dev/null @@ -1 +0,0 @@ -Add `memberships` endpoint to the admin API. This is useful for forensics and T&S purpose. diff --git a/changelog.d/19262.misc b/changelog.d/19262.misc deleted file mode 100644 index 31906e6623..0000000000 --- a/changelog.d/19262.misc +++ /dev/null @@ -1 +0,0 @@ -Drop the broken netlify documentation workflow until a new one is implemented. \ No newline at end of file diff --git a/changelog.d/19267.bugfix b/changelog.d/19267.bugfix deleted file mode 100644 index 6c7ed750ec..0000000000 --- a/changelog.d/19267.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix bug where `Duration` was logged incorrectly. diff --git a/changelog.d/19268.feature b/changelog.d/19268.feature deleted file mode 100644 index cb7035fee2..0000000000 --- a/changelog.d/19268.feature +++ /dev/null @@ -1 +0,0 @@ -Add an admin API for retrieving a paginated list of quarantined media. \ No newline at end of file diff --git a/changelog.d/19270.doc b/changelog.d/19270.doc deleted file mode 100644 index fdb7e2e51c..0000000000 --- a/changelog.d/19270.doc +++ /dev/null @@ -1 +0,0 @@ -Document the importance of `public_baseurl` when configuring OpenID Connect authentication. diff --git a/changelog.d/19274.bugfix b/changelog.d/19274.bugfix deleted file mode 100644 index 92aaa0fe6d..0000000000 --- a/changelog.d/19274.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix bug introduced in 1.143.0 that broke support for versions of `zope-interface` older than 6.2. diff --git a/changelog.d/19275.feature b/changelog.d/19275.feature deleted file mode 100644 index 5147c546cf..0000000000 --- a/changelog.d/19275.feature +++ /dev/null @@ -1 +0,0 @@ -Server admins can bypass the quarantine media check when downloading media by setting the `admin_unsafely_bypass_quarantine` query parameter to `true` on Client-Server API media download requests. \ No newline at end of file diff --git a/changelog.d/19278.misc b/changelog.d/19278.misc deleted file mode 100644 index d1425ff38c..0000000000 --- a/changelog.d/19278.misc +++ /dev/null @@ -1 +0,0 @@ -Don't include debug logs in `Clock` unless explicitly enabled. diff --git a/changelog.d/19279.feature b/changelog.d/19279.feature deleted file mode 100644 index 031e48dceb..0000000000 --- a/changelog.d/19279.feature +++ /dev/null @@ -1 +0,0 @@ -Implemented pagination for the [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666) mutual rooms endpoint. Contributed by @tulir @ Beeper. diff --git a/changelog.d/19281.feature b/changelog.d/19281.feature deleted file mode 100644 index 78d3002d90..0000000000 --- a/changelog.d/19281.feature +++ /dev/null @@ -1 +0,0 @@ -Admin API: add worker support to `GET /_synapse/admin/v2/users/`. diff --git a/changelog.d/19289.misc b/changelog.d/19289.misc deleted file mode 100644 index 4ad0dbc430..0000000000 --- a/changelog.d/19289.misc +++ /dev/null @@ -1 +0,0 @@ -Use `uv` to test olddeps to ensure all transitive dependencies use minimum versions. diff --git a/changelog.d/19291.misc b/changelog.d/19291.misc deleted file mode 100644 index bac12b8506..0000000000 --- a/changelog.d/19291.misc +++ /dev/null @@ -1 +0,0 @@ -Add a config to be able to rate limit search in the user directory. diff --git a/changelog.d/19297.misc b/changelog.d/19297.misc deleted file mode 100644 index aec97fd973..0000000000 --- a/changelog.d/19297.misc +++ /dev/null @@ -1 +0,0 @@ -Log the original bind exception when encountering `Failed to listen on 0.0.0.0, continuing because listening on [::]`. diff --git a/changelog.d/19300.feature b/changelog.d/19300.feature deleted file mode 100644 index 97e43e9b28..0000000000 --- a/changelog.d/19300.feature +++ /dev/null @@ -1 +0,0 @@ -Improve proxy support for the `federation_client.py` dev script. Contributed by Denis Kasak (@dkasak). diff --git a/changelog.d/19302.misc b/changelog.d/19302.misc deleted file mode 100644 index 606ab5b52d..0000000000 --- a/changelog.d/19302.misc +++ /dev/null @@ -1 +0,0 @@ -Unpin the version of Rust we use to build Synapse wheels (was 1.82.0) now that MacOS support has been dropped. \ No newline at end of file diff --git a/changelog.d/19323.misc b/changelog.d/19323.misc deleted file mode 100644 index 6699d7ea54..0000000000 --- a/changelog.d/19323.misc +++ /dev/null @@ -1 +0,0 @@ -Make it more clear how `shared_extra_conf` is combined in our Docker configuration scripts. diff --git a/changelog.d/19324.docker b/changelog.d/19324.docker deleted file mode 100644 index 52bf9cb7ae..0000000000 --- a/changelog.d/19324.docker +++ /dev/null @@ -1 +0,0 @@ -Add a way to expose metrics from the Docker image (`SYNAPSE_ENABLE_METRICS`). diff --git a/changelog.d/19326.misc b/changelog.d/19326.misc deleted file mode 100644 index 37493c7488..0000000000 --- a/changelog.d/19326.misc +++ /dev/null @@ -1 +0,0 @@ -Update CI to stream Complement progress and format logs in a separate step after all tests are done. diff --git a/changelog.d/19327.misc b/changelog.d/19327.misc deleted file mode 100644 index d61a66907e..0000000000 --- a/changelog.d/19327.misc +++ /dev/null @@ -1 +0,0 @@ -Format `.github/workflows/tests.yml`. diff --git a/changelog.d/19340.bugfix b/changelog.d/19340.bugfix deleted file mode 100644 index 38de156aa7..0000000000 --- a/changelog.d/19340.bugfix +++ /dev/null @@ -1 +0,0 @@ -Transform events with client metadata before serialising in /event response. \ No newline at end of file diff --git a/debian/changelog b/debian/changelog index 15ff7cbd9d..3b7d0b773e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +matrix-synapse-py3 (1.145.0~rc1) stable; urgency=medium + + * New Synapse release 1.145.0rc1. + + -- Synapse Packaging team Tue, 06 Jan 2026 09:29:39 -0700 + matrix-synapse-py3 (1.144.0) stable; urgency=medium * New Synapse release 1.144.0. diff --git a/pyproject.toml b/pyproject.toml index 09ca2a9e77..7aa5840a9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "matrix-synapse" -version = "1.144.0" +version = "1.145.0rc1" description = "Homeserver for the Matrix decentralised comms protocol" readme = "README.rst" authors = [ diff --git a/schema/synapse-config.schema.yaml b/schema/synapse-config.schema.yaml index ca8db9c9ee..3b58db6938 100644 --- a/schema/synapse-config.schema.yaml +++ b/schema/synapse-config.schema.yaml @@ -1,5 +1,5 @@ $schema: https://element-hq.github.io/synapse/latest/schema/v1/meta.schema.json -$id: https://element-hq.github.io/synapse/schema/synapse/v1.144/synapse-config.schema.json +$id: https://element-hq.github.io/synapse/schema/synapse/v1.145/synapse-config.schema.json type: object properties: modules: From d6d1404a8ee36501b733d780d44d91dbe42cd806 Mon Sep 17 00:00:00 2001 From: Devon Hudson Date: Tue, 6 Jan 2026 09:49:48 -0700 Subject: [PATCH 2/6] Add nifty titles to top level deprecations --- CHANGES.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 1f6ed01c20..d075da21c2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,12 @@ # Synapse 1.145.0rc1 (2026-01-06) -- Ubuntu 25.04 (Plucky Puffin) will be end of life on Jan 17, 2026. Synapse will stop building packages for Ubuntu 25.04 shortly thereafter. -- Remove the "Updates to locked dependencies" section from the changelog due to lack of use and the maintenance burden. ([\#19254](https://github.com/element-hq/synapse/issues/19254)) +## End of Life of Ubuntu 25.04 Plucky Puffin + +Ubuntu 25.04 (Plucky Puffin) will be end of life on Jan 17, 2026. Synapse will stop building packages for Ubuntu 25.04 shortly thereafter. + +## Updates to Locked Dependencies No Longer Included in Changelog + +The "Updates to locked dependencies" section has been removed from the changelog due to lack of use and the maintenance burden. ([\#19254](https://github.com/element-hq/synapse/issues/19254)) ## Features From 6ac61e4be494cb3467348882343dd19a0a249994 Mon Sep 17 00:00:00 2001 From: Devon Hudson Date: Tue, 6 Jan 2026 21:37:23 +0000 Subject: [PATCH 3/6] Revert "Add an Admin API endpoint for listing quarantined media (#19268)" (#19351) Fixes #19349 This reverts commit 3f636386a66cbc57a6a3c3e641dfd6f1917c838e (https://github.com/element-hq/synapse/pull/19268) as the DB migration was taking too long and blocking media access while it happened. See https://github.com/element-hq/synapse/issues/19349 for further information. ### 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: Travis Ralston --- changelog.d/19351.misc | 1 + docs/admin_api/media_admin_api.md | 27 ----- synapse/media/media_repository.py | 2 - synapse/rest/admin/media.py | 33 ------ .../databases/main/media_repository.py | 10 +- synapse/storage/databases/main/room.py | 70 ++---------- .../93/04_add_quarantined_ts_to_media.sql | 27 ----- tests/rest/admin/test_media.py | 106 ------------------ 8 files changed, 11 insertions(+), 265 deletions(-) create mode 100644 changelog.d/19351.misc delete mode 100644 synapse/storage/schema/main/delta/93/04_add_quarantined_ts_to_media.sql diff --git a/changelog.d/19351.misc b/changelog.d/19351.misc new file mode 100644 index 0000000000..5e186b9a0c --- /dev/null +++ b/changelog.d/19351.misc @@ -0,0 +1 @@ +Revert "Add an Admin API endpoint for listing quarantined media (#19268)". diff --git a/docs/admin_api/media_admin_api.md b/docs/admin_api/media_admin_api.md index 25481a8c55..6b96eb3356 100644 --- a/docs/admin_api/media_admin_api.md +++ b/docs/admin_api/media_admin_api.md @@ -73,33 +73,6 @@ Response: } ``` -## Listing all quarantined media - -This API returns a list of all quarantined media on the server. It is paginated, and can be scoped to either local or -remote media. Note that the pagination values are also scoped to the request parameters - changing them but keeping the -same pagination values will result in unexpected results. - -Request: -```http -GET /_synapse/admin/v1/media/quarantined?from=0&limit=100&kind=local -``` - -`from` and `limit` are optional parameters, and default to `0` and `100` respectively. They are the row index and number -of rows to return - they are not timestamps. - -`kind` *MUST* either be `local` or `remote`. - -The API returns a JSON body containing MXC URIs for the quarantined media, like the following: - -```json -{ - "media": [ - "mxc://localhost/xwvutsrqponmlkjihgfedcba", - "mxc://localhost/abcdefghijklmnopqrstuvwx" - ] -} -``` - # Quarantine media Quarantining media means that it is marked as inaccessible by users. It applies diff --git a/synapse/media/media_repository.py b/synapse/media/media_repository.py index cb745b96ad..8d38c1655f 100644 --- a/synapse/media/media_repository.py +++ b/synapse/media/media_repository.py @@ -928,7 +928,6 @@ class MediaRepository: filesystem_id=file_id, last_access_ts=time_now_ms, quarantined_by=None, - quarantined_ts=None, authenticated=authenticated, sha256=sha256writer.hexdigest(), ) @@ -1062,7 +1061,6 @@ class MediaRepository: filesystem_id=file_id, last_access_ts=time_now_ms, quarantined_by=None, - quarantined_ts=None, authenticated=authenticated, sha256=sha256writer.hexdigest(), ) diff --git a/synapse/rest/admin/media.py b/synapse/rest/admin/media.py index 4cfd9da0f9..d5346fe0d5 100644 --- a/synapse/rest/admin/media.py +++ b/synapse/rest/admin/media.py @@ -293,38 +293,6 @@ class ListMediaInRoom(RestServlet): return HTTPStatus.OK, {"local": local_mxcs, "remote": remote_mxcs} -class ListQuarantinedMedia(RestServlet): - """Lists all quarantined media on the server.""" - - PATTERNS = admin_patterns("/media/quarantined$") - - def __init__(self, hs: "HomeServer"): - self.store = hs.get_datastores().main - self.auth = hs.get_auth() - - async def on_GET( - self, - request: SynapseRequest, - ) -> tuple[int, JsonDict]: - await assert_requester_is_admin(self.auth, request) - - start = parse_integer(request, "from", default=0) - limit = parse_integer(request, "limit", default=100) - local_or_remote = parse_string(request, "kind", required=True) - - if local_or_remote not in ["local", "remote"]: - raise SynapseError( - HTTPStatus.BAD_REQUEST, - "Query parameter `kind` must be either 'local' or 'remote'.", - ) - - mxcs = await self.store.get_quarantined_media_mxcs( - start, limit, local_or_remote == "local" - ) - - return HTTPStatus.OK, {"media": mxcs} - - class PurgeMediaCacheRestServlet(RestServlet): PATTERNS = admin_patterns("/purge_media_cache$") @@ -564,7 +532,6 @@ def register_servlets_for_media_repo(hs: "HomeServer", http_server: HttpServer) ProtectMediaByID(hs).register(http_server) UnprotectMediaByID(hs).register(http_server) ListMediaInRoom(hs).register(http_server) - ListQuarantinedMedia(hs).register(http_server) # XXX DeleteMediaByDateSize must be registered before DeleteMediaByID as # their URL routes overlap. DeleteMediaByDateSize(hs).register(http_server) diff --git a/synapse/storage/databases/main/media_repository.py b/synapse/storage/databases/main/media_repository.py index c27c68fbc2..50664d63e5 100644 --- a/synapse/storage/databases/main/media_repository.py +++ b/synapse/storage/databases/main/media_repository.py @@ -61,7 +61,6 @@ class LocalMedia: url_cache: str | None last_access_ts: int quarantined_by: str | None - quarantined_ts: int | None safe_from_quarantine: bool user_id: str | None authenticated: bool | None @@ -79,7 +78,6 @@ class RemoteMedia: created_ts: int last_access_ts: int quarantined_by: str | None - quarantined_ts: int | None authenticated: bool | None sha256: str | None @@ -245,7 +243,6 @@ class MediaRepositoryStore(MediaRepositoryBackgroundUpdateStore): "user_id", "authenticated", "sha256", - "quarantined_ts", ), allow_none=True, desc="get_local_media", @@ -265,7 +262,6 @@ class MediaRepositoryStore(MediaRepositoryBackgroundUpdateStore): user_id=row[8], authenticated=row[9], sha256=row[10], - quarantined_ts=row[11], ) async def get_local_media_by_user_paginate( @@ -323,8 +319,7 @@ class MediaRepositoryStore(MediaRepositoryBackgroundUpdateStore): safe_from_quarantine, user_id, authenticated, - sha256, - quarantined_ts + sha256 FROM local_media_repository WHERE user_id = ? ORDER BY {order_by_column} {order}, media_id ASC @@ -350,7 +345,6 @@ class MediaRepositoryStore(MediaRepositoryBackgroundUpdateStore): user_id=row[9], authenticated=row[10], sha256=row[11], - quarantined_ts=row[12], ) for row in txn ] @@ -701,7 +695,6 @@ class MediaRepositoryStore(MediaRepositoryBackgroundUpdateStore): "quarantined_by", "authenticated", "sha256", - "quarantined_ts", ), allow_none=True, desc="get_cached_remote_media", @@ -720,7 +713,6 @@ class MediaRepositoryStore(MediaRepositoryBackgroundUpdateStore): quarantined_by=row[6], authenticated=row[7], sha256=row[8], - quarantined_ts=row[9], ) async def store_cached_remote_media( diff --git a/synapse/storage/databases/main/room.py b/synapse/storage/databases/main/room.py index 182e55743a..633df07736 100644 --- a/synapse/storage/databases/main/room.py +++ b/synapse/storage/databases/main/room.py @@ -945,50 +945,6 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): max_lifetime=max_lifetime, ) - async def get_quarantined_media_mxcs( - self, index_start: int, index_limit: int, local: bool - ) -> list[str]: - """Retrieves all the quarantined media MXC URIs starting from the given position, - ordered from oldest quarantined timestamp, then alphabetically by media ID - (including origin). - - Note that on established servers the "quarantined timestamp" may be zero due to - being introduced after the quarantine timestamp field was introduced. - - Args: - index_start: The position to start from. - index_limit: The maximum number of results to return. - local: When true, only local media will be returned. When false, only remote media will be returned. - - Returns: - The quarantined media as a list of media IDs. - """ - - def _get_quarantined_media_mxcs_txn( - txn: LoggingTransaction, - ) -> list[str]: - # We order by quarantined timestamp *and* media ID (including origin, when - # known) to ensure the ordering is stable for established servers. - if local: - sql = "SELECT '' as media_origin, media_id FROM local_media_repository WHERE quarantined_by IS NOT NULL ORDER BY quarantined_ts, media_id ASC LIMIT ? OFFSET ?" - else: - sql = "SELECT media_origin, media_id FROM remote_media_cache WHERE quarantined_by IS NOT NULL ORDER BY quarantined_ts, media_origin, media_id ASC LIMIT ? OFFSET ?" - txn.execute(sql, (index_limit, index_start)) - - mxcs = [] - - for media_origin, media_id in txn: - if local: - media_origin = self.hs.hostname - mxcs.append(f"mxc://{media_origin}/{media_id}") - - return mxcs - - return await self.db_pool.runInteraction( - "get_quarantined_media_mxcs", - _get_quarantined_media_mxcs_txn, - ) - async def get_media_mxcs_in_room(self, room_id: str) -> tuple[list[str], list[str]]: """Retrieves all the local and remote media MXC URIs in a given room @@ -996,7 +952,7 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): room_id Returns: - The local and remote media as lists of the media IDs. + The local and remote media as a lists of the media IDs. """ def _get_media_mxcs_in_room_txn( @@ -1191,10 +1147,6 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): The total number of media items quarantined """ total_media_quarantined = 0 - now_ts: int | None = self.clock.time_msec() - - if quarantined_by is None: - now_ts = None # Effectively a legacy path, update any media that was explicitly named. if media_ids: @@ -1203,13 +1155,13 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): ) sql = f""" UPDATE local_media_repository - SET quarantined_by = ?, quarantined_ts = ? + SET quarantined_by = ? WHERE {sql_many_clause_sql}""" if quarantined_by is not None: sql += " AND safe_from_quarantine = FALSE" - txn.execute(sql, [quarantined_by, now_ts] + sql_many_clause_args) + txn.execute(sql, [quarantined_by] + sql_many_clause_args) # Note that a rowcount of -1 can be used to indicate no rows were affected. total_media_quarantined += txn.rowcount if txn.rowcount > 0 else 0 @@ -1220,13 +1172,13 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): ) sql = f""" UPDATE local_media_repository - SET quarantined_by = ?, quarantined_ts = ? + SET quarantined_by = ? WHERE {sql_many_clause_sql}""" if quarantined_by is not None: sql += " AND safe_from_quarantine = FALSE" - txn.execute(sql, [quarantined_by, now_ts] + sql_many_clause_args) + txn.execute(sql, [quarantined_by] + sql_many_clause_args) total_media_quarantined += txn.rowcount if txn.rowcount > 0 else 0 return total_media_quarantined @@ -1250,10 +1202,6 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): The total number of media items quarantined """ total_media_quarantined = 0 - now_ts: int | None = self.clock.time_msec() - - if quarantined_by is None: - now_ts = None if media: sql_in_list_clause, sql_args = make_tuple_in_list_sql_clause( @@ -1263,10 +1211,10 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): ) sql = f""" UPDATE remote_media_cache - SET quarantined_by = ?, quarantined_ts = ? + SET quarantined_by = ? WHERE {sql_in_list_clause}""" - txn.execute(sql, [quarantined_by, now_ts] + sql_args) + txn.execute(sql, [quarantined_by] + sql_args) total_media_quarantined += txn.rowcount if txn.rowcount > 0 else 0 total_media_quarantined = 0 @@ -1276,9 +1224,9 @@ class RoomWorkerStore(CacheInvalidationWorkerStore): ) sql = f""" UPDATE remote_media_cache - SET quarantined_by = ?, quarantined_ts = ? + SET quarantined_by = ? WHERE {sql_many_clause_sql}""" - txn.execute(sql, [quarantined_by, now_ts] + sql_many_clause_args) + txn.execute(sql, [quarantined_by] + sql_many_clause_args) total_media_quarantined += txn.rowcount if txn.rowcount > 0 else 0 return total_media_quarantined diff --git a/synapse/storage/schema/main/delta/93/04_add_quarantined_ts_to_media.sql b/synapse/storage/schema/main/delta/93/04_add_quarantined_ts_to_media.sql deleted file mode 100644 index 18b76804ff..0000000000 --- a/synapse/storage/schema/main/delta/93/04_add_quarantined_ts_to_media.sql +++ /dev/null @@ -1,27 +0,0 @@ --- --- This file is licensed under the Affero General Public License (AGPL) version 3. --- --- Copyright (C) 2025 Element Creations, Ltd --- --- This program is free software: you can redistribute it and/or modify --- it under the terms of the GNU Affero General Public License as --- published by the Free Software Foundation, either version 3 of the --- License, or (at your option) any later version. --- --- See the GNU Affero General Public License for more details: --- . - --- Add a timestamp for when the sliding sync connection position was last used, --- only updated with a small granularity. --- --- This should be NOT NULL, but we need to consider existing rows. In future we --- may want to either backfill this or delete all rows with a NULL value (and --- then make it NOT NULL). -ALTER TABLE local_media_repository ADD COLUMN quarantined_ts BIGINT; -ALTER TABLE remote_media_cache ADD COLUMN quarantined_ts BIGINT; - -UPDATE local_media_repository SET quarantined_ts = 0 WHERE quarantined_by IS NOT NULL; -UPDATE remote_media_cache SET quarantined_ts = 0 WHERE quarantined_by IS NOT NULL; - --- Note: We *probably* should have an index on quarantined_ts, but we're going --- to try to defer that to a future migration after seeing the performance impact. diff --git a/tests/rest/admin/test_media.py b/tests/rest/admin/test_media.py index e45cc4d208..8cc54cc80c 100644 --- a/tests/rest/admin/test_media.py +++ b/tests/rest/admin/test_media.py @@ -756,112 +756,6 @@ class DeleteMediaByDateSizeTestCase(_AdminMediaTests): self.assertFalse(os.path.exists(local_path)) -class ListQuarantinedMediaTestCase(_AdminMediaTests): - def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: - self.store = hs.get_datastores().main - self.server_name = hs.hostname - - @parameterized.expand(["local", "remote"]) - def test_no_auth(self, kind: str) -> None: - """ - Try to list quarantined media without authentication. - """ - - channel = self.make_request( - "GET", - "/_synapse/admin/v1/media/quarantined?kind=%s" % (kind,), - ) - - self.assertEqual(401, channel.code, msg=channel.json_body) - self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"]) - - @parameterized.expand(["local", "remote"]) - def test_requester_is_not_admin(self, kind: str) -> None: - """ - If the user is not a server admin, an error is returned. - """ - self.other_user = self.register_user("user", "pass") - self.other_user_token = self.login("user", "pass") - - channel = self.make_request( - "GET", - "/_synapse/admin/v1/media/quarantined?kind=%s" % (kind,), - access_token=self.other_user_token, - ) - - self.assertEqual(403, channel.code, msg=channel.json_body) - self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"]) - - def test_list_quarantined_media(self) -> None: - """ - Ensure we actually get results for each page. We can't really test that - remote media is quarantined, but we can test that local media is. - """ - self.admin_user = self.register_user("admin", "pass", admin=True) - self.admin_user_tok = self.login("admin", "pass") - - def _upload() -> str: - return self.helper.upload_media( - SMALL_PNG, tok=self.admin_user_tok, expect_code=200 - )["content_uri"][6:].split("/")[1] # Cut off 'mxc://' and domain - - self.media_id_1 = _upload() - self.media_id_2 = _upload() - self.media_id_3 = _upload() - - def _quarantine(media_id: str) -> None: - channel = self.make_request( - "POST", - "/_synapse/admin/v1/media/quarantine/%s/%s" - % ( - self.server_name, - media_id, - ), - access_token=self.admin_user_tok, - ) - self.assertEqual(200, channel.code, msg=channel.json_body) - - _quarantine(self.media_id_1) - _quarantine(self.media_id_2) - _quarantine(self.media_id_3) - - # Page 1 - channel = self.make_request( - "GET", - "/_synapse/admin/v1/media/quarantined?kind=local&from=0&limit=1", - access_token=self.admin_user_tok, - ) - self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertEqual(1, len(channel.json_body["media"])) - - # Page 2 - channel = self.make_request( - "GET", - "/_synapse/admin/v1/media/quarantined?kind=local&from=1&limit=1", - access_token=self.admin_user_tok, - ) - self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertEqual(1, len(channel.json_body["media"])) - - # Page 3 - channel = self.make_request( - "GET", - "/_synapse/admin/v1/media/quarantined?kind=local&from=2&limit=1", - access_token=self.admin_user_tok, - ) - self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertEqual(1, len(channel.json_body["media"])) - - # Page 4 (no media) - channel = self.make_request( - "GET", - "/_synapse/admin/v1/media/quarantined?kind=local&from=3&limit=1", - access_token=self.admin_user_tok, - ) - self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertEqual(0, len(channel.json_body["media"])) - - class QuarantineMediaByIDTestCase(_AdminMediaTests): def upload_media_and_return_media_id(self, data: bytes) -> str: # Upload some media into the room From 16bc8c78ba14bfafcd21cc06489c4750b02fe56b Mon Sep 17 00:00:00 2001 From: Devon Hudson Date: Tue, 6 Jan 2026 14:49:09 -0700 Subject: [PATCH 4/6] Update changelog after reverting PR --- CHANGES.md | 1 - changelog.d/19351.misc | 1 - 2 files changed, 2 deletions(-) delete mode 100644 changelog.d/19351.misc diff --git a/CHANGES.md b/CHANGES.md index d075da21c2..8192a0c0ac 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,6 @@ The "Updates to locked dependencies" section has been removed from the changelog ## Features - Add `memberships` endpoint to the admin API. This is useful for forensics and T&S purpose. ([\#19260](https://github.com/element-hq/synapse/issues/19260)) -- Add an admin API for retrieving a paginated list of quarantined media. ([\#19268](https://github.com/element-hq/synapse/issues/19268)) - Server admins can bypass the quarantine media check when downloading media by setting the `admin_unsafely_bypass_quarantine` query parameter to `true` on Client-Server API media download requests. ([\#19275](https://github.com/element-hq/synapse/issues/19275)) - Implemented pagination for the [MSC2666](https://github.com/matrix-org/matrix-spec-proposals/pull/2666) mutual rooms endpoint. Contributed by @tulir @ Beeper. ([\#19279](https://github.com/element-hq/synapse/issues/19279)) - Admin API: add worker support to `GET /_synapse/admin/v2/users/`. ([\#19281](https://github.com/element-hq/synapse/issues/19281)) diff --git a/changelog.d/19351.misc b/changelog.d/19351.misc deleted file mode 100644 index 5e186b9a0c..0000000000 --- a/changelog.d/19351.misc +++ /dev/null @@ -1 +0,0 @@ -Revert "Add an Admin API endpoint for listing quarantined media (#19268)". From 13dff90b5bf94ae97644c0c8f19c444d4057d86b Mon Sep 17 00:00:00 2001 From: Devon Hudson Date: Wed, 7 Jan 2026 10:08:03 -0700 Subject: [PATCH 5/6] Fix sdist include formatting for maturin --- pyproject.toml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7aa5840a9d..026f3e5870 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -415,20 +415,22 @@ line-ending = "auto" manifest-path = "rust/Cargo.toml" module-name = "synapse.synapse_rust" python-source = "." -sdist-include = [ +include = [ "AUTHORS.rst", "book.toml", - "changelog.d", + "changelog.d/**/*", "CHANGES.md", "CONTRIBUTING.md", - "demo", - "docs", + "demo/**/*", + "docs/**/*", "INSTALL.md", + "LICENSE-AGPL-3.0", + "LICENSE-COMMERCIAL", "mypy.ini", - "scripts-dev", - "synmark", + "scripts-dev/**/*", + "synmark/**/*", "sytest-blacklist", - "tests", + "tests/**/*", "UPGRADE.rst", "Cargo.toml", "Cargo.lock", @@ -436,7 +438,7 @@ sdist-include = [ "rust/build.rs", "rust/src/**", ] -sdist-exclude = ["synapse/*.so"] +exclude = ["synapse/*.so"] [build-system] # The upper bounds here are defensive, intended to prevent situations like From ecd67df49d89b5efa413ca419def33f6c255312c Mon Sep 17 00:00:00 2001 From: Devon Hudson Date: Wed, 7 Jan 2026 10:11:44 -0700 Subject: [PATCH 6/6] 1.145.0rc2 --- CHANGES.md | 8 ++++++++ debian/changelog | 6 ++++++ pyproject.toml | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 8192a0c0ac..74a4c3d5e8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +# Synapse 1.145.0rc2 (2026-01-07) + +No significant changes since 1.145.0rc1. + +This RC fixes the source distribution packaging for uploading to PyPI. + + + # Synapse 1.145.0rc1 (2026-01-06) ## End of Life of Ubuntu 25.04 Plucky Puffin diff --git a/debian/changelog b/debian/changelog index 3b7d0b773e..b0870c798c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +matrix-synapse-py3 (1.145.0~rc2) stable; urgency=medium + + * New Synapse release 1.145.0rc2. + + -- Synapse Packaging team Wed, 07 Jan 2026 10:10:07 -0700 + matrix-synapse-py3 (1.145.0~rc1) stable; urgency=medium * New Synapse release 1.145.0rc1. diff --git a/pyproject.toml b/pyproject.toml index 026f3e5870..960d7891a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "matrix-synapse" -version = "1.145.0rc1" +version = "1.145.0rc2" description = "Homeserver for the Matrix decentralised comms protocol" readme = "README.rst" authors = [