Compare commits

...

37 Commits

Author SHA1 Message Date
Andrew Morgan
d3c904ab37 Merge branch 'develop' of github.com:element-hq/synapse into anoa/update_ci_rust 2025-07-02 19:17:24 +01:00
dependabot[bot]
87fc518e0c
Bump base64 from 0.21.7 to 0.22.1 (#18629)
Bumps [base64](https://github.com/marshallpierce/rust-base64) from
0.21.7 to 0.22.1.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md">base64's
changelog</a>.</em></p>
<blockquote>
<h1>0.22.1</h1>
<ul>
<li>Correct the symbols used for the predefined
<code>alphabet::BIN_HEX</code>.</li>
</ul>
<h1>0.22.0</h1>
<ul>
<li><code>DecodeSliceError::OutputSliceTooSmall</code> is now
conservative rather than precise. That is, the error will only occur if
the decoded output <em>cannot</em> fit, meaning that
<code>Engine::decode_slice</code> can now be used with exactly-sized
output slices. As part of this, <code>Engine::internal_decode</code> now
returns <code>DecodeSliceError</code> instead of
<code>DecodeError</code>, but that is not expected to affect any
external callers.</li>
<li><code>DecodeError::InvalidLength</code> now refers specifically to
the <em>number of valid symbols</em> being invalid (i.e. <code>len % 4
== 1</code>), rather than just the number of input bytes. This avoids
confusing scenarios when based on interpretation you could make a case
for either <code>InvalidLength</code> or <code>InvalidByte</code> being
appropriate.</li>
<li>Decoding is somewhat faster (5-10%)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e144006974"><code>e144006</code></a>
v0.22.1</li>
<li><a
href="64cca59ddb"><code>64cca59</code></a>
Merge pull request <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/271">#271</a>
from JobanSD/patch-1</li>
<li><a
href="838355e0ac"><code>838355e</code></a>
Correct BinHex 4.0 alphabet according to specifications</li>
<li><a
href="bf15ccf30a"><code>bf15ccf</code></a>
Merge pull request <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/270">#270</a>
from marshallpierce/mp/clippy</li>
<li><a
href="fc6aabee8a"><code>fc6aabe</code></a>
Appease clippy</li>
<li><a
href="9a518a2d5d"><code>9a518a2</code></a>
Merge pull request <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/267">#267</a>
from bdura/patch-1</li>
<li><a
href="d96c80f242"><code>d96c80f</code></a>
Merge branch 'marshallpierce:master' into patch-1</li>
<li><a
href="5d70ba7576"><code>5d70ba7</code></a>
Merge pull request <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/269">#269</a>
from marshallpierce/mp/decode-precisely</li>
<li><a
href="efb6c006c7"><code>efb6c00</code></a>
Release notes</li>
<li><a
href="2b91084a31"><code>2b91084</code></a>
Add some tests to boost coverage</li>
<li>Additional commits viewable in <a
href="https://github.com/marshallpierce/rust-base64/compare/v0.21.7...v0.22.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=base64&package-manager=cargo&previous-version=0.21.7&new-version=0.22.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 17:44:42 +00:00
dependabot[bot]
3bd476eb0d
Bump tokio from 1.45.1 to 1.46.0 (#18628)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.45.1 to 1.46.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/tokio-rs/tokio/releases">tokio's
releases</a>.</em></p>
<blockquote>
<h2>Tokio v1.46.0</h2>
<h1>1.46.0 (July 2nd, 2025)</h1>
<h3>Fixed</h3>
<ul>
<li>net: fixed <code>TcpStream::shutdown</code> incorrectly returning an
error on macOS (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7290">#7290</a>)</li>
</ul>
<h2>Added</h2>
<ul>
<li>sync: <code>mpsc::OwnedPermit::{same_channel,
same_channel_as_sender}</code> methods (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7389">#7389</a>)</li>
<li>macros: <code>biased</code> option for <code>join!</code> and
<code>try_join!</code>, similar to <code>select!</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7307">#7307</a>)</li>
<li>net: support for cygwin (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7393">#7393</a>)</li>
<li>net: support <code>pope::OpenOptions::read_write</code> on Android
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7426">#7426</a>)</li>
<li>net: add <code>Clone</code> implementation for
<code>net::unix::SocketAddr</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7422">#7422</a>)</li>
</ul>
<h2>Changed</h2>
<ul>
<li>runtime: eliminate unnecessary lfence while operating on
<code>queue::Local&lt;T&gt;</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7340">#7340</a>)</li>
<li>task: disallow blocking in <code>LocalSet::{poll,drop}</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7372">#7372</a>)</li>
</ul>
<h2>Unstable</h2>
<ul>
<li>runtime: add <code>TaskMeta::spawn_location</code> tracking where a
task was spawned (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7417">#7417</a>)</li>
<li>runtime: removed borrow from <code>LocalOptions</code> parameter to
<code>runtime::Builder::build_local</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7346">#7346</a>)</li>
</ul>
<h2>Documented</h2>
<ul>
<li>io: clarify behavior of seeking when <code>start_seek</code> is not
used (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7366">#7366</a>)</li>
<li>io: document cancellation safety of
<code>AsyncWriteExt::flush</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7364">#7364</a>)</li>
<li>net: fix docs for <code>recv_buffer_size</code> method (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7336">#7336</a>)</li>
<li>net: fix broken link of <code>RawFd</code> in <code>TcpSocket</code>
docs (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7416">#7416</a>)</li>
<li>net: update <code>AsRawFd</code> doc link to current Rust stdlib
location (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7429">#7429</a>)</li>
<li>readme: fix double period in reactor description (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7363">#7363</a>)</li>
<li>runtime: add doc note that <code>on_*_task_poll</code> is unstable
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7311">#7311</a>)</li>
<li>sync: update broadcast docs on allocation failure (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7352">#7352</a>)</li>
<li>time: add a missing panic scenario of <code>time::advance</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7394">#7394</a>)</li>
</ul>
<p><a
href="https://redirect.github.com/tokio-rs/tokio/issues/7290">#7290</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7290">tokio-rs/tokio#7290</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7307">#7307</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7307">tokio-rs/tokio#7307</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7311">#7311</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7311">tokio-rs/tokio#7311</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7336">#7336</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7336">tokio-rs/tokio#7336</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7340">#7340</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7340">tokio-rs/tokio#7340</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7346">#7346</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7346">tokio-rs/tokio#7346</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7352">#7352</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7352">tokio-rs/tokio#7352</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7363">#7363</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7363">tokio-rs/tokio#7363</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7364">#7364</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7364">tokio-rs/tokio#7364</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7366">#7366</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7366">tokio-rs/tokio#7366</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7372">#7372</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7372">tokio-rs/tokio#7372</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7389">#7389</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7389">tokio-rs/tokio#7389</a>
<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7393">#7393</a>:
<a
href="https://redirect.github.com/tokio-rs/tokio/pull/7393">tokio-rs/tokio#7393</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3f1f268583"><code>3f1f268</code></a>
chore: prepare Tokio v1.46.0 (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7437">#7437</a>)</li>
<li><a
href="3e890cc017"><code>3e890cc</code></a>
rt(unstable): add spawn <code>Location</code> to <code>TaskMeta</code>
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7417">#7417</a>)</li>
<li><a
href="69290a6432"><code>69290a6</code></a>
net: derive <code>Clone</code> for <code>net::unix::SocketAddr</code>
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7422">#7422</a>)</li>
<li><a
href="e2b175848b"><code>e2b1758</code></a>
fuzz: cfg fuzz tests under cfg(test) (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7428">#7428</a>)</li>
<li><a
href="b7a75b5be3"><code>b7a75b5</code></a>
net: update <code>AsRawFd</code> doc link to current Rust stdlib
location (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7429">#7429</a>)</li>
<li><a
href="6b705b3053"><code>6b705b3</code></a>
net: allow <code>pipe::OpenOptions::read_write</code> on Android (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7426">#7426</a>)</li>
<li><a
href="3636fd018a"><code>3636fd0</code></a>
net: fix broken link of <code>RawFd</code> in <code>TcpSocket</code>
docs (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7416">#7416</a>)</li>
<li><a
href="2506c9fa99"><code>2506c9f</code></a>
benches: revert &quot;properly gate unix benches&quot; (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7412">#7412</a>)</li>
<li><a
href="b3a14483bf"><code>b3a1448</code></a>
sync: improve docs of <code>tokio_util::sync::CancellationToken</code>
(<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7408">#7408</a>)</li>
<li><a
href="013f323def"><code>013f323</code></a>
docs: add a missing panic scenario of <code>time::advance</code> (<a
href="https://redirect.github.com/tokio-rs/tokio/issues/7394">#7394</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/tokio-rs/tokio/compare/tokio-1.45.1...tokio-1.46.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=tokio&package-manager=cargo&previous-version=1.45.1&new-version=1.46.0)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 17:44:22 +00:00
dependabot[bot]
717f67f3d3
Bump Swatinem/rust-cache from 2.7.8 to 2.8.0 (#18612)
Bumps [Swatinem/rust-cache](https://github.com/swatinem/rust-cache) from
2.7.8 to 2.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/swatinem/rust-cache/releases">Swatinem/rust-cache's
releases</a>.</em></p>
<blockquote>
<h2>v2.8.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add cache-workspace-crates feature by <a
href="https://github.com/jbransen"><code>@​jbransen</code></a> in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/246">Swatinem/rust-cache#246</a></li>
<li>Feat: support warpbuild cache provider by <a
href="https://github.com/stegaBOB"><code>@​stegaBOB</code></a> in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/247">Swatinem/rust-cache#247</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/jbransen"><code>@​jbransen</code></a>
made their first contribution in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/246">Swatinem/rust-cache#246</a></li>
<li><a href="https://github.com/stegaBOB"><code>@​stegaBOB</code></a>
made their first contribution in <a
href="https://redirect.github.com/Swatinem/rust-cache/pull/247">Swatinem/rust-cache#247</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/Swatinem/rust-cache/compare/v2.7.8...v2.8.0">https://github.com/Swatinem/rust-cache/compare/v2.7.8...v2.8.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Swatinem/rust-cache/blob/master/CHANGELOG.md">Swatinem/rust-cache's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>2.8.0</h2>
<ul>
<li>Add support for <code>warpbuild</code> cache provider</li>
<li>Add new <code>cache-workspace-crates</code> feature</li>
</ul>
<h2>2.7.8</h2>
<ul>
<li>Include CPU arch in the cache key</li>
</ul>
<h2>2.7.7</h2>
<ul>
<li>Also cache <code>cargo install</code> metadata</li>
</ul>
<h2>2.7.6</h2>
<ul>
<li>Allow opting out of caching $CARGO_HOME/bin</li>
<li>Add runner OS in cache key</li>
<li>Adds an option to do lookup-only of the cache</li>
</ul>
<h2>2.7.5</h2>
<ul>
<li>Support Cargo.lock format cargo-lock v4</li>
<li>Only run macOsWorkaround() on macOS</li>
</ul>
<h2>2.7.3</h2>
<ul>
<li>Work around upstream problem that causes cache saving to hang for
minutes.</li>
</ul>
<h2>2.7.2</h2>
<ul>
<li>Only key by <code>Cargo.toml</code> and <code>Cargo.lock</code>
files of workspace members.</li>
</ul>
<h2>2.7.1</h2>
<ul>
<li>Update toml parser to fix parsing errors.</li>
</ul>
<h2>2.7.0</h2>
<ul>
<li>Properly cache <code>trybuild</code> tests.</li>
</ul>
<h2>2.6.2</h2>
<ul>
<li>Fix <code>toml</code> parsing.</li>
</ul>
<h2>2.6.1</h2>
<ul>
<li>Fix hash contributions of
<code>Cargo.lock</code>/<code>Cargo.toml</code> files.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="98c8021b55"><code>98c8021</code></a>
2.8.0</li>
<li><a
href="14d3bc39c4"><code>14d3bc3</code></a>
update Changelog</li>
<li><a
href="52ea1434f8"><code>52ea143</code></a>
support warpbuild cache provider (<a
href="https://redirect.github.com/swatinem/rust-cache/issues/247">#247</a>)</li>
<li><a
href="eaa85be6b1"><code>eaa85be</code></a>
Add cache-workspace-crates feature (<a
href="https://redirect.github.com/swatinem/rust-cache/issues/246">#246</a>)</li>
<li><a
href="901019c0f8"><code>901019c</code></a>
Update the test lockfiles</li>
<li>See full diff in <a
href="9d47c6ad4b...98c8021b55">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Swatinem/rust-cache&package-manager=github_actions&previous-version=2.7.8&new-version=2.8.0)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 16:54:29 +00:00
dependabot[bot]
c2108948a3
Bump treq from 24.9.1 to 25.5.0 (#18610)
Bumps [treq](https://github.com/twisted/treq) from 24.9.1 to 25.5.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/twisted/treq/blob/trunk/CHANGELOG.rst">treq's
changelog</a>.</em></p>
<blockquote>
<h1>25.5.0 (2025-05-31)</h1>
<h2>Features</h2>
<ul>
<li>treq is packaged with Hatchling, and consequently no longer directly
depends on setuptools.
(<code>[#388](https://github.com/twisted/treq/issues/388)
&lt;https://github.com/twisted/treq/issues/388&gt;</code>__)</li>
</ul>
<h2>Improved Documentation</h2>
<ul>
<li>Update documentation to use <code>async</code>/<code>await</code>
syntax (<code>[#409](https://github.com/twisted/treq/issues/409)
&lt;https://github.com/twisted/treq/issues/409&gt;</code>__)</li>
</ul>
<h2>Deprecations and Removals</h2>
<ul>
<li>Support for Python 3.8, which has reached end of support, is
deprecated. This is the last release with support for Python 3.8.
(<code>[#407](https://github.com/twisted/treq/issues/407)
&lt;https://github.com/twisted/treq/issues/407&gt;</code>__)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="6869fa5d09"><code>6869fa5</code></a>
Merge pull request <a
href="https://redirect.github.com/twisted/treq/issues/410">#410</a> from
twisted/release-25.5.0</li>
<li><a
href="56266566cf"><code>5626656</code></a>
Test with Python 3.13 final</li>
<li><a
href="f10185e4da"><code>f10185e</code></a>
Generate the changelog</li>
<li><a
href="4b846664f1"><code>4b84666</code></a>
Version 25.5.0</li>
<li><a
href="72a4441f59"><code>72a4441</code></a>
Merge pull request <a
href="https://redirect.github.com/twisted/treq/issues/409">#409</a> from
twisted/rtd-shiny</li>
<li><a
href="0a814edd8a"><code>0a814ed</code></a>
Add changefragment</li>
<li><a
href="993cc47df5"><code>993cc47</code></a>
Fix changelog warnings</li>
<li><a
href="3992177456"><code>3992177</code></a>
Link to CookieJar</li>
<li><a
href="cff43d93b6"><code>cff43d9</code></a>
Update source_suffix conf</li>
<li><a
href="e39c8511b1"><code>e39c851</code></a>
async def print_response</li>
<li>Additional commits viewable in <a
href="https://github.com/twisted/treq/compare/treq-24.9.1...treq-25.5.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=treq&package-manager=pip&previous-version=24.9.1&new-version=25.5.0)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 16:51:43 +00:00
dependabot[bot]
cb4b5585a4
Bump prometheus-client from 0.21.0 to 0.22.1 (#18609)
Bumps [prometheus-client](https://github.com/prometheus/client_python)
from 0.21.0 to 0.22.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prometheus/client_python/releases">prometheus-client's
releases</a>.</em></p>
<blockquote>
<h2>v0.22.1</h2>
<h2>What's Changed</h2>
<ul>
<li>BugFix: Skip validating and parsing comment lines early (<a
href="https://redirect.github.com/prometheus/client_python/issues/1108">#1108</a>)
by <a href="https://github.com/wissamir"><code>@​wissamir</code></a> in
<a
href="https://redirect.github.com/prometheus/client_python/pull/1109">prometheus/client_python#1109</a></li>
<li>Use License Expressions in pyproject.toml by <a
href="https://github.com/csmarchbanks"><code>@​csmarchbanks</code></a>
in <a
href="https://redirect.github.com/prometheus/client_python/pull/1111">prometheus/client_python#1111</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/prometheus/client_python/compare/v0.22.0...v0.22.1">https://github.com/prometheus/client_python/compare/v0.22.0...v0.22.1</a></p>
<h2>v0.22.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add support for native histograms in OM parser by <a
href="https://github.com/vesari"><code>@​vesari</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1040">prometheus/client_python#1040</a></li>
<li>Add exemplar support to CounterMetricFamily [Fix <a
href="https://redirect.github.com/prometheus/client_python/issues/1062">#1062</a>]
by <a href="https://github.com/lod"><code>@​lod</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1063">prometheus/client_python#1063</a></li>
<li>Fix <code>write_to_textfile</code> leaves back temp files on errors
by <a href="https://github.com/ethanschen"><code>@​ethanschen</code></a>
in <a
href="https://redirect.github.com/prometheus/client_python/pull/1066">prometheus/client_python#1066</a></li>
<li>Support UTF-8 in metric creation, parsing, and exposition by <a
href="https://github.com/ywwg"><code>@​ywwg</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1070">prometheus/client_python#1070</a></li>
<li>Fix incorrect use of reentrant locks by <a
href="https://github.com/suligap"><code>@​suligap</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1076">prometheus/client_python#1076</a></li>
<li>Remove Python 3.8 support by <a
href="https://github.com/kajinamit"><code>@​kajinamit</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1075">prometheus/client_python#1075</a></li>
<li>Check if labelvalues is in _metrics before deletion in
MetricWrapperBase.remove() by <a
href="https://github.com/GlorifiedPig"><code>@​GlorifiedPig</code></a>
in <a
href="https://redirect.github.com/prometheus/client_python/pull/1077">prometheus/client_python#1077</a></li>
<li>Add support for Python 3.13 by <a
href="https://github.com/Pliner"><code>@​Pliner</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1080">prometheus/client_python#1080</a></li>
<li>Correct nh sample span structure and parsing by <a
href="https://github.com/vesari"><code>@​vesari</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1082">prometheus/client_python#1082</a></li>
<li>Migrate from setup.py to pyproject.toml by <a
href="https://github.com/csmarchbanks"><code>@​csmarchbanks</code></a>
in <a
href="https://redirect.github.com/prometheus/client_python/pull/1084">prometheus/client_python#1084</a></li>
<li>Changed pushgateway.md by <a
href="https://github.com/mallika-mur"><code>@​mallika-mur</code></a> in
<a
href="https://redirect.github.com/prometheus/client_python/pull/1083">prometheus/client_python#1083</a></li>
<li>Fix order-dependent flaky tests related to UTF-8 support by <a
href="https://github.com/dg98"><code>@​dg98</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1093">prometheus/client_python#1093</a></li>
<li>Update versions for docs Github actions by <a
href="https://github.com/csmarchbanks"><code>@​csmarchbanks</code></a>
in <a
href="https://redirect.github.com/prometheus/client_python/pull/1096">prometheus/client_python#1096</a></li>
<li>Documentation Updates by <a
href="https://github.com/ethanschen"><code>@​ethanschen</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1097">prometheus/client_python#1097</a></li>
<li>Add note on gauge.set_function not working with multiprocessing by
<a href="https://github.com/aapeliv"><code>@​aapeliv</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1098">prometheus/client_python#1098</a></li>
<li>Don't send an empty HTTP header for /favicon.ico by <a
href="https://github.com/noselasd"><code>@​noselasd</code></a> in <a
href="https://redirect.github.com/prometheus/client_python/pull/1101">prometheus/client_python#1101</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/prometheus/client_python/compare/v0.21.0...v0.22.0">https://github.com/prometheus/client_python/compare/v0.21.0...v0.22.0</a></p>
<h2>0.21.1 / 2024-12-03</h2>
<h2>What's Changed</h2>
<p>[BUGFIX] Revert incorrect use of reentrant locks. <a
href="https://redirect.github.com/prometheus/client_python/issues/1076">#1076</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d24220a6c4"><code>d24220a</code></a>
Release 0.22.1</li>
<li><a
href="f294cbbf1d"><code>f294cbb</code></a>
Use License Expressions in pyproject.toml (<a
href="https://redirect.github.com/prometheus/client_python/issues/1111">#1111</a>)</li>
<li><a
href="938b73e0bc"><code>938b73e</code></a>
BugFix: Skip validating and parsing comment lines early (<a
href="https://redirect.github.com/prometheus/client_python/issues/1108">#1108</a>)
(<a
href="https://redirect.github.com/prometheus/client_python/issues/1109">#1109</a>)</li>
<li><a
href="8dfa10e5ff"><code>8dfa10e</code></a>
Release 0.22.0</li>
<li><a
href="e3902ea45b"><code>e3902ea</code></a>
Don't send an empty HTTP header. (<a
href="https://redirect.github.com/prometheus/client_python/issues/1101">#1101</a>)</li>
<li><a
href="23ab8264ce"><code>23ab826</code></a>
Add note on gauge.set_function not working with mp, see <a
href="https://redirect.github.com/prometheus/client_python/issues/504">#504</a>
(<a
href="https://redirect.github.com/prometheus/client_python/issues/1098">#1098</a>)</li>
<li><a
href="c1ff3b28d3"><code>c1ff3b2</code></a>
Update docs (<a
href="https://redirect.github.com/prometheus/client_python/issues/1097">#1097</a>)</li>
<li><a
href="e3bfa1f101"><code>e3bfa1f</code></a>
Update versions for docs Github actions (<a
href="https://redirect.github.com/prometheus/client_python/issues/1096">#1096</a>)</li>
<li><a
href="de8bb4adf7"><code>de8bb4a</code></a>
Fix order-dependent flaky tests related to UTF-8 support (<a
href="https://redirect.github.com/prometheus/client_python/issues/1093">#1093</a>)</li>
<li><a
href="46eae7bae8"><code>46eae7b</code></a>
Changed pushgateway.md (<a
href="https://redirect.github.com/prometheus/client_python/issues/1083">#1083</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/prometheus/client_python/compare/v0.21.0...v0.22.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=prometheus-client&package-manager=pip&previous-version=0.21.0&new-version=0.22.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 16:39:13 +00:00
dependabot[bot]
a3ec2d3b3f
Bump pillow from 11.2.1 to 11.3.0 (#18624)
Bumps [pillow](https://github.com/python-pillow/Pillow) from 11.2.1 to
11.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/python-pillow/Pillow/releases">pillow's
releases</a>.</em></p>
<blockquote>
<h2>11.3.0</h2>
<p><a
href="https://pillow.readthedocs.io/en/stable/releasenotes/11.3.0.html">https://pillow.readthedocs.io/en/stable/releasenotes/11.3.0.html</a></p>
<h2>Deprecations</h2>
<ul>
<li>Deprecate fromarray mode argument <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9018">#9018</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Deprecate saving I mode images as PNG <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9023">#9023</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
</ul>
<h2>Documentation</h2>
<ul>
<li>Added release notes for <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9041">#9041</a>
<a
href="https://redirect.github.com/python-pillow/Pillow/issues/9042">#9042</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Add release notes for <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8912">#8912</a>
and <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8969">#8969</a>
<a
href="https://redirect.github.com/python-pillow/Pillow/issues/9019">#9019</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>ImageFont does not handle multiline text <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9000">#9000</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Updated Ubuntu CI targets <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8988">#8988</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Update MinGW package names <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8987">#8987</a>
[<a href="https://github.com/H4M5TER"><code>@​H4M5TER</code></a>]</li>
<li>Updated docstring <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8943">#8943</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Mention that tobytes() with the raw encoder uses Pack.c <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8878">#8878</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Refactor docs <code>Makefile</code> <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8933">#8933</a>
[<a href="https://github.com/hugovk"><code>@​hugovk</code></a>]</li>
<li>Add template for quarterly release issue <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8932">#8932</a>
[<a
href="https://github.com/aclark4life"><code>@​aclark4life</code></a>]</li>
<li>Add list of third party plugins <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8910">#8910</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Update redirected URL <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8919">#8919</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Docs: use sentence case for headers <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8914">#8914</a>
[<a href="https://github.com/hugovk"><code>@​hugovk</code></a>]</li>
<li>Docs: remove unused Makefile targets <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8917">#8917</a>
[<a href="https://github.com/hugovk"><code>@​hugovk</code></a>]</li>
<li>Remove indentation from lists <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8915">#8915</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Python 3.13 is tested on Arch <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8894">#8894</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Move XV Thumbnails to read only section <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8893">#8893</a>
[<a
href="https://github.com/aclark4life"><code>@​aclark4life</code></a>]</li>
<li>Updated macOS tested Pillow versions <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8890">#8890</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
</ul>
<h2>Dependencies</h2>
<ul>
<li>Add AVIF to wheels using only aomenc and dav1d AVIF codecs for
reduced size <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8858">#8858</a>
[<a href="https://github.com/fdintino"><code>@​fdintino</code></a>]</li>
<li>Use same AVIF URL when fetching dependency <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8871">#8871</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Update dependency mypy to v1.16.1 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9026">#9026</a>
[@<a href="https://github.com/apps/renovate">renovate[bot]</a>]</li>
<li>Update libpng to 1.6.49 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9014">#9014</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Update dependency cibuildwheel to v3 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9010">#9010</a>
[@<a href="https://github.com/apps/renovate">renovate[bot]</a>]</li>
<li>Updated libjpeg-turbo to 3.1.1 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9009">#9009</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Update dependency mypy to v1.16.0 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8991">#8991</a>
[@<a href="https://github.com/apps/renovate">renovate[bot]</a>]</li>
<li>Updated libpng to 1.6.48 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8940">#8940</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Updated Ghostscript to 10.5.1 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8939">#8939</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Updated harfbuzz to 11.2.1 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8937">#8937</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Updated libavif to 1.3.0 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8949">#8949</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Update dependency cibuildwheel to v2.23.3 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8931">#8931</a>
[@<a href="https://github.com/apps/renovate">renovate[bot]</a>]</li>
<li>Updated harfbuzz to 11.1.0 <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8904">#8904</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
</ul>
<h2>Testing</h2>
<ul>
<li>Add <code>match</code> parameter to <code>pytest.warns()</code> <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9038">#9038</a>
[<a href="https://github.com/hugovk"><code>@​hugovk</code></a>]</li>
<li>Increase pytest verbosity <a
href="https://redirect.github.com/python-pillow/Pillow/issues/9040">#9040</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Improve SgiImagePlugin test coverage <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8896">#8896</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
<li>Update ruff pre-commit ID <a
href="https://redirect.github.com/python-pillow/Pillow/issues/8994">#8994</a>
[<a
href="https://github.com/radarhere"><code>@​radarhere</code></a>]</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="89f1f4626a"><code>89f1f46</code></a>
11.3.0 version bump</li>
<li><a
href="f2de251c76"><code>f2de251</code></a>
Updated check script paths (<a
href="https://redirect.github.com/python-pillow/Pillow/issues/9052">#9052</a>)</li>
<li><a
href="84855d11c8"><code>84855d1</code></a>
Raise FileNotFoundError when opening an empty path (<a
href="https://redirect.github.com/python-pillow/Pillow/issues/9048">#9048</a>)</li>
<li><a
href="204d11d4da"><code>204d11d</code></a>
Raise FileNotFoundError when opening an empty path</li>
<li><a
href="2b39f7581e"><code>2b39f75</code></a>
Handle IPTC TIFF tags with incorrect type (<a
href="https://redirect.github.com/python-pillow/Pillow/issues/8925">#8925</a>)</li>
<li><a
href="e7a53ba19b"><code>e7a53ba</code></a>
Do not update palette for L mode GIF frame (<a
href="https://redirect.github.com/python-pillow/Pillow/issues/8924">#8924</a>)</li>
<li><a
href="c22230b761"><code>c22230b</code></a>
Use save parameters as encoderinfo defaults (<a
href="https://redirect.github.com/python-pillow/Pillow/issues/9001">#9001</a>)</li>
<li><a
href="da10ed1cf3"><code>da10ed1</code></a>
Add support for iOS (<a
href="https://redirect.github.com/python-pillow/Pillow/issues/9030">#9030</a>)</li>
<li><a
href="be2b4e7864"><code>be2b4e7</code></a>
Fix qtables and quality scaling (<a
href="https://redirect.github.com/python-pillow/Pillow/issues/8879">#8879</a>)</li>
<li><a
href="d4162f8505"><code>d4162f8</code></a>
Updated return type</li>
<li>Additional commits viewable in <a
href="https://github.com/python-pillow/Pillow/compare/11.2.1...11.3.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pillow&package-manager=pip&previous-version=11.2.1&new-version=11.3.0)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-07-02 18:29:37 +02:00
dependabot[bot]
81ca2923d1
Bump types-jsonschema from 4.23.0.20250516 to 4.24.0.20250528 (#18611)
Bumps
[types-jsonschema](https://github.com/typeshed-internal/stub_uploader)
from 4.23.0.20250516 to 4.24.0.20250528.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/typeshed-internal/stub_uploader/commits">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=types-jsonschema&package-manager=pip&previous-version=4.23.0.20250516&new-version=4.24.0.20250528)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 18:25:50 +02:00
dependabot[bot]
2372f3e6b7
Bump sigstore/cosign-installer from 3.9.0 to 3.9.1 (#18608)
Bumps
[sigstore/cosign-installer](https://github.com/sigstore/cosign-installer)
from 3.9.0 to 3.9.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sigstore/cosign-installer/releases">sigstore/cosign-installer's
releases</a>.</em></p>
<blockquote>
<h2>v3.9.1</h2>
<h2>What's Changed</h2>
<ul>
<li>default action install to use release v2.5.1 by <a
href="https://github.com/cpanato"><code>@​cpanato</code></a> in <a
href="https://redirect.github.com/sigstore/cosign-installer/pull/193">sigstore/cosign-installer#193</a></li>
<li>default cosign to v2.5.2 by <a
href="https://github.com/cpanato"><code>@​cpanato</code></a> in <a
href="https://redirect.github.com/sigstore/cosign-installer/pull/194">sigstore/cosign-installer#194</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/sigstore/cosign-installer/compare/v3.9.0...v3.9.1">https://github.com/sigstore/cosign-installer/compare/v3.9.0...v3.9.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="398d4b0eee"><code>398d4b0</code></a>
default cosign to v2.5.2 (<a
href="https://redirect.github.com/sigstore/cosign-installer/issues/194">#194</a>)</li>
<li><a
href="84f54a2bcd"><code>84f54a2</code></a>
default action install to use release v2.5.1 (<a
href="https://redirect.github.com/sigstore/cosign-installer/issues/193">#193</a>)</li>
<li>See full diff in <a
href="fb28c2b633...398d4b0eee">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sigstore/cosign-installer&package-manager=github_actions&previous-version=3.9.0&new-version=3.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 18:22:41 +02:00
dependabot[bot]
82757144e9
Bump stefanzweifel/git-auto-commit-action from 5.2.0 to 6.0.1 (#18607)
Bumps
[stefanzweifel/git-auto-commit-action](https://github.com/stefanzweifel/git-auto-commit-action)
from 5.2.0 to 6.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/stefanzweifel/git-auto-commit-action/releases">stefanzweifel/git-auto-commit-action's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.1</h2>
<h2>Fixed</h2>
<ul>
<li>Disable Check if Repo is in Detached State (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/379">#379</a>)
<a
href="https://github.com/@stefanzweifel"><code>@​stefanzweifel</code></a></li>
</ul>
<h2>v6.0.0</h2>
<h2>Added</h2>
<ul>
<li>Throw error early if repository is in a detached state (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/357">#357</a>)</li>
</ul>
<h2>Fixed</h2>
<ul>
<li>Fix PAT instructions with Dependabot (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/376">#376</a>)
<a
href="https://github.com/@Dreamsorcerer"><code>@​Dreamsorcerer</code></a></li>
</ul>
<h2>Removed</h2>
<ul>
<li>Remove support for <code>create_branch</code>,
<code>skip_checkout</code>, <code>skip_Fetch</code> (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/314">#314</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/stefanzweifel/git-auto-commit-action/blob/master/CHANGELOG.md">stefanzweifel/git-auto-commit-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>The format is based on <a
href="http://keepachangelog.com/en/1.0.0/">Keep a Changelog</a>
and this project adheres to <a
href="http://semver.org/spec/v2.0.0.html">Semantic Versioning</a>.</p>
<h2><a
href="https://github.com/stefanzweifel/git-auto-commit-action/compare/v6.0.1...HEAD">Unreleased</a></h2>
<blockquote>
<p>TBD</p>
</blockquote>
<h2><a
href="https://github.com/stefanzweifel/git-auto-commit-action/compare/v6.0.0...v6.0.1">v6.0.1</a>
- 2025-06-11</h2>
<h3>Fixed</h3>
<ul>
<li>Disable Check if Repo is in Detached State (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/379">#379</a>)
<a
href="https://github.com/@stefanzweifel"><code>@​stefanzweifel</code></a></li>
</ul>
<h2><a
href="https://github.com/stefanzweifel/git-auto-commit-action/compare/v5.2.0...v6.0.0">v6.0.0</a>
- 2025-06-10</h2>
<h3>Added</h3>
<ul>
<li>Throw error early if repository is in a detached state (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/357">#357</a>)</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fix PAT instructions with Dependabot (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/376">#376</a>)
<a
href="https://github.com/@Dreamsorcerer"><code>@​Dreamsorcerer</code></a></li>
</ul>
<h3>Removed</h3>
<ul>
<li>Remove support for <code>create_branch</code>,
<code>skip_checkout</code>, <code>skip_Fetch</code> (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/314">#314</a>)</li>
</ul>
<h2><a
href="https://github.com/stefanzweifel/git-auto-commit-action/compare/v5.1.0...v5.2.0">v5.2.0</a>
- 2025-04-19</h2>
<h3>Added</h3>
<ul>
<li>Add <code>create_git_tag_only</code> option to skip commiting and
always create a git-tag. (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/364">#364</a>)
<a href="https://github.com/@zMynxx"><code>@​zMynxx</code></a></li>
<li>Add Test for <code>create_git_tag_only</code> feature (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/367">#367</a>)
<a
href="https://github.com/@stefanzweifel"><code>@​stefanzweifel</code></a></li>
</ul>
<h3>Fixed</h3>
<ul>
<li>docs: Update README.md per <a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/issues/354">#354</a>
(<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/361">#361</a>)
<a href="https://github.com/@rasa"><code>@​rasa</code></a></li>
</ul>
<h2><a
href="https://github.com/stefanzweifel/git-auto-commit-action/compare/v5.0.1...v5.1.0">v5.1.0</a>
- 2025-01-11</h2>
<h3>Changed</h3>
<ul>
<li>Include <code>github.actor_id</code> in default
<code>commit_author</code> (<a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/pull/354">#354</a>)
<a
href="https://github.com/@parkerbxyz"><code>@​parkerbxyz</code></a></li>
</ul>
<h3>Fixed</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="778341af66"><code>778341a</code></a>
Merge pull request <a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/issues/379">#379</a>
from stefanzweifel/disable-detached-state-check</li>
<li><a
href="33b203d92a"><code>33b203d</code></a>
Disable Check if Repo is in Detached State</li>
<li><a
href="a82d80a75f"><code>a82d80a</code></a>
Update CHANGELOG</li>
<li><a
href="3cc016cfc8"><code>3cc016c</code></a>
Merge pull request <a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/issues/375">#375</a>
from stefanzweifel/v6-next</li>
<li><a
href="ddb7ae4159"><code>ddb7ae4</code></a>
Merge pull request <a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/issues/376">#376</a>
from Dreamsorcerer/patch-1</li>
<li><a
href="b001e5f0ff"><code>b001e5f</code></a>
Apply suggestions from code review</li>
<li><a
href="6494dc61d3"><code>6494dc6</code></a>
Fix PAT instructions with Dependabot</li>
<li><a
href="76180511d9"><code>7618051</code></a>
Add deprecated inputs to fix unbound variable issue</li>
<li><a
href="ae114628ea"><code>ae11462</code></a>
Merge pull request <a
href="https://redirect.github.com/stefanzweifel/git-auto-commit-action/issues/371">#371</a>
from stefanzweifel/dependabot/npm_and_yarn/bats-1.12.0</li>
<li><a
href="3058f91afb"><code>3058f91</code></a>
Bump bats from 1.11.1 to 1.12.0</li>
<li>Additional commits viewable in <a
href="b863ae1933...778341af66">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=stefanzweifel/git-auto-commit-action&package-manager=github_actions&previous-version=5.2.0&new-version=6.0.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-02 18:21:51 +02:00
Andrew Ferrazzutti
2f9c9d5eba
Forbid locked users from using POST /login (#18594)
Discussed in the [Synapse Dev
room](https://matrix.to/#/!vcyiEtMVHIhWXcJAfl:sw1v.org/$K4UojQtvaSpxSe35TWFXtKWGoAuHwHFcKo8qn2lwxSs?via=matrix.org&via=element.io&via=envs.net)

### 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))
2025-07-02 18:18:33 +02:00
V02460
6ddbb03612
Raise poetry-core version cap to 2.1.3 (#18575)
Request to raise the defensive version cap for poetry-core from 1.9.1 to
2.1.3.

My understanding is that the major version bump of poetry signals the
transition to standardized pyproject.toml metadata, but does not affect
backwards compatibility.

This is a subset of the changes in #18432

Fixes #18200

### 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))
2025-07-02 15:57:30 +00:00
Erik Johnston
cc8da2c5ed
Log the room ID we're purging state for (#18625)
So we can see what we're deleting.
2025-07-02 15:02:12 +01:00
reivilibre
c17fd947f3
Fix documentation of the Delete Room Admin API's status field. (#18519)
Fixes: #18502

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2025-07-01 17:55:38 +01:00
Quentin Gliech
24bcdb3f3c
Merge branch 'master' into develop 2025-07-01 17:37:49 +02:00
Quentin Gliech
e3ed93adf3
Add a note in the changelog about the manylinux wheels 2025-07-01 16:01:28 +02:00
Quentin Gliech
214ac2f005
1.133.0 2025-07-01 15:13:42 +02:00
Quentin Gliech
c471e84697
Bump cibuildwheel to 3.0.0 to fix the building of wheels (#18615)
Fixes https://github.com/element-hq/synapse/issues/18614

This upgrade CIBW to 3.0, which now builds using the manylinux_2_28
image, as the previous image is EOL and not supported by some of our
dependencies anymore.

This also updates the job to use the `ubuntu-24.04` base image instead
of `ubuntu-22.04`
2025-07-01 14:54:33 +02:00
Andrew Morgan
291880012f
Stop sending or processing the origin field in PDUs (#18418)
Co-authored-by: Quentin Gliech <quenting@element.io>
Co-authored-by: Eric Eastwood <erice@element.io>
2025-07-01 12:04:23 +01:00
Krishan
a2bee2f255
Add via param to hierarchy enpoint (#18070)
### Pull Request Checklist

Implementation of
[MSC4235](https://github.com/matrix-org/matrix-spec-proposals/pull/4235)
as per suggestion in [pull request
17750](https://github.com/element-hq/synapse/pull/17750#issuecomment-2411248598).

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

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

---------

Co-authored-by: Quentin Gliech <quenting@element.io>
2025-06-30 12:42:14 +00:00
Erik Johnston
3878699df7
Speed up device deletion (#18602)
This is to handle the case of deleting lots of "bot" devices at once.

Reviewable commit-by-commit

---------

Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-06-30 11:48:57 +01:00
Travis Ralston
b35c6483d5
Skip processing policy server events through policy server (#18605)
Co-authored-by: Andrew Morgan <andrew@amorgan.xyz>
2025-06-30 11:45:23 +01:00
reivilibre
bfb3a6e700
Improve performance of device deletion by adding missing index. (#18582)
<ol>
<li>

Reorder columns in `event_txn_id_device_id_txn_id` index \
This now satisfies the foreign key on `(user_id, device_id)` making
reverse lookups, as needed for device deletions, more efficient.

This improves device deletion performance by on the order of 8 to 10×
on matrix.org.


</li>
</ol>


Rationale:

## On the `event_txn_id_device_id` table:

We currently have this index:
```sql
-- This ensures that there is only one mapping per (room_id, user_id, device_id, txn_id) tuple.
CREATE UNIQUE INDEX IF NOT EXISTS event_txn_id_device_id_txn_id 
    ON event_txn_id_device_id(room_id, user_id, device_id, txn_id);
```

The main way we use this table is
```python
        return await self.db_pool.simple_select_one_onecol(
            table="event_txn_id_device_id",
            keyvalues={
                "room_id": room_id,
                "user_id": user_id,
                "device_id": device_id,
                "txn_id": txn_id,
            },
            retcol="event_id",
            allow_none=True,
            desc="get_event_id_from_transaction_id_and_device_id",
        )
```

But this foreign key is relatively unsupported, making deletions in
the devices table inefficient (full index scan on the above index):
```sql
    FOREIGN KEY (user_id, device_id)
        REFERENCES devices (user_id, device_id) ON DELETE CASCADE
```

I propose re-ordering the columns in that index to: `(user_id,
device_id, room_id, txn_id)` (by replacing it).

That way the foreign key back-check can rely on the prefix of this
index, but it's still useful for the original purpose it was made for.

It doesn't take any extra disk space and does not harm write performance
(because the same amount of writing work needs to be performed).

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2025-06-30 10:36:12 +01:00
reivilibre
8afea3d51d
Improve docstring on simple_upsert_many. (#18573)
It came up that this was somewhat confusing and an example might help.

So here's an example :)

---------

Signed-off-by: Olivier 'reivilibre <oliverw@matrix.org>
2025-06-30 10:35:23 +01:00
Johannes Marbach
db710cf29b
Add forget_forced_upon_leave capability as per MSC4267 (#18196)
This adds the capability from
https://github.com/matrix-org/matrix-spec-proposals/pull/4267 under an
experimental feature.

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2025-06-27 15:07:24 -05:00
Erik Johnston
de29c13d41
Fix backwards compat for DirectServeJsonResource (#18600)
As that appears in the module API.

Broke in #18595.
2025-06-26 14:05:48 +00:00
Tulir Asokan
434e38941a
Add federated_user_may_invite spam checker callback (#18241)
Co-authored-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2025-06-26 12:27:21 +01:00
dependabot[bot]
b1396475c4
Bump base64 from 0.21.7 to 0.22.1 (#18589)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-25 17:22:39 +01:00
dependabot[bot]
b088194f48
Bump docker/build-push-action from 6.17.0 to 6.18.0 (#18497)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-25 17:12:24 +01:00
dependabot[bot]
2f21b27465
Bump pyasn1-modules from 0.4.1 to 0.4.2 (#18495)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-25 17:00:19 +01:00
dependabot[bot]
3807fd42e1
Bump urllib3 from 2.2.2 to 2.5.0 (#18572) 2025-06-25 15:50:11 +01:00
dependabot[bot]
99474e7fdf
Bump sigstore/cosign-installer from 3.8.2 to 3.9.0 (#18588) 2025-06-25 15:49:25 +01:00
dependabot[bot]
ec13ed4169
Bump docker/setup-buildx-action from 3.10.0 to 3.11.1 (#18587) 2025-06-25 15:46:10 +01:00
dependabot[bot]
62b5b0b962
Bump reqwest from 0.12.15 to 0.12.20 (#18590) 2025-06-25 15:45:28 +01:00
Erik Johnston
0779587f9f
Lift pausing on ratelimited requests to http layer (#18595)
When a request gets ratelimited we (optionally) wait ~500ms before
returning to mitigate clients that like to tightloop on request
failures. However, this is currently implemented by pausing request
processing when we check for ratelimits, which might be deep within
request processing, and e.g. while locks are held. Instead, let's hoist
the pause to the very top of the HTTP handler.

Hopefully, this mitigates the issue where a user sending lots of events
to a single room can see their requests time out due to the combination
of the linearizer and the pausing of the request. Instead, they should
see the requests 429 after ~500ms.

The first commit is a refactor to pass the `Clock` to `AsyncResource`,
the second commit is the behavioural change.
2025-06-25 14:32:55 +00:00
Patrick Cloke
0c7d9919fa
Fix registering of background updates for split main/state db (#18509)
The background updates are being registered on an object that is for the
_state_ database, but the actual tables are on the _main_ database. This
just moves them to a different store that can access the right stuff.

I noticed this when trying to do a full schema dump cause I was curious
what has changed since the last one.

Fixes #16054

### 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))
2025-06-25 13:59:18 +01:00
dependabot[bot]
6fabf82f4f
Bump types-opentracing from 2.4.10.6 to 2.4.10.20250622 (#18586)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-24 17:30:36 +01:00
86 changed files with 988 additions and 511 deletions

View File

@ -24,13 +24,13 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- name: Inspect builder - name: Inspect builder
run: docker buildx inspect run: docker buildx inspect
- name: Install Cosign - name: Install Cosign
uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@ -72,7 +72,7 @@ jobs:
- name: Build and push all platforms - name: Build and push all platforms
id: build-and-push id: build-and-push
uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v6.17.0 uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with: with:
push: true push: true
labels: | labels: |

View File

@ -25,7 +25,7 @@ jobs:
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
components: clippy, rustfmt components: clippy, rustfmt
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: Setup Poetry - name: Setup Poetry
uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0 uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
@ -47,6 +47,6 @@ jobs:
- run: cargo fmt - run: cargo fmt
continue-on-error: true continue-on-error: true
- uses: stefanzweifel/git-auto-commit-action@b863ae1933cb653a53c021fe36dbb774e1fb9403 # v5.2.0 - uses: stefanzweifel/git-auto-commit-action@778341af668090896ca464160c2def5d1d1a3eb0 # v6.0.1
with: with:
commit_message: "Attempt to fix linting" commit_message: "Attempt to fix linting"

View File

@ -47,7 +47,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
# The dev dependencies aren't exposed in the wheel metadata (at least with current # The dev dependencies aren't exposed in the wheel metadata (at least with current
# poetry-core versions), so we install with poetry. # poetry-core versions), so we install with poetry.
@ -83,7 +83,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- run: sudo apt-get -qq install xmlsec1 - run: sudo apt-get -qq install xmlsec1
- name: Set up PostgreSQL ${{ matrix.postgres-version }} - name: Set up PostgreSQL ${{ matrix.postgres-version }}
@ -158,7 +158,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: Ensure sytest runs `pip install` - name: Ensure sytest runs `pip install`
# Delete the lockfile so sytest will `pip install` rather than `poetry install` # Delete the lockfile so sytest will `pip install` rather than `poetry install`

View File

@ -61,7 +61,7 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
with: with:
install: true install: true
@ -111,7 +111,7 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-22.04, macos-13] os: [ubuntu-24.04, macos-13]
arch: [x86_64, aarch64] arch: [x86_64, aarch64]
# is_pr is a flag used to exclude certain jobs from the matrix on PRs. # is_pr is a flag used to exclude certain jobs from the matrix on PRs.
# It is not read by the rest of the workflow. # It is not read by the rest of the workflow.
@ -139,7 +139,7 @@ jobs:
python-version: "3.x" python-version: "3.x"
- name: Install cibuildwheel - name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.23.0 run: python -m pip install cibuildwheel==3.0.0
- name: Set up QEMU to emulate aarch64 - name: Set up QEMU to emulate aarch64
if: matrix.arch == 'aarch64' if: matrix.arch == 'aarch64'

View File

@ -91,7 +91,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0 - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
with: with:
python-version: "3.x" python-version: "3.x"
@ -157,7 +157,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: Setup Poetry - name: Setup Poetry
uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0 uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
@ -220,7 +220,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0 - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
with: with:
poetry-version: "2.1.1" poetry-version: "2.1.1"
@ -240,7 +240,7 @@ jobs:
with: with:
components: clippy components: clippy
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- run: cargo clippy -- -D warnings - run: cargo clippy -- -D warnings
@ -259,7 +259,7 @@ jobs:
with: with:
toolchain: nightly-2025-04-23 toolchain: nightly-2025-04-23
components: clippy components: clippy
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- run: cargo clippy --all-features -- -D warnings - run: cargo clippy --all-features -- -D warnings
@ -277,7 +277,7 @@ jobs:
# We use nightly so that it correctly groups together imports # We use nightly so that it correctly groups together imports
toolchain: nightly-2025-04-23 toolchain: nightly-2025-04-23
components: rustfmt components: rustfmt
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- run: cargo fmt --check - run: cargo fmt --check
@ -375,7 +375,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0 - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
with: with:
@ -419,7 +419,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
# There aren't wheels for some of the older deps, so we need to install # There aren't wheels for some of the older deps, so we need to install
# their build dependencies # their build dependencies
@ -536,7 +536,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: Run SyTest - name: Run SyTest
run: /bootstrap.sh synapse run: /bootstrap.sh synapse
@ -682,7 +682,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: Prepare Complement's Prerequisites - name: Prepare Complement's Prerequisites
run: synapse/.ci/scripts/setup_complement_prerequisites.sh run: synapse/.ci/scripts/setup_complement_prerequisites.sh
@ -716,7 +716,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- run: cargo test - run: cargo test
@ -736,7 +736,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: nightly-2022-12-01 toolchain: nightly-2022-12-01
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- run: cargo bench --no-run - run: cargo bench --no-run

View File

@ -49,7 +49,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0 - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
with: with:
@ -77,7 +77,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0 - uses: matrix-org/setup-python-poetry@5bbf6603c5c930615ec8a29f1b5d7d258d905aa4 # v2.0.0
with: with:
@ -123,7 +123,7 @@ jobs:
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # master
with: with:
toolchain: ${{ env.RUST_VERSION }} toolchain: ${{ env.RUST_VERSION }}
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
- name: Patch dependencies - name: Patch dependencies
# Note: The poetry commands want to create a virtualenv in /src/.venv/, # Note: The poetry commands want to create a virtualenv in /src/.venv/,

View File

@ -1,3 +1,21 @@
# Synapse 1.133.0 (2025-07-01)
Pre-built wheels are now built using the [manylinux_2_28](https://github.com/pypa/manylinux#manylinux_2_28-almalinux-8-based) base, which is expected to be compatible with distros using glibc 2.28 or later, including:
- Debian 10+
- Ubuntu 18.10+
- Fedora 29+
- CentOS/RHEL 8+
Previously, wheels were built using the [manylinux2014](https://github.com/pypa/manylinux#manylinux2014-centos-7-based-glibc-217) base, which was expected to be compatible with distros using glibc 2.17 or later.
### Bugfixes
- Bump `cibuildwheel` to 3.0.0 to fix the `manylinux` wheel builds. ([\#18615](https://github.com/element-hq/synapse/issues/18615))
# Synapse 1.133.0rc1 (2025-06-24) # Synapse 1.133.0rc1 (2025-06-24)
### Features ### Features

207
Cargo.lock generated
View File

@ -62,15 +62,9 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
"object", "object",
"rustc-demangle", "rustc-demangle",
"windows-targets 0.52.6", "windows-targets",
] ]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.22.1" version = "0.22.1"
@ -331,7 +325,7 @@ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"wasi 0.13.3+wasi-0.2.2", "wasi 0.13.3+wasi-0.2.2",
"windows-targets 0.52.6", "windows-targets",
] ]
[[package]] [[package]]
@ -371,7 +365,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb"
dependencies = [ dependencies = [
"base64 0.22.1", "base64",
"bytes", "bytes",
"headers-core", "headers-core",
"http", "http",
@ -487,17 +481,21 @@ dependencies = [
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.11" version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
dependencies = [ dependencies = [
"base64",
"bytes", "bytes",
"futures-channel", "futures-channel",
"futures-core",
"futures-util", "futures-util",
"http", "http",
"http-body", "http-body",
"hyper", "hyper",
"ipnet",
"libc", "libc",
"percent-encoding",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio", "tokio",
@ -660,12 +658,33 @@ version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "io-uring"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
dependencies = [
"bitflags",
"cfg-if",
"libc",
]
[[package]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.11.0" version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
[[package]]
name = "iri-string"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.11" version = "1.0.11"
@ -1041,11 +1060,11 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.15" version = "0.12.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
dependencies = [ dependencies = [
"base64 0.22.1", "base64",
"bytes", "bytes",
"futures-core", "futures-core",
"futures-util", "futures-util",
@ -1056,17 +1075,13 @@ dependencies = [
"hyper", "hyper",
"hyper-rustls", "hyper-rustls",
"hyper-util", "hyper-util",
"ipnet",
"js-sys", "js-sys",
"log", "log",
"mime",
"once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"quinn", "quinn",
"rustls", "rustls",
"rustls-native-certs", "rustls-native-certs",
"rustls-pemfile",
"rustls-pki-types", "rustls-pki-types",
"serde", "serde",
"serde_json", "serde_json",
@ -1076,13 +1091,13 @@ dependencies = [
"tokio-rustls", "tokio-rustls",
"tokio-util", "tokio-util",
"tower", "tower",
"tower-http",
"tower-service", "tower-service",
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-streams", "wasm-streams",
"web-sys", "web-sys",
"windows-registry",
] ]
[[package]] [[package]]
@ -1137,15 +1152,6 @@ dependencies = [
"security-framework", "security-framework",
] ]
[[package]]
name = "rustls-pemfile"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [
"rustls-pki-types",
]
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.11.0" version = "1.11.0"
@ -1332,7 +1338,7 @@ name = "synapse"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.21.7", "base64",
"blake2", "blake2",
"bytes", "bytes",
"futures", "futures",
@ -1428,15 +1434,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.45.1" version = "1.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" checksum = "1140bb80481756a8cbe10541f37433b459c5aa1e727b4c020fbfebdc25bf3ec4"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",
"io-uring",
"libc", "libc",
"mio", "mio",
"pin-project-lite", "pin-project-lite",
"slab",
"socket2", "socket2",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@ -1479,6 +1487,24 @@ dependencies = [
"tower-service", "tower-service",
] ]
[[package]]
name = "tower-http"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
dependencies = [
"bitflags",
"bytes",
"futures-util",
"http",
"http-body",
"iri-string",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
]
[[package]] [[package]]
name = "tower-layer" name = "tower-layer"
version = "0.3.3" version = "0.3.3"
@ -1707,48 +1733,13 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "windows-link"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-registry"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [
"windows-result",
"windows-strings",
"windows-targets 0.53.0",
]
[[package]]
name = "windows-result"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
dependencies = [
"windows-link",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets 0.52.6", "windows-targets",
] ]
[[package]] [[package]]
@ -1757,7 +1748,7 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [ dependencies = [
"windows-targets 0.52.6", "windows-targets",
] ]
[[package]] [[package]]
@ -1766,30 +1757,14 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm 0.52.6", "windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.52.6", "windows_aarch64_msvc",
"windows_i686_gnu 0.52.6", "windows_i686_gnu",
"windows_i686_gnullvm 0.52.6", "windows_i686_gnullvm",
"windows_i686_msvc 0.52.6", "windows_i686_msvc",
"windows_x86_64_gnu 0.52.6", "windows_x86_64_gnu",
"windows_x86_64_gnullvm 0.52.6", "windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.52.6", "windows_x86_64_msvc",
]
[[package]]
name = "windows-targets"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
dependencies = [
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
"windows_i686_gnullvm 0.53.0",
"windows_i686_msvc 0.53.0",
"windows_x86_64_gnu 0.53.0",
"windows_x86_64_gnullvm 0.53.0",
"windows_x86_64_msvc 0.53.0",
] ]
[[package]] [[package]]
@ -1798,96 +1773,48 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
[[package]] [[package]]
name = "windows_i686_gnullvm" name = "windows_i686_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]] [[package]]
name = "wit-bindgen-rt" name = "wit-bindgen-rt"
version = "0.33.0" version = "0.33.0"

View File

@ -0,0 +1 @@
Support for [MSC4235](https://github.com/matrix-org/matrix-spec-proposals/pull/4235): via query param for hierarchy endpoint. Contributed by Krishan (@kfiven).

View File

@ -0,0 +1 @@
Add `forget_forced_upon_leave` capability as per [MSC4267](https://github.com/matrix-org/matrix-spec-proposals/pull/4267).

View File

@ -0,0 +1 @@
Add `federated_user_may_invite` spam checker callback which receives the entire invite event. Contributed by @tulir @ Beeper.

View File

@ -0,0 +1 @@
Stop adding the "origin" field to newly-created events (PDUs).

1
changelog.d/18509.bugfix Normal file
View File

@ -0,0 +1 @@
Fix `KeyError` on background updates when using split main/state databases.

1
changelog.d/18519.doc Normal file
View File

@ -0,0 +1 @@
Fix documentation of the Delete Room Admin API's status field.

1
changelog.d/18573.misc Normal file
View File

@ -0,0 +1 @@
Improve docstring on `simple_upsert_many`.

1
changelog.d/18575.misc Normal file
View File

@ -0,0 +1 @@
Raise poetry-core version cap to 2.1.3.

1
changelog.d/18582.bugfix Normal file
View File

@ -0,0 +1 @@
Improve performance of device deletion by adding missing index.

1
changelog.d/18594.bugfix Normal file
View File

@ -0,0 +1 @@
Respond with 401 & `M_USER_LOCKED` when a locked user calls `POST /login`, as per the spec.

1
changelog.d/18595.misc Normal file
View File

@ -0,0 +1 @@
Better handling of ratelimited requests.

1
changelog.d/18600.misc Normal file
View File

@ -0,0 +1 @@
Better handling of ratelimited requests.

1
changelog.d/18602.misc Normal file
View File

@ -0,0 +1 @@
Speed up bulk device deletion.

1
changelog.d/18605.bugfix Normal file
View File

@ -0,0 +1 @@
Ensure policy servers are not asked to scan policy server change events, allowing rooms to disable the use of a policy server while the policy server is down.

1
changelog.d/18625.misc Normal file
View File

@ -0,0 +1 @@
Log the room ID we're purging state for.

View File

@ -45,6 +45,10 @@ def make_graph(pdus: List[dict], filename_prefix: str) -> None:
colors = {"red", "green", "blue", "yellow", "purple"} colors = {"red", "green", "blue", "yellow", "purple"}
for pdu in pdus: for pdu in pdus:
# TODO: The "origin" field has since been removed from events generated
# by Synapse. We should consider removing it here as well but since this
# is part of `contrib/`, it is left for the community to revise and ensure things
# still work correctly.
origins.add(pdu.get("origin")) origins.add(pdu.get("origin"))
color_map = {color: color for color in colors if color in origins} color_map = {color: color for color in colors if color in origins}

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
matrix-synapse-py3 (1.133.0) stable; urgency=medium
* New synapse release 1.133.0.
-- Synapse Packaging team <packages@matrix.org> Tue, 01 Jul 2025 13:13:24 +0000
matrix-synapse-py3 (1.133.0~rc1) stable; urgency=medium matrix-synapse-py3 (1.133.0~rc1) stable; urgency=medium
* New Synapse release 1.133.0rc1. * New Synapse release 1.133.0rc1.

View File

@ -117,7 +117,6 @@ It returns a JSON body like the following:
"hashes": { "hashes": {
"sha256": "xK1//xnmvHJIOvbgXlkI8eEqdvoMmihVDJ9J4SNlsAw" "sha256": "xK1//xnmvHJIOvbgXlkI8eEqdvoMmihVDJ9J4SNlsAw"
}, },
"origin": "matrix.org",
"origin_server_ts": 1592291711430, "origin_server_ts": 1592291711430,
"prev_events": [ "prev_events": [
"$YK4arsKKcc0LRoe700pS8DSjOvUT4NDv0HfInlMFw2M" "$YK4arsKKcc0LRoe700pS8DSjOvUT4NDv0HfInlMFw2M"

View File

@ -806,7 +806,7 @@ A response body like the following is returned:
}, { }, {
"delete_id": "delete_id2", "delete_id": "delete_id2",
"room_id": "!roomid:example.com", "room_id": "!roomid:example.com",
"status": "purging", "status": "active",
"shutdown_room": { "shutdown_room": {
"kicked_users": [ "kicked_users": [
"@foobar:example.com" "@foobar:example.com"
@ -843,7 +843,7 @@ A response body like the following is returned:
```json ```json
{ {
"status": "purging", "status": "active",
"delete_id": "bHkCNQpHqOaFhPtK", "delete_id": "bHkCNQpHqOaFhPtK",
"room_id": "!roomid:example.com", "room_id": "!roomid:example.com",
"shutdown_room": { "shutdown_room": {
@ -876,8 +876,8 @@ The following fields are returned in the JSON response body:
- `delete_id` - The ID for this purge - `delete_id` - The ID for this purge
- `room_id` - The ID of the room being deleted - `room_id` - The ID of the room being deleted
- `status` - The status will be one of: - `status` - The status will be one of:
- `shutting_down` - The process is removing users from the room. - `scheduled` - The deletion is waiting to be started
- `purging` - The process is purging the room and event data from database. - `active` - The process is purging the room and event data from database.
- `complete` - The process has completed successfully. - `complete` - The process has completed successfully.
- `failed` - The process is aborted, an error has occurred. - `failed` - The process is aborted, an error has occurred.
- `error` - A string that shows an error message if `status` is `failed`. - `error` - A string that shows an error message if `status` is `failed`.

View File

@ -80,6 +80,8 @@ Called when processing an invitation, both when one is created locally or when
receiving an invite over federation. Both inviter and invitee are represented by receiving an invite over federation. Both inviter and invitee are represented by
their Matrix user ID (e.g. `@alice:example.com`). their Matrix user ID (e.g. `@alice:example.com`).
Note that federated invites will call `federated_user_may_invite` before this callback.
The callback must return one of: The callback must return one of:
- `synapse.module_api.NOT_SPAM`, to allow the operation. Other callbacks may still - `synapse.module_api.NOT_SPAM`, to allow the operation. Other callbacks may still
@ -97,6 +99,34 @@ be used. If this happens, Synapse will not call any of the subsequent implementa
this callback. this callback.
### `federated_user_may_invite`
_First introduced in Synapse v1.133.0_
```python
async def federated_user_may_invite(event: "synapse.events.EventBase") -> Union["synapse.module_api.NOT_SPAM", "synapse.module_api.errors.Codes", bool]
```
Called when processing an invitation received over federation. Unlike `user_may_invite`,
this callback receives the entire event, including any stripped state in the `unsigned`
section, not just the room and user IDs.
The callback must return one of:
- `synapse.module_api.NOT_SPAM`, to allow the operation. Other callbacks may still
decide to reject it.
- `synapse.module_api.errors.Codes` to reject the operation with an error code. In case
of doubt, `synapse.module_api.errors.Codes.FORBIDDEN` is a good error code.
If multiple modules implement this callback, they will be considered in order. If a
callback returns `synapse.module_api.NOT_SPAM`, Synapse falls through to the next one.
The value of the first callback that does not return `synapse.module_api.NOT_SPAM` will
be used. If this happens, Synapse will not call any of the subsequent implementations of
this callback.
If all of the callbacks return `synapse.module_api.NOT_SPAM`, Synapse will also fall
through to the `user_may_invite` callback before approving the invite.
### `user_may_send_3pid_invite` ### `user_may_send_3pid_invite`
_First introduced in Synapse v1.45.0_ _First introduced in Synapse v1.45.0_

291
poetry.lock generated
View File

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. # This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
[[package]] [[package]]
name = "annotated-types" name = "annotated-types"
@ -39,7 +39,7 @@ description = "The ultimate Python library in building OAuth and OpenID Connect
optional = true optional = true
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
markers = "extra == \"oidc\" or extra == \"jwt\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"jwt\" or extra == \"oidc\""
files = [ files = [
{file = "authlib-1.5.2-py2.py3-none-any.whl", hash = "sha256:8804dd4402ac5e4a0435ac49e0b6e19e395357cfa632a3f624dcb4f6df13b4b1"}, {file = "authlib-1.5.2-py2.py3-none-any.whl", hash = "sha256:8804dd4402ac5e4a0435ac49e0b6e19e395357cfa632a3f624dcb4f6df13b4b1"},
{file = "authlib-1.5.2.tar.gz", hash = "sha256:fe85ec7e50c5f86f1e2603518bb3b4f632985eb4a355e52256530790e326c512"}, {file = "authlib-1.5.2.tar.gz", hash = "sha256:fe85ec7e50c5f86f1e2603518bb3b4f632985eb4a355e52256530790e326c512"},
@ -450,7 +450,7 @@ description = "XML bomb protection for Python stdlib modules"
optional = true optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
groups = ["main"] groups = ["main"]
markers = "extra == \"saml2\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"saml2\""
files = [ files = [
{file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"},
{file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"},
@ -493,7 +493,7 @@ description = "XPath 1.0/2.0/3.0/3.1 parsers and selectors for ElementTree and l
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
groups = ["main"] groups = ["main"]
markers = "extra == \"saml2\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"saml2\""
files = [ files = [
{file = "elementpath-4.1.5-py3-none-any.whl", hash = "sha256:2ac1a2fb31eb22bbbf817f8cf6752f844513216263f0e3892c8e79782fe4bb55"}, {file = "elementpath-4.1.5-py3-none-any.whl", hash = "sha256:2ac1a2fb31eb22bbbf817f8cf6752f844513216263f0e3892c8e79782fe4bb55"},
{file = "elementpath-4.1.5.tar.gz", hash = "sha256:c2d6dc524b29ef751ecfc416b0627668119d8812441c555d7471da41d4bacb8d"}, {file = "elementpath-4.1.5.tar.gz", hash = "sha256:c2d6dc524b29ef751ecfc416b0627668119d8812441c555d7471da41d4bacb8d"},
@ -543,7 +543,7 @@ description = "Python wrapper for hiredis"
optional = true optional = true
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
markers = "extra == \"redis\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"redis\""
files = [ files = [
{file = "hiredis-3.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:2892db9db21f0cf7cc298d09f85d3e1f6dc4c4c24463ab67f79bc7a006d51867"}, {file = "hiredis-3.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:2892db9db21f0cf7cc298d09f85d3e1f6dc4c4c24463ab67f79bc7a006d51867"},
{file = "hiredis-3.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:93cfa6cc25ee2ceb0be81dc61eca9995160b9e16bdb7cca4a00607d57e998918"}, {file = "hiredis-3.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:93cfa6cc25ee2ceb0be81dc61eca9995160b9e16bdb7cca4a00607d57e998918"},
@ -889,7 +889,7 @@ description = "Jaeger Python OpenTracing Tracer implementation"
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
groups = ["main"] groups = ["main"]
markers = "extra == \"opentracing\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"opentracing\""
files = [ files = [
{file = "jaeger-client-4.8.0.tar.gz", hash = "sha256:3157836edab8e2c209bd2d6ae61113db36f7ee399e66b1dcbb715d87ab49bfe0"}, {file = "jaeger-client-4.8.0.tar.gz", hash = "sha256:3157836edab8e2c209bd2d6ae61113db36f7ee399e66b1dcbb715d87ab49bfe0"},
] ]
@ -1027,7 +1027,7 @@ description = "A strictly RFC 4510 conforming LDAP V3 pure Python client library
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"matrix-synapse-ldap3\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"matrix-synapse-ldap3\""
files = [ files = [
{file = "ldap3-2.9.1-py2.py3-none-any.whl", hash = "sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70"}, {file = "ldap3-2.9.1-py2.py3-none-any.whl", hash = "sha256:5869596fc4948797020d3f03b7939da938778a0f9e2009f7a072ccf92b8e8d70"},
{file = "ldap3-2.9.1.tar.gz", hash = "sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f"}, {file = "ldap3-2.9.1.tar.gz", hash = "sha256:f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f"},
@ -1043,7 +1043,7 @@ description = "Powerful and Pythonic XML processing library combining libxml2/li
optional = true optional = true
python-versions = ">=3.6" python-versions = ">=3.6"
groups = ["main"] groups = ["main"]
markers = "extra == \"url-preview\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"url-preview\""
files = [ files = [
{file = "lxml-5.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c"}, {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c"},
{file = "lxml-5.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7"}, {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7"},
@ -1323,7 +1323,7 @@ description = "An LDAP3 auth provider for Synapse"
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
groups = ["main"] groups = ["main"]
markers = "extra == \"matrix-synapse-ldap3\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"matrix-synapse-ldap3\""
files = [ files = [
{file = "matrix-synapse-ldap3-0.3.0.tar.gz", hash = "sha256:8bb6517173164d4b9cc44f49de411d8cebdb2e705d5dd1ea1f38733c4a009e1d"}, {file = "matrix-synapse-ldap3-0.3.0.tar.gz", hash = "sha256:8bb6517173164d4b9cc44f49de411d8cebdb2e705d5dd1ea1f38733c4a009e1d"},
{file = "matrix_synapse_ldap3-0.3.0-py3-none-any.whl", hash = "sha256:8b4d701f8702551e98cc1d8c20dbed532de5613584c08d0df22de376ba99159d"}, {file = "matrix_synapse_ldap3-0.3.0-py3-none-any.whl", hash = "sha256:8b4d701f8702551e98cc1d8c20dbed532de5613584c08d0df22de376ba99159d"},
@ -1436,6 +1436,22 @@ files = [
{file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"},
] ]
[[package]]
name = "multipart"
version = "1.2.1"
description = "Parser for multipart/form-data"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "multipart-1.2.1-py3-none-any.whl", hash = "sha256:c03dc203bc2e67f6b46a599467ae0d87cf71d7530504b2c1ff4a9ea21d8b8c8c"},
{file = "multipart-1.2.1.tar.gz", hash = "sha256:829b909b67bc1ad1c6d4488fcdc6391c2847842b08323addf5200db88dbe9480"},
]
[package.extras]
dev = ["build", "pytest", "pytest-cov", "twine"]
docs = ["sphinx (>=8,<9)", "sphinx-autobuild"]
[[package]] [[package]]
name = "mypy" name = "mypy"
version = "1.13.0" version = "1.13.0"
@ -1544,7 +1560,7 @@ description = "OpenTracing API for Python. See documentation at http://opentraci
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"opentracing\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"opentracing\""
files = [ files = [
{file = "opentracing-2.4.0.tar.gz", hash = "sha256:a173117e6ef580d55874734d1fa7ecb6f3655160b8b8974a2a1e98e5ec9c840d"}, {file = "opentracing-2.4.0.tar.gz", hash = "sha256:a173117e6ef580d55874734d1fa7ecb6f3655160b8b8974a2a1e98e5ec9c840d"},
] ]
@ -1593,114 +1609,119 @@ files = [
[[package]] [[package]]
name = "pillow" name = "pillow"
version = "11.2.1" version = "11.3.0"
description = "Python Imaging Library (Fork)" description = "Python Imaging Library (Fork)"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047"}, {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"},
{file = "pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95"}, {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"},
{file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61"}, {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"},
{file = "pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1"}, {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"},
{file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c"}, {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"},
{file = "pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d"}, {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"},
{file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97"}, {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"},
{file = "pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579"}, {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"},
{file = "pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d"}, {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"},
{file = "pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad"}, {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"},
{file = "pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2"}, {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"},
{file = "pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70"}, {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"},
{file = "pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf"}, {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"},
{file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7"}, {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"},
{file = "pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8"}, {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"},
{file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600"}, {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"},
{file = "pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788"}, {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"},
{file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e"}, {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"},
{file = "pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e"}, {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"},
{file = "pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6"}, {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"},
{file = "pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193"}, {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"},
{file = "pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7"}, {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"},
{file = "pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f"}, {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"},
{file = "pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b"}, {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"},
{file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d"}, {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"},
{file = "pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4"}, {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"},
{file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d"}, {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"},
{file = "pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4"}, {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"},
{file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443"}, {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"},
{file = "pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c"}, {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"},
{file = "pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3"}, {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"},
{file = "pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941"}, {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"},
{file = "pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb"}, {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"},
{file = "pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28"}, {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"},
{file = "pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830"}, {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"},
{file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0"}, {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"},
{file = "pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1"}, {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"},
{file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f"}, {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"},
{file = "pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155"}, {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"},
{file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14"}, {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"},
{file = "pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b"}, {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"},
{file = "pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2"}, {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"},
{file = "pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691"}, {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"},
{file = "pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c"}, {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"},
{file = "pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22"}, {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"},
{file = "pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7"}, {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"},
{file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16"}, {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"},
{file = "pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b"}, {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"},
{file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406"}, {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"},
{file = "pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91"}, {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"},
{file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751"}, {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"},
{file = "pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9"}, {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"},
{file = "pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd"}, {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"},
{file = "pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e"}, {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"},
{file = "pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681"}, {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"},
{file = "pillow-11.2.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:7491cf8a79b8eb867d419648fff2f83cb0b3891c8b36da92cc7f1931d46108c8"}, {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"},
{file = "pillow-11.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8b02d8f9cb83c52578a0b4beadba92e37d83a4ef11570a8688bbf43f4ca50909"}, {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"},
{file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:014ca0050c85003620526b0ac1ac53f56fc93af128f7546623cc8e31875ab928"}, {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"},
{file = "pillow-11.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3692b68c87096ac6308296d96354eddd25f98740c9d2ab54e1549d6c8aea9d79"}, {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"},
{file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:f781dcb0bc9929adc77bad571b8621ecb1e4cdef86e940fe2e5b5ee24fd33b35"}, {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"},
{file = "pillow-11.2.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:2b490402c96f907a166615e9a5afacf2519e28295f157ec3a2bb9bd57de638cb"}, {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"},
{file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dd6b20b93b3ccc9c1b597999209e4bc5cf2853f9ee66e3fc9a400a78733ffc9a"}, {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"},
{file = "pillow-11.2.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4b835d89c08a6c2ee7781b8dd0a30209a8012b5f09c0a665b65b0eb3560b6f36"}, {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"},
{file = "pillow-11.2.1-cp39-cp39-win32.whl", hash = "sha256:b10428b3416d4f9c61f94b494681280be7686bda15898a3a9e08eb66a6d92d67"}, {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"},
{file = "pillow-11.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:6ebce70c3f486acf7591a3d73431fa504a4e18a9b97ff27f5f47b7368e4b9dd1"}, {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"},
{file = "pillow-11.2.1-cp39-cp39-win_arm64.whl", hash = "sha256:c27476257b2fdcd7872d54cfd119b3a9ce4610fb85c8e32b70b42e3680a29a1e"}, {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"},
{file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156"}, {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"},
{file = "pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772"}, {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"},
{file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363"}, {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"},
{file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0"}, {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"},
{file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01"}, {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"},
{file = "pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193"}, {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"},
{file = "pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013"}, {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"},
{file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed"}, {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"},
{file = "pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c"}, {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"},
{file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd"}, {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"},
{file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076"}, {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"},
{file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b"}, {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"},
{file = "pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f"}, {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"},
{file = "pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044"}, {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"},
{file = "pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6"}, {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"},
{file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"},
] ]
[package.extras] [package.extras]
docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
fpx = ["olefile"] fpx = ["olefile"]
mic = ["olefile"] mic = ["olefile"]
test-arrow = ["pyarrow"] test-arrow = ["pyarrow"]
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
typing = ["typing-extensions ; python_version < \"3.10\""] typing = ["typing-extensions ; python_version < \"3.10\""]
xmp = ["defusedxml"] xmp = ["defusedxml"]
[[package]] [[package]]
name = "prometheus-client" name = "prometheus-client"
version = "0.21.0" version = "0.22.1"
description = "Python client for the Prometheus monitoring system." description = "Python client for the Prometheus monitoring system."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "prometheus_client-0.21.0-py3-none-any.whl", hash = "sha256:4fa6b4dd0ac16d58bb587c04b1caae65b8c5043e85f778f42f5f632f6af2e166"}, {file = "prometheus_client-0.22.1-py3-none-any.whl", hash = "sha256:cca895342e308174341b2cbf99a56bef291fbc0ef7b9e5412a0f26d653ba7094"},
{file = "prometheus_client-0.21.0.tar.gz", hash = "sha256:96c83c606b71ff2b0a433c98889d275f51ffec6c5e267de37c7a2b5c9aa9233e"}, {file = "prometheus_client-0.22.1.tar.gz", hash = "sha256:190f1331e783cf21eb60bca559354e0a4d4378facecf78f5428c39b675d20d28"},
] ]
[package.extras] [package.extras]
@ -1713,7 +1734,7 @@ description = "psycopg2 - Python-PostgreSQL Database Adapter"
optional = true optional = true
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
markers = "extra == \"postgres\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"postgres\""
files = [ files = [
{file = "psycopg2-2.9.10-cp310-cp310-win32.whl", hash = "sha256:5df2b672140f95adb453af93a7d669d7a7bf0a56bcd26f1502329166f4a61716"}, {file = "psycopg2-2.9.10-cp310-cp310-win32.whl", hash = "sha256:5df2b672140f95adb453af93a7d669d7a7bf0a56bcd26f1502329166f4a61716"},
{file = "psycopg2-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:c6f7b8561225f9e711a9c47087388a97fdc948211c10a4bccbf0ba68ab7b3b5a"}, {file = "psycopg2-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:c6f7b8561225f9e711a9c47087388a97fdc948211c10a4bccbf0ba68ab7b3b5a"},
@ -1721,6 +1742,7 @@ files = [
{file = "psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4"}, {file = "psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4"},
{file = "psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067"}, {file = "psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067"},
{file = "psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e"}, {file = "psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e"},
{file = "psycopg2-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:91fd603a2155da8d0cfcdbf8ab24a2d54bca72795b90d2a3ed2b6da8d979dee2"},
{file = "psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b"}, {file = "psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b"},
{file = "psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442"}, {file = "psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442"},
{file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"}, {file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"},
@ -1733,7 +1755,7 @@ description = ".. image:: https://travis-ci.org/chtd/psycopg2cffi.svg?branch=mas
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "platform_python_implementation == \"PyPy\" and (extra == \"postgres\" or extra == \"all\")" markers = "platform_python_implementation == \"PyPy\" and (extra == \"all\" or extra == \"postgres\")"
files = [ files = [
{file = "psycopg2cffi-2.9.0.tar.gz", hash = "sha256:7e272edcd837de3a1d12b62185eb85c45a19feda9e62fa1b120c54f9e8d35c52"}, {file = "psycopg2cffi-2.9.0.tar.gz", hash = "sha256:7e272edcd837de3a1d12b62185eb85c45a19feda9e62fa1b120c54f9e8d35c52"},
] ]
@ -1749,7 +1771,7 @@ description = "A Simple library to enable psycopg2 compatability"
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "platform_python_implementation == \"PyPy\" and (extra == \"postgres\" or extra == \"all\")" markers = "platform_python_implementation == \"PyPy\" and (extra == \"all\" or extra == \"postgres\")"
files = [ files = [
{file = "psycopg2cffi-compat-1.1.tar.gz", hash = "sha256:d25e921748475522b33d13420aad5c2831c743227dc1f1f2585e0fdb5c914e05"}, {file = "psycopg2cffi-compat-1.1.tar.gz", hash = "sha256:d25e921748475522b33d13420aad5c2831c743227dc1f1f2585e0fdb5c914e05"},
] ]
@ -1771,18 +1793,18 @@ files = [
[[package]] [[package]]
name = "pyasn1-modules" name = "pyasn1-modules"
version = "0.4.1" version = "0.4.2"
description = "A collection of ASN.1-based protocols modules" description = "A collection of ASN.1-based protocols modules"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"},
{file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"},
] ]
[package.dependencies] [package.dependencies]
pyasn1 = ">=0.4.6,<0.7.0" pyasn1 = ">=0.6.1,<0.7.0"
[[package]] [[package]]
name = "pycparser" name = "pycparser"
@ -1972,7 +1994,7 @@ description = "Python extension wrapping the ICU C++ API"
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"user-search\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"user-search\""
files = [ files = [
{file = "PyICU-2.14.tar.gz", hash = "sha256:acc7eb92bd5c554ed577249c6978450a4feda0aa6f01470152b3a7b382a02132"}, {file = "PyICU-2.14.tar.gz", hash = "sha256:acc7eb92bd5c554ed577249c6978450a4feda0aa6f01470152b3a7b382a02132"},
] ]
@ -2021,7 +2043,7 @@ description = "A development tool to measure, monitor and analyze the memory beh
optional = true optional = true
python-versions = ">=3.6" python-versions = ">=3.6"
groups = ["main"] groups = ["main"]
markers = "extra == \"cache-memory\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"cache-memory\""
files = [ files = [
{file = "Pympler-1.0.1-py3-none-any.whl", hash = "sha256:d260dda9ae781e1eab6ea15bacb84015849833ba5555f141d2d9b7b7473b307d"}, {file = "Pympler-1.0.1-py3-none-any.whl", hash = "sha256:d260dda9ae781e1eab6ea15bacb84015849833ba5555f141d2d9b7b7473b307d"},
{file = "Pympler-1.0.1.tar.gz", hash = "sha256:993f1a3599ca3f4fcd7160c7545ad06310c9e12f70174ae7ae8d4e25f6c5d3fa"}, {file = "Pympler-1.0.1.tar.gz", hash = "sha256:993f1a3599ca3f4fcd7160c7545ad06310c9e12f70174ae7ae8d4e25f6c5d3fa"},
@ -2081,7 +2103,7 @@ description = "Python implementation of SAML Version 2 Standard"
optional = true optional = true
python-versions = ">=3.9,<4.0" python-versions = ">=3.9,<4.0"
groups = ["main"] groups = ["main"]
markers = "extra == \"saml2\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"saml2\""
files = [ files = [
{file = "pysaml2-7.5.0-py3-none-any.whl", hash = "sha256:bc6627cc344476a83c757f440a73fda1369f13b6fda1b4e16bca63ffbabb5318"}, {file = "pysaml2-7.5.0-py3-none-any.whl", hash = "sha256:bc6627cc344476a83c757f440a73fda1369f13b6fda1b4e16bca63ffbabb5318"},
{file = "pysaml2-7.5.0.tar.gz", hash = "sha256:f36871d4e5ee857c6b85532e942550d2cf90ea4ee943d75eb681044bbc4f54f7"}, {file = "pysaml2-7.5.0.tar.gz", hash = "sha256:f36871d4e5ee857c6b85532e942550d2cf90ea4ee943d75eb681044bbc4f54f7"},
@ -2106,7 +2128,7 @@ description = "Extensions to the standard Python datetime module"
optional = true optional = true
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"] groups = ["main"]
markers = "extra == \"saml2\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"saml2\""
files = [ files = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
@ -2134,7 +2156,7 @@ description = "World timezone definitions, modern and historical"
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"saml2\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"saml2\""
files = [ files = [
{file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"},
{file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"},
@ -2498,7 +2520,7 @@ description = "Python client for Sentry (https://sentry.io)"
optional = true optional = true
python-versions = ">=3.6" python-versions = ">=3.6"
groups = ["main"] groups = ["main"]
markers = "extra == \"sentry\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"sentry\""
files = [ files = [
{file = "sentry_sdk-2.22.0-py2.py3-none-any.whl", hash = "sha256:3d791d631a6c97aad4da7074081a57073126c69487560c6f8bffcf586461de66"}, {file = "sentry_sdk-2.22.0-py2.py3-none-any.whl", hash = "sha256:3d791d631a6c97aad4da7074081a57073126c69487560c6f8bffcf586461de66"},
{file = "sentry_sdk-2.22.0.tar.gz", hash = "sha256:b4bf43bb38f547c84b2eadcefbe389b36ef75f3f38253d7a74d6b928c07ae944"}, {file = "sentry_sdk-2.22.0.tar.gz", hash = "sha256:b4bf43bb38f547c84b2eadcefbe389b36ef75f3f38253d7a74d6b928c07ae944"},
@ -2686,7 +2708,7 @@ description = "Tornado IOLoop Backed Concurrent Futures"
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"opentracing\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"opentracing\""
files = [ files = [
{file = "threadloop-1.0.2-py2-none-any.whl", hash = "sha256:5c90dbefab6ffbdba26afb4829d2a9df8275d13ac7dc58dccb0e279992679599"}, {file = "threadloop-1.0.2-py2-none-any.whl", hash = "sha256:5c90dbefab6ffbdba26afb4829d2a9df8275d13ac7dc58dccb0e279992679599"},
{file = "threadloop-1.0.2.tar.gz", hash = "sha256:8b180aac31013de13c2ad5c834819771992d350267bddb854613ae77ef571944"}, {file = "threadloop-1.0.2.tar.gz", hash = "sha256:8b180aac31013de13c2ad5c834819771992d350267bddb854613ae77ef571944"},
@ -2702,7 +2724,7 @@ description = "Python bindings for the Apache Thrift RPC system"
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"opentracing\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"opentracing\""
files = [ files = [
{file = "thrift-0.16.0.tar.gz", hash = "sha256:2b5b6488fcded21f9d312aa23c9ff6a0195d0f6ae26ddbd5ad9e3e25dfc14408"}, {file = "thrift-0.16.0.tar.gz", hash = "sha256:2b5b6488fcded21f9d312aa23c9ff6a0195d0f6ae26ddbd5ad9e3e25dfc14408"},
] ]
@ -2764,7 +2786,7 @@ description = "Tornado is a Python web framework and asynchronous networking lib
optional = true optional = true
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["main"] groups = ["main"]
markers = "extra == \"opentracing\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"opentracing\""
files = [ files = [
{file = "tornado-6.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:f81067dad2e4443b015368b24e802d0083fecada4f0a4572fdb72fc06e54a9a6"}, {file = "tornado-6.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:f81067dad2e4443b015368b24e802d0083fecada4f0a4572fdb72fc06e54a9a6"},
{file = "tornado-6.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ac1cbe1db860b3cbb251e795c701c41d343f06a96049d6274e7c77559117e41"}, {file = "tornado-6.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9ac1cbe1db860b3cbb251e795c701c41d343f06a96049d6274e7c77559117e41"},
@ -2804,27 +2826,28 @@ dev = ["furo (>=2024.05.06)", "nox", "packaging", "sphinx (>=5)", "twisted"]
[[package]] [[package]]
name = "treq" name = "treq"
version = "24.9.1" version = "25.5.0"
description = "High-level Twisted HTTP Client API" description = "High-level Twisted HTTP Client API"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8.0"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "treq-24.9.1-py3-none-any.whl", hash = "sha256:eee4756fd9a857c77f180fd5202b52c518f2d3e2826dce28b89066c03bfc45d0"}, {file = "treq-25.5.0-py3-none-any.whl", hash = "sha256:e99d4e66cacaa1f0da82bb60b317d104c29dbd8ac0a75d7f657b348178d830f4"},
{file = "treq-24.9.1.tar.gz", hash = "sha256:15da7fc404f3e4ed59d0abe5f8eef4966fabbe618039a2a23bc7c15305cefea8"}, {file = "treq-25.5.0.tar.gz", hash = "sha256:25dde3a55ae85ec2f2c56332c99aef255ab14f997d0d00552ebff13538a9804a"},
] ]
[package.dependencies] [package.dependencies]
attrs = "*" attrs = "*"
hyperlink = ">=21.0.0" hyperlink = ">=21.0.0"
incremental = "*" incremental = ">=24.7.2"
multipart = "*"
requests = ">=2.1.0" requests = ">=2.1.0"
Twisted = {version = ">=22.10.0", extras = ["tls"]} twisted = {version = ">=22.10.0", extras = ["tls"]}
typing-extensions = ">=3.10.0" typing-extensions = ">=3.10.0"
[package.extras] [package.extras]
dev = ["httpbin (==0.7.0)", "pep8", "pyflakes", "werkzeug (==2.0.3)"] dev = ["httpbin (==0.7.0)", "pep8", "pyflakes", "werkzeug (==2.0.3)"]
docs = ["sphinx (<7.0.0)"] docs = ["sphinx", "sphinx-rtd-theme"]
[[package]] [[package]]
name = "twine" name = "twine"
@ -2900,7 +2923,7 @@ description = "non-blocking redis client for python"
optional = true optional = true
python-versions = "*" python-versions = "*"
groups = ["main"] groups = ["main"]
markers = "extra == \"redis\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"redis\""
files = [ files = [
{file = "txredisapi-1.4.11-py3-none-any.whl", hash = "sha256:ac64d7a9342b58edca13ef267d4fa7637c1aa63f8595e066801c1e8b56b22d0b"}, {file = "txredisapi-1.4.11-py3-none-any.whl", hash = "sha256:ac64d7a9342b58edca13ef267d4fa7637c1aa63f8595e066801c1e8b56b22d0b"},
{file = "txredisapi-1.4.11.tar.gz", hash = "sha256:3eb1af99aefdefb59eb877b1dd08861efad60915e30ad5bf3d5bf6c5cedcdbc6"}, {file = "txredisapi-1.4.11.tar.gz", hash = "sha256:3eb1af99aefdefb59eb877b1dd08861efad60915e30ad5bf3d5bf6c5cedcdbc6"},
@ -2966,14 +2989,14 @@ files = [
[[package]] [[package]]
name = "types-jsonschema" name = "types-jsonschema"
version = "4.23.0.20250516" version = "4.24.0.20250528"
description = "Typing stubs for jsonschema" description = "Typing stubs for jsonschema"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "types_jsonschema-4.23.0.20250516-py3-none-any.whl", hash = "sha256:e7d0dd7db7e59e63c26e3230e26ffc64c4704cc5170dc21270b366a35ead1618"}, {file = "types_jsonschema-4.24.0.20250528-py3-none-any.whl", hash = "sha256:6a906b5ff73ac11c8d1e0b6c30a9693e1e4e1ab56c56c932b3a7e081b86d187b"},
{file = "types_jsonschema-4.23.0.20250516.tar.gz", hash = "sha256:9ace09d9d35c4390a7251ccd7d833b92ccc189d24d1b347f26212afce361117e"}, {file = "types_jsonschema-4.24.0.20250528.tar.gz", hash = "sha256:7e28c64e0ae7980eeb158105b20663fc6a6b8f81d5f86ea6614aa0014417bd1e"},
] ]
[package.dependencies] [package.dependencies]
@ -2993,14 +3016,14 @@ files = [
[[package]] [[package]]
name = "types-opentracing" name = "types-opentracing"
version = "2.4.10.6" version = "2.4.10.20250622"
description = "Typing stubs for opentracing" description = "Typing stubs for opentracing"
optional = false optional = false
python-versions = "*" python-versions = ">=3.9"
groups = ["dev"] groups = ["dev"]
files = [ files = [
{file = "types-opentracing-2.4.10.6.tar.gz", hash = "sha256:87a1bdfce9de5e555e30497663583b9b9c3bb494d029ef9806aa1f137c19e744"}, {file = "types_opentracing-2.4.10.20250622-py3-none-any.whl", hash = "sha256:26bc21f9e385d54898b47e9bd1fa13f200c2dada50394f6eafd063ed53813062"},
{file = "types_opentracing-2.4.10.6-py3-none-any.whl", hash = "sha256:25914c834db033a4a38fc322df0b5e5e14503b0ac97f78304ae180d721555e97"}, {file = "types_opentracing-2.4.10.20250622.tar.gz", hash = "sha256:00db48b7f57136c45ac3250218bd0f18b9792566dfcbd5ad1de9f7e180347e74"},
] ]
[[package]] [[package]]
@ -3123,14 +3146,14 @@ files = [
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "2.2.2" version = "2.5.0"
description = "HTTP library with thread-safe connection pooling, file post, and more." description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.9"
groups = ["main", "dev"] groups = ["main", "dev"]
files = [ files = [
{file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"},
{file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"},
] ]
[package.extras] [package.extras]
@ -3243,7 +3266,7 @@ description = "An XML Schema validator and decoder"
optional = true optional = true
python-versions = ">=3.7" python-versions = ">=3.7"
groups = ["main"] groups = ["main"]
markers = "extra == \"saml2\" or extra == \"all\"" markers = "extra == \"all\" or extra == \"saml2\""
files = [ files = [
{file = "xmlschema-2.4.0-py3-none-any.whl", hash = "sha256:dc87be0caaa61f42649899189aab2fd8e0d567f2cf548433ba7b79278d231a4a"}, {file = "xmlschema-2.4.0-py3-none-any.whl", hash = "sha256:dc87be0caaa61f42649899189aab2fd8e0d567f2cf548433ba7b79278d231a4a"},
{file = "xmlschema-2.4.0.tar.gz", hash = "sha256:d74cd0c10866ac609e1ef94a5a69b018ad16e39077bc6393408b40c6babee793"}, {file = "xmlschema-2.4.0.tar.gz", hash = "sha256:d74cd0c10866ac609e1ef94a5a69b018ad16e39077bc6393408b40c6babee793"},

View File

@ -101,7 +101,7 @@ module-name = "synapse.synapse_rust"
[tool.poetry] [tool.poetry]
name = "matrix-synapse" name = "matrix-synapse"
version = "1.133.0rc1" version = "1.133.0"
description = "Homeserver for the Matrix decentralised comms protocol" description = "Homeserver for the Matrix decentralised comms protocol"
authors = ["Matrix.org Team and Contributors <packages@matrix.org>"] authors = ["Matrix.org Team and Contributors <packages@matrix.org>"]
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
@ -374,7 +374,7 @@ tomli = ">=1.2.3"
# runtime errors caused by build system changes. # runtime errors caused by build system changes.
# We are happy to raise these upper bounds upon request, # We are happy to raise these upper bounds upon request,
# provided we check that it's safe to do so (i.e. that CI passes). # provided we check that it's safe to do so (i.e. that CI passes).
requires = ["poetry-core>=1.1.0,<=1.9.1", "setuptools_rust>=1.3,<=1.10.2"] requires = ["poetry-core>=1.1.0,<=2.1.3", "setuptools_rust>=1.3,<=1.10.2"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"

View File

@ -27,7 +27,7 @@ pub enum IdentifierError {
impl fmt::Display for IdentifierError { impl fmt::Display for IdentifierError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self) write!(f, "{self:?}")
} }
} }

View File

@ -29,6 +29,7 @@ from synapse.api.errors import (
InvalidClientTokenError, InvalidClientTokenError,
MissingClientTokenError, MissingClientTokenError,
UnrecognizedRequestError, UnrecognizedRequestError,
UserLockedError,
) )
from synapse.http.site import SynapseRequest from synapse.http.site import SynapseRequest
from synapse.logging.opentracing import active_span, force_tracing, start_active_span from synapse.logging.opentracing import active_span, force_tracing, start_active_span
@ -162,12 +163,7 @@ class InternalAuth(BaseAuth):
if not allow_locked and await self.store.get_user_locked_status( if not allow_locked and await self.store.get_user_locked_status(
requester.user.to_string() requester.user.to_string()
): ):
raise AuthError( raise UserLockedError()
401,
"User account has been locked",
errcode=Codes.USER_LOCKED,
additional_fields={"soft_logout": True},
)
# Deny the request if the user account has expired. # Deny the request if the user account has expired.
# This check is only done for regular users, not appservice ones. # This check is only done for regular users, not appservice ones.

View File

@ -306,6 +306,20 @@ class UserDeactivatedError(SynapseError):
) )
class UserLockedError(SynapseError):
"""The error returned to the client when the user attempted to access an
authenticated endpoint, but the account has been locked.
"""
def __init__(self) -> None:
super().__init__(
code=HTTPStatus.UNAUTHORIZED,
msg="User account has been locked",
errcode=Codes.USER_LOCKED,
additional_fields={"soft_logout": True},
)
class FederationDeniedError(SynapseError): class FederationDeniedError(SynapseError):
"""An error raised when the server tries to federate with a server which """An error raised when the server tries to federate with a server which
is not on its federation whitelist. is not on its federation whitelist.
@ -527,7 +541,11 @@ class InvalidCaptchaError(SynapseError):
class LimitExceededError(SynapseError): class LimitExceededError(SynapseError):
"""A client has sent too many requests and is being throttled.""" """A client has sent too many requests and is being throttled.
Args:
pause: Optional time in seconds to pause before responding to the client.
"""
def __init__( def __init__(
self, self,
@ -535,6 +553,7 @@ class LimitExceededError(SynapseError):
code: int = 429, code: int = 429,
retry_after_ms: Optional[int] = None, retry_after_ms: Optional[int] = None,
errcode: str = Codes.LIMIT_EXCEEDED, errcode: str = Codes.LIMIT_EXCEEDED,
pause: Optional[float] = None,
): ):
# Use HTTP header Retry-After to enable library-assisted retry handling. # Use HTTP header Retry-After to enable library-assisted retry handling.
headers = ( headers = (
@ -545,6 +564,7 @@ class LimitExceededError(SynapseError):
super().__init__(code, "Too Many Requests", errcode, headers=headers) super().__init__(code, "Too Many Requests", errcode, headers=headers)
self.retry_after_ms = retry_after_ms self.retry_after_ms = retry_after_ms
self.limiter_name = limiter_name self.limiter_name = limiter_name
self.pause = pause
def error_dict(self, config: Optional["HomeServerConfig"]) -> "JsonDict": def error_dict(self, config: Optional["HomeServerConfig"]) -> "JsonDict":
return cs_error(self.msg, self.errcode, retry_after_ms=self.retry_after_ms) return cs_error(self.msg, self.errcode, retry_after_ms=self.retry_after_ms)

View File

@ -338,12 +338,10 @@ class Ratelimiter:
) )
if not allowed: if not allowed:
if pause:
await self.clock.sleep(pause)
raise LimitExceededError( raise LimitExceededError(
limiter_name=self._limiter_name, limiter_name=self._limiter_name,
retry_after_ms=int(1000 * (time_allowed - time_now_s)), retry_after_ms=int(1000 * (time_allowed - time_now_s)),
pause=pause,
) )

View File

@ -561,11 +561,17 @@ class ExperimentalConfig(Config):
# MSC4076: Add `disable_badge_count`` to pusher configuration # MSC4076: Add `disable_badge_count`` to pusher configuration
self.msc4076_enabled: bool = experimental.get("msc4076_enabled", False) self.msc4076_enabled: bool = experimental.get("msc4076_enabled", False)
# MSC4235: Add `via` param to hierarchy endpoint
self.msc4235_enabled: bool = experimental.get("msc4235_enabled", False)
# MSC4263: Preventing MXID enumeration via key queries # MSC4263: Preventing MXID enumeration via key queries
self.msc4263_limit_key_queries_to_users_who_share_rooms = experimental.get( self.msc4263_limit_key_queries_to_users_who_share_rooms = experimental.get(
"msc4263_limit_key_queries_to_users_who_share_rooms", "msc4263_limit_key_queries_to_users_who_share_rooms",
False, False,
) )
# MSC4267: Automatically forgetting rooms on leave
self.msc4267_enabled: bool = experimental.get("msc4267_enabled", False)
# MSC4155: Invite filtering # MSC4155: Invite filtering
self.msc4155_enabled: bool = experimental.get("msc4155_enabled", False) self.msc4155_enabled: bool = experimental.get("msc4155_enabled", False)

View File

@ -85,4 +85,4 @@ class RoomConfig(Config):
# When enabled, users will forget rooms when they leave them, either via a # When enabled, users will forget rooms when they leave them, either via a
# leave, kick or ban. # leave, kick or ban.
self.forget_on_leave = config.get("forget_rooms_on_leave", False) self.forget_on_leave: bool = config.get("forget_rooms_on_leave", False)

View File

@ -208,7 +208,6 @@ class EventBase(metaclass=abc.ABCMeta):
depth: DictProperty[int] = DictProperty("depth") depth: DictProperty[int] = DictProperty("depth")
content: DictProperty[JsonDict] = DictProperty("content") content: DictProperty[JsonDict] = DictProperty("content")
hashes: DictProperty[Dict[str, str]] = DictProperty("hashes") hashes: DictProperty[Dict[str, str]] = DictProperty("hashes")
origin: DictProperty[str] = DictProperty("origin")
origin_server_ts: DictProperty[int] = DictProperty("origin_server_ts") origin_server_ts: DictProperty[int] = DictProperty("origin_server_ts")
room_id: DictProperty[str] = DictProperty("room_id") room_id: DictProperty[str] = DictProperty("room_id")
sender: DictProperty[str] = DictProperty("sender") sender: DictProperty[str] = DictProperty("sender")

View File

@ -302,8 +302,8 @@ def create_local_event_from_event_dict(
event_dict: JsonDict, event_dict: JsonDict,
internal_metadata_dict: Optional[JsonDict] = None, internal_metadata_dict: Optional[JsonDict] = None,
) -> EventBase: ) -> EventBase:
"""Takes a fully formed event dict, ensuring that fields like `origin` """Takes a fully formed event dict, ensuring that fields like
and `origin_server_ts` have correct values for a locally produced event, `origin_server_ts` have correct values for a locally produced event,
then signs and hashes it. then signs and hashes it.
""" """
@ -319,7 +319,6 @@ def create_local_event_from_event_dict(
if format_version == EventFormatVersions.ROOM_V1_V2: if format_version == EventFormatVersions.ROOM_V1_V2:
event_dict["event_id"] = _create_event_id(clock, hostname) event_dict["event_id"] = _create_event_id(clock, hostname)
event_dict["origin"] = hostname
event_dict.setdefault("origin_server_ts", time_now) event_dict.setdefault("origin_server_ts", time_now)
event_dict.setdefault("unsigned", {}) event_dict.setdefault("unsigned", {})

View File

@ -67,7 +67,6 @@ class EventValidator:
"auth_events", "auth_events",
"content", "content",
"hashes", "hashes",
"origin",
"prev_events", "prev_events",
"sender", "sender",
"type", "type",
@ -77,13 +76,6 @@ class EventValidator:
if k not in event: if k not in event:
raise SynapseError(400, "Event does not have key %s" % (k,)) raise SynapseError(400, "Event does not have key %s" % (k,))
# Check that the following keys have string values
event_strings = ["origin"]
for s in event_strings:
if not isinstance(getattr(event, s), str):
raise SynapseError(400, "'%s' not a string type" % (s,))
# Depending on the room version, ensure the data is spec compliant JSON. # Depending on the room version, ensure the data is spec compliant JSON.
if event.room_version.strict_canonicaljson: if event.room_version.strict_canonicaljson:
validate_canonicaljson(event.get_pdu_json()) validate_canonicaljson(event.get_pdu_json())

View File

@ -322,8 +322,7 @@ def event_from_pdu_json(pdu_json: JsonDict, room_version: RoomVersion) -> EventB
SynapseError: if the pdu is missing required fields or is otherwise SynapseError: if the pdu is missing required fields or is otherwise
not a valid matrix event not a valid matrix event
""" """
# we could probably enforce a bunch of other fields here (room_id, sender, # we could probably enforce a bunch of other fields here (room_id, sender, etc.)
# origin, etc etc)
assert_params_in_dict(pdu_json, ("type", "depth")) assert_params_in_dict(pdu_json, ("type", "depth"))
# Strip any unauthorized values from "unsigned" if they exist # Strip any unauthorized values from "unsigned" if they exist

View File

@ -76,7 +76,7 @@ from synapse.storage.databases.main.registration import (
LoginTokenLookupResult, LoginTokenLookupResult,
LoginTokenReused, LoginTokenReused,
) )
from synapse.types import JsonDict, Requester, UserID from synapse.types import JsonDict, Requester, StrCollection, UserID
from synapse.util import stringutils as stringutils from synapse.util import stringutils as stringutils
from synapse.util.async_helpers import delay_cancellation, maybe_awaitable from synapse.util.async_helpers import delay_cancellation, maybe_awaitable
from synapse.util.msisdn import phone_number_to_msisdn from synapse.util.msisdn import phone_number_to_msisdn
@ -1547,6 +1547,31 @@ class AuthHandler:
user_id, (token_id for _, token_id, _ in tokens_and_devices) user_id, (token_id for _, token_id, _ in tokens_and_devices)
) )
async def delete_access_tokens_for_devices(
self,
user_id: str,
device_ids: StrCollection,
) -> None:
"""Invalidate access tokens for the devices
Args:
user_id: ID of user the tokens belong to
device_ids: ID of device the tokens are associated with.
If None, tokens associated with any device (or no device) will
be deleted
"""
tokens_and_devices = await self.store.user_delete_access_tokens_for_devices(
user_id,
device_ids,
)
# see if any modules want to know about this
if self.password_auth_provider.on_logged_out_callbacks:
for token, _, device_id in tokens_and_devices:
await self.password_auth_provider.on_logged_out(
user_id=user_id, device_id=device_id, access_token=token
)
async def add_threepid( async def add_threepid(
self, user_id: str, medium: str, address: str, validated_at: int self, user_id: str, medium: str, address: str, validated_at: int
) -> None: ) -> None:

View File

@ -671,12 +671,12 @@ class DeviceHandler(DeviceWorkerHandler):
except_device_id: optional device id which should not be deleted except_device_id: optional device id which should not be deleted
""" """
device_map = await self.store.get_devices_by_user(user_id) device_map = await self.store.get_devices_by_user(user_id)
device_ids = list(device_map)
if except_device_id is not None: if except_device_id is not None:
device_ids = [d for d in device_ids if d != except_device_id] device_map.pop(except_device_id, None)
await self.delete_devices(user_id, device_ids) user_device_ids = device_map.keys()
await self.delete_devices(user_id, user_device_ids)
async def delete_devices(self, user_id: str, device_ids: List[str]) -> None: async def delete_devices(self, user_id: str, device_ids: StrCollection) -> None:
"""Delete several devices """Delete several devices
Args: Args:
@ -695,17 +695,10 @@ class DeviceHandler(DeviceWorkerHandler):
else: else:
raise raise
# Delete data specific to each device. Not optimised as it is not # Delete data specific to each device. Not optimised as its an
# considered as part of a critical path. # experimental MSC.
for device_id in device_ids:
await self._auth_handler.delete_access_tokens_for_user(
user_id, device_id=device_id
)
await self.store.delete_e2e_keys_by_device(
user_id=user_id, device_id=device_id
)
if self.hs.config.experimental.msc3890_enabled: if self.hs.config.experimental.msc3890_enabled:
for device_id in device_ids:
# Remove any local notification settings for this device in accordance # Remove any local notification settings for this device in accordance
# with MSC3890. # with MSC3890.
await self._account_data_handler.remove_account_data_for_user( await self._account_data_handler.remove_account_data_for_user(
@ -713,6 +706,13 @@ class DeviceHandler(DeviceWorkerHandler):
f"org.matrix.msc3890.local_notification_settings.{device_id}", f"org.matrix.msc3890.local_notification_settings.{device_id}",
) )
# If we're deleting a lot of devices, a bunch of them may not have any
# to-device messages queued up. We filter those out to avoid scheduling
# unnecessary tasks.
devices_with_messages = await self.store.get_devices_with_messages(
user_id, device_ids
)
for device_id in devices_with_messages:
# Delete device messages asynchronously and in batches using the task scheduler # Delete device messages asynchronously and in batches using the task scheduler
# We specify an upper stream id to avoid deleting non delivered messages # We specify an upper stream id to avoid deleting non delivered messages
# if an user re-uses a device ID. # if an user re-uses a device ID.
@ -726,6 +726,10 @@ class DeviceHandler(DeviceWorkerHandler):
}, },
) )
await self._auth_handler.delete_access_tokens_for_devices(
user_id, device_ids=device_ids
)
# Pushers are deleted after `delete_access_tokens_for_user` is called so that # Pushers are deleted after `delete_access_tokens_for_user` is called so that
# modules using `on_logged_out` hook can use them if needed. # modules using `on_logged_out` hook can use them if needed.
await self.hs.get_pusherpool().remove_pushers_by_devices(user_id, device_ids) await self.hs.get_pusherpool().remove_pushers_by_devices(user_id, device_ids)
@ -819,6 +823,7 @@ class DeviceHandler(DeviceWorkerHandler):
# This should only happen if there are no updates, so we bail. # This should only happen if there are no updates, so we bail.
return return
if logger.isEnabledFor(logging.DEBUG):
for device_id in device_ids: for device_id in device_ids:
logger.debug( logger.debug(
"Notifying about update %r/%r, ID: %r", user_id, device_id, position "Notifying about update %r/%r, ID: %r", user_id, device_id, position
@ -922,9 +927,6 @@ class DeviceHandler(DeviceWorkerHandler):
# can't call self.delete_device because that will clobber the # can't call self.delete_device because that will clobber the
# access token so call the storage layer directly # access token so call the storage layer directly
await self.store.delete_devices(user_id, [old_device_id]) await self.store.delete_devices(user_id, [old_device_id])
await self.store.delete_e2e_keys_by_device(
user_id=user_id, device_id=old_device_id
)
# tell everyone that the old device is gone and that the dehydrated # tell everyone that the old device is gone and that the dehydrated
# device has a new display name # device has a new display name
@ -946,7 +948,6 @@ class DeviceHandler(DeviceWorkerHandler):
raise errors.NotFoundError() raise errors.NotFoundError()
await self.delete_devices(user_id, [device_id]) await self.delete_devices(user_id, [device_id])
await self.store.delete_e2e_keys_by_device(user_id=user_id, device_id=device_id)
@wrap_as_background_process("_handle_new_device_update_async") @wrap_as_background_process("_handle_new_device_update_async")
async def _handle_new_device_update_async(self) -> None: async def _handle_new_device_update_async(self) -> None:

View File

@ -1062,8 +1062,8 @@ class FederationHandler:
if self.hs.config.server.block_non_admin_invites: if self.hs.config.server.block_non_admin_invites:
raise SynapseError(403, "This server does not accept room invites") raise SynapseError(403, "This server does not accept room invites")
spam_check = await self._spam_checker_module_callbacks.user_may_invite( spam_check = (
event.sender, event.state_key, event.room_id await self._spam_checker_module_callbacks.federated_user_may_invite(event)
) )
if spam_check != NOT_SPAM: if spam_check != NOT_SPAM:
raise SynapseError( raise SynapseError(

View File

@ -54,6 +54,9 @@ class RoomPolicyHandler:
Returns: Returns:
bool: True if the event is allowed in the room, False otherwise. bool: True if the event is allowed in the room, False otherwise.
""" """
if event.type == "org.matrix.msc4284.policy" and event.state_key is not None:
return True # always allow policy server change events
policy_event = await self._storage_controllers.state.get_current_state_event( policy_event = await self._storage_controllers.state.get_current_state_event(
event.room_id, "org.matrix.msc4284.policy", "" event.room_id, "org.matrix.msc4284.policy", ""
) )

View File

@ -111,7 +111,15 @@ class RoomSummaryHandler:
# If a user tries to fetch the same page multiple times in quick succession, # If a user tries to fetch the same page multiple times in quick succession,
# only process the first attempt and return its result to subsequent requests. # only process the first attempt and return its result to subsequent requests.
self._pagination_response_cache: ResponseCache[ self._pagination_response_cache: ResponseCache[
Tuple[str, str, bool, Optional[int], Optional[int], Optional[str]] Tuple[
str,
str,
bool,
Optional[int],
Optional[int],
Optional[str],
Optional[Tuple[str, ...]],
]
] = ResponseCache( ] = ResponseCache(
hs.get_clock(), hs.get_clock(),
"get_room_hierarchy", "get_room_hierarchy",
@ -126,6 +134,7 @@ class RoomSummaryHandler:
max_depth: Optional[int] = None, max_depth: Optional[int] = None,
limit: Optional[int] = None, limit: Optional[int] = None,
from_token: Optional[str] = None, from_token: Optional[str] = None,
remote_room_hosts: Optional[Tuple[str, ...]] = None,
) -> JsonDict: ) -> JsonDict:
""" """
Implementation of the room hierarchy C-S API. Implementation of the room hierarchy C-S API.
@ -143,6 +152,9 @@ class RoomSummaryHandler:
limit: An optional limit on the number of rooms to return per limit: An optional limit on the number of rooms to return per
page. Must be a positive integer. page. Must be a positive integer.
from_token: An optional pagination token. from_token: An optional pagination token.
remote_room_hosts: An optional list of remote homeserver server names. If defined,
each host will be used to try and fetch the room hierarchy. Must be a tuple so
that it can be hashed by the `RoomSummaryHandler._pagination_response_cache`.
Returns: Returns:
The JSON hierarchy dictionary. The JSON hierarchy dictionary.
@ -162,6 +174,7 @@ class RoomSummaryHandler:
max_depth, max_depth,
limit, limit,
from_token, from_token,
remote_room_hosts,
), ),
self._get_room_hierarchy, self._get_room_hierarchy,
requester.user.to_string(), requester.user.to_string(),
@ -170,6 +183,7 @@ class RoomSummaryHandler:
max_depth, max_depth,
limit, limit,
from_token, from_token,
remote_room_hosts,
) )
async def _get_room_hierarchy( async def _get_room_hierarchy(
@ -180,6 +194,7 @@ class RoomSummaryHandler:
max_depth: Optional[int] = None, max_depth: Optional[int] = None,
limit: Optional[int] = None, limit: Optional[int] = None,
from_token: Optional[str] = None, from_token: Optional[str] = None,
remote_room_hosts: Optional[Tuple[str, ...]] = None,
) -> JsonDict: ) -> JsonDict:
"""See docstring for SpaceSummaryHandler.get_room_hierarchy.""" """See docstring for SpaceSummaryHandler.get_room_hierarchy."""
@ -199,7 +214,7 @@ class RoomSummaryHandler:
if not local_room: if not local_room:
room_hierarchy = await self._summarize_remote_room_hierarchy( room_hierarchy = await self._summarize_remote_room_hierarchy(
_RoomQueueEntry(requested_room_id, ()), _RoomQueueEntry(requested_room_id, remote_room_hosts or ()),
False, False,
) )
root_room_entry = room_hierarchy[0] root_room_entry = room_hierarchy[0]
@ -240,7 +255,7 @@ class RoomSummaryHandler:
processed_rooms = set(pagination_session["processed_rooms"]) processed_rooms = set(pagination_session["processed_rooms"])
else: else:
# The queue of rooms to process, the next room is last on the stack. # The queue of rooms to process, the next room is last on the stack.
room_queue = [_RoomQueueEntry(requested_room_id, ())] room_queue = [_RoomQueueEntry(requested_room_id, remote_room_hosts or ())]
# Rooms we have already processed. # Rooms we have already processed.
processed_rooms = set() processed_rooms = set()

View File

@ -53,7 +53,7 @@ class AdditionalResource(DirectServeJsonResource):
hs: homeserver hs: homeserver
handler: function to be called to handle the request. handler: function to be called to handle the request.
""" """
super().__init__() super().__init__(clock=hs.get_clock())
self._handler = handler self._handler = handler
async def _async_render(self, request: Request) -> Optional[Tuple[int, Any]]: async def _async_render(self, request: Request) -> Optional[Tuple[int, Any]]:

View File

@ -106,7 +106,7 @@ class ProxyResource(_AsyncResource):
isLeaf = True isLeaf = True
def __init__(self, reactor: ISynapseReactor, hs: "HomeServer"): def __init__(self, reactor: ISynapseReactor, hs: "HomeServer"):
super().__init__(True) super().__init__(hs.get_clock(), True)
self.reactor = reactor self.reactor = reactor
self.agent = hs.get_federation_http_client().agent self.agent = hs.get_federation_http_client().agent

View File

@ -42,6 +42,7 @@ from typing import (
Protocol, Protocol,
Tuple, Tuple,
Union, Union,
cast,
) )
import attr import attr
@ -49,8 +50,9 @@ import jinja2
from canonicaljson import encode_canonical_json from canonicaljson import encode_canonical_json
from zope.interface import implementer from zope.interface import implementer
from twisted.internet import defer, interfaces from twisted.internet import defer, interfaces, reactor
from twisted.internet.defer import CancelledError from twisted.internet.defer import CancelledError
from twisted.internet.interfaces import IReactorTime
from twisted.python import failure from twisted.python import failure
from twisted.web import resource from twisted.web import resource
@ -67,6 +69,7 @@ from twisted.web.util import redirectTo
from synapse.api.errors import ( from synapse.api.errors import (
CodeMessageException, CodeMessageException,
Codes, Codes,
LimitExceededError,
RedirectException, RedirectException,
SynapseError, SynapseError,
UnrecognizedRequestError, UnrecognizedRequestError,
@ -74,7 +77,7 @@ from synapse.api.errors import (
from synapse.config.homeserver import HomeServerConfig from synapse.config.homeserver import HomeServerConfig
from synapse.logging.context import defer_to_thread, preserve_fn, run_in_background from synapse.logging.context import defer_to_thread, preserve_fn, run_in_background
from synapse.logging.opentracing import active_span, start_active_span, trace_servlet from synapse.logging.opentracing import active_span, start_active_span, trace_servlet
from synapse.util import json_encoder from synapse.util import Clock, json_encoder
from synapse.util.caches import intern_dict from synapse.util.caches import intern_dict
from synapse.util.cancellation import is_function_cancellable from synapse.util.cancellation import is_function_cancellable
from synapse.util.iterutils import chunk_seq from synapse.util.iterutils import chunk_seq
@ -308,9 +311,10 @@ class _AsyncResource(resource.Resource, metaclass=abc.ABCMeta):
context from the request the servlet is handling. context from the request the servlet is handling.
""" """
def __init__(self, extract_context: bool = False): def __init__(self, clock: Clock, extract_context: bool = False):
super().__init__() super().__init__()
self._clock = clock
self._extract_context = extract_context self._extract_context = extract_context
def render(self, request: "SynapseRequest") -> int: def render(self, request: "SynapseRequest") -> int:
@ -329,7 +333,12 @@ class _AsyncResource(resource.Resource, metaclass=abc.ABCMeta):
request.request_metrics.name = self.__class__.__name__ request.request_metrics.name = self.__class__.__name__
with trace_servlet(request, self._extract_context): with trace_servlet(request, self._extract_context):
try:
callback_return = await self._async_render(request) callback_return = await self._async_render(request)
except LimitExceededError as e:
if e.pause:
self._clock.sleep(e.pause)
raise
if callback_return is not None: if callback_return is not None:
code, response = callback_return code, response = callback_return
@ -393,8 +402,17 @@ class DirectServeJsonResource(_AsyncResource):
formatting responses and errors as JSON. formatting responses and errors as JSON.
""" """
def __init__(self, canonical_json: bool = False, extract_context: bool = False): def __init__(
super().__init__(extract_context) self,
canonical_json: bool = False,
extract_context: bool = False,
# Clock is optional as this class is exposed to the module API.
clock: Optional[Clock] = None,
):
if clock is None:
clock = Clock(cast(IReactorTime, reactor))
super().__init__(clock, extract_context)
self.canonical_json = canonical_json self.canonical_json = canonical_json
def _send_response( def _send_response(
@ -450,8 +468,8 @@ class JsonResource(DirectServeJsonResource):
canonical_json: bool = True, canonical_json: bool = True,
extract_context: bool = False, extract_context: bool = False,
): ):
super().__init__(canonical_json, extract_context)
self.clock = hs.get_clock() self.clock = hs.get_clock()
super().__init__(canonical_json, extract_context, clock=self.clock)
# Map of path regex -> method -> callback. # Map of path regex -> method -> callback.
self._routes: Dict[Pattern[str], Dict[bytes, _PathEntry]] = {} self._routes: Dict[Pattern[str], Dict[bytes, _PathEntry]] = {}
self.hs = hs self.hs = hs
@ -564,6 +582,17 @@ class DirectServeHtmlResource(_AsyncResource):
# The error template to use for this resource # The error template to use for this resource
ERROR_TEMPLATE = HTML_ERROR_TEMPLATE ERROR_TEMPLATE = HTML_ERROR_TEMPLATE
def __init__(
self,
extract_context: bool = False,
# Clock is optional as this class is exposed to the module API.
clock: Optional[Clock] = None,
):
if clock is None:
clock = Clock(cast(IReactorTime, reactor))
super().__init__(clock, extract_context)
def _send_response( def _send_response(
self, self,
request: "SynapseRequest", request: "SynapseRequest",

View File

@ -104,6 +104,7 @@ from synapse.module_api.callbacks.spamchecker_callbacks import (
CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK, CHECK_MEDIA_FILE_FOR_SPAM_CALLBACK,
CHECK_REGISTRATION_FOR_SPAM_CALLBACK, CHECK_REGISTRATION_FOR_SPAM_CALLBACK,
CHECK_USERNAME_FOR_SPAM_CALLBACK, CHECK_USERNAME_FOR_SPAM_CALLBACK,
FEDERATED_USER_MAY_INVITE_CALLBACK,
SHOULD_DROP_FEDERATED_EVENT_CALLBACK, SHOULD_DROP_FEDERATED_EVENT_CALLBACK,
USER_MAY_CREATE_ROOM_ALIAS_CALLBACK, USER_MAY_CREATE_ROOM_ALIAS_CALLBACK,
USER_MAY_CREATE_ROOM_CALLBACK, USER_MAY_CREATE_ROOM_CALLBACK,
@ -315,6 +316,7 @@ class ModuleApi:
] = None, ] = None,
user_may_join_room: Optional[USER_MAY_JOIN_ROOM_CALLBACK] = None, user_may_join_room: Optional[USER_MAY_JOIN_ROOM_CALLBACK] = None,
user_may_invite: Optional[USER_MAY_INVITE_CALLBACK] = None, user_may_invite: Optional[USER_MAY_INVITE_CALLBACK] = None,
federated_user_may_invite: Optional[FEDERATED_USER_MAY_INVITE_CALLBACK] = None,
user_may_send_3pid_invite: Optional[USER_MAY_SEND_3PID_INVITE_CALLBACK] = None, user_may_send_3pid_invite: Optional[USER_MAY_SEND_3PID_INVITE_CALLBACK] = None,
user_may_create_room: Optional[USER_MAY_CREATE_ROOM_CALLBACK] = None, user_may_create_room: Optional[USER_MAY_CREATE_ROOM_CALLBACK] = None,
user_may_create_room_alias: Optional[ user_may_create_room_alias: Optional[
@ -338,6 +340,7 @@ class ModuleApi:
should_drop_federated_event=should_drop_federated_event, should_drop_federated_event=should_drop_federated_event,
user_may_join_room=user_may_join_room, user_may_join_room=user_may_join_room,
user_may_invite=user_may_invite, user_may_invite=user_may_invite,
federated_user_may_invite=federated_user_may_invite,
user_may_send_3pid_invite=user_may_send_3pid_invite, user_may_send_3pid_invite=user_may_send_3pid_invite,
user_may_create_room=user_may_create_room, user_may_create_room=user_may_create_room,
user_may_create_room_alias=user_may_create_room_alias, user_may_create_room_alias=user_may_create_room_alias,

View File

@ -105,6 +105,22 @@ USER_MAY_INVITE_CALLBACK = Callable[
] ]
], ],
] ]
FEDERATED_USER_MAY_INVITE_CALLBACK = Callable[
["synapse.events.EventBase"],
Awaitable[
Union[
Literal["NOT_SPAM"],
Codes,
# Highly experimental, not officially part of the spamchecker API, may
# disappear without warning depending on the results of ongoing
# experiments.
# Use this to return additional information as part of an error.
Tuple[Codes, JsonDict],
# Deprecated
bool,
]
],
]
USER_MAY_SEND_3PID_INVITE_CALLBACK = Callable[ USER_MAY_SEND_3PID_INVITE_CALLBACK = Callable[
[str, str, str, str], [str, str, str, str],
Awaitable[ Awaitable[
@ -266,6 +282,7 @@ def load_legacy_spam_checkers(hs: "synapse.server.HomeServer") -> None:
spam_checker_methods = { spam_checker_methods = {
"check_event_for_spam", "check_event_for_spam",
"user_may_invite", "user_may_invite",
"federated_user_may_invite",
"user_may_create_room", "user_may_create_room",
"user_may_create_room_alias", "user_may_create_room_alias",
"user_may_publish_room", "user_may_publish_room",
@ -347,6 +364,9 @@ class SpamCheckerModuleApiCallbacks:
] = [] ] = []
self._user_may_join_room_callbacks: List[USER_MAY_JOIN_ROOM_CALLBACK] = [] self._user_may_join_room_callbacks: List[USER_MAY_JOIN_ROOM_CALLBACK] = []
self._user_may_invite_callbacks: List[USER_MAY_INVITE_CALLBACK] = [] self._user_may_invite_callbacks: List[USER_MAY_INVITE_CALLBACK] = []
self._federated_user_may_invite_callbacks: List[
FEDERATED_USER_MAY_INVITE_CALLBACK
] = []
self._user_may_send_3pid_invite_callbacks: List[ self._user_may_send_3pid_invite_callbacks: List[
USER_MAY_SEND_3PID_INVITE_CALLBACK USER_MAY_SEND_3PID_INVITE_CALLBACK
] = [] ] = []
@ -377,6 +397,7 @@ class SpamCheckerModuleApiCallbacks:
] = None, ] = None,
user_may_join_room: Optional[USER_MAY_JOIN_ROOM_CALLBACK] = None, user_may_join_room: Optional[USER_MAY_JOIN_ROOM_CALLBACK] = None,
user_may_invite: Optional[USER_MAY_INVITE_CALLBACK] = None, user_may_invite: Optional[USER_MAY_INVITE_CALLBACK] = None,
federated_user_may_invite: Optional[FEDERATED_USER_MAY_INVITE_CALLBACK] = None,
user_may_send_3pid_invite: Optional[USER_MAY_SEND_3PID_INVITE_CALLBACK] = None, user_may_send_3pid_invite: Optional[USER_MAY_SEND_3PID_INVITE_CALLBACK] = None,
user_may_create_room: Optional[USER_MAY_CREATE_ROOM_CALLBACK] = None, user_may_create_room: Optional[USER_MAY_CREATE_ROOM_CALLBACK] = None,
user_may_create_room_alias: Optional[ user_may_create_room_alias: Optional[
@ -406,6 +427,11 @@ class SpamCheckerModuleApiCallbacks:
if user_may_invite is not None: if user_may_invite is not None:
self._user_may_invite_callbacks.append(user_may_invite) self._user_may_invite_callbacks.append(user_may_invite)
if federated_user_may_invite is not None:
self._federated_user_may_invite_callbacks.append(
federated_user_may_invite,
)
if user_may_send_3pid_invite is not None: if user_may_send_3pid_invite is not None:
self._user_may_send_3pid_invite_callbacks.append( self._user_may_send_3pid_invite_callbacks.append(
user_may_send_3pid_invite, user_may_send_3pid_invite,
@ -605,6 +631,43 @@ class SpamCheckerModuleApiCallbacks:
# No spam-checker has rejected the request, let it pass. # No spam-checker has rejected the request, let it pass.
return self.NOT_SPAM return self.NOT_SPAM
async def federated_user_may_invite(
self, event: "synapse.events.EventBase"
) -> Union[Tuple[Codes, dict], Literal["NOT_SPAM"]]:
"""Checks if a given user may send an invite
Args:
event: The event to be checked
Returns:
NOT_SPAM if the operation is permitted, Codes otherwise.
"""
for callback in self._federated_user_may_invite_callbacks:
with Measure(self.clock, f"{callback.__module__}.{callback.__qualname__}"):
res = await delay_cancellation(callback(event))
# Normalize return values to `Codes` or `"NOT_SPAM"`.
if res is True or res is self.NOT_SPAM:
continue
elif res is False:
return synapse.api.errors.Codes.FORBIDDEN, {}
elif isinstance(res, synapse.api.errors.Codes):
return res, {}
elif (
isinstance(res, tuple)
and len(res) == 2
and isinstance(res[0], synapse.api.errors.Codes)
and isinstance(res[1], dict)
):
return res
else:
logger.warning(
"Module returned invalid value, rejecting invite as spam"
)
return synapse.api.errors.Codes.FORBIDDEN, {}
# Check the standard user_may_invite callback if no module has rejected the invite yet.
return await self.user_may_invite(event.sender, event.state_key, event.room_id)
async def user_may_send_3pid_invite( async def user_may_send_3pid_invite(
self, inviter_userid: str, medium: str, address: str, room_id: str self, inviter_userid: str, medium: str, address: str, room_id: str
) -> Union[Tuple[Codes, dict], Literal["NOT_SPAM"]]: ) -> Union[Tuple[Codes, dict], Literal["NOT_SPAM"]]:

View File

@ -109,6 +109,11 @@ class CapabilitiesRestServlet(RestServlet):
"disallowed" "disallowed"
] = disallowed ] = disallowed
if self.config.experimental.msc4267_enabled:
response["capabilities"]["org.matrix.msc4267.forget_forced_upon_leave"] = {
"enabled": self.config.room.forget_on_leave,
}
return HTTPStatus.OK, response return HTTPStatus.OK, response

View File

@ -42,6 +42,7 @@ from synapse.api.errors import (
NotApprovedError, NotApprovedError,
SynapseError, SynapseError,
UserDeactivatedError, UserDeactivatedError,
UserLockedError,
) )
from synapse.api.ratelimiting import Ratelimiter from synapse.api.ratelimiting import Ratelimiter
from synapse.api.urls import CLIENT_API_PREFIX from synapse.api.urls import CLIENT_API_PREFIX
@ -313,7 +314,7 @@ class LoginRestServlet(RestServlet):
should_issue_refresh_token=should_issue_refresh_token, should_issue_refresh_token=should_issue_refresh_token,
# The user represented by an appservice's configured sender_localpart # The user represented by an appservice's configured sender_localpart
# is not actually created in Synapse. # is not actually created in Synapse.
should_check_deactivated=qualified_user_id != appservice.sender, should_check_deactivated_or_locked=qualified_user_id != appservice.sender,
request_info=request_info, request_info=request_info,
) )
@ -367,7 +368,7 @@ class LoginRestServlet(RestServlet):
auth_provider_id: Optional[str] = None, auth_provider_id: Optional[str] = None,
should_issue_refresh_token: bool = False, should_issue_refresh_token: bool = False,
auth_provider_session_id: Optional[str] = None, auth_provider_session_id: Optional[str] = None,
should_check_deactivated: bool = True, should_check_deactivated_or_locked: bool = True,
*, *,
request_info: RequestInfo, request_info: RequestInfo,
) -> LoginResponse: ) -> LoginResponse:
@ -389,8 +390,8 @@ class LoginRestServlet(RestServlet):
should_issue_refresh_token: True if this login should issue should_issue_refresh_token: True if this login should issue
a refresh token alongside the access token. a refresh token alongside the access token.
auth_provider_session_id: The session ID got during login from the SSO IdP. auth_provider_session_id: The session ID got during login from the SSO IdP.
should_check_deactivated: True if the user should be checked for should_check_deactivated_or_locked: True if the user should be checked for
deactivation status before logging in. deactivation or locked status before logging in.
This exists purely for appservice's configured sender_localpart This exists purely for appservice's configured sender_localpart
which doesn't have an associated user in the database. which doesn't have an associated user in the database.
@ -415,11 +416,14 @@ class LoginRestServlet(RestServlet):
) )
user_id = canonical_uid user_id = canonical_uid
# If the account has been deactivated, do not proceed with the login. # If the account has been deactivated or locked, do not proceed with the login.
if should_check_deactivated: if should_check_deactivated_or_locked:
deactivated = await self._main_store.get_user_deactivated_status(user_id) deactivated = await self._main_store.get_user_deactivated_status(user_id)
if deactivated: if deactivated:
raise UserDeactivatedError("This account has been deactivated") raise UserDeactivatedError("This account has been deactivated")
locked = await self._main_store.get_user_locked_status(user_id)
if locked:
raise UserLockedError()
device_id = login_submission.get("device_id") device_id = login_submission.get("device_id")

View File

@ -1538,6 +1538,7 @@ class RoomHierarchyRestServlet(RestServlet):
super().__init__() super().__init__()
self._auth = hs.get_auth() self._auth = hs.get_auth()
self._room_summary_handler = hs.get_room_summary_handler() self._room_summary_handler = hs.get_room_summary_handler()
self.msc4235_enabled = hs.config.experimental.msc4235_enabled
async def on_GET( async def on_GET(
self, request: SynapseRequest, room_id: str self, request: SynapseRequest, room_id: str
@ -1547,6 +1548,15 @@ class RoomHierarchyRestServlet(RestServlet):
max_depth = parse_integer(request, "max_depth") max_depth = parse_integer(request, "max_depth")
limit = parse_integer(request, "limit") limit = parse_integer(request, "limit")
# twisted.web.server.Request.args is incorrectly defined as Optional[Any]
remote_room_hosts = None
if self.msc4235_enabled:
args: Dict[bytes, List[bytes]] = request.args # type: ignore
via_param = parse_strings_from_args(
args, "org.matrix.msc4235.via", required=False
)
remote_room_hosts = tuple(via_param or [])
return 200, await self._room_summary_handler.get_room_hierarchy( return 200, await self._room_summary_handler.get_room_hierarchy(
requester, requester,
room_id, room_id,
@ -1554,6 +1564,7 @@ class RoomHierarchyRestServlet(RestServlet):
max_depth=max_depth, max_depth=max_depth,
limit=limit, limit=limit,
from_token=parse_string(request, "from"), from_token=parse_string(request, "from"),
remote_room_hosts=remote_room_hosts,
) )

View File

@ -81,7 +81,7 @@ class ConsentResource(DirectServeHtmlResource):
""" """
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self.hs = hs self.hs = hs
self.store = hs.get_datastores().main self.store = hs.get_datastores().main

View File

@ -44,7 +44,7 @@ class FederationWhitelistResource(DirectServeJsonResource):
PATH = "/_synapse/client/v1/config/federation_whitelist" PATH = "/_synapse/client/v1/config/federation_whitelist"
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._federation_whitelist = hs.config.federation.federation_domain_whitelist self._federation_whitelist = hs.config.federation.federation_domain_whitelist

View File

@ -33,7 +33,7 @@ logger = logging.getLogger(__name__)
class JwksResource(DirectServeJsonResource): class JwksResource(DirectServeJsonResource):
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__(extract_context=True) super().__init__(clock=hs.get_clock(), extract_context=True)
# Parameters that are allowed to be exposed in the public key. # Parameters that are allowed to be exposed in the public key.
# This is done manually, because authlib's private to public key conversion # This is done manually, because authlib's private to public key conversion

View File

@ -48,7 +48,7 @@ class NewUserConsentResource(DirectServeHtmlResource):
""" """
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._sso_handler = hs.get_sso_handler() self._sso_handler = hs.get_sso_handler()
self._server_name = hs.hostname self._server_name = hs.hostname
self._consent_version = hs.config.consent.user_consent_version self._consent_version = hs.config.consent.user_consent_version

View File

@ -35,7 +35,7 @@ class OIDCBackchannelLogoutResource(DirectServeJsonResource):
isLeaf = 1 isLeaf = 1
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._oidc_handler = hs.get_oidc_handler() self._oidc_handler = hs.get_oidc_handler()
async def _async_render_POST(self, request: SynapseRequest) -> None: async def _async_render_POST(self, request: SynapseRequest) -> None:

View File

@ -35,7 +35,7 @@ class OIDCCallbackResource(DirectServeHtmlResource):
isLeaf = 1 isLeaf = 1
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._oidc_handler = hs.get_oidc_handler() self._oidc_handler = hs.get_oidc_handler()
async def _async_render_GET(self, request: SynapseRequest) -> None: async def _async_render_GET(self, request: SynapseRequest) -> None:

View File

@ -47,7 +47,7 @@ class PasswordResetSubmitTokenResource(DirectServeHtmlResource):
Args: Args:
hs: server hs: server
""" """
super().__init__() super().__init__(clock=hs.get_clock())
self.clock = hs.get_clock() self.clock = hs.get_clock()
self.store = hs.get_datastores().main self.store = hs.get_datastores().main

View File

@ -44,7 +44,7 @@ class PickIdpResource(DirectServeHtmlResource):
""" """
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._sso_handler = hs.get_sso_handler() self._sso_handler = hs.get_sso_handler()
self._sso_login_idp_picker_template = ( self._sso_login_idp_picker_template = (
hs.config.sso.sso_login_idp_picker_template hs.config.sso.sso_login_idp_picker_template

View File

@ -62,7 +62,7 @@ def pick_username_resource(hs: "HomeServer") -> Resource:
class AvailabilityCheckResource(DirectServeJsonResource): class AvailabilityCheckResource(DirectServeJsonResource):
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._sso_handler = hs.get_sso_handler() self._sso_handler = hs.get_sso_handler()
async def _async_render_GET(self, request: Request) -> Tuple[int, JsonDict]: async def _async_render_GET(self, request: Request) -> Tuple[int, JsonDict]:
@ -78,7 +78,7 @@ class AvailabilityCheckResource(DirectServeJsonResource):
class AccountDetailsResource(DirectServeHtmlResource): class AccountDetailsResource(DirectServeHtmlResource):
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._sso_handler = hs.get_sso_handler() self._sso_handler = hs.get_sso_handler()
def template_search_dirs() -> Generator[str, None, None]: def template_search_dirs() -> Generator[str, None, None]:

View File

@ -30,7 +30,7 @@ class MSC4108RendezvousSessionResource(DirectServeJsonResource):
isLeaf = True isLeaf = True
def __init__(self, hs: "HomeServer") -> None: def __init__(self, hs: "HomeServer") -> None:
super().__init__() super().__init__(clock=hs.get_clock())
self._handler = hs.get_rendezvous_handler() self._handler = hs.get_rendezvous_handler()
async def _async_render_GET(self, request: SynapseRequest) -> None: async def _async_render_GET(self, request: SynapseRequest) -> None:

View File

@ -35,7 +35,7 @@ class SAML2ResponseResource(DirectServeHtmlResource):
isLeaf = 1 isLeaf = 1
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._saml_handler = hs.get_saml_handler() self._saml_handler = hs.get_saml_handler()
self._sso_handler = hs.get_sso_handler() self._sso_handler = hs.get_sso_handler()

View File

@ -43,7 +43,7 @@ class SsoRegisterResource(DirectServeHtmlResource):
""" """
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._sso_handler = hs.get_sso_handler() self._sso_handler = hs.get_sso_handler()
async def _async_render_GET(self, request: Request) -> None: async def _async_render_GET(self, request: Request) -> None:

View File

@ -38,7 +38,7 @@ class UnsubscribeResource(DirectServeHtmlResource):
SUCCESS_HTML = b"<html><body>You have been unsubscribed</body><html>" SUCCESS_HTML = b"<html><body>You have been unsubscribed</body><html>"
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self.notifier = hs.get_notifier() self.notifier = hs.get_notifier()
self.auth = hs.get_auth() self.auth = hs.get_auth()
self.pusher_pool = hs.get_pusherpool() self.pusher_pool = hs.get_pusherpool()

View File

@ -86,7 +86,7 @@ class ClientWellKnownResource(DirectServeJsonResource):
isLeaf = 1 isLeaf = 1
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__() super().__init__(clock=hs.get_clock())
self._well_known_builder = WellKnownBuilder(hs) self._well_known_builder = WellKnownBuilder(hs)
async def _async_render_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: async def _async_render_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:

View File

@ -34,6 +34,7 @@ from synapse.metrics.background_process_metrics import wrap_as_background_proces
from synapse.storage.database import LoggingTransaction from synapse.storage.database import LoggingTransaction
from synapse.storage.databases import Databases from synapse.storage.databases import Databases
from synapse.types.storage import _BackgroundUpdates from synapse.types.storage import _BackgroundUpdates
from synapse.util.stringutils import shortstr
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.server import HomeServer from synapse.server import HomeServer
@ -167,6 +168,12 @@ class PurgeEventsStorageController:
break break
(room_id, groups_to_sequences) = next_to_delete (room_id, groups_to_sequences) = next_to_delete
logger.info(
"[purge] deleting state groups for room %s: %s",
room_id,
shortstr(groups_to_sequences.keys(), maxitems=10),
)
made_progress = await self._delete_state_groups( made_progress = await self._delete_state_groups(
room_id, groups_to_sequences room_id, groups_to_sequences
) )

View File

@ -1478,13 +1478,49 @@ class DatabasePool:
""" """
Upsert, many times. Upsert, many times.
This executes a query equivalent to `INSERT INTO ... ON CONFLICT DO UPDATE`,
with multiple value rows.
The query may use emulated upserts if the database engine does not support upserts,
or if the table is currently unsafe to upsert.
If there are no value columns, this instead generates a `ON CONFLICT DO NOTHING`.
Args: Args:
table: The table to upsert into table: The table to upsert into
key_names: The key column names. key_names: The unique key column names. These are the columns used in the ON CONFLICT clause.
key_values: A list of each row's key column values. key_values: A list of each row's key column values, in the same order as `key_names`.
value_names: The value column names value_names: The non-unique value column names
value_values: A list of each row's value column values. value_values: A list of each row's value column values, in the same order as `value_names`.
Ignored if value_names is empty. Ignored if value_names is empty.
Example:
```python
simple_upsert_many(
"mytable",
key_names=("room_id", "user_id"),
key_values=[
("!room1:example.org", "@user1:example.org"),
("!room2:example.org", "@user2:example.org"),
],
value_names=("wombat_count", "is_updated"),
value_values=[
(42, True),
(7, False)
],
)
```
gives something equivalent to:
```sql
INSERT INTO mytable (room_id, user_id, wombat_count, is_updated)
VALUES
('!room1:example.org', '@user1:example.org', 42, True),
('!room2:example.org', '@user2:example.org', 7, False)
ON CONFLICT DO UPDATE SET
wombat_count = EXCLUDED.wombat_count,
is_updated = EXCLUDED.is_updated
```
""" """
# We can autocommit if it safe to upsert # We can autocommit if it safe to upsert
@ -1513,6 +1549,8 @@ class DatabasePool:
""" """
Upsert, many times. Upsert, many times.
See the documentation for `simple_upsert_many` for examples.
Args: Args:
table: The table to upsert into table: The table to upsert into
key_names: The key column names. key_names: The key column names.

View File

@ -52,10 +52,11 @@ from synapse.storage.database import (
make_in_list_sql_clause, make_in_list_sql_clause,
) )
from synapse.storage.util.id_generators import MultiWriterIdGenerator from synapse.storage.util.id_generators import MultiWriterIdGenerator
from synapse.types import JsonDict from synapse.types import JsonDict, StrCollection
from synapse.util import Duration, json_encoder from synapse.util import Duration, json_encoder
from synapse.util.caches.expiringcache import ExpiringCache from synapse.util.caches.expiringcache import ExpiringCache
from synapse.util.caches.stream_change_cache import StreamChangeCache from synapse.util.caches.stream_change_cache import StreamChangeCache
from synapse.util.iterutils import batch_iter
from synapse.util.stringutils import parse_and_validate_server_name from synapse.util.stringutils import parse_and_validate_server_name
if TYPE_CHECKING: if TYPE_CHECKING:
@ -1027,6 +1028,40 @@ class DeviceInboxWorkerStore(SQLBaseStore):
# loop first time we run this. # loop first time we run this.
self._clock.sleep(1) self._clock.sleep(1)
async def get_devices_with_messages(
self, user_id: str, device_ids: StrCollection
) -> StrCollection:
"""Get the matching device IDs that have messages in the device inbox."""
def get_devices_with_messages_txn(
txn: LoggingTransaction,
batch_device_ids: StrCollection,
) -> StrCollection:
clause, args = make_in_list_sql_clause(
self.database_engine, "device_id", batch_device_ids
)
sql = f"""
SELECT DISTINCT device_id FROM device_inbox
WHERE {clause} AND user_id = ?
"""
args.append(user_id)
txn.execute(sql, args)
return {row[0] for row in txn}
results: Set[str] = set()
for batch_device_ids in batch_iter(device_ids, 1000):
batch_results = await self.db_pool.runInteraction(
"get_devices_with_messages",
get_devices_with_messages_txn,
batch_device_ids,
# We don't need to run in a transaction as it's a single query
db_autocommit=True,
)
results.update(batch_results)
return results
class DeviceInboxBackgroundUpdateStore(SQLBaseStore): class DeviceInboxBackgroundUpdateStore(SQLBaseStore):
DEVICE_INBOX_STREAM_ID = "device_inbox_stream_drop" DEVICE_INBOX_STREAM_ID = "device_inbox_stream_drop"

View File

@ -282,7 +282,7 @@ class DeviceWorkerStore(RoomMemberWorkerStore, EndToEndKeyWorkerStore):
"count_devices_by_users", count_devices_by_users_txn, user_ids "count_devices_by_users", count_devices_by_users_txn, user_ids
) )
@cached() @cached(tree=True)
async def get_device( async def get_device(
self, user_id: str, device_id: str self, user_id: str, device_id: str
) -> Optional[Mapping[str, Any]]: ) -> Optional[Mapping[str, Any]]:
@ -1861,7 +1861,7 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
) )
raise StoreError(500, "Problem storing device.") raise StoreError(500, "Problem storing device.")
async def delete_devices(self, user_id: str, device_ids: List[str]) -> None: async def delete_devices(self, user_id: str, device_ids: StrCollection) -> None:
"""Deletes several devices. """Deletes several devices.
Args: Args:
@ -1885,11 +1885,49 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
values=device_ids, values=device_ids,
keyvalues={"user_id": user_id}, keyvalues={"user_id": user_id},
) )
self._invalidate_cache_and_stream_bulk(
txn, self.get_device, [(user_id, device_id) for device_id in device_ids] # Also delete associated e2e keys.
self.db_pool.simple_delete_many_txn(
txn,
table="e2e_device_keys_json",
keyvalues={"user_id": user_id},
column="device_id",
values=device_ids,
)
self.db_pool.simple_delete_many_txn(
txn,
table="e2e_one_time_keys_json",
keyvalues={"user_id": user_id},
column="device_id",
values=device_ids,
)
self.db_pool.simple_delete_many_txn(
txn,
table="dehydrated_devices",
keyvalues={"user_id": user_id},
column="device_id",
values=device_ids,
)
self.db_pool.simple_delete_many_txn(
txn,
table="e2e_fallback_keys_json",
keyvalues={"user_id": user_id},
column="device_id",
values=device_ids,
) )
for batch in batch_iter(device_ids, 100): # We're bulk deleting potentially many devices at once, so
# let's not invalidate the cache for each device individually.
# Instead, we will invalidate the cache for the user as a whole.
self._invalidate_cache_and_stream(txn, self.get_device, (user_id,))
self._invalidate_cache_and_stream(
txn, self.count_e2e_one_time_keys, (user_id,)
)
self._invalidate_cache_and_stream(
txn, self.get_e2e_unused_fallback_key_types, (user_id,)
)
for batch in batch_iter(device_ids, 1000):
await self.db_pool.runInteraction( await self.db_pool.runInteraction(
"delete_devices", _delete_devices_txn, batch "delete_devices", _delete_devices_txn, batch
) )
@ -2061,30 +2099,34 @@ class DeviceStore(DeviceWorkerStore, DeviceBackgroundUpdateStore):
context = get_active_span_text_map() context = get_active_span_text_map()
def add_device_changes_txn( def add_device_changes_txn(
txn: LoggingTransaction, stream_ids: List[int] txn: LoggingTransaction,
batch_device_ids: StrCollection,
stream_ids: List[int],
) -> None: ) -> None:
self._add_device_change_to_stream_txn( self._add_device_change_to_stream_txn(
txn, txn,
user_id, user_id,
device_ids, batch_device_ids,
stream_ids, stream_ids,
) )
self._add_device_outbound_room_poke_txn( self._add_device_outbound_room_poke_txn(
txn, txn,
user_id, user_id,
device_ids, batch_device_ids,
room_ids, room_ids,
stream_ids, stream_ids,
context, context,
) )
for batch_device_ids in batch_iter(device_ids, 1000):
async with self._device_list_id_gen.get_next_mult( async with self._device_list_id_gen.get_next_mult(
len(device_ids) len(device_ids)
) as stream_ids: ) as stream_ids:
await self.db_pool.runInteraction( await self.db_pool.runInteraction(
"add_device_change_to_stream", "add_device_change_to_stream",
add_device_changes_txn, add_device_changes_txn,
batch_device_ids,
stream_ids, stream_ids,
) )

View File

@ -593,7 +593,7 @@ class EndToEndKeyWorkerStore(EndToEndKeyBackgroundStore, CacheInvalidationWorker
txn, self.count_e2e_one_time_keys, (user_id, device_id) txn, self.count_e2e_one_time_keys, (user_id, device_id)
) )
@cached(max_entries=10000) @cached(max_entries=10000, tree=True)
async def count_e2e_one_time_keys( async def count_e2e_one_time_keys(
self, user_id: str, device_id: str self, user_id: str, device_id: str
) -> Mapping[str, int]: ) -> Mapping[str, int]:
@ -808,7 +808,7 @@ class EndToEndKeyWorkerStore(EndToEndKeyBackgroundStore, CacheInvalidationWorker
}, },
) )
@cached(max_entries=10000) @cached(max_entries=10000, tree=True)
async def get_e2e_unused_fallback_key_types( async def get_e2e_unused_fallback_key_types(
self, user_id: str, device_id: str self, user_id: str, device_id: str
) -> Sequence[str]: ) -> Sequence[str]:
@ -1632,46 +1632,6 @@ class EndToEndKeyStore(EndToEndKeyWorkerStore, SQLBaseStore):
log_kv({"message": "Device keys stored."}) log_kv({"message": "Device keys stored."})
return True return True
async def delete_e2e_keys_by_device(self, user_id: str, device_id: str) -> None:
def delete_e2e_keys_by_device_txn(txn: LoggingTransaction) -> None:
log_kv(
{
"message": "Deleting keys for device",
"device_id": device_id,
"user_id": user_id,
}
)
self.db_pool.simple_delete_txn(
txn,
table="e2e_device_keys_json",
keyvalues={"user_id": user_id, "device_id": device_id},
)
self.db_pool.simple_delete_txn(
txn,
table="e2e_one_time_keys_json",
keyvalues={"user_id": user_id, "device_id": device_id},
)
self._invalidate_cache_and_stream(
txn, self.count_e2e_one_time_keys, (user_id, device_id)
)
self.db_pool.simple_delete_txn(
txn,
table="dehydrated_devices",
keyvalues={"user_id": user_id, "device_id": device_id},
)
self.db_pool.simple_delete_txn(
txn,
table="e2e_fallback_keys_json",
keyvalues={"user_id": user_id, "device_id": device_id},
)
self._invalidate_cache_and_stream(
txn, self.get_e2e_unused_fallback_key_types, (user_id, device_id)
)
await self.db_pool.runInteraction(
"delete_e2e_keys_by_device", delete_e2e_keys_by_device_txn
)
def _set_e2e_cross_signing_key_txn( def _set_e2e_cross_signing_key_txn(
self, self,
txn: LoggingTransaction, txn: LoggingTransaction,

View File

@ -294,6 +294,27 @@ class EventsBackgroundUpdatesStore(StreamWorkerStore, StateDeltasStore, SQLBaseS
where_clause="NOT outlier", where_clause="NOT outlier",
) )
# These indices are needed to validate the foreign key constraint
# when events are deleted.
self.db_pool.updates.register_background_index_update(
_BackgroundUpdates.CURRENT_STATE_EVENTS_STREAM_ORDERING_INDEX_UPDATE_NAME,
index_name="current_state_events_stream_ordering_idx",
table="current_state_events",
columns=["event_stream_ordering"],
)
self.db_pool.updates.register_background_index_update(
_BackgroundUpdates.ROOM_MEMBERSHIPS_STREAM_ORDERING_INDEX_UPDATE_NAME,
index_name="room_memberships_stream_ordering_idx",
table="room_memberships",
columns=["event_stream_ordering"],
)
self.db_pool.updates.register_background_index_update(
_BackgroundUpdates.LOCAL_CURRENT_MEMBERSHIP_STREAM_ORDERING_INDEX_UPDATE_NAME,
index_name="local_current_membership_stream_ordering_idx",
table="local_current_membership",
columns=["event_stream_ordering"],
)
# Handle background updates for Sliding Sync tables # Handle background updates for Sliding Sync tables
# #
self.db_pool.updates.register_background_update_handler( self.db_pool.updates.register_background_update_handler(

View File

@ -349,6 +349,19 @@ class EventsWorkerStore(SQLBaseStore):
where_clause="type = 'm.room.member'", where_clause="type = 'm.room.member'",
) )
# Added to support efficient reverse lookups on the foreign key
# (user_id, device_id) when deleting devices.
# We already had a UNIQUE index on these 4 columns but out-of-order
# so replace that one.
self.db_pool.updates.register_background_index_update(
update_name="event_txn_id_device_id_txn_id2",
index_name="event_txn_id_device_id_txn_id2",
table="event_txn_id_device_id",
columns=("user_id", "device_id", "room_id", "txn_id"),
unique=True,
replaces_index="event_txn_id_device_id_txn_id",
)
def get_un_partial_stated_events_token(self, instance_name: str) -> int: def get_un_partial_stated_events_token(self, instance_name: str) -> int:
return ( return (
self._un_partial_stated_events_stream_id_gen.get_current_token_for_writer( self._un_partial_stated_events_stream_id_gen.get_current_token_for_writer(

View File

@ -40,14 +40,16 @@ from synapse.storage.database import (
DatabasePool, DatabasePool,
LoggingDatabaseConnection, LoggingDatabaseConnection,
LoggingTransaction, LoggingTransaction,
make_in_list_sql_clause,
) )
from synapse.storage.databases.main.cache import CacheInvalidationWorkerStore from synapse.storage.databases.main.cache import CacheInvalidationWorkerStore
from synapse.storage.databases.main.stats import StatsStore from synapse.storage.databases.main.stats import StatsStore
from synapse.storage.types import Cursor from synapse.storage.types import Cursor
from synapse.storage.util.id_generators import IdGenerator from synapse.storage.util.id_generators import IdGenerator
from synapse.storage.util.sequence import build_sequence_generator from synapse.storage.util.sequence import build_sequence_generator
from synapse.types import JsonDict, UserID, UserInfo from synapse.types import JsonDict, StrCollection, UserID, UserInfo
from synapse.util.caches.descriptors import cached from synapse.util.caches.descriptors import cached
from synapse.util.iterutils import batch_iter
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.server import HomeServer from synapse.server import HomeServer
@ -2801,6 +2803,81 @@ class RegistrationStore(StatsStore, RegistrationBackgroundUpdateStore):
return await self.db_pool.runInteraction("user_delete_access_tokens", f) return await self.db_pool.runInteraction("user_delete_access_tokens", f)
async def user_delete_access_tokens_for_devices(
self,
user_id: str,
device_ids: StrCollection,
) -> List[Tuple[str, int, Optional[str]]]:
"""
Invalidate access and refresh tokens belonging to a user
Args:
user_id: ID of user the tokens belong to
device_ids: The devices to delete tokens for.
Returns:
A tuple of (token, token id, device id) for each of the deleted tokens
"""
def user_delete_access_tokens_for_devices_txn(
txn: LoggingTransaction, batch_device_ids: StrCollection
) -> List[Tuple[str, int, Optional[str]]]:
self.db_pool.simple_delete_many_txn(
txn,
table="refresh_tokens",
keyvalues={"user_id": user_id},
column="device_id",
values=batch_device_ids,
)
clause, args = make_in_list_sql_clause(
txn.database_engine, "device_id", batch_device_ids
)
args.append(user_id)
if self.database_engine.supports_returning:
sql = f"""
DELETE FROM access_tokens
WHERE {clause} AND user_id = ?
RETURNING token, id, device_id
"""
txn.execute(sql, args)
tokens_and_devices = txn.fetchall()
else:
tokens_and_devices = self.db_pool.simple_select_many_txn(
txn,
table="access_tokens",
column="device_id",
iterable=batch_device_ids,
keyvalues={"user_id": user_id},
retcols=("token", "id", "device_id"),
)
self.db_pool.simple_delete_many_txn(
txn,
table="access_tokens",
keyvalues={"user_id": user_id},
column="device_id",
values=batch_device_ids,
)
self._invalidate_cache_and_stream_bulk(
txn,
self.get_user_by_access_token,
[(t[0],) for t in tokens_and_devices],
)
return tokens_and_devices
results = []
for batch_device_ids in batch_iter(device_ids, 1000):
tokens_and_devices = await self.db_pool.runInteraction(
"user_delete_access_tokens_for_devices",
user_delete_access_tokens_for_devices_txn,
batch_device_ids,
)
results.extend(tokens_and_devices)
return results
async def delete_access_token(self, access_token: str) -> None: async def delete_access_token(self, access_token: str) -> None:
def f(txn: LoggingTransaction) -> None: def f(txn: LoggingTransaction) -> None:
self.db_pool.simple_delete_one_txn( self.db_pool.simple_delete_one_txn(

View File

@ -290,16 +290,6 @@ class StateBackgroundUpdateStore(StateGroupBackgroundUpdateStore):
STATE_GROUPS_ROOM_INDEX_UPDATE_NAME = "state_groups_room_id_idx" STATE_GROUPS_ROOM_INDEX_UPDATE_NAME = "state_groups_room_id_idx"
STATE_GROUP_EDGES_UNIQUE_INDEX_UPDATE_NAME = "state_group_edges_unique_idx" STATE_GROUP_EDGES_UNIQUE_INDEX_UPDATE_NAME = "state_group_edges_unique_idx"
CURRENT_STATE_EVENTS_STREAM_ORDERING_INDEX_UPDATE_NAME = (
"current_state_events_stream_ordering_idx"
)
ROOM_MEMBERSHIPS_STREAM_ORDERING_INDEX_UPDATE_NAME = (
"room_memberships_stream_ordering_idx"
)
LOCAL_CURRENT_MEMBERSHIP_STREAM_ORDERING_INDEX_UPDATE_NAME = (
"local_current_membership_stream_ordering_idx"
)
def __init__( def __init__(
self, self,
database: DatabasePool, database: DatabasePool,
@ -336,27 +326,6 @@ class StateBackgroundUpdateStore(StateGroupBackgroundUpdateStore):
replaces_index="state_group_edges_idx", replaces_index="state_group_edges_idx",
) )
# These indices are needed to validate the foreign key constraint
# when events are deleted.
self.db_pool.updates.register_background_index_update(
self.CURRENT_STATE_EVENTS_STREAM_ORDERING_INDEX_UPDATE_NAME,
index_name="current_state_events_stream_ordering_idx",
table="current_state_events",
columns=["event_stream_ordering"],
)
self.db_pool.updates.register_background_index_update(
self.ROOM_MEMBERSHIPS_STREAM_ORDERING_INDEX_UPDATE_NAME,
index_name="room_memberships_stream_ordering_idx",
table="room_memberships",
columns=["event_stream_ordering"],
)
self.db_pool.updates.register_background_index_update(
self.LOCAL_CURRENT_MEMBERSHIP_STREAM_ORDERING_INDEX_UPDATE_NAME,
index_name="local_current_membership_stream_ordering_idx",
table="local_current_membership",
columns=["event_stream_ordering"],
)
async def _background_deduplicate_state( async def _background_deduplicate_state(
self, progress: dict, batch_size: int self, progress: dict, batch_size: int
) -> int: ) -> int:

View File

@ -0,0 +1,15 @@
--
-- This file is licensed under the Affero General Public License (AGPL) version 3.
--
-- Copyright (C) 2025 New Vector, 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:
-- <https://www.gnu.org/licenses/agpl-3.0.html>.
INSERT INTO background_updates (ordering, update_name, progress_json) VALUES
(9207, 'event_txn_id_device_id_txn_id2', '{}');

View File

@ -38,6 +38,16 @@ class _BackgroundUpdates:
EVENTS_JUMP_TO_DATE_INDEX = "events_jump_to_date_index" EVENTS_JUMP_TO_DATE_INDEX = "events_jump_to_date_index"
CURRENT_STATE_EVENTS_STREAM_ORDERING_INDEX_UPDATE_NAME = (
"current_state_events_stream_ordering_idx"
)
ROOM_MEMBERSHIPS_STREAM_ORDERING_INDEX_UPDATE_NAME = (
"room_memberships_stream_ordering_idx"
)
LOCAL_CURRENT_MEMBERSHIP_STREAM_ORDERING_INDEX_UPDATE_NAME = (
"local_current_membership_stream_ordering_idx"
)
SLIDING_SYNC_PREFILL_JOINED_ROOMS_TO_RECALCULATE_TABLE_BG_UPDATE = ( SLIDING_SYNC_PREFILL_JOINED_ROOMS_TO_RECALCULATE_TABLE_BG_UPDATE = (
"sliding_sync_prefill_joined_rooms_to_recalculate_table_bg_update" "sliding_sync_prefill_joined_rooms_to_recalculate_table_bg_update"
) )

View File

@ -225,7 +225,7 @@ KNOWN_KEYS = {
"depth", "depth",
"event_id", "event_id",
"hashes", "hashes",
"origin", "origin", # old events were created with an origin field.
"origin_server_ts", "origin_server_ts",
"prev_events", "prev_events",
"room_id", "room_id",

View File

@ -48,7 +48,6 @@ class EventSigningTestCase(unittest.TestCase):
def test_sign_minimal(self) -> None: def test_sign_minimal(self) -> None:
event_dict = { event_dict = {
"event_id": "$0:domain", "event_id": "$0:domain",
"origin": "domain",
"origin_server_ts": 1000000, "origin_server_ts": 1000000,
"signatures": {}, "signatures": {},
"type": "X", "type": "X",
@ -64,7 +63,7 @@ class EventSigningTestCase(unittest.TestCase):
self.assertTrue(hasattr(event, "hashes")) self.assertTrue(hasattr(event, "hashes"))
self.assertIn("sha256", event.hashes) self.assertIn("sha256", event.hashes)
self.assertEqual( self.assertEqual(
event.hashes["sha256"], "6tJjLpXtggfke8UxFhAKg82QVkJzvKOVOOSjUDK4ZSI" event.hashes["sha256"], "A6Nco6sqoy18PPfPDVdYvoowfc0PVBk9g9OiyT3ncRM"
) )
self.assertTrue(hasattr(event, "signatures")) self.assertTrue(hasattr(event, "signatures"))
@ -72,15 +71,14 @@ class EventSigningTestCase(unittest.TestCase):
self.assertIn(KEY_NAME, event.signatures["domain"]) self.assertIn(KEY_NAME, event.signatures["domain"])
self.assertEqual( self.assertEqual(
event.signatures[HOSTNAME][KEY_NAME], event.signatures[HOSTNAME][KEY_NAME],
"2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+" "PBc48yDVszWB9TRaB/+CZC1B+pDAC10F8zll006j+NN"
"aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA", "fe4PEMWcVuLaG63LFTK9e4rwJE8iLZMPtCKhDTXhpAQ",
) )
def test_sign_message(self) -> None: def test_sign_message(self) -> None:
event_dict = { event_dict = {
"content": {"body": "Here is the message content"}, "content": {"body": "Here is the message content"},
"event_id": "$0:domain", "event_id": "$0:domain",
"origin": "domain",
"origin_server_ts": 1000000, "origin_server_ts": 1000000,
"type": "m.room.message", "type": "m.room.message",
"room_id": "!r:domain", "room_id": "!r:domain",
@ -98,7 +96,7 @@ class EventSigningTestCase(unittest.TestCase):
self.assertTrue(hasattr(event, "hashes")) self.assertTrue(hasattr(event, "hashes"))
self.assertIn("sha256", event.hashes) self.assertIn("sha256", event.hashes)
self.assertEqual( self.assertEqual(
event.hashes["sha256"], "onLKD1bGljeBWQhWZ1kaP9SorVmRQNdN5aM2JYU2n/g" event.hashes["sha256"], "rDCeYBepPlI891h/RkI2/Lkf9bt7u0TxFku4tMs7WKk"
) )
self.assertTrue(hasattr(event, "signatures")) self.assertTrue(hasattr(event, "signatures"))
@ -106,6 +104,6 @@ class EventSigningTestCase(unittest.TestCase):
self.assertIn(KEY_NAME, event.signatures["domain"]) self.assertIn(KEY_NAME, event.signatures["domain"])
self.assertEqual( self.assertEqual(
event.signatures[HOSTNAME][KEY_NAME], event.signatures[HOSTNAME][KEY_NAME],
"Wm+VzmOUOz08Ds+0NTWb1d4CZrVsJSikkeRxh6aCcUw" "Ay4aj2b5oJ1k8INYZ9n3KnszCflM0emwcmQQ7vxpbdc"
"u6pNC78FunoD7KNWzqFn241eYHYMGCA5McEiVPdhzBA", "Sv9bkJxIZdWX1IJllcZLq89+D3sSabE+vqPtZs9akDw",
) )

View File

@ -122,7 +122,7 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
"prev_events": "prev_events", "prev_events": "prev_events",
"prev_state": "prev_state", "prev_state": "prev_state",
"auth_events": "auth_events", "auth_events": "auth_events",
"origin": "domain", "origin": "domain", # historical top-level field that still exists on old events
"origin_server_ts": 1234, "origin_server_ts": 1234,
"membership": "join", "membership": "join",
# Also include a key that should be removed. # Also include a key that should be removed.
@ -139,7 +139,7 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
"prev_events": "prev_events", "prev_events": "prev_events",
"prev_state": "prev_state", "prev_state": "prev_state",
"auth_events": "auth_events", "auth_events": "auth_events",
"origin": "domain", "origin": "domain", # historical top-level field that still exists on old events
"origin_server_ts": 1234, "origin_server_ts": 1234,
"membership": "join", "membership": "join",
"content": {}, "content": {},
@ -148,13 +148,12 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
}, },
) )
# As of room versions we now redact the membership, prev_states, and origin keys. # As of room versions we now redact the membership and prev_states keys.
self.run_test( self.run_test(
{ {
"type": "A", "type": "A",
"prev_state": "prev_state", "prev_state": "prev_state",
"membership": "join", "membership": "join",
"origin": "example.com",
}, },
{"type": "A", "content": {}, "signatures": {}, "unsigned": {}}, {"type": "A", "content": {}, "signatures": {}, "unsigned": {}},
room_version=RoomVersions.V11, room_version=RoomVersions.V11,
@ -238,7 +237,6 @@ class PruneEventTestCase(stdlib_unittest.TestCase):
{ {
"type": "m.room.create", "type": "m.room.create",
"content": {"not_a_real_key": True}, "content": {"not_a_real_key": True},
"origin": "some_homeserver",
"nonsense_field": "some_random_garbage", "nonsense_field": "some_random_garbage",
}, },
{ {

View File

@ -535,7 +535,6 @@ class StripUnsignedFromEventsTestCase(unittest.TestCase):
"depth": 1000, "depth": 1000,
"origin_server_ts": 1, "origin_server_ts": 1,
"type": "m.room.member", "type": "m.room.member",
"origin": "test.servx",
"content": {"membership": "join"}, "content": {"membership": "join"},
"auth_events": [], "auth_events": [],
"unsigned": {"malicious garbage": "hackz", "more warez": "more hackz"}, "unsigned": {"malicious garbage": "hackz", "more warez": "more hackz"},
@ -552,7 +551,6 @@ class StripUnsignedFromEventsTestCase(unittest.TestCase):
"depth": 1000, "depth": 1000,
"origin_server_ts": 1, "origin_server_ts": 1,
"type": "m.room.member", "type": "m.room.member",
"origin": "test.servx",
"auth_events": [], "auth_events": [],
"content": {"membership": "join"}, "content": {"membership": "join"},
"unsigned": { "unsigned": {
@ -579,7 +577,6 @@ class StripUnsignedFromEventsTestCase(unittest.TestCase):
"depth": 1000, "depth": 1000,
"origin_server_ts": 1, "origin_server_ts": 1,
"type": "m.room.power_levels", "type": "m.room.power_levels",
"origin": "test.servx",
"content": {}, "content": {},
"auth_events": [], "auth_events": [],
"unsigned": { "unsigned": {

View File

@ -1080,6 +1080,62 @@ class SpaceSummaryTestCase(unittest.HomeserverTestCase):
self.assertEqual(federation_requests, 2) self.assertEqual(federation_requests, 2)
self._assert_hierarchy(result, expected) self._assert_hierarchy(result, expected)
def test_fed_remote_room_hosts(self) -> None:
"""
Test if requested room is available over federation using via's.
"""
fed_hostname = self.hs.hostname + "2"
fed_space = "#fed_space:" + fed_hostname
fed_subroom = "#fed_sub_room:" + fed_hostname
remote_room_hosts = tuple(fed_hostname)
requested_room_entry = _RoomEntry(
fed_space,
{
"room_id": fed_space,
"world_readable": True,
"join_rule": "public",
"room_type": RoomTypes.SPACE,
},
[
{
"type": EventTypes.SpaceChild,
"room_id": fed_space,
"state_key": fed_subroom,
"content": {"via": [fed_hostname]},
}
],
)
child_room = {
"room_id": fed_subroom,
"world_readable": True,
"join_rule": "public",
}
async def summarize_remote_room_hierarchy(
_self: Any, room: Any, suggested_only: bool
) -> Tuple[Optional[_RoomEntry], Dict[str, JsonDict], Set[str]]:
return requested_room_entry, {fed_subroom: child_room}, set()
expected = [
(fed_space, [fed_subroom]),
(fed_subroom, ()),
]
with mock.patch(
"synapse.handlers.room_summary.RoomSummaryHandler._summarize_remote_room_hierarchy",
new=summarize_remote_room_hierarchy,
):
result = self.get_success(
self.handler.get_room_hierarchy(
create_requester(self.user),
fed_space,
remote_room_hosts=remote_room_hosts,
)
)
self._assert_hierarchy(result, expected)
class RoomSummaryTestCase(unittest.HomeserverTestCase): class RoomSummaryTestCase(unittest.HomeserverTestCase):
servlets = [ servlets = [

View File

@ -2846,6 +2846,16 @@ class UserRestTestCase(unittest.HomeserverTestCase):
self.assertEqual(Codes.USER_LOCKED, channel.json_body["errcode"]) self.assertEqual(Codes.USER_LOCKED, channel.json_body["errcode"])
self.assertTrue(channel.json_body["soft_logout"]) self.assertTrue(channel.json_body["soft_logout"])
# User is not authorized to log in anymore
channel = self.make_request(
"POST",
"/_matrix/client/r0/login",
{"type": "m.login.password", "user": "user", "password": "pass"},
)
self.assertEqual(401, channel.code, msg=channel.json_body)
self.assertEqual(Codes.USER_LOCKED, channel.json_body["errcode"])
self.assertTrue(channel.json_body["soft_logout"])
@override_config({"user_directory": {"enabled": True, "search_all_users": True}}) @override_config({"user_directory": {"enabled": True, "search_all_users": True}})
def test_locked_user_not_in_user_dir(self) -> None: def test_locked_user_not_in_user_dir(self) -> None:
# User is available in the user dir # User is available in the user dir

View File

@ -264,3 +264,43 @@ class CapabilitiesTestCase(unittest.HomeserverTestCase):
self.assertEqual(channel.code, HTTPStatus.OK) self.assertEqual(channel.code, HTTPStatus.OK)
self.assertTrue(capabilities["m.get_login_token"]["enabled"]) self.assertTrue(capabilities["m.get_login_token"]["enabled"])
@override_config(
{
"experimental_features": {"msc4267_enabled": True},
"forget_rooms_on_leave": True,
}
)
def test_get_forget_forced_upon_leave_with_auto_forget(self) -> None:
# Server auto-forgets on /leave, expect enabled client capability
access_token = self.get_success(
self.auth_handler.create_access_token_for_user_id(
self.user, device_id=None, valid_until_ms=None
)
)
channel = self.make_request("GET", self.url, access_token=access_token)
capabilities = channel.json_body["capabilities"]
self.assertEqual(channel.code, HTTPStatus.OK)
self.assertTrue(
capabilities["org.matrix.msc4267.forget_forced_upon_leave"]["enabled"]
)
@override_config(
{
"experimental_features": {"msc4267_enabled": True},
"forget_rooms_on_leave": False,
}
)
def test_get_forget_forced_upon_leave_without_auto_forget(self) -> None:
# Server doesn't auto-forget on /leave, expect disabled client capability
access_token = self.get_success(
self.auth_handler.create_access_token_for_user_id(
self.user, device_id=None, valid_until_ms=None
)
)
channel = self.make_request("GET", self.url, access_token=access_token)
capabilities = channel.json_body["capabilities"]
self.assertEqual(channel.code, HTTPStatus.OK)
self.assertFalse(
capabilities["org.matrix.msc4267.forget_forced_upon_leave"]["enabled"]
)

View File

@ -316,15 +316,16 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
await self.callback(request) await self.callback(request)
def setUp(self) -> None: def setUp(self) -> None:
reactor, _ = get_clock() reactor, clock = get_clock()
self.reactor = reactor self.reactor = reactor
self.clock = clock
def test_good_response(self) -> None: def test_good_response(self) -> None:
async def callback(request: SynapseRequest) -> None: async def callback(request: SynapseRequest) -> None:
request.write(b"response") request.write(b"response")
request.finish() request.finish()
res = WrapHtmlRequestHandlerTests.TestResource() res = WrapHtmlRequestHandlerTests.TestResource(clock=self.clock)
res.callback = callback res.callback = callback
channel = make_request( channel = make_request(
@ -344,7 +345,7 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
async def callback(request: SynapseRequest, **kwargs: object) -> None: async def callback(request: SynapseRequest, **kwargs: object) -> None:
raise RedirectException(b"/look/an/eagle", 301) raise RedirectException(b"/look/an/eagle", 301)
res = WrapHtmlRequestHandlerTests.TestResource() res = WrapHtmlRequestHandlerTests.TestResource(clock=self.clock)
res.callback = callback res.callback = callback
channel = make_request( channel = make_request(
@ -366,7 +367,7 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
e.cookies.append(b"session=yespls") e.cookies.append(b"session=yespls")
raise e raise e
res = WrapHtmlRequestHandlerTests.TestResource() res = WrapHtmlRequestHandlerTests.TestResource(clock=self.clock)
res.callback = callback res.callback = callback
channel = make_request( channel = make_request(
@ -387,7 +388,7 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
request.write(b"response") request.write(b"response")
request.finish() request.finish()
res = WrapHtmlRequestHandlerTests.TestResource() res = WrapHtmlRequestHandlerTests.TestResource(clock=self.clock)
res.callback = callback res.callback = callback
channel = make_request( channel = make_request(
@ -400,7 +401,7 @@ class WrapHtmlRequestHandlerTests(unittest.TestCase):
class CancellableDirectServeJsonResource(DirectServeJsonResource): class CancellableDirectServeJsonResource(DirectServeJsonResource):
def __init__(self, clock: Clock): def __init__(self, clock: Clock):
super().__init__() super().__init__(clock=clock)
self.clock = clock self.clock = clock
@cancellable @cancellable
@ -417,7 +418,7 @@ class CancellableDirectServeHtmlResource(DirectServeHtmlResource):
ERROR_TEMPLATE = "{code} {msg}" ERROR_TEMPLATE = "{code} {msg}"
def __init__(self, clock: Clock): def __init__(self, clock: Clock):
super().__init__() super().__init__(clock=clock)
self.clock = clock self.clock = clock
@cancellable @cancellable