mirror of
https://forgejo.ellis.link/continuwuation/continuwuity/
synced 2026-07-05 00:31:40 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 38e93cde3e | |||
| 7e501cdb09 | |||
| da182c162d | |||
| 9a3f7f4af7 | |||
| 5ce1f682f6 | |||
| 5feb08dff2 | |||
| 1e527c1075 | |||
| c6943ae683 | |||
| 8932dacdc4 | |||
| 0be3d850ac | |||
| 57e7cf7057 | |||
| 1005585ccb | |||
| 1188566dbd | |||
| 0058212757 | |||
| dbf8fd3320 | |||
| ce295b079e | |||
| 5eb74bc1dd | |||
| da561ab792 | |||
| 80c9bb4796 | |||
| 22a47d1e59 | |||
| 83883a002c | |||
| 8dd4b71e0e | |||
| 6fe3b1563c | |||
| 44d3825c8e | |||
| d6c5484c3a | |||
| 1fd6056f3f | |||
| 525a0ae52b | |||
| 60210754d9 | |||
| 08dd787083 | |||
| 2c7233812b | |||
| d725e98220 | |||
| 0226ca1e83 | |||
| 1695b6d19e | |||
| c40cc3b236 | |||
| 754959e80d | |||
| 37888fb670 | |||
| 7207398a9e | |||
| 1a7bda209b | |||
| 7e1950b3d2 | |||
| b507898c62 | |||
| f4af67575e | |||
| 6adb99397e | |||
| 8ce83a8a14 |
@@ -30,22 +30,22 @@ jobs:
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "distribution=$DISTRIBUTION" >> $GITHUB_OUTPUT
|
||||
echo "Debian distribution: $DISTRIBUTION ($VERSION)"
|
||||
- name: Work around llvm-project#153385
|
||||
id: llvm-workaround
|
||||
run: |
|
||||
if [ -f /usr/share/apt/default-sequoia.config ]; then
|
||||
echo "Applying workaround for llvm-project#153385"
|
||||
mkdir -p /etc/crypto-policies/back-ends/
|
||||
cp /usr/share/apt/default-sequoia.config /etc/crypto-policies/back-ends/apt-sequoia.config
|
||||
sed -i 's/\(sha1\.second_preimage_resistance = \)2026-02-01/\12026-06-01/' /etc/crypto-policies/back-ends/apt-sequoia.config
|
||||
else
|
||||
echo "No workaround needed for llvm-project#153385"
|
||||
fi
|
||||
#- name: Work around llvm-project#153385
|
||||
# id: llvm-workaround
|
||||
# run: |
|
||||
# if [ -f /usr/share/apt/default-sequoia.config ]; then
|
||||
# echo "Applying workaround for llvm-project#153385"
|
||||
# mkdir -p /etc/crypto-policies/back-ends/
|
||||
# cp /usr/share/apt/default-sequoia.config /etc/crypto-policies/back-ends/apt-sequoia.config
|
||||
# sed -i 's/\(sha1\.second_preimage_resistance = \)2026-02-01/\12026-06-01/' /etc/crypto-policies/back-ends/apt-sequoia.config
|
||||
# else
|
||||
# echo "No workaround needed for llvm-project#153385"
|
||||
# fi
|
||||
- name: Pick compatible clang version
|
||||
id: clang-version
|
||||
run: |
|
||||
# both latest need to use clang-23, but oldstable and previous can just use clang
|
||||
if [[ "${{ matrix.container }}" == "ubuntu-latest" || "${{ matrix.container }}" == "debian-latest" ]]; then
|
||||
if [[ "${{ matrix.container }}" == "ubuntu-latest" ]]; then
|
||||
echo "Using clang-23 package for ${{ matrix.container }}"
|
||||
echo "version=clang-23" >> $GITHUB_OUTPUT
|
||||
else
|
||||
|
||||
+14
-2
@@ -1,5 +1,6 @@
|
||||
default_install_hook_types:
|
||||
- pre-commit
|
||||
- pre-push
|
||||
- commit-msg
|
||||
default_stages:
|
||||
- pre-commit
|
||||
@@ -23,7 +24,7 @@ repos:
|
||||
- id: check-added-large-files
|
||||
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: v1.43.5
|
||||
rev: v1.44.0
|
||||
hooks:
|
||||
- id: typos
|
||||
- id: typos
|
||||
@@ -31,7 +32,7 @@ repos:
|
||||
stages: [commit-msg]
|
||||
|
||||
- repo: https://github.com/crate-ci/committed
|
||||
rev: v1.1.10
|
||||
rev: v1.1.11
|
||||
hooks:
|
||||
- id: committed
|
||||
|
||||
@@ -45,3 +46,14 @@ repos:
|
||||
pass_filenames: false
|
||||
stages:
|
||||
- pre-commit
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: cargo-clippy
|
||||
name: cargo clippy
|
||||
entry: cargo clippy -- -D warnings
|
||||
language: system
|
||||
pass_filenames: false
|
||||
types: [rust]
|
||||
stages:
|
||||
- pre-push
|
||||
|
||||
@@ -1,3 +1,32 @@
|
||||
# Continuwuity 0.5.6 (2026-03-03)
|
||||
|
||||
## Security
|
||||
|
||||
- Admin escape commands received over federation will never be executed, as this is never valid in a genuine situation. Contributed by @Jade.
|
||||
- Fixed data amplification vulnerability (CWE-409) that affected configurations with server-side compression enabled (non-default). Contributed by @nex.
|
||||
|
||||
## Features
|
||||
|
||||
- Outgoing presence is now disabled by default, and the config option documentation has been adjusted to more accurately represent the weight of presence, typing indicators, and read receipts. Contributed by @nex. ([#1399](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1399))
|
||||
- Improved the concurrency handling of federation transactions, vastly improving performance and reliability by more accurately handling inbound transactions and reducing the amount of repeated wasted work. Contributed by @nex and @Jade. ([#1428](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1428))
|
||||
- Added [MSC3202](https://github.com/matrix-org/matrix-spec-proposals/pull/3202) Device masquerading (not all of MSC3202). This should fix issues with enabling [MSC4190](https://github.com/matrix-org/matrix-spec-proposals/pull/4190) for some Mautrix bridges. Contributed by @Jade ([#1435](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1435))
|
||||
- Added [MSC3814](https://github.com/matrix-org/matrix-spec-proposals/pull/3814) Dehydrated Devices - you can now decrypt messages sent while all devices were logged out. ([#1436](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1436))
|
||||
- Implement [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143) MatrixRTC transport discovery endpoint. Move RTC foci configuration from `[global.well_known]` to a new `[global.matrix_rtc]` section with a `foci` field. Contributed by @0xnim ([#1442](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1442))
|
||||
- Updated `list-backups` admin command to output one backup per line. ([#1394](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1394))
|
||||
- Improved URL preview fetching with a more compatible user agent for sites like YouTube Music. Added `!admin media delete-url-preview <url>` command to clear cached URL previews that were stuck and broken. ([#1434](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1434))
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Removed non-compliant nor functional room alias lookups over federation. Contributed by @nex ([#1393](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1393))
|
||||
- Removed ability to set rocksdb as read only. Doing so would cause unintentional and buggy behaviour. Contributed by @Terryiscool160. ([#1418](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1418))
|
||||
- Fixed a startup crash in the sender service if we can't detect the number of CPU cores, even if the `sender_workers` config option is set correctly. Contributed by @katie. ([#1421](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1421))
|
||||
- Removed the `allow_public_room_directory_without_auth` config option. Contributed by @0xnim. ([#1441](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1441))
|
||||
- Fixed sliding sync v5 list ranges always starting from 0, causing extra rooms to be unnecessarily processed and returned. Contributed by @0xnim ([#1445](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1445))
|
||||
- Fixed a bug that (repairably) caused a room split between continuwuity and non-continuwuity servers when the room had both `m.room.policy` and `org.matrix.msc4284.policy` in its room state. Contributed by @nex ([#1481](https://forgejo.ellis.link/continuwuation/continuwuity/pulls/1481))
|
||||
- Fixed `!admin media delete --mxc <url>` responding with an error message when the media was deleted successfully. Contributed by @lynxize
|
||||
- Fixed spurious 404 media errors in the logs. Contributed by @benbot.
|
||||
- Fixed spurious warn about needed backfill via federation for non-federated rooms. Contributed by @kraem.
|
||||
|
||||
# Continuwuity v0.5.5 (2026-02-15)
|
||||
|
||||
## Features
|
||||
|
||||
Generated
+43
-29
@@ -445,13 +445,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "axum-extra"
|
||||
version = "0.10.3"
|
||||
version = "0.12.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96"
|
||||
checksum = "fef252edff26ddba56bbcdf2ee3307b8129acb86f5749b68990c168a6fcc9c76"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http",
|
||||
@@ -459,8 +460,6 @@ dependencies = [
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"serde_core",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -888,7 +887,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"conduwuit_admin",
|
||||
@@ -920,7 +919,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_admin"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"conduwuit_api",
|
||||
@@ -941,7 +940,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_api"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
@@ -973,14 +972,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_build_metadata"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"built",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_core"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"arrayvec",
|
||||
@@ -1042,7 +1041,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_database"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"conduwuit_core",
|
||||
@@ -1060,7 +1059,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_macros"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"proc-macro2",
|
||||
@@ -1070,7 +1069,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_router"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-client-ip",
|
||||
@@ -1104,7 +1103,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_service"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"askama",
|
||||
"async-trait",
|
||||
@@ -1146,7 +1145,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "conduwuit_web"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"askama",
|
||||
"axum",
|
||||
@@ -1222,7 +1221,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "continuwuity-admin-api"
|
||||
version = "0.1.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"ruma-common",
|
||||
"serde",
|
||||
@@ -1601,7 +1600,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "draupnir-antispam"
|
||||
version = "0.1.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"ruma-common",
|
||||
"serde",
|
||||
@@ -3003,7 +3002,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
[[package]]
|
||||
name = "meowlnir-antispam"
|
||||
version = "0.1.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"ruma-common",
|
||||
"serde",
|
||||
@@ -4056,12 +4055,14 @@ dependencies = [
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
]
|
||||
@@ -4095,7 +4096,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma"
|
||||
version = "0.10.1"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"assign",
|
||||
"continuwuity-admin-api",
|
||||
@@ -4118,7 +4119,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-appservice-api"
|
||||
version = "0.10.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
@@ -4130,7 +4131,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-client-api"
|
||||
version = "0.18.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"assign",
|
||||
@@ -4153,7 +4154,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-common"
|
||||
version = "0.13.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"base64 0.22.1",
|
||||
@@ -4185,7 +4186,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-events"
|
||||
version = "0.28.1"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"as_variant",
|
||||
"indexmap",
|
||||
@@ -4210,7 +4211,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-federation-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"headers",
|
||||
@@ -4232,7 +4233,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-identifiers-validation"
|
||||
version = "0.9.5"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"thiserror 2.0.18",
|
||||
@@ -4241,7 +4242,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-identity-service-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
@@ -4251,7 +4252,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-macros"
|
||||
version = "0.13.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro-crate",
|
||||
@@ -4266,7 +4267,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-push-gateway-api"
|
||||
version = "0.9.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
@@ -4278,7 +4279,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ruma-signatures"
|
||||
version = "0.15.0"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf#a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=bb12ed288a31a23aa11b10ba0fad22b7f985eb88#bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"ed25519-dalek",
|
||||
@@ -5869,6 +5870,19 @@ dependencies = [
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.244.0"
|
||||
@@ -6333,7 +6347,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"askama",
|
||||
"cargo_metadata",
|
||||
|
||||
+6
-3
@@ -12,7 +12,7 @@ license = "Apache-2.0"
|
||||
# See also `rust-toolchain.toml`
|
||||
readme = "README.md"
|
||||
repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
|
||||
[workspace.metadata.crane]
|
||||
name = "conduwuit"
|
||||
@@ -97,7 +97,7 @@ features = [
|
||||
]
|
||||
|
||||
[workspace.dependencies.axum-extra]
|
||||
version = "0.10.1"
|
||||
version = "0.12.0"
|
||||
default-features = false
|
||||
features = ["typed-header", "tracing"]
|
||||
|
||||
@@ -144,6 +144,7 @@ features = [
|
||||
"socks",
|
||||
"hickory-dns",
|
||||
"http2",
|
||||
"stream",
|
||||
]
|
||||
|
||||
[workspace.dependencies.serde]
|
||||
@@ -343,7 +344,7 @@ version = "0.1.2"
|
||||
[workspace.dependencies.ruma]
|
||||
git = "https://forgejo.ellis.link/continuwuation/ruwuma"
|
||||
#branch = "conduwuit-changes"
|
||||
rev = "a4b5e89f4951c87e903ef224c2d1c2c4ef1ebeaf"
|
||||
rev = "bb12ed288a31a23aa11b10ba0fad22b7f985eb88"
|
||||
features = [
|
||||
"compat",
|
||||
"rand",
|
||||
@@ -363,6 +364,7 @@ features = [
|
||||
"unstable-msc2870",
|
||||
"unstable-msc3026",
|
||||
"unstable-msc3061",
|
||||
"unstable-msc3814",
|
||||
"unstable-msc3245",
|
||||
"unstable-msc3266",
|
||||
"unstable-msc3381", # polls
|
||||
@@ -381,6 +383,7 @@ features = [
|
||||
"unstable-pdu",
|
||||
"unstable-msc4155",
|
||||
"unstable-msc4143", # livekit well_known response
|
||||
"unstable-msc4284"
|
||||
]
|
||||
|
||||
[workspace.dependencies.rust-rocksdb]
|
||||
|
||||
+2
-2
@@ -6,10 +6,10 @@ set -euo pipefail
|
||||
COMPLEMENT_SRC="${COMPLEMENT_SRC:-$1}"
|
||||
|
||||
# A `.jsonl` file to write test logs to
|
||||
LOG_FILE="${2:-complement_test_logs.jsonl}"
|
||||
LOG_FILE="${2:-tests/test_results/complement/test_logs.jsonl}"
|
||||
|
||||
# A `.jsonl` file to write test results to
|
||||
RESULTS_FILE="${3:-complement_test_results.jsonl}"
|
||||
RESULTS_FILE="${3:-tests/test_results/complement/test_results.jsonl}"
|
||||
|
||||
# The base docker image to use for complement tests
|
||||
# You can build the default with `docker build -t continuwuity:complement -f ./docker/complement.Dockerfile .`
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Stopped left rooms from being unconditionally sent on initial sync, hopefully fixing spurious appearances of left rooms in some clients (and making sync faster as a bonus). Contributed by @ginger
|
||||
@@ -0,0 +1 @@
|
||||
Re-added support for reading registration tokens from a file. Contributed by @ginger and @benbot.
|
||||
@@ -1 +0,0 @@
|
||||
Removed non-compliant nor functional room alias lookups over federation. Contributed by @nex
|
||||
@@ -1 +0,0 @@
|
||||
Outgoing presence is now disabled by default, and the config option documentation has been adjusted to more accurately represent the weight of presence, typing indicators, and read receipts. Contributed by @nex.
|
||||
@@ -1 +0,0 @@
|
||||
Removed ability to set rocksdb as read only. Doing so would cause unintentional and buggy behaviour. Contributed by @Terryiscool160.
|
||||
@@ -1 +0,0 @@
|
||||
Fixed a startup crash in the sender service if we can't detect the number of CPU cores, even if the `sender_workers' config option is set correctly. Contributed by @katie.
|
||||
@@ -1 +0,0 @@
|
||||
Improved the concurrency handling of federation transactions, vastly improving performance and reliability by more accurately handling inbound transactions and reducing the amount of repeated wasted work. Contributed by @nex and @Jade.
|
||||
@@ -1 +0,0 @@
|
||||
Added MSC3202 Device masquerading (not all of MSC3202). This should fix issues with enabling MSC4190 for some Mautrix bridges. Contributed by @Jade
|
||||
@@ -1 +0,0 @@
|
||||
Removed the `allow_public_room_directory_without_auth` config option. Contributed by @0xnim.
|
||||
@@ -1 +0,0 @@
|
||||
Implement MSC4143 MatrixRTC transport discovery endpoint. Move RTC foci configuration from `[global.well_known]` to a new `[global.matrix_rtc]` section with a `foci` field. Contributed by @0xnim
|
||||
@@ -1 +0,0 @@
|
||||
Fixed sliding sync v5 list ranges always starting from 0, causing extra rooms to be unnecessarily processed and returned. Contributed by @0xnim
|
||||
@@ -0,0 +1 @@
|
||||
Prevent removing the admin room alias (`#admins`) to avoid accidentally breaking admin room functionality. Contributed by @0xnim
|
||||
@@ -1 +0,0 @@
|
||||
Updated `list-backups` admin command to output one backup per line.
|
||||
@@ -1 +0,0 @@
|
||||
Improved URL preview fetching with a more compatible user agent for sites like YouTube Music. Added `!admin media delete-url-preview <url>` command to clear cached URL previews that were stuck and broken.
|
||||
+15
-3
@@ -15,6 +15,18 @@ disallowed-macros = [
|
||||
{ path = "log::trace", reason = "use conduwuit_core::trace" },
|
||||
]
|
||||
|
||||
disallowed-methods = [
|
||||
{ path = "tokio::spawn", reason = "use and pass conduuwit_core::server::Server::runtime() to spawn from" },
|
||||
]
|
||||
[[disallowed-methods]]
|
||||
path = "tokio::spawn"
|
||||
reason = "use and pass conduwuit_core::server::Server::runtime() to spawn from"
|
||||
|
||||
[[disallowed-methods]]
|
||||
path = "reqwest::Response::bytes"
|
||||
reason = "bytes is unsafe, use limit_read via the conduwuit_core::utils::LimitReadExt trait instead"
|
||||
|
||||
[[disallowed-methods]]
|
||||
path = "reqwest::Response::text"
|
||||
reason = "text is unsafe, use limit_read_text via the conduwuit_core::utils::LimitReadExt trait instead"
|
||||
|
||||
[[disallowed-methods]]
|
||||
path = "reqwest::Response::json"
|
||||
reason = "json is unsafe, use limit_read_text via the conduwuit_core::utils::LimitReadExt trait instead"
|
||||
|
||||
@@ -11,7 +11,7 @@ allow_guest_registration = true
|
||||
allow_public_room_directory_over_federation = true
|
||||
allow_registration = true
|
||||
database_path = "/database"
|
||||
log = "trace,h2=debug,hyper=debug"
|
||||
log = "trace,h2=debug,hyper=debug,conduwuit_database=warn,conduwuit_service::manager=info,conduwuit_api::router=error,conduwuit_router=error,tower_http=error"
|
||||
port = [8008, 8448]
|
||||
trusted_servers = []
|
||||
only_query_trusted_key_servers = false
|
||||
@@ -24,7 +24,7 @@ url_preview_domain_explicit_denylist = ["*"]
|
||||
media_compat_file_link = false
|
||||
media_startup_check = true
|
||||
prune_missing_media = true
|
||||
log_colors = true
|
||||
log_colors = false
|
||||
admin_room_notices = false
|
||||
allow_check_for_updates = false
|
||||
intentionally_unknown_config_option_for_testing = true
|
||||
@@ -47,6 +47,7 @@ federation_idle_timeout = 300
|
||||
sender_timeout = 300
|
||||
sender_idle_timeout = 300
|
||||
sender_retry_backoff_limit = 300
|
||||
force_disable_first_run_mode = true
|
||||
|
||||
[global.tls]
|
||||
dual_protocol = true
|
||||
|
||||
+14
-7
@@ -476,18 +476,25 @@
|
||||
#yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = false
|
||||
|
||||
# A static registration token that new users will have to provide when
|
||||
# creating an account. If unset and `allow_registration` is true,
|
||||
# you must set
|
||||
# `yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse`
|
||||
# to true to allow open registration without any conditions.
|
||||
#
|
||||
# If you do not want to set a static token, the `!admin token` commands
|
||||
# may also be used to manage registration tokens.
|
||||
# creating an account. This token does not supersede tokens from other
|
||||
# sources, such as the `!admin token` command or the
|
||||
# `registration_token_file` configuration option.
|
||||
#
|
||||
# example: "o&^uCtes4HPf0Vu@F20jQeeWE7"
|
||||
#
|
||||
#registration_token =
|
||||
|
||||
# A path to a file containing static registration tokens, one per line.
|
||||
# Tokens in this file do not supersede tokens from other sources, such as
|
||||
# the `!admin token` command or the `registration_token` configuration
|
||||
# option.
|
||||
#
|
||||
# The file will be read once, when Continuwuity starts. It is not
|
||||
# currently reread when the server configuration is reloaded. If the file
|
||||
# cannot be read, Continuwuity will fail to start.
|
||||
#
|
||||
#registration_token_file =
|
||||
|
||||
# The public site key for reCaptcha. If this is provided, reCaptcha
|
||||
# becomes required during registration. If both captcha *and*
|
||||
# registration token are enabled, both will be required during
|
||||
|
||||
+8
-3
@@ -48,7 +48,7 @@ EOF
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.17.5
|
||||
ENV BINSTALL_VERSION=1.17.6
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
@@ -180,6 +180,11 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
export RUSTFLAGS="${RUSTFLAGS}"
|
||||
fi
|
||||
|
||||
RUST_PROFILE_DIR="${RUST_PROFILE}"
|
||||
if [[ "${RUST_PROFILE}" == "dev" ]]; then
|
||||
RUST_PROFILE_DIR="debug"
|
||||
fi
|
||||
|
||||
TARGET_DIR=($(cargo metadata --no-deps --format-version 1 | \
|
||||
jq -r ".target_directory"))
|
||||
mkdir /out/sbin
|
||||
@@ -191,8 +196,8 @@ RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
jq -r ".packages[] | select(.name == \"$PACKAGE\") | .targets[] | select( .kind | map(. == \"bin\") | any ) | .name"))
|
||||
for BINARY in "${BINARIES[@]}"; do
|
||||
echo $BINARY
|
||||
xx-verify $TARGET_DIR/$(xx-cargo --print-target-triple)/${RUST_PROFILE}/$BINARY
|
||||
cp $TARGET_DIR/$(xx-cargo --print-target-triple)/${RUST_PROFILE}/$BINARY /out/sbin/$BINARY
|
||||
xx-verify $TARGET_DIR/$(xx-cargo --print-target-triple)/${RUST_PROFILE_DIR}/$BINARY
|
||||
cp $TARGET_DIR/$(xx-cargo --print-target-triple)/${RUST_PROFILE_DIR}/$BINARY /out/sbin/$BINARY
|
||||
done
|
||||
EOF
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ RUN --mount=type=cache,target=/etc/apk/cache apk add \
|
||||
|
||||
# Developer tool versions
|
||||
# renovate: datasource=github-releases depName=cargo-bins/cargo-binstall
|
||||
ENV BINSTALL_VERSION=1.17.5
|
||||
ENV BINSTALL_VERSION=1.17.6
|
||||
# renovate: datasource=github-releases depName=psastras/sbom-rs
|
||||
ENV CARGO_SBOM_VERSION=0.9.1
|
||||
# renovate: datasource=crate depName=lddtree
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
"name": "troubleshooting",
|
||||
"label": "Troubleshooting"
|
||||
},
|
||||
{
|
||||
"type": "dir",
|
||||
"name": "advanced",
|
||||
"label": "Advanced"
|
||||
},
|
||||
"security",
|
||||
{
|
||||
"type": "dir-section-header",
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"text": "Guide",
|
||||
"link": "/introduction",
|
||||
"activeMatch": "^/(introduction|configuration|deploying|calls|appservices|maintenance|troubleshooting)"
|
||||
"activeMatch": "^/(introduction|configuration|deploying|calls|appservices|maintenance|troubleshooting|advanced)"
|
||||
},
|
||||
{
|
||||
"text": "Development",
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"type": "file",
|
||||
"name": "delegation",
|
||||
"label": "Delegation / split-domain"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,209 @@
|
||||
# Delegation/split-domain deployment
|
||||
|
||||
Matrix allows clients and servers to discover a homeserver's "true" destination via **`.well-known` delegation**. This is especially useful if you would like to:
|
||||
|
||||
- Serve Continuwuity on a subdomain while having only the base domain for your usernames
|
||||
- Use a port other than `:8448` for server-to-server connections
|
||||
|
||||
This guide will show you how to have `@user:example.com` usernames while serving Continuwuity on `https://matrix.example.com`. It assumes you are using port 443 for both client-to-server connections and server-to-server federation.
|
||||
|
||||
## Configuration
|
||||
|
||||
First, ensure you have set up A/AAAA records for `matrix.example.com` and `example.com` pointing to your IP.
|
||||
|
||||
Then, ensure that the `server_name` field matches your intended username suffix. If this is not the case, you **MUST** wipe the database directory and reinstall Continuwuity with your desired `server_name`.
|
||||
|
||||
Then, in the `[global.well_known]` section of your config file, add the following fields:
|
||||
|
||||
```toml
|
||||
[global.well_known]
|
||||
|
||||
client = "https://matrix.example.com"
|
||||
|
||||
# port number MUST be specified
|
||||
server = "matrix.example.com:443"
|
||||
|
||||
# (optional) customize your support contacts
|
||||
#support_page =
|
||||
#support_role = "m.role.admin"
|
||||
#support_email =
|
||||
#support_mxid = "@user:example.com"
|
||||
```
|
||||
|
||||
Alternatively if you are using Docker, you can set the `CONTINUWUITY_WELL_KNOWN` environment variable as below:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
continuwuity:
|
||||
...
|
||||
environment:
|
||||
CONTINUWUITY_WELL_KNOWN: |
|
||||
{
|
||||
client=https://matrix.example.com,
|
||||
server=matrix.example.com:443
|
||||
}
|
||||
```
|
||||
|
||||
## Serving with a reverse proxy
|
||||
|
||||
After doing the steps above, Continuwuity will serve these 3 JSON files:
|
||||
|
||||
- `/.well-known/matrix/client`: for Client-Server discovery
|
||||
- `/.well-known/matrix/server`: for Server-Server (federation) discovery
|
||||
- `/.well-known/matrix/support`: admin contact details (strongly recommended to have)
|
||||
|
||||
To enable full discovery, you will need to reverse proxy these paths from the base domain back to Continuwuity.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>For Caddy</summary>
|
||||
|
||||
```
|
||||
matrix.example.com:443 {
|
||||
reverse_proxy 127.0.0.1:8008
|
||||
}
|
||||
|
||||
example.com:443 {
|
||||
reverse_proxy /.well-known/matrix* 127.0.0.1:8008
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>For Traefik (via Docker labels)</summary>
|
||||
|
||||
```
|
||||
services:
|
||||
continuwuity:
|
||||
...
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.continuwuity.rule=(Host(`matrix.example.com`) || (Host(`example.com`) && PathPrefix(`/.well-known/matrix`)))"
|
||||
- "traefik.http.routers.continuwuity.service=continuwuity"
|
||||
- "traefik.http.services.continuwuity.loadbalancer.server.port=8008"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Restart Continuwuity and your reverse proxy. Once that's done, visit these routes and check that the responses match the examples below:
|
||||
|
||||
<details open>
|
||||
|
||||
<summary>`https://example.com/.well-known/matrix/server`</summary>
|
||||
|
||||
```json
|
||||
{
|
||||
"m.server": "matrix.example.com:443"
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details open>
|
||||
|
||||
<summary>`https://example.com/.well-known/matrix/client`</summary>
|
||||
|
||||
```json
|
||||
{
|
||||
"m.homeserver": {
|
||||
"base_url": "https://matrix.example.com/"
|
||||
},
|
||||
"org.matrix.msc3575.proxy": {
|
||||
"url": "https://matrix.example.com/"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Cannot log in with web clients
|
||||
|
||||
Make sure there is an `Access-Control-Allow-Origin: *` header in your `/.well-known/matrix/client` path. While Continuwuity serves this header by default, it may be dropped by reverse proxies or other middlewares.
|
||||
|
||||
---
|
||||
|
||||
## Using SRV records (not recommended)
|
||||
|
||||
:::warning
|
||||
The following methods are **not recommended** due to increased complexity with little benefits. If you have already set up `.well-known` delegation as above, you can safely skip this part.
|
||||
:::
|
||||
|
||||
The following methods uses SRV DNS records and only work with federation traffic. They are only included for completeness.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Using only SRV records</summary>
|
||||
|
||||
If you can't set up `/.well-known/matrix/server` on :443 for some reason, you can set up a SRV record (via your DNS provider) as below:
|
||||
|
||||
- Service and name: `_matrix-fed._tcp.example.com.`
|
||||
- Priority: `10` (can be any number)
|
||||
- Weight: `10` (can be any number)
|
||||
- Port: `443`
|
||||
- Target: `matrix.example.com.`
|
||||
|
||||
On the target's IP at port 443, you must configure a valid route and cert for your server name, `example.com`. Therefore, this method only works to redirect traffic into the right IP/port combo, and can not delegate your federation to a different domain.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Using SRV records + .well-known</summary>
|
||||
|
||||
You can also set up `/.well-known/matrix/server` with a delegated domain but no ports:
|
||||
|
||||
```toml
|
||||
[global.well_known]
|
||||
server = "matrix.example.com"
|
||||
```
|
||||
|
||||
Then, set up a SRV record (via your DNS provider) to announce the port number as below:
|
||||
|
||||
- Service and name: `_matrix-fed._tcp.matrix.example.com.`
|
||||
- Priority: `10` (can be any number)
|
||||
- Weight: `10` (can be any number)
|
||||
- Port: `443`
|
||||
- Target: `matrix.example.com.`
|
||||
|
||||
On the target's IP at port 443, you'll need to provide a valid route and cert for `matrix.example.com`. It provides the same feature as pure `.well-known` delegation, albeit with more parts to handle.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Using SRV records as a fallback for .well-known delegation</summary>
|
||||
|
||||
Assume your delegation is as below:
|
||||
|
||||
```toml
|
||||
[global.well_known]
|
||||
server = "example.com:443"
|
||||
```
|
||||
|
||||
If your Continuwuity instance becomes temporarily unreachable, other servers will not be able to find your `/.well-known/matrix/server` file, and defaults to using `server_name:8448`. This incorrect cache can persist for a long time, and would hinder re-federation when your server eventually comes back online.
|
||||
|
||||
If you want other servers to default to using port :443 even when it is offline, you could set up a SRV record (via your DNS provider) as follows:
|
||||
|
||||
- Service and name: `_matrix-fed._tcp.example.com.`
|
||||
- Priority: `10` (can be any number)
|
||||
- Weight: `10` (can be any number)
|
||||
- Port: `443`
|
||||
- Target: `example.com.`
|
||||
|
||||
On the target's IP at port 443, you'll need to provide a valid route and cert for `example.com`.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
See the following Matrix Specs for full details on client/server resolution mechanisms:
|
||||
|
||||
- [Server-to-Server resolution](https://spec.matrix.org/v1.17/server-server-api/#resolving-server-names) (see this for more information on SRV records)
|
||||
- [Client-to-Server resolution](https://spec.matrix.org/v1.17/client-server-api/#server-discovery)
|
||||
- [MSC1929: Homeserver Admin Contact and Support page](https://github.com/matrix-org/matrix-spec-proposals/pull/1929)
|
||||
+1
-1
@@ -10,4 +10,4 @@ # Calls
|
||||
For either one to work correctly, you have to do some additional setup.
|
||||
|
||||
- For legacy calls to work, you need to set up a TURN/STUN server. [Read the TURN guide for tips on how to set up coturn](./calls/turn.mdx)
|
||||
- For MatrixRTC / Element Call to work, you have to set up the LiveKit backend (foci). LiveKit also uses TURN/STUN to increase reliability - you can setup its inbuilt TURN server, or integrate with an existing one. [Read the LiveKit guide](./calls/livekit.mdx)
|
||||
- For MatrixRTC / Element Call to work, you have to set up the LiveKit backend (foci). LiveKit also uses TURN/STUN to increase reliability, so you might want to configure your TURN server first. [Read the LiveKit guide](./calls/livekit.mdx)
|
||||
|
||||
+53
-168
@@ -4,10 +4,6 @@ # Matrix RTC/Element Call Setup
|
||||
This guide assumes that you are using docker compose for deployment. LiveKit only provides Docker images.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
You can find help setting up Matrix RTC in our dedicated room - [#matrixrtc:continuwuity.org](https://matrix.to/#/%23matrixrtc%3Acontinuwuity.org)
|
||||
:::
|
||||
|
||||
## Instructions
|
||||
|
||||
### 1. Domain
|
||||
@@ -18,20 +14,17 @@ ### 1. Domain
|
||||
|
||||
### 2. Services
|
||||
|
||||
Using LiveKit with Matrix requires two services - LiveKit itself, and a service (`lk-jwt-service`) that grants Matrix users permission to connect to it.
|
||||
Using LiveKit with Matrix requires two services - Livekit itself, and a service (`lk-jwt-service`) that grants Matrix users permission to connect to it.
|
||||
|
||||
You must generate a key and secret to allow the Matrix service to authenticate with LiveKit. `LK_MATRIX_KEY` should be around 20 random characters, and `LK_MATRIX_SECRET` should be around 64. Remember to replace these with the actual values!
|
||||
|
||||
:::tip Generating the secrets
|
||||
LiveKit provides a utility to generate secure random keys
|
||||
```bash
|
||||
~$ docker run --rm livekit/livekit-server:latest generate-keys
|
||||
API Key: APIUxUnMnSkuFWV
|
||||
API Secret: t93ZVjPeoEdyx7Wbet3kG4L3NGZIZVEFvqe0UuiVc22A
|
||||
docker run --rm livekit/livekit-server:latest generate-keys
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
```yaml
|
||||
services:
|
||||
lk-jwt-service:
|
||||
@@ -77,8 +70,6 @@ # - "50100-50200:50100-50200/udp"
|
||||
enable_loopback_candidate: false
|
||||
keys:
|
||||
LK_MATRIX_KEY: LK_MATRIX_SECRET
|
||||
# replace these with your key-secret pair. Example:
|
||||
# APIUxUnMnSkuFWV: t93ZVjPeoEdyx7Wbet3kG4L3NGZIZVEFvqe0UuiVc22A
|
||||
```
|
||||
|
||||
#### Firewall hints
|
||||
@@ -104,7 +95,7 @@ ### 4. Configure your Reverse Proxy
|
||||
|
||||
Reverse proxies can be configured in many different ways - so we can't provide a step by step for this.
|
||||
|
||||
By default, all routes should be forwarded to LiveKit with the exception of the following path prefixes, which should be forwarded to the JWT/Authentication service:
|
||||
By default, all routes should be forwarded to Livekit with the exception of the following path prefixes, which should be forwarded to the JWT/Authentication service:
|
||||
|
||||
- `/sfu/get`
|
||||
- `/healthz`
|
||||
@@ -113,7 +104,7 @@ ### 4. Configure your Reverse Proxy
|
||||
<details>
|
||||
<summary>Example caddy config</summary>
|
||||
```
|
||||
livekit.example.com {
|
||||
matrix-rtc.example.com {
|
||||
|
||||
# for lk-jwt-service
|
||||
@lk-jwt-service path /sfu/get* /healthz* /get_token*
|
||||
@@ -131,7 +122,7 @@ ### 4. Configure your Reverse Proxy
|
||||
<summary>Example nginx config</summary>
|
||||
```
|
||||
server {
|
||||
server_name livekit.example.com;
|
||||
server_name matrix-rtc.example.com;
|
||||
|
||||
# for lk-jwt-service
|
||||
location ~ ^/(sfu/get|healthz|get_token) {
|
||||
@@ -142,7 +133,7 @@ ### 4. Configure your Reverse Proxy
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# for LiveKit
|
||||
# for livekit
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:7880$request_uri;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
@@ -182,11 +173,44 @@ ### 6. Start Everything
|
||||
|
||||
Start up the services using your usual method - for example `docker compose up -d`.
|
||||
|
||||
## Additional TURN configuration
|
||||
## Additional Configuration
|
||||
|
||||
### Using LiveKit's built in TURN server
|
||||
### TURN Integration
|
||||
|
||||
LiveKit includes a built in TURN server which can be used in place of an external option. This TURN server will only work with LiveKit, so you can't use it for legacy Matrix calling or anything else.
|
||||
If you've already set up coturn, there may be a port clash between the two services. To fix this, make sure the `min-port` and `max-port` for coturn so it doesn't overlap with LiveKit's range:
|
||||
|
||||
```ini
|
||||
min-port=50201
|
||||
max-port=65535
|
||||
```
|
||||
|
||||
To improve LiveKit's reliability, you can configure it to use your coturn server.
|
||||
|
||||
Generate a long random secret for LiveKit, and add it to your coturn config under the `static-auth-secret` option. You can add as many secrets as you want - so set a different one for each thing using your TURN server.
|
||||
|
||||
Then configure livekit, making sure to replace `COTURN_SECRET`:
|
||||
|
||||
```yaml
|
||||
# livekit.yaml
|
||||
rtc:
|
||||
turn_servers:
|
||||
- host: coturn.ellis.link
|
||||
port: 3478
|
||||
protocol: tcp
|
||||
secret: "COTURN_SECRET"
|
||||
- host: coturn.ellis.link
|
||||
port: 5349
|
||||
protocol: tls # Only if you've set up TLS in your coturn
|
||||
secret: "COTURN_SECRET"
|
||||
- host: coturn.ellis.link
|
||||
port: 3478
|
||||
protocol: udp
|
||||
secret: "COTURN_SECRET"
|
||||
```
|
||||
|
||||
## LiveKit's built in TURN server
|
||||
|
||||
Livekit includes a built in TURN server which can be used in place of an external option. This TURN server will only work with Livekit, so you can't use it for legacy Matrix calling - or anything else.
|
||||
|
||||
If you don't want to set up a separate TURN server, you can enable this with the following changes:
|
||||
|
||||
@@ -197,159 +221,20 @@ ### add this to livekit.yaml ###
|
||||
udp_port: 3478
|
||||
relay_range_start: 50300
|
||||
relay_range_end: 50400
|
||||
domain: livekit.example.com
|
||||
domain: matrix-rtc.example.com
|
||||
```
|
||||
|
||||
```yaml
|
||||
### add these to livekit's docker-compose ###
|
||||
ports:
|
||||
- "3478:3478/udp"
|
||||
- "50300-50400:50300-50400/udp"
|
||||
### if you're using `network_mode: host`, you can skip this part
|
||||
### Add these to docker-compose ###
|
||||
- "3478:3478/udp"
|
||||
- "50300-50400:50300-50400/udp"
|
||||
```
|
||||
|
||||
Remember to allow the new `3478/udp` and `50100:50200/udp` ports through your firewall.
|
||||
### Related Documentation
|
||||
|
||||
### Integration with an external TURN server
|
||||
|
||||
If you've already set up coturn, there may be a port clash between the two services. To fix this, make sure coturn's `min-port` and `max-port` do not overlap with LiveKit's range:
|
||||
|
||||
```ini
|
||||
min-port=50201
|
||||
max-port=65535
|
||||
```
|
||||
|
||||
To improve LiveKit's reliability, you can configure it to use your coturn server.
|
||||
|
||||
Generate a long random secret for LiveKit, and add it to your coturn config under the `static-auth-secret` option. You can add as many secrets as you want, so set a different one for each thing using your TURN server.
|
||||
|
||||
Then configure LiveKit, making sure to replace `COTURN_SECRET` with the ones you generated:
|
||||
|
||||
```yaml
|
||||
# livekit.yaml
|
||||
rtc:
|
||||
turn_servers:
|
||||
- host: coturn.example.com
|
||||
port: 3478
|
||||
protocol: tcp
|
||||
secret: "COTURN_SECRET"
|
||||
- host: coturn.example.com
|
||||
port: 5349
|
||||
protocol: tls # Only if you've set up TLS in your coturn
|
||||
secret: "COTURN_SECRET"
|
||||
- host: coturn.example.com
|
||||
port: 3478
|
||||
protocol: udp
|
||||
secret: "COTURN_SECRET"
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
To test that LiveKit is successfully integrated with Continuwuity, you will need to replicate its [Token Exchange Flow](https://github.com/element-hq/lk-jwt-service#%EF%B8%8F-how-it-works--token-exchange-flow).
|
||||
|
||||
First, you will need an access token for your current login session. These can be found in your client's settings or obtained via [this website](https://timedout.uk/mxtoken.html).
|
||||
|
||||
Then, using that token, request another OpenID token for use with the lk-jwt-service:
|
||||
|
||||
```bash
|
||||
~$ curl -X POST -H "Authorization: Bearer <session-access-token>" \
|
||||
https://matrix.example.com/_matrix/client/v3/user/@user:example.com/openid/request_token
|
||||
{"access_token":"<openid_access_token>","token_type":"Bearer","matrix_server_name":"example.com","expires_in":3600}
|
||||
```
|
||||
|
||||
Next, create a `payload.json` file with the following content:
|
||||
|
||||
<details>
|
||||
|
||||
<summary>`payload.json`</summary>
|
||||
|
||||
```json
|
||||
{
|
||||
"room_id": "abc",
|
||||
"slot_id": "xyz",
|
||||
"openid_token": {
|
||||
"matrix_server_name": "example.com",
|
||||
"access_token": "<openid_access_token>",
|
||||
"token_type": "Bearer"
|
||||
},
|
||||
"member": {
|
||||
"id": "xyz",
|
||||
"claimed_device_id": "DEVICEID",
|
||||
"claimed_user_id": "@user:example.com"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Replace `matrix_server_name` and `claimed_user_id` with your information, and `<openid_access_token>` with the one you got from the previous step. Other values can be left as-is.
|
||||
|
||||
</details>
|
||||
|
||||
You can then send this payload to the lk-jwt-service:
|
||||
|
||||
```bash
|
||||
~$ curl -X POST -d @payload.json https://livekit.example.com/get_token
|
||||
{"url":"wss://livekit.example.com","jwt":"a_really_really_long_string"}
|
||||
```
|
||||
|
||||
The lk-jwt-service will, after checking against Continuwuity, answer with a `jwt` token to create a LiveKit media room. Use this token to test at the [LiveKit Connection Tester](https://livekit.io/connection-test). If everything works there, then you have set up LiveKit successfully!
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
To debug any issues, you can place a call or redo the Testing instructions, and check the container logs for any specific errors. Use `docker-compose logs --follow` to follow them in real-time.
|
||||
|
||||
### Common errors in Element Call UI
|
||||
|
||||
- `MISSING_MATRIX_RTC_FOCUS`: LiveKit is missing from Continuwuity's config file
|
||||
- "Waiting for media" popup always showing: a LiveKit URL has been configured in Continuwuity, but your client cannot connect to it for some reason
|
||||
|
||||
### Docker loopback networking issues
|
||||
|
||||
Some distros do not allow Docker containers to connect to its host's public IP by default. This would cause `lk-jwt-service` to fail connecting to `livekit` or `continuwuity` on the same host. As a result, you would see connection refused/connection timeouts log entries in the JWT service, even when `LIVEKIT_URL` has been configured correctly.
|
||||
|
||||
To alleviate this, you can try one of the following workarounds:
|
||||
|
||||
- Use `network_mode: host` for the `lk-jwt-service` container (instead of the default bridge networking).
|
||||
|
||||
- Add an `extra_hosts` file mapping livekit's (and continuwuity's) domain name to a localhost address:
|
||||
|
||||
```diff
|
||||
# in docker-compose.yaml
|
||||
services:
|
||||
lk-jwt-service:
|
||||
...
|
||||
+ extra_hosts:
|
||||
+ - "livekit.example.com:127.0.0.1"
|
||||
+ - "matrix.example.com:127.0.0.1"
|
||||
```
|
||||
|
||||
- (**untested, use at your own risk**) Implement an iptables workaround as shown [here](https://forums.docker.com/t/unable-to-connect-to-host-service-from-inside-docker-container/145749/6).
|
||||
|
||||
After implementing the changes and restarting your compose, you can test whether the connection works by cURLing from a sidecar container:
|
||||
|
||||
```bash
|
||||
~$ docker run --rm --net container:lk-jwt-service docker.io/curlimages/curl https://livekit.example.com
|
||||
OK
|
||||
```
|
||||
|
||||
### Workaround for non-federating servers
|
||||
|
||||
When deploying on servers with disabled federation (`enable_registration = false`), LiveKit will fail as it can't fetch the required [OpenID endpoint](https://spec.matrix.org/v1.17/server-server-api/#get_matrixfederationv1openiduserinfo) via federation paths. You can find a workaround for this limitation [here](https://forgejo.ellis.link/continuwuation/continuwuity/issues/1440).
|
||||
|
||||
## Related Documentation
|
||||
|
||||
Guides:
|
||||
|
||||
- [Element Call self-hosting documentation](https://github.com/element-hq/element-call/blob/livekit/docs/self-hosting.md)
|
||||
- [Community guide with overview of LiveKit's mechanisms](https://tomfos.tr/matrix/livekit/)
|
||||
- [Community guide using systemd](https://blog.kimiblock.top/2024/12/24/hosting-element-call/)
|
||||
|
||||
Specifications:
|
||||
|
||||
- [MatrixRTC proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4143)
|
||||
- [LiveKit proposal](https://github.com/matrix-org/matrix-spec-proposals/pull/4195)
|
||||
|
||||
Source code:
|
||||
|
||||
- [Element Call](https://github.com/element-hq/element-call)
|
||||
- [lk-jwt-service](https://github.com/element-hq/lk-jwt-service)
|
||||
- [LiveKit server](https://github.com/livekit/livekit)
|
||||
- [LiveKit GitHub](https://github.com/livekit/livekit)
|
||||
- [LiveKit Connection Tester](https://livekit.io/connection-test) - use with the token returned by `/sfu/get` or `/get_token`
|
||||
- [MatrixRTC proposal](https://half-shot.github.io/msc-crafter/#msc/4143)
|
||||
- [Synapse documentation](https://github.com/element-hq/element-call/blob/livekit/docs/self-hosting.md)
|
||||
- [Community guide](https://tomfos.tr/matrix/livekit/)
|
||||
- [Community guide](https://blog.kimiblock.top/2024/12/24/hosting-element-call/)
|
||||
|
||||
@@ -13,8 +13,9 @@ ## Basics
|
||||
|
||||
The config file to use can be specified on the commandline when running
|
||||
Continuwuity by specifying the `-c`, `--config` flag. Alternatively, you can use
|
||||
the environment variable `CONDUWUIT_CONFIG` to specify the config file to used.
|
||||
Conduit's environment variables are supported for backwards compatibility.
|
||||
the environment variable `CONTINUWUITY_CONFIG` to specify the config file to be
|
||||
used; see [the section on environment variables](#environment-variables) for
|
||||
more information.
|
||||
|
||||
## Option commandline flag
|
||||
|
||||
@@ -52,13 +53,15 @@ ## Environment variables
|
||||
|
||||
All of the settings that are found in the config file can be specified by using
|
||||
environment variables. The environment variable names should be all caps and
|
||||
prefixed with `CONDUWUIT_`.
|
||||
prefixed with `CONTINUWUITY_`.
|
||||
|
||||
For example, if the setting you are changing is `max_request_size`, then the
|
||||
environment variable to set is `CONDUWUIT_MAX_REQUEST_SIZE`.
|
||||
environment variable to set is `CONTINUWUITY_MAX_REQUEST_SIZE`.
|
||||
|
||||
To modify config options not in the `[global]` context such as
|
||||
`[global.well_known]`, use the `__` suffix split: `CONDUWUIT_WELL_KNOWN__SERVER`
|
||||
`[global.well_known]`, use the `__` suffix split:
|
||||
`CONTINUWUITY_WELL_KNOWN__SERVER`
|
||||
|
||||
Conduit's environment variables are supported for backwards compatibility (e.g.
|
||||
Conduit and conduwuit's environment variables are also supported for backwards
|
||||
compatibility, via the `CONDUIT_` and `CONDUWUIT_` prefixes respectively (e.g.
|
||||
`CONDUIT_SERVER_NAME`).
|
||||
|
||||
@@ -16,8 +16,7 @@ services:
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
caddy: example.com
|
||||
caddy.0_respond: /.well-known/matrix/server {"m.server":"matrix.example.com:443"}
|
||||
caddy.1_respond: /.well-known/matrix/client {"m.server":{"base_url":"https://matrix.example.com"},"m.homeserver":{"base_url":"https://matrix.example.com"},"org.matrix.msc3575.proxy":{"url":"https://matrix.example.com"}}
|
||||
caddy.reverse_proxy: /.well-known/matrix/* homeserver:6167
|
||||
|
||||
homeserver:
|
||||
### If you already built the Continuwuity image with 'docker build' or want to use a registry image,
|
||||
@@ -42,6 +41,10 @@ services:
|
||||
#CONTINUWUITY_LOG: warn,state_res=warn
|
||||
CONTINUWUITY_ADDRESS: 0.0.0.0
|
||||
#CONTINUWUITY_CONFIG: '/etc/continuwuity.toml' # Uncomment if you mapped config toml above
|
||||
|
||||
# Required for .well-known delegation - edit these according to your chosen domain
|
||||
CONTINUWUITY_WELL_KNOWN__CLIENT: https://matrix.example.com
|
||||
CONTINUWUITY_WELL_KNOWN__SERVER: matrix.example.com:443
|
||||
networks:
|
||||
- caddy
|
||||
labels:
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
"message": "Welcome to Continuwuity! Important announcements about the project will appear here."
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"id": 10,
|
||||
"mention_room": false,
|
||||
"date": "2026-02-09",
|
||||
"message": "Yesterday we released [v0.5.4](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.4). Bugfixes, performance improvements and more moderation features! There's also a security fix, so please update as soon as possible. Don't forget to join [our announcements channel](https://matrix.to/#/!jIdNjSM5X-V5JVx2h2kAhUZIIQ08GyzPL55NFZAH1vM/%2489TY9CqRg4-ff1MGo3Ulc5r5X4pakfdzT-99RD8Docc?via=ellis.link&via=explodie.org&via=matrix.org) to get important information sooner <3 "
|
||||
"date": "2026-03-03",
|
||||
"message": "We've just released [v0.5.6](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.6), which contains a few security improvements - plus significant reliability and performance improvements. Please update as soon as possible. \n\nWe released [v0.5.5](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.5) two weeks ago, but it skipped your admin room straight to [our announcements channel](https://matrix.to/#/!jIdNjSM5X-V5JVx2h2kAhUZIIQ08GyzPL55NFZAH1vM?via=ellis.link&via=gingershaped.computer&via=matrix.org). Make sure you're there to get important information as soon as we announce it! [Our space](https://matrix.to/#/!8cR4g-i9ucof69E4JHNg9LbPVkGprHb3SzcrGBDDJgk?via=continuwuity.org&via=ellis.link&via=matrix.org) has also gained a bunch of new and interesting rooms - be there or be square."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ ## `!admin media delete-past-remote-media`
|
||||
* Delete all remote and local media from 3 days ago, up until now:
|
||||
|
||||
`!admin media delete-past-remote-media -a 3d
|
||||
-yes-i-want-to-delete-local-media`
|
||||
--yes-i-want-to-delete-local-media`
|
||||
|
||||
## `!admin media delete-all-from-user`
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
rocksdbAllFeatures = self'.packages.rocksdb.override {
|
||||
enableJemalloc = true;
|
||||
enableLiburing = true;
|
||||
};
|
||||
|
||||
commonAttrs = (uwulib.build.commonAttrs { }) // {
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
commonAttrsArgs.profile = "release";
|
||||
rocksdb = self'.packages.rocksdb.override {
|
||||
enableJemalloc = true;
|
||||
enableLiburing = true;
|
||||
};
|
||||
features = {
|
||||
enabledFeatures = "all";
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
rust-jemalloc-sys-unprefixed,
|
||||
|
||||
enableJemalloc ? false,
|
||||
enableLiburing ? false,
|
||||
|
||||
fetchFromGitea,
|
||||
|
||||
@@ -32,7 +31,7 @@ in
|
||||
|
||||
# for some reason enableLiburing in nixpkgs rocksdb is default true
|
||||
# which breaks Darwin entirely
|
||||
enableLiburing = enableLiburing && notDarwin;
|
||||
enableLiburing = notDarwin;
|
||||
}).overrideAttrs
|
||||
(old: {
|
||||
src = fetchFromGitea {
|
||||
@@ -74,7 +73,7 @@ in
|
||||
"USE_RTTI"
|
||||
]);
|
||||
|
||||
enableLiburing = enableLiburing && notDarwin;
|
||||
enableLiburing = notDarwin;
|
||||
|
||||
# outputs has "tools" which we don't need or use
|
||||
outputs = [ "out" ];
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
uwulib = inputs.self.uwulib.init pkgs;
|
||||
rocksdbAllFeatures = self'.packages.rocksdb.override {
|
||||
enableJemalloc = true;
|
||||
enableLiburing = true;
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
Generated
+188
-153
@@ -119,15 +119,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rsbuild/core": {
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-dfH+Pt2GuF3rWOWGsf5XOhn3Zarvr4DoHwoI1arAsCGvpzoeud3DNGmWPy13tngj0r/YvQRcPTRBCRV4RP5CMw==",
|
||||
"version": "2.0.0-beta.6",
|
||||
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.0.0-beta.6.tgz",
|
||||
"integrity": "sha512-DUBhUzvzj6xlGUAHTTipFskSuZmVEuTX7lGU+ToPuo8n3bsQrWn/UBOEQAd45g66k7QfXadoZ/v7eodQErpvGQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rspack/core": "2.0.0-beta.0",
|
||||
"@swc/helpers": "^0.5.18",
|
||||
"jiti": "^2.6.1"
|
||||
"@rspack/core": "2.0.0-beta.3",
|
||||
"@swc/helpers": "^0.5.19"
|
||||
},
|
||||
"bin": {
|
||||
"rsbuild": "bin/rsbuild.js"
|
||||
@@ -159,28 +158,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-L6PPqhwZWC2vzwdhBItNPXw+7V4sq+MBDRXLdd8NMqaJSCB5iKdJIbpbEQucST9Nn7V28IYoQTXs6+ol5vWUBA==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-GSj+d8AlLs1oElhYq32vIN/eAsxWG9jy0EiNgSxWTt5Gdamv87kcvsV4jwfWIjlltdnBIJgey2RnU+hDZlTAvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"@rspack/binding-darwin-arm64": "2.0.0-beta.0",
|
||||
"@rspack/binding-darwin-x64": "2.0.0-beta.0",
|
||||
"@rspack/binding-linux-arm64-gnu": "2.0.0-beta.0",
|
||||
"@rspack/binding-linux-arm64-musl": "2.0.0-beta.0",
|
||||
"@rspack/binding-linux-x64-gnu": "2.0.0-beta.0",
|
||||
"@rspack/binding-linux-x64-musl": "2.0.0-beta.0",
|
||||
"@rspack/binding-wasm32-wasi": "2.0.0-beta.0",
|
||||
"@rspack/binding-win32-arm64-msvc": "2.0.0-beta.0",
|
||||
"@rspack/binding-win32-ia32-msvc": "2.0.0-beta.0",
|
||||
"@rspack/binding-win32-x64-msvc": "2.0.0-beta.0"
|
||||
"@rspack/binding-darwin-arm64": "2.0.0-beta.3",
|
||||
"@rspack/binding-darwin-x64": "2.0.0-beta.3",
|
||||
"@rspack/binding-linux-arm64-gnu": "2.0.0-beta.3",
|
||||
"@rspack/binding-linux-arm64-musl": "2.0.0-beta.3",
|
||||
"@rspack/binding-linux-x64-gnu": "2.0.0-beta.3",
|
||||
"@rspack/binding-linux-x64-musl": "2.0.0-beta.3",
|
||||
"@rspack/binding-wasm32-wasi": "2.0.0-beta.3",
|
||||
"@rspack/binding-win32-arm64-msvc": "2.0.0-beta.3",
|
||||
"@rspack/binding-win32-ia32-msvc": "2.0.0-beta.3",
|
||||
"@rspack/binding-win32-x64-msvc": "2.0.0-beta.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding-darwin-arm64": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-PPx1+SPEROSvDKmBuCbsE7W9tk07ajPosyvyuafv2wbBI6PW2rNcz62uzpIFS+FTgwwZ5u/06WXRtlD2xW9bKg==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-QebSomLWlCbFsC0sfDuGqLJtkgyrnr38vrCepWukaAXIY4ANy5QB49LDKdLpVv6bKlC95MpnW37NvSNWY5GMYA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -192,9 +191,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-darwin-x64": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-GucsfjrSKBZ9cuOTXmHWxeY2wPmaNyvGNxTyzttjRcfwqOWz8r+ku6PCsMSXUqxZRYWW1L9mvtTdlDrzTYJZ0w==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-EysmBq+sz+Ph0bu0gXpU1uuZG9gXgjqY+w3MJel+ieTFyQO3L/R56V32McgssMbheJbYcviDDn7Tz4D+lTvdJA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -206,9 +205,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-arm64-gnu": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-nTtYtklRZD4sb2RIFCF9YS8tZ/MjpqIBKVS3YIvdXcfHUdVfmQHTZGtwEuZGg6AxTC5L1hcvkYmTXCG0ok7auw==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-iFPj4TQZKewnqWPfTbyk3F8QCBI/Edv7TVSRIPBHRnCM0lvYZl/8IZlUzXSamLvrtDpouF0nUzht/fktoWOhAg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -220,9 +219,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-arm64-musl": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-S2fshx0Rf7/XYwoMLaqFsVg4y+VAfHzubrczy8AW5xIs6UNC3eRLVTgShLerUPtF6SG+v6NQxQ9JI3vOo2qPOA==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-355mygfCNb0eF/y4HgtJcd0i9csNTG4Z15PCCplIkSAKJpFpkORM2xJb50BqsbhVafYl6AHoBlGWAo9iIzUb/w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -234,9 +233,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-x64-gnu": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-yx5Fk1gl7lfkvqcjolNLCNeduIs6C2alMsQ/kZ1pLeP5MPquVOYNqs6EcDPIp+fUjo3lZYtnJBiZKK+QosbzYg==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-U8a+bcP/tkMyiwiO9XfeRYYO20YPGiZNxWWt7FEsdmRuRAl6M+EmWaJllJFQtKH+GG8IN93pNoVPMvARjLoJOQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -248,9 +247,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-x64-musl": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-sBX4b2W0PgehlAVT224k0Q6GaH6t9HP+hBNDrbX/g6d0hfxZN56gm5NfOTOD1Rien4v7OBEejJ3/uFbm1WjwYQ==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-g81rqkaqDFRTID2VrHBYeM+xZe8yWov7IcryTrl9RGXXr61s+6Tu/mWyM378PuHOCyMNu7G3blVaSjLvKauG6Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -262,9 +261,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-wasm32-wasi": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-o6OatnNvb4kCzXbCaomhENGaCsO3naIyAqqErew90HeAwa1lfY3NhRfDLeIyuANQ+xqFl34/R7n8q3ZDx3nd4Q==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-tzGd8H2oj5F3oR/Hxp+J68zVU/nG+9ndH2KK3/RieVjNAiVNHCR0/ZU9D47s6fnmvWOqAQ1qO8gnVoVLopC4YA==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
@@ -276,9 +275,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-arm64-msvc": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-neCzVllXzIqM8p8qKb89qV7wyk233gC/V9VrHIKbGeQjAEzpBsk5GOWlFbq5DDL6tivQ+uzYaTrZWm9tb2qxXg==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-TZZRSWa34sm5WyoQHwnyBjLJ4w3fcWRYA9ybYjSVWjUU6tVGdMiHiZp+WexUpIETvChLXU1JENNmBg/U7wvZEA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -290,9 +289,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-ia32-msvc": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-/f0n2eO+DxMKQm9IebeMQJITx8M/+RvY/i8d3sAQZBgR53izn8y7EcDlidXpr24/2DvkLbiub8IyCKPlhLB+1A==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-VFnfdbJhyl6gNW1VzTyd1ZrHCboHPR7vrOalEsulQRqVNbtDkjm1sqLHtDcLmhTEv0a9r4lli8uubWDwmel8KQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -304,9 +303,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-x64-msvc": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-dx4zgiAT88EQE7kEUpr7Z9EZAwLnO5FhzWzvd/cDK4bkqYsx+rTklgf/c0EYPBeroXCxlGiMsuC9wHAFNK7sFw==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-rwZ6Y3b3oqPj+ZDPPRxr3136HUPKDSlPQa4v7bBOPLDlrFDFOynMIEqDUUi5+8lPaUQ8WWR0aJK4cgcTTT0Siw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -318,20 +317,19 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/core": {
|
||||
"version": "2.0.0-beta.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.0.0-beta.0.tgz",
|
||||
"integrity": "sha512-aEqlQQjiXixT5i9S4DFtiAap8ZjF6pOgfY2ALHOizins/QqWyB8dyLxSoXdzt7JixmKcFmHkbL9XahO28BlVUA==",
|
||||
"version": "2.0.0-beta.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.0.0-beta.3.tgz",
|
||||
"integrity": "sha512-VuLteRIesuyFFTXZaciUY0lwDZiwMc7JcpE8guvjArztDhtpVvlaOcLlVBp/Yza8c/Tk8Dxwe1ARzFL7xG1/0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rspack/binding": "2.0.0-beta.0",
|
||||
"@rspack/lite-tapable": "1.1.0"
|
||||
"@rspack/binding": "2.0.0-beta.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@module-federation/runtime-tools": ">=0.22.0",
|
||||
"@module-federation/runtime-tools": "^0.24.1 || ^2.0.0",
|
||||
"@swc/helpers": ">=0.5.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
@@ -343,13 +341,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/lite-tapable": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz",
|
||||
"integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rspack/plugin-react-refresh": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.6.0.tgz",
|
||||
@@ -371,22 +362,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/core": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.3.tgz",
|
||||
"integrity": "sha512-a+JJFiALqMxGJBqR38/lkN6tas42UF4jRIhu6RilC/3DdqpfqR8j6jjQFOmqoNKo6ZGXW2W+i1Pscn6drvoG3w==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/core/-/core-2.0.4.tgz",
|
||||
"integrity": "sha512-OdeGMY75OFzyRZvXuBEMre3q8Y4/OjYJa4vVBDp4Z2E65LSt8+hYkzzkarEl6sFWqbp8c1o9qfSUf4xMctmKvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mdx-js/mdx": "^3.1.1",
|
||||
"@mdx-js/react": "^3.1.1",
|
||||
"@rsbuild/core": "2.0.0-beta.3",
|
||||
"@rsbuild/core": "2.0.0-beta.6",
|
||||
"@rsbuild/plugin-react": "~1.4.5",
|
||||
"@rspress/shared": "2.0.3",
|
||||
"@shikijs/rehype": "^3.21.0",
|
||||
"@rspress/shared": "2.0.4",
|
||||
"@shikijs/rehype": "^4.0.1",
|
||||
"@types/unist": "^3.0.3",
|
||||
"@unhead/react": "^2.1.4",
|
||||
"@unhead/react": "^2.1.9",
|
||||
"body-scroll-lock": "4.0.0-beta.0",
|
||||
"cac": "^6.7.14",
|
||||
"cac": "^7.0.0",
|
||||
"chokidar": "^3.6.0",
|
||||
"clsx": "2.1.1",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
@@ -404,7 +395,8 @@
|
||||
"react-dom": "^19.2.4",
|
||||
"react-lazy-with-preload": "^2.2.1",
|
||||
"react-reconciler": "0.33.0",
|
||||
"react-router-dom": "^7.13.0",
|
||||
"react-render-to-markdown": "19.0.1",
|
||||
"react-router-dom": "^7.13.1",
|
||||
"rehype-external-links": "^3.0.0",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
@@ -412,7 +404,7 @@
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-stringify": "^11.0.0",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"shiki": "^3.21.0",
|
||||
"shiki": "^4.0.1",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"tinypool": "^1.1.1",
|
||||
"unified": "^11.0.5",
|
||||
@@ -428,125 +420,162 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/plugin-client-redirects": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.3.tgz",
|
||||
"integrity": "sha512-9+SoAbfoxM6OCRWx8jWHHi2zwJDcNaej/URx0CWZk8tvQ618yJW5mXJydknlac62399eYh/F7C3w8TZM3ORGVA==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-client-redirects/-/plugin-client-redirects-2.0.4.tgz",
|
||||
"integrity": "sha512-cm7VNfisVCHe+YHNjd9YrWt6/WtJ5I/oNRyjt+tqCeOcC1IJSX2LhNXpNN5h9az3wxYn37kVctBUjzqkj2FQ+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rspress/core": "^2.0.3"
|
||||
"@rspress/core": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/plugin-sitemap": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.3.tgz",
|
||||
"integrity": "sha512-SKa7YEAdkUqya2YjMKbakg3kcYMkXgXhTQdDsHd+QlJWN8j8cDPiCcctMZu8iIPeKZlb+hTJkTWvh27LSIKdOA==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/plugin-sitemap/-/plugin-sitemap-2.0.4.tgz",
|
||||
"integrity": "sha512-TKaj3/8+P1fP3sD5NOaWVMXvRvJFQmuJQlUBxhRM0oiUHhzNNkVy/2YXkjYJuXuMhFPLnOWCjrYjTG3xcZE7Wg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@rspress/core": "^2.0.3"
|
||||
"@rspress/core": "^2.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@rspress/shared": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.3.tgz",
|
||||
"integrity": "sha512-yI9G4P165fSsmm6QoYTUrdgUis1aFnDh04GcM4SQIpL3itvEZhGtItgoeGkX9EWbnEjhriwI8mTqDDJIp+vrGA==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@rspress/shared/-/shared-2.0.4.tgz",
|
||||
"integrity": "sha512-os2nzsPgHKVFXjDoW7N53rmhLChCw/y2O2TGilT4w2A4HNJa2oJwRk0UryXbxxWD5C85HErTjovs2uBdhdOTtA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rsbuild/core": "2.0.0-beta.3",
|
||||
"@shikijs/rehype": "^3.21.0",
|
||||
"@rsbuild/core": "2.0.0-beta.6",
|
||||
"@shikijs/rehype": "^4.0.1",
|
||||
"gray-matter": "4.0.3",
|
||||
"lodash-es": "^4.17.23",
|
||||
"unified": "^11.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/core": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.22.0.tgz",
|
||||
"integrity": "sha512-iAlTtSDDbJiRpvgL5ugKEATDtHdUVkqgHDm/gbD2ZS9c88mx7G1zSYjjOxp5Qa0eaW0MAQosFRmJSk354PRoQA==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.1.tgz",
|
||||
"integrity": "sha512-vWvqi9JNgz1dRL9Nvog5wtx7RuNkf7MEPl2mU/cyUUxJeH1CAr3t+81h8zO8zs7DK6cKLMoU9TvukWIDjP4Lzg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.22.0",
|
||||
"@shikijs/primitive": "4.0.1",
|
||||
"@shikijs/types": "4.0.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4",
|
||||
"hast-util-to-html": "^9.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/engine-javascript": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.22.0.tgz",
|
||||
"integrity": "sha512-jdKhfgW9CRtj3Tor0L7+yPwdG3CgP7W+ZEqSsojrMzCjD1e0IxIbwUMDDpYlVBlC08TACg4puwFGkZfLS+56Tw==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.1.tgz",
|
||||
"integrity": "sha512-DJK9NiwtGYqMuKCRO4Ip0FKNDQpmaiS+K5bFjJ7DWFn4zHueDWgaUG8kAofkrnXF6zPPYYQY7J5FYVW9MbZyBg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.22.0",
|
||||
"@shikijs/types": "4.0.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"oniguruma-to-es": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/engine-oniguruma": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.22.0.tgz",
|
||||
"integrity": "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.1.tgz",
|
||||
"integrity": "sha512-oCWdCTDch3J8Kc0OZJ98KuUPC02O1VqIE3W/e2uvrHqTxYRR21RGEJMtchrgrxhsoJJCzmIciKsqG+q/yD+Cxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.22.0",
|
||||
"@shikijs/types": "4.0.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/langs": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.22.0.tgz",
|
||||
"integrity": "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.1.tgz",
|
||||
"integrity": "sha512-v/mluaybWdnGJR4GqAR6zh8qAZohW9k+cGYT28Y7M8+jLbC0l4yG085O1A+WkseHTn+awd+P3UBymb2+MXFc8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.22.0"
|
||||
"@shikijs/types": "4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/primitive": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.1.tgz",
|
||||
"integrity": "sha512-ns0hHZc5eWZuvuIEJz2pTx3Qecz0aRVYumVQJ8JgWY2tq/dH8WxdcVM49Fc2NsHEILNIT6vfdW9MF26RANWiTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "4.0.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/rehype": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-3.22.0.tgz",
|
||||
"integrity": "sha512-69b2VPc6XBy/VmAJlpBU5By+bJSBdE2nvgRCZXav7zujbrjXuT0F60DIrjKuutjPqNufuizE+E8tIZr2Yn8Z+g==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.0.1.tgz",
|
||||
"integrity": "sha512-bx7bYA0/p/pgeEICaPO0jT6TXrXHmr9tGRUDhOMy1cAUN2YA0iANfXX7seBnImy8DGu/rxm1ij9/ZofYrAaUjQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.22.0",
|
||||
"@shikijs/types": "4.0.1",
|
||||
"@types/hast": "^3.0.4",
|
||||
"hast-util-to-string": "^3.0.1",
|
||||
"shiki": "3.22.0",
|
||||
"shiki": "4.0.1",
|
||||
"unified": "^11.0.5",
|
||||
"unist-util-visit": "^5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/themes": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz",
|
||||
"integrity": "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.1.tgz",
|
||||
"integrity": "sha512-FW41C/D6j/yKQkzVdjrRPiJCtgeDaYRJFEyCKFCINuRJRj9WcmubhP4KQHPZ4+9eT87jruSrYPyoblNRyDFzvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.22.0"
|
||||
"@shikijs/types": "4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/types": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.22.0.tgz",
|
||||
"integrity": "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.1.tgz",
|
||||
"integrity": "sha512-EaygPEn57+jJ76mw+nTLvIpJMAcMPokFbrF8lufsZP7Ukk+ToJYEcswN1G0e49nUZAq7aCQtoeW219A8HK1ZOw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/vscode-textmate": {
|
||||
@@ -557,9 +586,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.18",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz",
|
||||
"integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==",
|
||||
"version": "0.5.19",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.19.tgz",
|
||||
"integrity": "sha512-QamiFeIK3txNjgUTNppE6MiG3p7TdninpZu0E0PbqVh1a9FNLT2FRhisaa4NcaX52XVhA5l7Pk58Ft7Sqi/2sA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -664,13 +693,13 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@unhead/react": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@unhead/react/-/react-2.1.4.tgz",
|
||||
"integrity": "sha512-3DzMi5nJkUyLVfQF/q78smCvcSy84TTYgTwXVz5s3AjUcLyHro5Z7bLWriwk1dn5+YRfEsec8aPkLCMi5VjMZg==",
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@unhead/react/-/react-2.1.10.tgz",
|
||||
"integrity": "sha512-z9IzzkaCI1GyiBwVRMt4dGc2mOvsj9drbAdXGMy6DWpu9FwTR37ZTmAi7UeCVyIkpVdIaNalz7vkbvGG8afFng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"unhead": "2.1.4"
|
||||
"unhead": "2.1.10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/harlan-zw"
|
||||
@@ -781,13 +810,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cac": {
|
||||
"version": "6.7.14",
|
||||
"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
|
||||
"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz",
|
||||
"integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=20.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ccount": {
|
||||
@@ -1698,16 +1727,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||
@@ -3019,10 +3038,23 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-render-to-markdown": {
|
||||
"version": "19.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-render-to-markdown/-/react-render-to-markdown-19.0.1.tgz",
|
||||
"integrity": "sha512-BPv48o+ubcu2JyUDIktvJXFqLIZqR7hA4mvGu1eFIofz9fogT2me9UvXwRvqvGs9jEtNaJkxZIUKUX0oiK4hDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-reconciler": "0.33.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=19"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.13.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz",
|
||||
"integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==",
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.1.tgz",
|
||||
"integrity": "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3043,13 +3075,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.13.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz",
|
||||
"integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==",
|
||||
"version": "7.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.1.tgz",
|
||||
"integrity": "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-router": "7.13.0"
|
||||
"react-router": "7.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@@ -3345,20 +3377,23 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shiki": {
|
||||
"version": "3.22.0",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-3.22.0.tgz",
|
||||
"integrity": "sha512-LBnhsoYEe0Eou4e1VgJACes+O6S6QC0w71fCSp5Oya79inkwkm15gQ1UF6VtQ8j/taMDh79hAB49WUk8ALQW3g==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.1.tgz",
|
||||
"integrity": "sha512-EkAEhDTN5WhpoQFXFw79OHIrSAfHhlImeCdSyg4u4XvrpxKEmdo/9x/HWSowujAnUrFsGOwWiE58a6GVentMnQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/core": "3.22.0",
|
||||
"@shikijs/engine-javascript": "3.22.0",
|
||||
"@shikijs/engine-oniguruma": "3.22.0",
|
||||
"@shikijs/langs": "3.22.0",
|
||||
"@shikijs/themes": "3.22.0",
|
||||
"@shikijs/types": "3.22.0",
|
||||
"@shikijs/core": "4.0.1",
|
||||
"@shikijs/engine-javascript": "4.0.1",
|
||||
"@shikijs/engine-oniguruma": "4.0.1",
|
||||
"@shikijs/langs": "4.0.1",
|
||||
"@shikijs/themes": "4.0.1",
|
||||
"@shikijs/types": "4.0.1",
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
@@ -3563,9 +3598,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/unhead": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.4.tgz",
|
||||
"integrity": "sha512-+5091sJqtNNmgfQ07zJOgUnMIMKzVKAWjeMlSrTdSGPB6JSozhpjUKuMfWEoLxlMAfhIvgOU8Me0XJvmMA/0fA==",
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/unhead/-/unhead-2.1.10.tgz",
|
||||
"integrity": "sha512-We8l9uNF8zz6U8lfQaVG70+R/QBfQx1oPIgXin4BtZnK2IQpz6yazQ0qjMNVBDw2ADgF2ea58BtvSK+XX5AS7g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use conduwuit::{Err, Result};
|
||||
use conduwuit::{Err, Result, utils::response::LimitReadExt};
|
||||
use futures::StreamExt;
|
||||
use ruma::{OwnedRoomId, OwnedServerName, OwnedUserId};
|
||||
|
||||
@@ -55,7 +55,15 @@ pub(super) async fn fetch_support_well_known(&self, server_name: OwnedServerName
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let text = response.text().await?;
|
||||
let text = response
|
||||
.limit_read_text(
|
||||
self.services
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("u64 fits into usize"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if text.is_empty() {
|
||||
return Err!("Response text/body is empty.");
|
||||
|
||||
@@ -40,7 +40,7 @@ pub enum MediaCommand {
|
||||
/// * Delete all remote and local media from 3 days ago, up until now:
|
||||
///
|
||||
/// `!admin media delete-past-remote-media -a 3d
|
||||
///-yes-i-want-to-delete-local-media`
|
||||
///--yes-i-want-to-delete-local-media`
|
||||
#[command(verbatim_doc_comment)]
|
||||
DeletePastRemoteMedia {
|
||||
/// The relative time (e.g. 30s, 5m, 7d) from now within which to
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
},
|
||||
events::{
|
||||
AnyGlobalAccountDataEventContent, AnyRoomAccountDataEventContent,
|
||||
GlobalAccountDataEventType, RoomAccountDataEventType,
|
||||
RoomAccountDataEventType,
|
||||
},
|
||||
serde::Raw,
|
||||
};
|
||||
@@ -126,12 +126,6 @@ async fn set_account_data(
|
||||
)));
|
||||
}
|
||||
|
||||
if event_type_s == GlobalAccountDataEventType::PushRules.to_cow_str() {
|
||||
return Err!(Request(BadJson(
|
||||
"This endpoint cannot be used for setting/configuring push rules."
|
||||
)));
|
||||
}
|
||||
|
||||
let data: serde_json::Value = serde_json::from_str(data.get())
|
||||
.map_err(|e| err!(Request(BadJson(warn!("Invalid JSON provided: {e}")))))?;
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduwuit::{Err, Result, at};
|
||||
use futures::StreamExt;
|
||||
use ruma::api::client::dehydrated_device::{
|
||||
delete_dehydrated_device::unstable as delete_dehydrated_device,
|
||||
get_dehydrated_device::unstable as get_dehydrated_device, get_events::unstable as get_events,
|
||||
put_dehydrated_device::unstable as put_dehydrated_device,
|
||||
};
|
||||
|
||||
use crate::Ruma;
|
||||
|
||||
const MAX_BATCH_EVENTS: usize = 50;
|
||||
|
||||
/// # `PUT /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Creates or overwrites the user's dehydrated device.
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn put_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
body: Ruma<put_dehydrated_device::Request>,
|
||||
) -> Result<put_dehydrated_device::Response> {
|
||||
let sender_user = body
|
||||
.sender_user
|
||||
.as_deref()
|
||||
.expect("AccessToken authentication required");
|
||||
|
||||
let device_id = body.body.device_id.clone();
|
||||
|
||||
services
|
||||
.users
|
||||
.set_dehydrated_device(sender_user, body.body)
|
||||
.await?;
|
||||
|
||||
Ok(put_dehydrated_device::Response { device_id })
|
||||
}
|
||||
|
||||
/// # `DELETE /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Deletes the user's dehydrated device without replacement.
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn delete_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
body: Ruma<delete_dehydrated_device::Request>,
|
||||
) -> Result<delete_dehydrated_device::Response> {
|
||||
let sender_user = body.sender_user();
|
||||
|
||||
let device_id = services.users.get_dehydrated_device_id(sender_user).await?;
|
||||
|
||||
services.users.remove_device(sender_user, &device_id).await;
|
||||
|
||||
Ok(delete_dehydrated_device::Response { device_id })
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/../dehydrated_device`
|
||||
///
|
||||
/// Gets the user's dehydrated device
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn get_dehydrated_device_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
body: Ruma<get_dehydrated_device::Request>,
|
||||
) -> Result<get_dehydrated_device::Response> {
|
||||
let sender_user = body.sender_user();
|
||||
|
||||
let device = services.users.get_dehydrated_device(sender_user).await?;
|
||||
|
||||
Ok(get_dehydrated_device::Response {
|
||||
device_id: device.device_id,
|
||||
device_data: device.device_data,
|
||||
})
|
||||
}
|
||||
|
||||
/// # `GET /_matrix/client/../dehydrated_device/{device_id}/events`
|
||||
///
|
||||
/// Paginates the events of the dehydrated device.
|
||||
#[tracing::instrument(skip_all, fields(%client))]
|
||||
pub(crate) async fn get_dehydrated_events_route(
|
||||
State(services): State<crate::State>,
|
||||
InsecureClientIp(client): InsecureClientIp,
|
||||
body: Ruma<get_events::Request>,
|
||||
) -> Result<get_events::Response> {
|
||||
let sender_user = body.sender_user();
|
||||
|
||||
let device_id = &body.body.device_id;
|
||||
let existing_id = services.users.get_dehydrated_device_id(sender_user).await;
|
||||
|
||||
if existing_id.as_ref().is_err()
|
||||
|| existing_id
|
||||
.as_ref()
|
||||
.is_ok_and(|existing_id| existing_id != device_id)
|
||||
{
|
||||
return Err!(Request(Forbidden("Not the dehydrated device_id.")));
|
||||
}
|
||||
|
||||
let since: Option<u64> = body
|
||||
.body
|
||||
.next_batch
|
||||
.as_deref()
|
||||
.map(str::parse)
|
||||
.transpose()?;
|
||||
|
||||
let mut next_batch: Option<u64> = None;
|
||||
let events = services
|
||||
.users
|
||||
.get_to_device_events(sender_user, device_id, since, None)
|
||||
.take(MAX_BATCH_EVENTS)
|
||||
.inspect(|&(count, _)| {
|
||||
next_batch.replace(count);
|
||||
})
|
||||
.map(at!(1))
|
||||
.collect()
|
||||
.await;
|
||||
|
||||
Ok(get_events::Response {
|
||||
events,
|
||||
next_batch: next_batch.as_ref().map(ToString::to_string),
|
||||
})
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
pub(super) mod backup;
|
||||
pub(super) mod capabilities;
|
||||
pub(super) mod context;
|
||||
pub(super) mod dehydrated_device;
|
||||
pub(super) mod device;
|
||||
pub(super) mod directory;
|
||||
pub(super) mod filter;
|
||||
@@ -49,6 +50,7 @@
|
||||
pub(super) use backup::*;
|
||||
pub(super) use capabilities::*;
|
||||
pub(super) use context::*;
|
||||
pub(super) use dehydrated_device::*;
|
||||
pub(super) use device::*;
|
||||
pub(super) use directory::*;
|
||||
pub(super) use filter::*;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use conduwuit::{
|
||||
Event, PduCount, PduEvent, Result, at, debug_warn,
|
||||
Event, PduEvent, Result, at, debug_warn,
|
||||
pdu::EventHash,
|
||||
trace,
|
||||
utils::{self, IterStream, future::ReadyEqExt, stream::WidebandExt as _},
|
||||
@@ -68,9 +68,13 @@ pub(super) async fn load_left_room(
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// return early if this is an incremental sync, and we've already synced this
|
||||
// leave to the user, and `include_leave` isn't set on the filter.
|
||||
if !filter.room.include_leave && last_sync_end_count >= Some(left_count) {
|
||||
// return early if:
|
||||
// - this is an initial sync and the room filter doesn't include leaves, or
|
||||
// - this is an incremental sync, and we've already synced the leave, and the
|
||||
// room filter doesn't include leaves
|
||||
if last_sync_end_count.is_none_or(|last_sync_end_count| last_sync_end_count >= left_count)
|
||||
&& !filter.room.include_leave
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
@@ -195,27 +199,13 @@ async fn build_left_state_and_timeline(
|
||||
leave_shortstatehash: ShortStateHash,
|
||||
prev_membership_event: PduEvent,
|
||||
) -> Result<(TimelinePdus, Vec<PduEvent>)> {
|
||||
let SyncContext {
|
||||
syncing_user,
|
||||
last_sync_end_count,
|
||||
filter,
|
||||
..
|
||||
} = sync_context;
|
||||
let SyncContext { syncing_user, filter, .. } = sync_context;
|
||||
|
||||
let timeline_start_count = if let Some(last_sync_end_count) = last_sync_end_count {
|
||||
// for incremental syncs, start the timeline after `since`
|
||||
PduCount::Normal(last_sync_end_count)
|
||||
} else {
|
||||
// for initial syncs, start the timeline after the previous membership
|
||||
// event. we don't want to include the membership event itself
|
||||
// because clients get confused when they see a `join`
|
||||
// membership event in a `leave` room.
|
||||
services
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu_count(&prev_membership_event.event_id)
|
||||
.await?
|
||||
};
|
||||
let timeline_start_count = services
|
||||
.rooms
|
||||
.timeline
|
||||
.get_pdu_count(&prev_membership_event.event_id)
|
||||
.await?;
|
||||
|
||||
// end the timeline at the user's leave event
|
||||
let timeline_end_count = services
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
use axum::extract::State;
|
||||
use axum_client_ip::InsecureClientIp;
|
||||
use conduwuit::{
|
||||
Result, extract_variant,
|
||||
Result, at, extract_variant,
|
||||
utils::{
|
||||
ReadyExt, TryFutureExtExt,
|
||||
stream::{BroadbandExt, Tools, WidebandExt},
|
||||
@@ -297,12 +297,18 @@ pub(crate) async fn build_sync_events(
|
||||
.rooms
|
||||
.state_cache
|
||||
.rooms_left(syncing_user)
|
||||
.broad_filter_map(|(room_id, leave_pdu)| {
|
||||
load_left_room(services, context, room_id.clone(), leave_pdu)
|
||||
.map_ok(move |left_room| (room_id, left_room))
|
||||
.ok()
|
||||
.broad_filter_map(|(room_id, leave_pdu)| async {
|
||||
let left_room = load_left_room(services, context, room_id.clone(), leave_pdu).await;
|
||||
|
||||
match left_room {
|
||||
| Ok(Some(left_room)) => Some((room_id, left_room)),
|
||||
| Ok(None) => None,
|
||||
| Err(err) => {
|
||||
warn!(?err, %room_id, "error loading joined room");
|
||||
None
|
||||
},
|
||||
}
|
||||
})
|
||||
.ready_filter_map(|(room_id, left_room)| left_room.map(|left_room| (room_id, left_room)))
|
||||
.collect();
|
||||
|
||||
let invited_rooms = services
|
||||
@@ -385,6 +391,7 @@ pub(crate) async fn build_sync_events(
|
||||
last_sync_end_count,
|
||||
Some(current_count),
|
||||
)
|
||||
.map(at!(1))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let device_one_time_keys_count = services
|
||||
|
||||
@@ -1029,6 +1029,7 @@ async fn collect_to_device(
|
||||
events: services
|
||||
.users
|
||||
.get_to_device_events(sender_user, sender_device, None, Some(next_batch))
|
||||
.map(at!(1))
|
||||
.collect()
|
||||
.await,
|
||||
})
|
||||
|
||||
@@ -50,6 +50,7 @@ pub(crate) async fn get_supported_versions_route(
|
||||
("org.matrix.msc2836".to_owned(), true), /* threading/threads (https://github.com/matrix-org/matrix-spec-proposals/pull/2836) */
|
||||
("org.matrix.msc2946".to_owned(), true), /* spaces/hierarchy summaries (https://github.com/matrix-org/matrix-spec-proposals/pull/2946) */
|
||||
("org.matrix.msc3026.busy_presence".to_owned(), true), /* busy presence status (https://github.com/matrix-org/matrix-spec-proposals/pull/3026) */
|
||||
("org.matrix.msc3814".to_owned(), true), /* dehydrated devices */
|
||||
("org.matrix.msc3827".to_owned(), true), /* filtering of /publicRooms by room type (https://github.com/matrix-org/matrix-spec-proposals/pull/3827) */
|
||||
("org.matrix.msc3952_intentional_mentions".to_owned(), true), /* intentional mentions (https://github.com/matrix-org/matrix-spec-proposals/pull/3952) */
|
||||
("org.matrix.msc3916.stable".to_owned(), true), /* authenticated media (https://github.com/matrix-org/matrix-spec-proposals/pull/3916) */
|
||||
|
||||
@@ -160,6 +160,10 @@ pub fn build(router: Router<State>, server: &Server) -> Router<State> {
|
||||
.ruma_route(&client::update_device_route)
|
||||
.ruma_route(&client::delete_device_route)
|
||||
.ruma_route(&client::delete_devices_route)
|
||||
.ruma_route(&client::put_dehydrated_device_route)
|
||||
.ruma_route(&client::delete_dehydrated_device_route)
|
||||
.ruma_route(&client::get_dehydrated_device_route)
|
||||
.ruma_route(&client::get_dehydrated_events_route)
|
||||
.ruma_route(&client::get_tags_route)
|
||||
.ruma_route(&client::update_tag_route)
|
||||
.ruma_route(&client::delete_tag_route)
|
||||
|
||||
@@ -174,6 +174,7 @@ pub fn check(config: &Config) -> Result {
|
||||
if config.allow_registration
|
||||
&& config.yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse
|
||||
&& config.registration_token.is_none()
|
||||
&& config.registration_token_file.is_none()
|
||||
{
|
||||
warn!(
|
||||
"Open registration is enabled via setting \
|
||||
|
||||
+23
-7
@@ -609,19 +609,25 @@ pub struct Config {
|
||||
pub yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse: bool,
|
||||
|
||||
/// A static registration token that new users will have to provide when
|
||||
/// creating an account. If unset and `allow_registration` is true,
|
||||
/// you must set
|
||||
/// `yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse`
|
||||
/// to true to allow open registration without any conditions.
|
||||
///
|
||||
/// If you do not want to set a static token, the `!admin token` commands
|
||||
/// may also be used to manage registration tokens.
|
||||
/// creating an account. This token does not supersede tokens from other
|
||||
/// sources, such as the `!admin token` command or the
|
||||
/// `registration_token_file` configuration option.
|
||||
///
|
||||
/// example: "o&^uCtes4HPf0Vu@F20jQeeWE7"
|
||||
///
|
||||
/// display: sensitive
|
||||
pub registration_token: Option<String>,
|
||||
|
||||
/// A path to a file containing static registration tokens, one per line.
|
||||
/// Tokens in this file do not supersede tokens from other sources, such as
|
||||
/// the `!admin token` command or the `registration_token` configuration
|
||||
/// option.
|
||||
///
|
||||
/// The file will be read once, when Continuwuity starts. It is not
|
||||
/// currently reread when the server configuration is reloaded. If the file
|
||||
/// cannot be read, Continuwuity will fail to start.
|
||||
pub registration_token_file: Option<PathBuf>,
|
||||
|
||||
/// The public site key for reCaptcha. If this is provided, reCaptcha
|
||||
/// becomes required during registration. If both captcha *and*
|
||||
/// registration token are enabled, both will be required during
|
||||
@@ -2068,6 +2074,16 @@ pub struct Config {
|
||||
pub allow_invalid_tls_certificates_yes_i_know_what_the_fuck_i_am_doing_with_this_and_i_know_this_is_insecure:
|
||||
bool,
|
||||
|
||||
/// Forcibly disables first-run mode.
|
||||
///
|
||||
/// This is intended to be used for Complement testing to allow the test
|
||||
/// suite to register users, because first-run mode interferes with open
|
||||
/// registration.
|
||||
///
|
||||
/// display: hidden
|
||||
#[serde(default)]
|
||||
pub force_disable_first_run_mode: bool,
|
||||
|
||||
/// display: nested
|
||||
#[serde(default)]
|
||||
pub ldap: LdapConfig,
|
||||
|
||||
@@ -191,6 +191,7 @@ pub fn status_code(&self) -> http::StatusCode {
|
||||
| Self::Reqwest(error) => error.status().unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
|
||||
| Self::Conflict(_) => StatusCode::CONFLICT,
|
||||
| Self::Io(error) => response::io_error_code(error.kind()),
|
||||
| Self::Uiaa(_) => StatusCode::UNAUTHORIZED,
|
||||
| _ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
pub mod math;
|
||||
pub mod mutex_map;
|
||||
pub mod rand;
|
||||
pub mod response;
|
||||
pub mod result;
|
||||
pub mod set;
|
||||
pub mod stream;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
use futures::StreamExt;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::Err;
|
||||
|
||||
/// Reads the response body while enforcing a maximum size limit to prevent
|
||||
/// memory exhaustion.
|
||||
pub async fn limit_read(response: reqwest::Response, max_size: u64) -> crate::Result<Vec<u8>> {
|
||||
if response.content_length().is_some_and(|len| len > max_size) {
|
||||
return Err!(BadServerResponse("Response too large"));
|
||||
}
|
||||
let mut data = Vec::new();
|
||||
let mut reader = response.bytes_stream();
|
||||
|
||||
while let Some(chunk) = reader.next().await {
|
||||
let chunk = chunk?;
|
||||
data.extend_from_slice(&chunk);
|
||||
|
||||
if data.len() > max_size.to_usize().expect("max_size must fit in usize") {
|
||||
return Err!(BadServerResponse("Response too large"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
/// Reads the response body as text while enforcing a maximum size limit to
|
||||
/// prevent memory exhaustion.
|
||||
pub async fn limit_read_text(
|
||||
response: reqwest::Response,
|
||||
max_size: u64,
|
||||
) -> crate::Result<String> {
|
||||
let text = String::from_utf8(limit_read(response, max_size).await?)?;
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
#[allow(async_fn_in_trait)]
|
||||
pub trait LimitReadExt {
|
||||
async fn limit_read(self, max_size: u64) -> crate::Result<Vec<u8>>;
|
||||
async fn limit_read_text(self, max_size: u64) -> crate::Result<String>;
|
||||
}
|
||||
|
||||
impl LimitReadExt for reqwest::Response {
|
||||
async fn limit_read(self, max_size: u64) -> crate::Result<Vec<u8>> {
|
||||
limit_read(self, max_size).await
|
||||
}
|
||||
|
||||
async fn limit_read_text(self, max_size: u64) -> crate::Result<String> {
|
||||
limit_read_text(self, max_size).await
|
||||
}
|
||||
}
|
||||
@@ -362,6 +362,10 @@ pub(super) fn open_list(db: &Arc<Engine>, maps: &[Descriptor]) -> Result<Maps> {
|
||||
name: "userid_blurhash",
|
||||
..descriptor::RANDOM_SMALL
|
||||
},
|
||||
Descriptor {
|
||||
name: "userid_dehydrateddevice",
|
||||
..descriptor::RANDOM_SMALL
|
||||
},
|
||||
Descriptor {
|
||||
name: "userid_devicelistversion",
|
||||
..descriptor::RANDOM_SMALL
|
||||
|
||||
@@ -530,7 +530,12 @@ async fn handle_response_error(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn is_admin_command<E>(&self, event: &E, body: &str) -> Option<InvocationSource>
|
||||
pub async fn is_admin_command<E>(
|
||||
&self,
|
||||
event: &E,
|
||||
body: &str,
|
||||
sent_locally: bool,
|
||||
) -> Option<InvocationSource>
|
||||
where
|
||||
E: Event + Send + Sync,
|
||||
{
|
||||
@@ -580,6 +585,15 @@ pub async fn is_admin_command<E>(&self, event: &E, body: &str) -> Option<Invocat
|
||||
return None;
|
||||
}
|
||||
|
||||
// Escaped commands must be sent locally (via client API), not via federation
|
||||
if !sent_locally {
|
||||
conduwuit::warn!(
|
||||
"Ignoring escaped admin command from {} that arrived via federation",
|
||||
event.sender()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
// Looks good
|
||||
Some(InvocationSource::EscapedCommand)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use conduwuit::{Result, Server, debug, error, warn};
|
||||
use conduwuit::{Result, Server, debug, error, utils::response::LimitReadExt, warn};
|
||||
use database::{Deserialized, Map};
|
||||
use ruma::events::{Mentions, room::message::RoomMessageEventContent};
|
||||
use serde::Deserialize;
|
||||
@@ -137,7 +137,7 @@ async fn check(&self) -> Result<()> {
|
||||
.get(CHECK_FOR_ANNOUNCEMENTS_URL)
|
||||
.send()
|
||||
.await?
|
||||
.text()
|
||||
.limit_read_text(1024 * 1024)
|
||||
.await?;
|
||||
|
||||
let response = serde_json::from_str::<CheckForAnnouncementsResponse>(&response)?;
|
||||
|
||||
@@ -19,10 +19,9 @@ impl Service {
|
||||
/// Get the registration token set in the config file, if it exists.
|
||||
#[must_use]
|
||||
pub fn get_config_file_token(&self) -> Option<ValidToken> {
|
||||
self.registration_token.clone().map(|token| ValidToken {
|
||||
token,
|
||||
source: ValidTokenSource::ConfigFile,
|
||||
})
|
||||
self.registration_token
|
||||
.clone()
|
||||
.map(|token| ValidToken { token, source: ValidTokenSource::Config })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, debug, debug::INFO_SPAN_LEVEL, debug_error, debug_warn, err,
|
||||
error::inspect_debug_log, implement, trace,
|
||||
Err, Error, Result, debug, debug::INFO_SPAN_LEVEL, debug_error, debug_warn, err, implement,
|
||||
trace, utils::response::LimitReadExt,
|
||||
};
|
||||
use http::{HeaderValue, header::AUTHORIZATION};
|
||||
use ipaddress::IPAddress;
|
||||
@@ -133,7 +133,22 @@ async fn handle_response<T>(
|
||||
where
|
||||
T: OutgoingRequest + Send,
|
||||
{
|
||||
let response = into_http_response(dest, actual, method, url, response).await?;
|
||||
const HUGE_ENDPOINTS: [&str; 2] =
|
||||
["/_matrix/federation/v2/send_join/", "/_matrix/federation/v2/state/"];
|
||||
let size_limit: u64 = if HUGE_ENDPOINTS.iter().any(|e| url.path().starts_with(e)) {
|
||||
// Some federation endpoints can return huge response bodies, so we'll bump the
|
||||
// limit for those endpoints specifically.
|
||||
self.services
|
||||
.server
|
||||
.config
|
||||
.max_request_size
|
||||
.saturating_mul(10)
|
||||
} else {
|
||||
self.services.server.config.max_request_size
|
||||
}
|
||||
.try_into()
|
||||
.expect("size_limit (usize) should fit within a u64");
|
||||
let response = into_http_response(dest, actual, method, url, response, size_limit).await?;
|
||||
|
||||
T::IncomingResponse::try_from_http_response(response)
|
||||
.map_err(|e| err!(BadServerResponse("Server returned bad 200 response: {e:?}")))
|
||||
@@ -145,6 +160,7 @@ async fn into_http_response(
|
||||
method: &Method,
|
||||
url: &Url,
|
||||
mut response: Response,
|
||||
max_size: u64,
|
||||
) -> Result<http::Response<Bytes>> {
|
||||
let status = response.status();
|
||||
trace!(
|
||||
@@ -167,14 +183,14 @@ async fn into_http_response(
|
||||
);
|
||||
|
||||
trace!("Waiting for response body...");
|
||||
let body = response
|
||||
.bytes()
|
||||
.await
|
||||
.inspect_err(inspect_debug_log)
|
||||
.unwrap_or_else(|_| Vec::new().into());
|
||||
|
||||
let http_response = http_response_builder
|
||||
.body(body)
|
||||
.body(
|
||||
response
|
||||
.limit_read(max_size)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.into(),
|
||||
)
|
||||
.expect("reqwest body is valid http body");
|
||||
|
||||
debug!("Got {status:?} for {method} {url}");
|
||||
|
||||
@@ -67,15 +67,17 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
|
||||
|
||||
async fn worker(self: Arc<Self>) -> Result {
|
||||
// first run mode will be enabled if there are no local users
|
||||
let is_first_run = self
|
||||
.services
|
||||
.users
|
||||
.list_local_users()
|
||||
.ready_filter(|user| *user != self.services.globals.server_user)
|
||||
.next()
|
||||
.await
|
||||
.is_none();
|
||||
// first run mode will be enabled if there are no local users, provided it's not
|
||||
// forcibly disabled for Complement tests
|
||||
let is_first_run = !self.services.config.force_disable_first_run_mode
|
||||
&& self
|
||||
.services
|
||||
.users
|
||||
.list_local_users()
|
||||
.ready_filter(|user| *user != self.services.globals.server_user)
|
||||
.next()
|
||||
.await
|
||||
.is_none();
|
||||
|
||||
self.first_run_marker
|
||||
.set(if is_first_run {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
use std::time::SystemTime;
|
||||
|
||||
use conduwuit::{Err, Result, debug, err};
|
||||
use conduwuit::{Err, Result, debug, err, utils::response::LimitReadExt};
|
||||
use conduwuit_core::implement;
|
||||
use ipaddress::IPAddress;
|
||||
use serde::Serialize;
|
||||
@@ -112,8 +112,22 @@ pub async fn download_image(&self, url: &str) -> Result<UrlPreviewData> {
|
||||
use image::ImageReader;
|
||||
use ruma::Mxc;
|
||||
|
||||
let image = self.services.client.url_preview.get(url).send().await?;
|
||||
let image = image.bytes().await?;
|
||||
let image = self
|
||||
.services
|
||||
.client
|
||||
.url_preview
|
||||
.get(url)
|
||||
.send()
|
||||
.await?
|
||||
.limit_read(
|
||||
self.services
|
||||
.server
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("u64 should fit in usize"),
|
||||
)
|
||||
.await?;
|
||||
let mxc = Mxc {
|
||||
server_name: self.services.globals.server_name(),
|
||||
media_id: &random_string(super::MXC_LENGTH),
|
||||
@@ -151,24 +165,20 @@ async fn download_html(&self, url: &str) -> Result<UrlPreviewData> {
|
||||
use webpage::HTML;
|
||||
|
||||
let client = &self.services.client.url_preview;
|
||||
let mut response = client.get(url).send().await?;
|
||||
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
while let Some(chunk) = response.chunk().await? {
|
||||
bytes.extend_from_slice(&chunk);
|
||||
if bytes.len() > self.services.globals.url_preview_max_spider_size() {
|
||||
debug!(
|
||||
"Response body from URL {} exceeds url_preview_max_spider_size ({}), not \
|
||||
processing the rest of the response body and assuming our necessary data is in \
|
||||
this range.",
|
||||
url,
|
||||
self.services.globals.url_preview_max_spider_size()
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let body = String::from_utf8_lossy(&bytes);
|
||||
let Ok(html) = HTML::from_string(body.to_string(), Some(url.to_owned())) else {
|
||||
let body = client
|
||||
.get(url)
|
||||
.send()
|
||||
.await?
|
||||
.limit_read_text(
|
||||
self.services
|
||||
.server
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("u64 should fit in usize"),
|
||||
)
|
||||
.await?;
|
||||
let Ok(html) = HTML::from_string(body.clone(), Some(url.to_owned())) else {
|
||||
return Err!(Request(Unknown("Failed to parse HTML")));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use conduwuit::{
|
||||
Err, Error, Result, debug_warn, err, implement,
|
||||
utils::content_disposition::make_content_disposition,
|
||||
utils::{content_disposition::make_content_disposition, response::LimitReadExt},
|
||||
};
|
||||
use http::header::{CONTENT_DISPOSITION, CONTENT_TYPE, HeaderValue};
|
||||
use ruma::{
|
||||
@@ -286,10 +286,15 @@ async fn location_request(&self, location: &str) -> Result<FileMeta> {
|
||||
.and_then(Result::ok);
|
||||
|
||||
response
|
||||
.bytes()
|
||||
.limit_read(
|
||||
self.services
|
||||
.server
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("u64 should fit in usize"),
|
||||
)
|
||||
.await
|
||||
.map(Vec::from)
|
||||
.map_err(Into::into)
|
||||
.map(|content| FileMeta {
|
||||
content: Some(content),
|
||||
content_type: content_type.clone(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::{fmt::Debug, mem, sync::Arc};
|
||||
|
||||
use bytes::BytesMut;
|
||||
use conduwuit::utils::response::LimitReadExt;
|
||||
use conduwuit_core::{
|
||||
Err, Event, Result, debug_warn, err, trace,
|
||||
utils::{stream::TryIgnore, string_from_bytes},
|
||||
@@ -30,7 +31,7 @@
|
||||
uint,
|
||||
};
|
||||
|
||||
use crate::{Dep, client, globals, rooms, sending, users};
|
||||
use crate::{Dep, client, config, globals, rooms, sending, users};
|
||||
|
||||
pub struct Service {
|
||||
db: Data,
|
||||
@@ -39,6 +40,7 @@ pub struct Service {
|
||||
|
||||
struct Services {
|
||||
globals: Dep<globals::Service>,
|
||||
config: Dep<config::Service>,
|
||||
client: Dep<client::Service>,
|
||||
state_accessor: Dep<rooms::state_accessor::Service>,
|
||||
state_cache: Dep<rooms::state_cache::Service>,
|
||||
@@ -61,6 +63,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
services: Services {
|
||||
globals: args.depend::<globals::Service>("globals"),
|
||||
client: args.depend::<client::Service>("client"),
|
||||
config: args.depend::<config::Service>("config"),
|
||||
state_accessor: args
|
||||
.depend::<rooms::state_accessor::Service>("rooms::state_accessor"),
|
||||
state_cache: args.depend::<rooms::state_cache::Service>("rooms::state_cache"),
|
||||
@@ -245,7 +248,15 @@ pub async fn send_request<T>(&self, dest: &str, request: T) -> Result<T::Incomin
|
||||
.expect("http::response::Builder is usable"),
|
||||
);
|
||||
|
||||
let body = response.bytes().await?;
|
||||
let body = response
|
||||
.limit_read(
|
||||
self.services
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("usize fits into u64"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if !status.is_success() {
|
||||
debug_warn!("Push gateway response body: {:?}", string_from_bytes(&body));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::{future::ready, pin::Pin, sync::Arc};
|
||||
|
||||
use conduwuit::{Err, Result, utils};
|
||||
use conduwuit::{Err, Result, err, utils};
|
||||
use data::Data;
|
||||
pub use data::{DatabaseTokenInfo, TokenExpires};
|
||||
use futures::{
|
||||
@@ -18,6 +18,9 @@
|
||||
pub struct Service {
|
||||
db: Data,
|
||||
services: Services,
|
||||
/// The registration tokens which were read from the registration token
|
||||
/// file, if one is configured.
|
||||
registration_tokens_from_file: Vec<String>,
|
||||
}
|
||||
|
||||
struct Services {
|
||||
@@ -45,34 +48,54 @@ fn eq(&self, other: &str) -> bool { self.token == other }
|
||||
/// The source of a valid database token.
|
||||
#[derive(Debug)]
|
||||
pub enum ValidTokenSource {
|
||||
/// The static token set in the homeserver's config file, which is
|
||||
/// always valid.
|
||||
ConfigFile,
|
||||
/// The static token set in the homeserver's config file.
|
||||
Config,
|
||||
/// A database token which has been checked to be valid.
|
||||
Database(DatabaseTokenInfo),
|
||||
/// The single-use token which may be used to create the homeserver's first
|
||||
/// account.
|
||||
FirstAccount,
|
||||
/// A registration token read from the registration token file set in the
|
||||
/// config.
|
||||
TokenFile,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ValidTokenSource {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
| Self::ConfigFile => write!(f, "Token defined in config."),
|
||||
| Self::Config => write!(f, "Static token set in the server configuration."),
|
||||
| Self::Database(info) => info.fmt(f),
|
||||
| Self::FirstAccount => write!(f, "Initial setup token."),
|
||||
| Self::TokenFile => write!(f, "Static token set in the registration token file."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Service for Service {
|
||||
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
let registration_tokens_from_file = args.server.config.registration_token_file
|
||||
.clone()
|
||||
// If the token file option was set, read the path it points to
|
||||
.map(std::fs::read_to_string)
|
||||
.transpose()
|
||||
.map_err(|err| err!("Failed to read registration token file: {err}"))
|
||||
.map(|tokens| {
|
||||
if let Some(tokens) = tokens {
|
||||
// If the token file option was set, return the file's lines as tokens
|
||||
tokens.lines().map(ToOwned::to_owned).collect()
|
||||
} else {
|
||||
// Otherwise, if the option wasn't set, return no tokens
|
||||
vec![]
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(Arc::new(Self {
|
||||
db: Data::new(args.db),
|
||||
services: Services {
|
||||
config: args.depend::<config::Service>("config"),
|
||||
firstrun: args.depend::<firstrun::Service>("firstrun"),
|
||||
},
|
||||
registration_tokens_from_file,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -97,12 +120,23 @@ pub fn issue_token(
|
||||
(token, info)
|
||||
}
|
||||
|
||||
/// Get all the "special" registration tokens that aren't defined in the
|
||||
/// Get all the static registration tokens that aren't defined in the
|
||||
/// database.
|
||||
fn iterate_static_tokens(&self) -> impl Iterator<Item = ValidToken> {
|
||||
// This does not include the first-account token, because it's special:
|
||||
// no other registration tokens are valid when it is set.
|
||||
self.services.config.get_config_file_token().into_iter()
|
||||
// This does not include the first-account token, because it has special
|
||||
// behavior: no other registration tokens are valid when it is set.
|
||||
self.services
|
||||
.config
|
||||
.get_config_file_token()
|
||||
.into_iter()
|
||||
.chain(
|
||||
self.registration_tokens_from_file
|
||||
.iter()
|
||||
.map(|token_string| ValidToken {
|
||||
token: token_string.clone(),
|
||||
source: ValidTokenSource::TokenFile,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Validate a registration token.
|
||||
@@ -158,7 +192,7 @@ pub fn mark_token_as_used(&self, ValidToken { token, source }: ValidToken) {
|
||||
/// revoked.
|
||||
pub fn revoke_token(&self, ValidToken { token, source }: ValidToken) -> Result {
|
||||
match source {
|
||||
| ValidTokenSource::ConfigFile => {
|
||||
| ValidTokenSource::Config => {
|
||||
Err!(
|
||||
"The token set in the config file cannot be revoked. Edit the config file \
|
||||
to change it."
|
||||
@@ -171,6 +205,12 @@ pub fn revoke_token(&self, ValidToken { token, source }: ValidToken) -> Result {
|
||||
| ValidTokenSource::FirstAccount => {
|
||||
Err!("The initial setup token cannot be revoked.")
|
||||
},
|
||||
| ValidTokenSource::TokenFile => {
|
||||
Err!(
|
||||
"Tokens set in the registration token file cannot be revoked. Edit the \
|
||||
registration token file and restart Continuwuity to change them."
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use conduwuit::{Result, debug, debug_error, debug_info, debug_warn, implement, trace};
|
||||
use conduwuit::{
|
||||
Result, debug, debug_error, debug_info, implement, trace, utils::response::LimitReadExt,
|
||||
};
|
||||
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(name = "well-known", level = "debug", skip(self, dest))]
|
||||
@@ -24,12 +26,8 @@ pub(super) async fn request_well_known(&self, dest: &str) -> Result<Option<Strin
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let text = response.text().await?;
|
||||
let text = response.limit_read_text(8192).await?;
|
||||
trace!("response text: {text:?}");
|
||||
if text.len() >= 12288 {
|
||||
debug_warn!("response contains junk");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let body: serde_json::Value = serde_json::from_str(&text).unwrap_or_default();
|
||||
|
||||
|
||||
@@ -94,6 +94,12 @@ pub fn set_alias(
|
||||
|
||||
#[tracing::instrument(skip(self))]
|
||||
pub async fn remove_alias(&self, alias: &RoomAliasId, user_id: &UserId) -> Result<()> {
|
||||
if alias == self.services.globals.admin_alias
|
||||
&& user_id != self.services.globals.server_user
|
||||
{
|
||||
return Err!(Request(Forbidden("Only the server user can remove this alias")));
|
||||
}
|
||||
|
||||
if !self.user_can_remove_alias(alias, user_id).await? {
|
||||
return Err!(Request(Forbidden("User is not permitted to remove this alias.")));
|
||||
}
|
||||
|
||||
@@ -63,7 +63,9 @@ pub(super) async fn fetch_state<Pdu>(
|
||||
},
|
||||
| hash_map::Entry::Occupied(_) => {
|
||||
return Err!(Database(
|
||||
"State event's type and state_key combination exists multiple times.",
|
||||
"State event's type and state_key combination exists multiple times: {}, {}",
|
||||
pdu.kind(),
|
||||
state_key
|
||||
));
|
||||
},
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ pub async fn handle_incoming_pdu<'a>(
|
||||
);
|
||||
return Err!(Request(TooLarge("PDU is too large")));
|
||||
}
|
||||
trace!("processing incoming pdu from {origin} for room {room_id} with event id {event_id}");
|
||||
trace!("processing incoming PDU from {origin} for room {room_id} with event id {event_id}");
|
||||
|
||||
// 1.1 Check we even know about the room
|
||||
let meta_exists = self.services.metadata.exists(room_id).map(Ok);
|
||||
@@ -164,7 +164,7 @@ pub async fn handle_incoming_pdu<'a>(
|
||||
sender_acl_check.map(|o| o.unwrap_or(Ok(()))),
|
||||
)
|
||||
.await
|
||||
.inspect_err(|e| debug_error!("failed to handle incoming PDU: {e}"))?;
|
||||
.inspect_err(|e| debug_error!(%origin, "failed to handle incoming PDU {event_id}: {e}"))?;
|
||||
|
||||
if is_disabled {
|
||||
return Err!(Request(Forbidden("Federation of this room is disabled by this server.")));
|
||||
@@ -195,6 +195,7 @@ pub async fn handle_incoming_pdu<'a>(
|
||||
}
|
||||
info!(
|
||||
%origin,
|
||||
%room_id,
|
||||
"Dropping inbound PDU for room we aren't participating in"
|
||||
);
|
||||
return Err!(Request(NotFound("This server is not participating in that room.")));
|
||||
|
||||
@@ -162,7 +162,9 @@ pub(super) async fn handle_outlier_pdu<'a, Pdu>(
|
||||
},
|
||||
| hash_map::Entry::Occupied(_) => {
|
||||
return Err!(Request(InvalidParam(
|
||||
"Auth event's type and state_key combination exists multiple times.",
|
||||
"Auth event's type and state_key combination exists multiple times: {}, {}",
|
||||
auth_event.kind,
|
||||
auth_event.state_key().unwrap_or("")
|
||||
)));
|
||||
},
|
||||
}
|
||||
|
||||
@@ -72,6 +72,26 @@ pub async fn append_incoming_pdu<'a, Leaves>(
|
||||
.append_pdu(pdu, pdu_json, new_room_leaves, state_lock, room_id)
|
||||
.await?;
|
||||
|
||||
// Process admin commands for federation events
|
||||
if *pdu.kind() == TimelineEventType::RoomMessage {
|
||||
let content: ExtractBody = pdu.get_content()?;
|
||||
if let Some(body) = content.body {
|
||||
if let Some(source) = self
|
||||
.services
|
||||
.admin
|
||||
.is_admin_command(pdu, &body, false)
|
||||
.await
|
||||
{
|
||||
self.services.admin.command_with_sender(
|
||||
body,
|
||||
Some(pdu.event_id().into()),
|
||||
source,
|
||||
pdu.sender.clone().into(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(pdu_id))
|
||||
}
|
||||
|
||||
@@ -334,15 +354,6 @@ pub async fn append_pdu<'a, Leaves>(
|
||||
let content: ExtractBody = pdu.get_content()?;
|
||||
if let Some(body) = content.body {
|
||||
self.services.search.index_pdu(shortroomid, &pdu_id, &body);
|
||||
|
||||
if let Some(source) = self.services.admin.is_admin_command(pdu, &body).await {
|
||||
self.services.admin.command_with_sender(
|
||||
body,
|
||||
Some((pdu.event_id()).into()),
|
||||
source,
|
||||
pdu.sender.clone().into(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
| _ => {},
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
use super::RoomMutexGuard;
|
||||
use super::{ExtractBody, RoomMutexGuard};
|
||||
|
||||
/// Creates a new persisted data unit and adds it to a room. This function
|
||||
/// takes a roomid_mutex_state, meaning that only this function is able to
|
||||
@@ -126,6 +126,26 @@ pub async fn build_and_append_pdu(
|
||||
.boxed()
|
||||
.await?;
|
||||
|
||||
// Process admin commands for locally sent events
|
||||
if *pdu.kind() == TimelineEventType::RoomMessage {
|
||||
let content: ExtractBody = pdu.get_content()?;
|
||||
if let Some(body) = content.body {
|
||||
if let Some(source) = self
|
||||
.services
|
||||
.admin
|
||||
.is_admin_command(&pdu, &body, true)
|
||||
.await
|
||||
{
|
||||
self.services.admin.command_with_sender(
|
||||
body,
|
||||
Some(pdu.event_id().into()),
|
||||
source,
|
||||
pdu.sender.clone().into(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We set the room state after inserting the pdu, so that we never have a moment
|
||||
// in time where events in the current room state do not exist
|
||||
trace!("Setting room state for room {room_id}");
|
||||
@@ -167,6 +187,8 @@ pub async fn build_and_append_pdu(
|
||||
Ok(pdu.event_id().to_owned())
|
||||
}
|
||||
|
||||
/// Assert invariants about the admin room, to prevent (for example) all admins
|
||||
/// from leaving or being banned from the room
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(skip_all, level = "debug")]
|
||||
async fn check_pdu_for_admin_room<Pdu>(&self, pdu: &Pdu, sender: &UserId) -> Result
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{fmt::Debug, mem};
|
||||
|
||||
use bytes::BytesMut;
|
||||
use conduwuit::{Err, Result, debug_error, err, utils, warn};
|
||||
use conduwuit::{Err, Result, debug_error, err, utils, utils::response::LimitReadExt, warn};
|
||||
use reqwest::Client;
|
||||
use ruma::api::{IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken};
|
||||
|
||||
@@ -38,7 +38,7 @@ pub(crate) async fn send_antispam_request<T>(
|
||||
.expect("http::response::Builder is usable"),
|
||||
);
|
||||
|
||||
let body = response.bytes().await?; // TODO: handle timeout
|
||||
let body = response.limit_read(65535).await?; // TODO: handle timeout
|
||||
|
||||
if !status.is_success() {
|
||||
debug_error!("Antispam response bytes: {:?}", utils::string_from_bytes(&body));
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::{fmt::Debug, mem};
|
||||
|
||||
use bytes::BytesMut;
|
||||
use conduwuit::{Err, Result, debug_error, err, implement, trace, utils, warn};
|
||||
use conduwuit::{
|
||||
Err, Result, debug_error, err, implement, trace, utils, utils::response::LimitReadExt, warn,
|
||||
};
|
||||
use ruma::api::{
|
||||
IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken, appservice::Registration,
|
||||
};
|
||||
@@ -77,7 +79,15 @@ pub async fn send_appservice_request<T>(
|
||||
.expect("http::response::Builder is usable"),
|
||||
);
|
||||
|
||||
let body = response.bytes().await?;
|
||||
let body = response
|
||||
.limit_read(
|
||||
self.server
|
||||
.config
|
||||
.max_request_size
|
||||
.try_into()
|
||||
.expect("usize fits into u64"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if !status.is_success() {
|
||||
debug_error!("Appservice response bytes: {:?}", utils::string_from_bytes(&body));
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use conduwuit_core::{
|
||||
Error, Event, Result, debug, err, error,
|
||||
Error, Event, Result, at, debug, err, error,
|
||||
result::LogErr,
|
||||
trace,
|
||||
utils::{
|
||||
@@ -175,7 +175,7 @@ async fn handle_response_ok<'a>(
|
||||
if !new_events.is_empty() {
|
||||
self.db.mark_as_active(new_events.iter());
|
||||
|
||||
let new_events_vec = new_events.into_iter().map(|(_, event)| event).collect();
|
||||
let new_events_vec = new_events.into_iter().map(at!(1)).collect();
|
||||
futures.push(self.send_events(dest.clone(), new_events_vec));
|
||||
} else {
|
||||
statuses.remove(dest);
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
use conduwuit::{Err, Result, implement, trace};
|
||||
use conduwuit_database::{Deserialized, Json};
|
||||
use ruma::{
|
||||
DeviceId, OwnedDeviceId, UserId,
|
||||
api::client::dehydrated_device::{
|
||||
DehydratedDeviceData, put_dehydrated_device::unstable::Request,
|
||||
},
|
||||
serde::Raw,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct DehydratedDevice {
|
||||
/// Unique ID of the device.
|
||||
pub device_id: OwnedDeviceId,
|
||||
|
||||
/// Contains serialized and encrypted private data.
|
||||
pub device_data: Raw<DehydratedDeviceData>,
|
||||
}
|
||||
|
||||
/// Creates or recreates the user's dehydrated device.
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(
|
||||
level = "info",
|
||||
skip_all,
|
||||
fields(
|
||||
%user_id,
|
||||
device_id = %request.device_id,
|
||||
display_name = ?request.initial_device_display_name,
|
||||
)
|
||||
)]
|
||||
pub async fn set_dehydrated_device(&self, user_id: &UserId, request: Request) -> Result {
|
||||
assert!(
|
||||
self.exists(user_id).await,
|
||||
"Tried to create dehydrated device for non-existent user"
|
||||
);
|
||||
|
||||
let existing_id = self.get_dehydrated_device_id(user_id).await;
|
||||
|
||||
if existing_id.is_err()
|
||||
&& self
|
||||
.get_device_metadata(user_id, &request.device_id)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return Err!("A hydrated device already exists with that ID.");
|
||||
}
|
||||
|
||||
if let Ok(existing_id) = existing_id {
|
||||
self.remove_device(user_id, &existing_id).await;
|
||||
}
|
||||
|
||||
self.create_device(
|
||||
user_id,
|
||||
&request.device_id,
|
||||
"",
|
||||
request.initial_device_display_name.clone(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
trace!(device_data = ?request.device_data);
|
||||
self.db.userid_dehydrateddevice.raw_put(
|
||||
user_id,
|
||||
Json(&DehydratedDevice {
|
||||
device_id: request.device_id.clone(),
|
||||
device_data: request.device_data,
|
||||
}),
|
||||
);
|
||||
|
||||
trace!(device_keys = ?request.device_keys);
|
||||
self.add_device_keys(user_id, &request.device_id, &request.device_keys)
|
||||
.await;
|
||||
|
||||
trace!(one_time_keys = ?request.one_time_keys);
|
||||
for (one_time_key_key, one_time_key_value) in &request.one_time_keys {
|
||||
self.add_one_time_key(user_id, &request.device_id, one_time_key_key, one_time_key_value)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes a user's dehydrated device.
|
||||
///
|
||||
/// Calling this directly will remove the dehydrated data but leak the frontage
|
||||
/// device. Thus this is called by the regular device interface such that the
|
||||
/// dehydrated data will not leak instead.
|
||||
///
|
||||
/// If device_id is given, the user's dehydrated device must match or this is a
|
||||
/// no-op, but an Err is still returned to indicate that. Otherwise returns the
|
||||
/// removed dehydrated device_id.
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(
|
||||
%user_id,
|
||||
device_id = ?maybe_device_id,
|
||||
)
|
||||
)]
|
||||
pub(super) async fn remove_dehydrated_device(
|
||||
&self,
|
||||
user_id: &UserId,
|
||||
maybe_device_id: Option<&DeviceId>,
|
||||
) -> Result<OwnedDeviceId> {
|
||||
let Ok(device_id) = self.get_dehydrated_device_id(user_id).await else {
|
||||
return Err!(Request(NotFound("No dehydrated device for this user.")));
|
||||
};
|
||||
|
||||
if let Some(maybe_device_id) = maybe_device_id {
|
||||
if maybe_device_id != device_id {
|
||||
return Err!(Request(NotFound("Not the user's dehydrated device.")));
|
||||
}
|
||||
}
|
||||
|
||||
self.db.userid_dehydrateddevice.remove(user_id);
|
||||
|
||||
Ok(device_id)
|
||||
}
|
||||
|
||||
/// Get the device_id of the user's dehydrated device.
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%user_id)
|
||||
)]
|
||||
pub async fn get_dehydrated_device_id(&self, user_id: &UserId) -> Result<OwnedDeviceId> {
|
||||
self.get_dehydrated_device(user_id)
|
||||
.await
|
||||
.map(|device| device.device_id)
|
||||
}
|
||||
|
||||
/// Get the dehydrated device private data
|
||||
#[implement(super::Service)]
|
||||
#[tracing::instrument(
|
||||
level = "debug",
|
||||
skip_all,
|
||||
fields(%user_id),
|
||||
ret,
|
||||
)]
|
||||
pub async fn get_dehydrated_device(&self, user_id: &UserId) -> Result<DehydratedDevice> {
|
||||
self.db
|
||||
.userid_dehydrateddevice
|
||||
.get(user_id)
|
||||
.await
|
||||
.deserialized()
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
pub(super) mod dehydrated_device;
|
||||
|
||||
#[cfg(feature = "ldap")]
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::BTreeMap, mem, net::IpAddr, sync::Arc};
|
||||
@@ -5,7 +7,7 @@
|
||||
#[cfg(feature = "ldap")]
|
||||
use conduwuit::result::LogErr;
|
||||
use conduwuit::{
|
||||
Err, Error, Result, Server, at, debug_warn, err, is_equal_to, trace,
|
||||
Err, Error, Result, Server, debug_warn, err, is_equal_to, trace,
|
||||
utils::{self, ReadyExt, stream::TryIgnore, string::Unquoted},
|
||||
};
|
||||
#[cfg(feature = "ldap")]
|
||||
@@ -70,6 +72,7 @@ struct Data {
|
||||
userfilterid_filter: Arc<Map>,
|
||||
userid_avatarurl: Arc<Map>,
|
||||
userid_blurhash: Arc<Map>,
|
||||
userid_dehydrateddevice: Arc<Map>,
|
||||
userid_devicelistversion: Arc<Map>,
|
||||
userid_displayname: Arc<Map>,
|
||||
userid_lastonetimekeyupdate: Arc<Map>,
|
||||
@@ -110,6 +113,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
|
||||
userfilterid_filter: args.db["userfilterid_filter"].clone(),
|
||||
userid_avatarurl: args.db["userid_avatarurl"].clone(),
|
||||
userid_blurhash: args.db["userid_blurhash"].clone(),
|
||||
userid_dehydrateddevice: args.db["userid_dehydrateddevice"].clone(),
|
||||
userid_devicelistversion: args.db["userid_devicelistversion"].clone(),
|
||||
userid_displayname: args.db["userid_displayname"].clone(),
|
||||
userid_lastonetimekeyupdate: args.db["userid_lastonetimekeyupdate"].clone(),
|
||||
@@ -480,6 +484,11 @@ pub async fn create_device(
|
||||
|
||||
/// Removes a device from a user.
|
||||
pub async fn remove_device(&self, user_id: &UserId, device_id: &DeviceId) {
|
||||
// Remove dehydrated device if this is the dehydrated device
|
||||
let _: Result<_> = self
|
||||
.remove_dehydrated_device(user_id, Some(device_id))
|
||||
.await;
|
||||
|
||||
let userdeviceid = (user_id, device_id);
|
||||
|
||||
// Remove tokens
|
||||
@@ -1003,7 +1012,7 @@ pub fn get_to_device_events<'a>(
|
||||
device_id: &'a DeviceId,
|
||||
since: Option<u64>,
|
||||
to: Option<u64>,
|
||||
) -> impl Stream<Item = Raw<AnyToDeviceEvent>> + Send + 'a {
|
||||
) -> impl Stream<Item = (u64, Raw<AnyToDeviceEvent>)> + Send + 'a {
|
||||
type Key<'a> = (&'a UserId, &'a DeviceId, u64);
|
||||
|
||||
let from = (user_id, device_id, since.map_or(0, |since| since.saturating_add(1)));
|
||||
@@ -1017,7 +1026,7 @@ pub fn get_to_device_events<'a>(
|
||||
&& device_id == *device_id_
|
||||
&& to.is_none_or(|to| *count <= to)
|
||||
})
|
||||
.map(at!(1))
|
||||
.map(|((_, _, count), event)| (count, event))
|
||||
}
|
||||
|
||||
pub async fn remove_to_device_events<Until>(
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
{"Action":"fail","Test":"TestArchivedRoomsHistory/timeline_has_events"}
|
||||
{"Action":"fail","Test":"TestArchivedRoomsHistory/timeline_has_events/incremental_sync"}
|
||||
{"Action":"fail","Test":"TestArchivedRoomsHistory/timeline_has_events/initial_sync"}
|
||||
{"Action":"pass","Test":"TestArchivedRoomsHistory/timeline_is_empty"}
|
||||
{"Action":"fail","Test":"TestArchivedRoomsHistory/timeline_is_empty"}
|
||||
{"Action":"skip","Test":"TestArchivedRoomsHistory/timeline_is_empty/incremental_sync"}
|
||||
{"Action":"pass","Test":"TestArchivedRoomsHistory/timeline_is_empty/initial_sync"}
|
||||
{"Action":"fail","Test":"TestArchivedRoomsHistory/timeline_is_empty/initial_sync"}
|
||||
{"Action":"fail","Test":"TestAsyncUpload"}
|
||||
{"Action":"fail","Test":"TestAsyncUpload/Cannot_upload_to_a_media_ID_that_has_already_been_uploaded_to"}
|
||||
{"Action":"fail","Test":"TestAsyncUpload/Create_media"}
|
||||
@@ -79,9 +79,11 @@
|
||||
{"Action":"fail","Test":"TestClientSpacesSummary/redact_link"}
|
||||
{"Action":"fail","Test":"TestClientSpacesSummary/suggested_only"}
|
||||
{"Action":"fail","Test":"TestClientSpacesSummaryJoinRules"}
|
||||
{"Action":"pass","Test":"TestComplementCanCreateValidV12Rooms"}
|
||||
{"Action":"pass","Test":"TestContent"}
|
||||
{"Action":"pass","Test":"TestContentCSAPIMediaV1"}
|
||||
{"Action":"pass","Test":"TestContentMediaV1"}
|
||||
{"Action":"fail","Test":"TestCorruptedAuthChain"}
|
||||
{"Action":"pass","Test":"TestCumulativeJoinLeaveJoinSync"}
|
||||
{"Action":"pass","Test":"TestDeactivateAccount"}
|
||||
{"Action":"pass","Test":"TestDeactivateAccount/After_deactivating_account,_can't_log_in_with_password"}
|
||||
@@ -89,19 +91,18 @@
|
||||
{"Action":"pass","Test":"TestDeactivateAccount/Can_deactivate_account"}
|
||||
{"Action":"pass","Test":"TestDeactivateAccount/Password_flow_is_available"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/cannot_update_a_delayed_event_with_an_invalid_action"}
|
||||
{"Action":"pass","Test":"TestDelayedEvents/cannot_update_a_delayed_event_without_a_delay_ID"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/cannot_update_a_delayed_event_without_a_request_body"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/cannot_update_a_delayed_event_without_an_action"}
|
||||
{"Action":"pass","Test":"TestDelayedEvents/cannot_update_a_delayed_event_with_an_invalid_action"}
|
||||
{"Action":"pass","Test":"TestDelayedEvents/cannot_update_a_delayed_event_without_an_action"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_event_lookups_are_authenticated"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_events_are_empty_on_startup"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_message_events_are_sent_on_timeout"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_events_are_cancelled_by_a_more_recent_state_event_from_another_user"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_events_are_cancelled_by_a_more_recent_state_event_from_the_same_user"}
|
||||
{"Action":"skip","Test":"TestDelayedEvents/delayed_state_events_are_kept_on_server_restart"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_events_are_sent_on_timeout"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_events_can_be_cancelled"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_events_can_be_restarted"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_events_can_be_sent_on_request"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_is_cancelled_by_new_state_from_another_user"}
|
||||
{"Action":"fail","Test":"TestDelayedEvents/delayed_state_is_not_cancelled_by_new_state_from_the_same_user"}
|
||||
{"Action":"pass","Test":"TestDelayedEvents/parallel"}
|
||||
{"Action":"pass","Test":"TestDelayedEvents/parallel/cannot_cancel_a_delayed_event_without_a_matching_delay_ID"}
|
||||
{"Action":"pass","Test":"TestDelayedEvents/parallel/cannot_restart_a_delayed_event_without_a_matching_delay_ID"}
|
||||
@@ -153,12 +154,14 @@
|
||||
{"Action":"fail","Test":"TestFederationKeyUploadQuery/Can_query_remote_device_keys_using_POST"}
|
||||
{"Action":"pass","Test":"TestFederationRedactSendsWithoutEvent"}
|
||||
{"Action":"pass","Test":"TestFederationRejectInvite"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel"}
|
||||
{"Action":"fail","Test":"TestFederationRoomsInvite"}
|
||||
{"Action":"fail","Test":"TestFederationRoomsInvite/Parallel"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Invited_user_can_reject_invite_over_federation"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Invited_user_can_reject_invite_over_federation_for_empty_room"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Invited_user_can_reject_invite_over_federation_several_times"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Invited_user_has_'is_direct'_flag_in_prev_content_after_joining"}
|
||||
{"Action":"fail","Test":"TestFederationRoomsInvite/Parallel/Inviter_user_can_rescind_invite_over_federation"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Non-invitee_user_cannot_rescind_invite_over_federation"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Remote_invited_user_can_join_the_room_when_homeserver_is_already_participating_in_the_room"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Remote_invited_user_can_reject_invite_when_homeserver_is_already_participating_in_the_room"}
|
||||
{"Action":"pass","Test":"TestFederationRoomsInvite/Parallel/Remote_invited_user_can_see_room_metadata"}
|
||||
@@ -191,6 +194,18 @@
|
||||
{"Action":"pass","Test":"TestInboundFederationProfile/Inbound_federation_can_query_profile_data"}
|
||||
{"Action":"pass","Test":"TestInboundFederationProfile/Non-numeric_ports_in_server_names_are_rejected"}
|
||||
{"Action":"fail","Test":"TestInboundFederationRejectsEventsWithRejectedAuthEvents"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_allow_a_user_from_a_blocked_server"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_block_a_single_user"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_block_a_user_from_an_allowed_server"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_block_a_whole_server"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_glob_serveral_servers"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_glob_serveral_users"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_ignore_a_single_user"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_ignore_a_whole_server"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Can_invite_users_normally_without_any_rules"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Will_allow_users_when_a_user_appears_in_multiple_fields"}
|
||||
{"Action":"pass","Test":"TestInviteFiltering/Will_ignore_null_fields"}
|
||||
{"Action":"pass","Test":"TestInviteFromIgnoredUsersDoesNotAppearInSync"}
|
||||
{"Action":"pass","Test":"TestIsDirectFlagFederation"}
|
||||
{"Action":"pass","Test":"TestIsDirectFlagLocal"}
|
||||
@@ -214,18 +229,20 @@
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/federation/looking_backwards,_should_be_able_to_find_event_that_was_sent_before_we_joined"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/federation/looking_forwards,_should_be_able_to_find_event_that_was_sent_before_we_joined"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/federation/when_looking_backwards_before_the_room_was_created,_should_be_able_to_find_event_that_was_imported"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_find_event_after_given_timestmap"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_find_event_before_given_timestmap"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_find_next_event_topologically_after_given_timestmap_when_all_message_timestamps_are_the_same"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_find_event_after_given_timestamp"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_find_event_before_given_timestamp"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_find_next_event_topologically_after_given_timestamp_when_all_message_timestamps_are_the_same"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_find_next_event_topologically_before_given_timestamp_when_all_message_timestamps_are_the_same"}
|
||||
{"Action":"pass","Test":"TestJumpToDateEndpoint/parallel/should_find_nothing_after_the_latest_timestmap"}
|
||||
{"Action":"pass","Test":"TestJumpToDateEndpoint/parallel/should_find_nothing_before_the_earliest_timestmap"}
|
||||
{"Action":"pass","Test":"TestJumpToDateEndpoint/parallel/should_find_nothing_after_the_latest_timestamp"}
|
||||
{"Action":"pass","Test":"TestJumpToDateEndpoint/parallel/should_find_nothing_before_the_earliest_timestamp"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_not_be_able_to_query_a_private_room_you_are_not_a_member_of"}
|
||||
{"Action":"fail","Test":"TestJumpToDateEndpoint/parallel/should_not_be_able_to_query_a_public_room_you_are_not_a_member_of"}
|
||||
{"Action":"fail","Test":"TestKeyChangesLocal"}
|
||||
{"Action":"fail","Test":"TestKeyChangesLocal/New_login_should_create_a_device_lists.changed_entry"}
|
||||
{"Action":"fail","Test":"TestKeyClaimOrdering"}
|
||||
{"Action":"pass","Test":"TestKeysQueryWithDeviceIDAsObjectFails"}
|
||||
{"Action":"pass","Test":"TestKnockRestrictedRoomsLocalJoinNoCreatorsUsesPowerLevelsV11"}
|
||||
{"Action":"pass","Test":"TestKnockRestrictedRoomsLocalJoinNoCreatorsUsesPowerLevelsV12"}
|
||||
{"Action":"fail","Test":"TestKnockRoomsInPublicRoomsDirectory"}
|
||||
{"Action":"fail","Test":"TestKnockRoomsInPublicRoomsDirectoryInMSC3787Room"}
|
||||
{"Action":"fail","Test":"TestKnocking"}
|
||||
@@ -252,8 +269,8 @@
|
||||
{"Action":"pass","Test":"TestKnocking/Knocking_on_a_room_with_a_join_rule_other_than_'knock'_should_fail#01"}
|
||||
{"Action":"fail","Test":"TestKnocking/Knocking_on_a_room_with_join_rule_'knock'_should_succeed"}
|
||||
{"Action":"fail","Test":"TestKnocking/Knocking_on_a_room_with_join_rule_'knock'_should_succeed#01"}
|
||||
{"Action":"pass","Test":"TestKnocking/Users_in_the_room_see_a_user's_membership_update_when_they_knock"}
|
||||
{"Action":"pass","Test":"TestKnocking/Users_in_the_room_see_a_user's_membership_update_when_they_knock#01"}
|
||||
{"Action":"fail","Test":"TestKnocking/Users_in_the_room_see_a_user's_membership_update_when_they_knock"}
|
||||
{"Action":"fail","Test":"TestKnocking/Users_in_the_room_see_a_user's_membership_update_when_they_knock#01"}
|
||||
{"Action":"fail","Test":"TestKnockingInMSC3787Room"}
|
||||
{"Action":"fail","Test":"TestKnockingInMSC3787Room/A_user_can_knock_on_a_room_without_a_reason"}
|
||||
{"Action":"fail","Test":"TestKnockingInMSC3787Room/A_user_can_knock_on_a_room_without_a_reason#01"}
|
||||
@@ -278,8 +295,8 @@
|
||||
{"Action":"pass","Test":"TestKnockingInMSC3787Room/Knocking_on_a_room_with_a_join_rule_other_than_'knock'_should_fail#01"}
|
||||
{"Action":"fail","Test":"TestKnockingInMSC3787Room/Knocking_on_a_room_with_join_rule_'knock'_should_succeed"}
|
||||
{"Action":"fail","Test":"TestKnockingInMSC3787Room/Knocking_on_a_room_with_join_rule_'knock'_should_succeed#01"}
|
||||
{"Action":"pass","Test":"TestKnockingInMSC3787Room/Users_in_the_room_see_a_user's_membership_update_when_they_knock"}
|
||||
{"Action":"pass","Test":"TestKnockingInMSC3787Room/Users_in_the_room_see_a_user's_membership_update_when_they_knock#01"}
|
||||
{"Action":"fail","Test":"TestKnockingInMSC3787Room/Users_in_the_room_see_a_user's_membership_update_when_they_knock"}
|
||||
{"Action":"fail","Test":"TestKnockingInMSC3787Room/Users_in_the_room_see_a_user's_membership_update_when_they_knock#01"}
|
||||
{"Action":"pass","Test":"TestLeakyTyping"}
|
||||
{"Action":"pass","Test":"TestLeaveEventInviteRejection"}
|
||||
{"Action":"fail","Test":"TestLeaveEventVisibility"}
|
||||
@@ -308,10 +325,43 @@
|
||||
{"Action":"pass","Test":"TestLogout/Request_to_logout_without_an_access_token_is_rejected"}
|
||||
{"Action":"fail","Test":"TestMSC3757OwnedState"}
|
||||
{"Action":"pass","Test":"TestMSC3967"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators/PL_event_is_missing_creator_in_users_map"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators/admin_with_>PL100_cannot_kick_creator"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators/admin_with_>PL100_sorts_after_the_room_creator_for_state_resolution"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators/creator_can_kick_admin"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators/creator_can_kick_admin_above_PL100"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators/creator_can_kick_admin_at_JSON_max_value"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators/creator_cannot_set_self_in_PL_event"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators/m.room.tombstone_needs_PL150_in_the_PL_event"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators/power_level_cannot_be_set_beyond_max_canonical_JSON_int"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators/power_level_content_override_can_be_set"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators/power_level_content_override_cannot_set_the_room_creator"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_Additional"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_AdditionalCreatorsAndInvited"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_AdditionalValidation"}
|
||||
{"Action":"pass","Test":"TestMSC4289PrivilegedRoomCreators_AdditionalValidation/additional_creators_are_valid"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_AdditionalValidation/additional_creators_elements_aren't_strings"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_AdditionalValidation/additional_creators_elements_aren't_user_ID_strings"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_AdditionalValidation/additional_creators_elements_aren't_valid_user_ID_strings_(domain)"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_AdditionalValidation/additional_creators_isn't_an_array"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_InvitedAreCreators"}
|
||||
{"Action":"fail","Test":"TestMSC4289PrivilegedRoomCreators_Upgrades"}
|
||||
{"Action":"pass","Test":"TestMSC4291RoomIDAsHashOfCreateEvent"}
|
||||
{"Action":"pass","Test":"TestMSC4291RoomIDAsHashOfCreateEvent_AuthEventsOmitsCreateEvent"}
|
||||
{"Action":"pass","Test":"TestMSC4291RoomIDAsHashOfCreateEvent_CannotSendCreateEvent"}
|
||||
{"Action":"pass","Test":"TestMSC4291RoomIDAsHashOfCreateEvent_RoomIDIsOnCreateEvent"}
|
||||
{"Action":"pass","Test":"TestMSC4291RoomIDAsHashOfCreateEvent_UpgradedRooms"}
|
||||
{"Action":"fail","Test":"TestMSC4297StateResolutionV2_1_includes_conflicted_subgraph"}
|
||||
{"Action":"fail","Test":"TestMSC4297StateResolutionV2_1_starts_from_empty_set"}
|
||||
{"Action":"fail","Test":"TestMSC4308ThreadSubscriptionsSlidingSync"}
|
||||
{"Action":"fail","Test":"TestMSC4308ThreadSubscriptionsSlidingSync/Receives_thread_subscriptions_over_incremental_sliding_sync"}
|
||||
{"Action":"fail","Test":"TestMSC4308ThreadSubscriptionsSlidingSync/Receives_thread_subscriptions_over_initial_sliding_sync"}
|
||||
{"Action":"fail","Test":"TestMSC4311FullCreateEventOnStrippedState"}
|
||||
{"Action":"pass","Test":"TestMediaConfig"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII"}
|
||||
{"Action":"fail","Test":"TestMediaFilenames"}
|
||||
{"Action":"fail","Test":"TestMediaFilenames/Parallel"}
|
||||
{"Action":"fail","Test":"TestMediaFilenames/Parallel/ASCII"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_file_'ascii'"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_file_'ascii'_over_/_matrix/client/v1/media/download"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_file_'name;with;semicolons'"}
|
||||
@@ -319,11 +369,11 @@
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_file_'name_with_spaces'"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_file_'name_with_spaces'_over_/_matrix/client/v1/media/download"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_specifying_a_different_ASCII_file_name"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_specifying_a_different_ASCII_file_name_over__matrix/client/v1/media/download"}
|
||||
{"Action":"fail","Test":"TestMediaFilenames/Parallel/ASCII/Can_download_specifying_a_different_ASCII_file_name_over__matrix/client/v1/media/download"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/ASCII/Can_upload_with_ASCII_file_name"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/Unicode"}
|
||||
{"Action":"fail","Test":"TestMediaFilenames/Parallel/Unicode"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/Unicode/Can_download_specifying_a_different_Unicode_file_name"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/Unicode/Can_download_specifying_a_different_Unicode_file_name_over__matrix/client/v1/media/download"}
|
||||
{"Action":"fail","Test":"TestMediaFilenames/Parallel/Unicode/Can_download_specifying_a_different_Unicode_file_name_over__matrix/client/v1/media/download"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/Unicode/Can_download_with_Unicode_file_name_locally"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/Unicode/Can_download_with_Unicode_file_name_locally_over__matrix/client/v1/media/download"}
|
||||
{"Action":"pass","Test":"TestMediaFilenames/Parallel/Unicode/Can_download_with_Unicode_file_name_over_federation"}
|
||||
@@ -352,9 +402,15 @@
|
||||
{"Action":"pass","Test":"TestMembersLocal/Parallel/Existing_members_see_new_members'_presence_(in_initial_sync)"}
|
||||
{"Action":"pass","Test":"TestMembersLocal/Parallel/New_room_members_see_their_own_join_event"}
|
||||
{"Action":"fail","Test":"TestMembershipOnEvents"}
|
||||
{"Action":"fail","Test":"TestNetworkPartitionOrdering"}
|
||||
{"Action":"fail","Test":"TestMessagesOverFederation"}
|
||||
{"Action":"pass","Test":"TestMessagesOverFederation/Visible_shared_history_after_joining_new_room_(backfill)"}
|
||||
{"Action":"pass","Test":"TestMessagesOverFederation/Visible_shared_history_after_joining_new_room_(backfill)/`messagesRequestLimit`_is_greater_than_the_number_of_messages_backfilled_(in_Synapse,_100)"}
|
||||
{"Action":"pass","Test":"TestMessagesOverFederation/Visible_shared_history_after_joining_new_room_(backfill)/`messagesRequestLimit`_is_lower_than_the_number_of_messages_backfilled_(assumed)"}
|
||||
{"Action":"fail","Test":"TestMessagesOverFederation/Visible_shared_history_after_re-joining_room_(backfill)"}
|
||||
{"Action":"fail","Test":"TestMessagesOverFederation/Visible_shared_history_after_re-joining_room_(backfill)/`messagesRequestLimit`_is_lower_than_the_number_of_messages_backfilled_(assumed)"}
|
||||
{"Action":"pass","Test":"TestNetworkPartitionOrdering"}
|
||||
{"Action":"pass","Test":"TestNotPresentUserCannotBanOthers"}
|
||||
{"Action":"pass","Test":"TestOlderLeftRoomsNotInLeaveSection"}
|
||||
{"Action":"fail","Test":"TestOlderLeftRoomsNotInLeaveSection"}
|
||||
{"Action":"fail","Test":"TestOutboundFederationEventSizeGetMissingEvents"}
|
||||
{"Action":"fail","Test":"TestOutboundFederationIgnoresMissingEventWithBadJSONForRoomVersion6"}
|
||||
{"Action":"pass","Test":"TestOutboundFederationProfile"}
|
||||
@@ -379,7 +435,23 @@
|
||||
{"Action":"pass","Test":"TestProfileDisplayName"}
|
||||
{"Action":"pass","Test":"TestProfileDisplayName/GET_/profile/:user_id/displayname_publicly_accessible"}
|
||||
{"Action":"pass","Test":"TestProfileDisplayName/PUT_/profile/:user_id/displayname_sets_my_name"}
|
||||
{"Action":"pass","Test":"TestPublicRooms"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Can_search_public_room_list"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct/Creating_room_with_alias_publicroom_with_unicode_chars_name"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct/Creating_room_with_alias_publicroom_with_unicode_chars_name_topic"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct/Creating_room_with_alias_publicroom_with_unicode_chars_topic"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct/Creating_room_with_alias_publicroomalias_no_name"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct/Creating_room_with_alias_publicroomalias_with_name"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct/Creating_room_with_alias_publicroomalias_with_name_topic"}
|
||||
{"Action":"pass","Test":"TestPublicRooms/Name/topic_keys_are_correct/Creating_room_with_alias_publicroomalias_with_topic"}
|
||||
{"Action":"pass","Test":"TestPushRuleCacheHealth"}
|
||||
{"Action":"fail","Test":"TestPushRuleRoomUpgrade"}
|
||||
{"Action":"fail","Test":"TestPushRuleRoomUpgrade/parallel"}
|
||||
{"Action":"fail","Test":"TestPushRuleRoomUpgrade/parallel/joining_a_remote_manually_upgraded_room_carries_over_existing_push_rules"}
|
||||
{"Action":"fail","Test":"TestPushRuleRoomUpgrade/parallel/joining_a_remote_upgraded_room_carries_over_existing_push_rules"}
|
||||
{"Action":"fail","Test":"TestPushRuleRoomUpgrade/parallel/manually_upgrading_a_room_carries_over_existing_push_rules_for_local_users"}
|
||||
{"Action":"fail","Test":"TestPushRuleRoomUpgrade/parallel/upgrading_a_room_carries_over_existing_push_rules_for_local_users"}
|
||||
{"Action":"pass","Test":"TestPushSync"}
|
||||
{"Action":"pass","Test":"TestPushSync/Adding_a_push_rule_wakes_up_an_incremental_/sync"}
|
||||
{"Action":"pass","Test":"TestPushSync/Disabling_a_push_rule_wakes_up_an_incremental_/sync"}
|
||||
@@ -440,14 +512,16 @@
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsLocalJoinInMSC3787Room/Join_should_fail_with_mangled_join_rules"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsLocalJoinInMSC3787Room/Join_should_succeed_when_invited"}
|
||||
{"Action":"fail","Test":"TestRestrictedRoomsLocalJoinInMSC3787Room/Join_should_succeed_when_joined_to_allowed_room"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsLocalJoinNoCreatorsUsesPowerLevelsV11"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsLocalJoinNoCreatorsUsesPowerLevelsV12"}
|
||||
{"Action":"fail","Test":"TestRestrictedRoomsRemoteJoin"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoin/Join_should_fail_initially"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoin/Join_should_fail_when_left_allowed_room"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoin/Join_should_fail_with_mangled_join_rules"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoin/Join_should_succeed_when_invited"}
|
||||
{"Action":"fail","Test":"TestRestrictedRoomsRemoteJoin/Join_should_succeed_when_joined_to_allowed_room"}
|
||||
{"Action":"fail","Test":"TestRestrictedRoomsRemoteJoinFailOver"}
|
||||
{"Action":"fail","Test":"TestRestrictedRoomsRemoteJoinFailOverInMSC3787Room"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoinFailOver"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoinFailOverInMSC3787Room"}
|
||||
{"Action":"fail","Test":"TestRestrictedRoomsRemoteJoinInMSC3787Room"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoinInMSC3787Room/Join_should_fail_initially"}
|
||||
{"Action":"pass","Test":"TestRestrictedRoomsRemoteJoinInMSC3787Room/Join_should_fail_when_left_allowed_room"}
|
||||
@@ -475,16 +549,19 @@
|
||||
{"Action":"fail","Test":"TestRoomCanonicalAlias/Parallel/m.room.canonical_alias_rejects_missing_aliases"}
|
||||
{"Action":"fail","Test":"TestRoomCanonicalAlias/Parallel/m.room.canonical_alias_rejects_missing_aliases#01"}
|
||||
{"Action":"fail","Test":"TestRoomCanonicalAlias/Parallel/m.room.canonical_alias_setting_rejects_deleted_aliases"}
|
||||
{"Action":"pass","Test":"TestRoomCreate"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel"}
|
||||
{"Action":"fail","Test":"TestRoomCreate"}
|
||||
{"Action":"fail","Test":"TestRoomCreate/Parallel"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/Can_/sync_newly_created_room"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_creates_a_room_with_the_given_version"}
|
||||
{"Action":"fail","Test":"TestRoomCreate/Parallel/POST_/createRoom_creates_a_room_with_the_given_version"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_ignores_attempts_to_set_the_room_version_via_creation_content"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_private_room"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_private_room_with_invites"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_public_room"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_room_with_a_name"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_room_with_a_topic"}
|
||||
{"Action":"fail","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_room_with_a_topic_and_writes_rich_topic_representation"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_room_with_a_topic_via_initial_state"}
|
||||
{"Action":"fail","Test":"TestRoomCreate/Parallel/POST_/createRoom_makes_a_room_with_a_topic_via_initial_state_overwritten_by_topic"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_rejects_attempts_to_create_rooms_with_numeric_versions"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/POST_/createRoom_rejects_attempts_to_create_rooms_with_unknown_versions"}
|
||||
{"Action":"pass","Test":"TestRoomCreate/Parallel/Rooms_can_be_created_with_an_initial_invite_list_(SYN-205)"}
|
||||
@@ -527,6 +604,7 @@
|
||||
{"Action":"pass","Test":"TestRoomMessagesLazyLoadingLocalUser"}
|
||||
{"Action":"pass","Test":"TestRoomReadMarkers"}
|
||||
{"Action":"pass","Test":"TestRoomReceipts"}
|
||||
{"Action":"pass","Test":"TestRoomReceipts/Receipts_DO_NOT_include_a_`room_id`_field"}
|
||||
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin"}
|
||||
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_mxid"}
|
||||
{"Action":"pass","Test":"TestRoomSpecificUsernameAtJoin/Bob_can_find_Alice_by_profile_display_name"}
|
||||
@@ -575,7 +653,7 @@
|
||||
{"Action":"pass","Test":"TestSearch/parallel/Search_results_with_recent_ordering_do_not_include_redacted_events"}
|
||||
{"Action":"pass","Test":"TestSearch/parallel/Search_works_across_an_upgraded_room_and_its_predecessor"}
|
||||
{"Action":"fail","Test":"TestSendAndFetchMessage"}
|
||||
{"Action":"skip","Test":"TestSendJoinPartialStateResponse"}
|
||||
{"Action":"fail","Test":"TestSendJoinPartialStateResponse"}
|
||||
{"Action":"pass","Test":"TestSendMessageWithTxn"}
|
||||
{"Action":"pass","Test":"TestServerCapabilities"}
|
||||
{"Action":"skip","Test":"TestServerNotices"}
|
||||
@@ -589,7 +667,7 @@
|
||||
{"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_has_correct_timeline_in_incremental_sync"}
|
||||
{"Action":"fail","Test":"TestSync/parallel/Newly_joined_room_includes_presence_in_incremental_sync"}
|
||||
{"Action":"pass","Test":"TestSync/parallel/Newly_joined_room_is_included_in_an_incremental_sync"}
|
||||
{"Action":"pass","Test":"TestSync/parallel/sync_should_succeed_even_if_the_sync_token_points_to_a_redaction_of_an_unknown_event"}
|
||||
{"Action":"fail","Test":"TestSync/parallel/sync_should_succeed_even_if_the_sync_token_points_to_a_redaction_of_an_unknown_event"}
|
||||
{"Action":"pass","Test":"TestSyncFilter"}
|
||||
{"Action":"pass","Test":"TestSyncFilter/Can_create_filter"}
|
||||
{"Action":"pass","Test":"TestSyncFilter/Can_download_filter"}
|
||||
@@ -603,12 +681,21 @@
|
||||
{"Action":"pass","Test":"TestSyncTimelineGap/incremental"}
|
||||
{"Action":"pass","Test":"TestTentativeEventualJoiningAfterRejecting"}
|
||||
{"Action":"fail","Test":"TestThreadReceiptsInSyncMSC4102"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions/Can_create_automatic_subscription_to_a_thread"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions/Can_subscribe_to_and_unsubscribe_from_a_thread"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions/Cannot_use_thread_root_as_automatic_subscription_cause_event"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions/Error_when_using_invalid_automatic_event_ID"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions/Manual_subscriptions_overwrite_automatic_subscriptions"}
|
||||
{"Action":"pass","Test":"TestThreadSubscriptions/Nonexistent_threads_return_404"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions/Server-side_automatic_subscription_ordering_conflict"}
|
||||
{"Action":"fail","Test":"TestThreadSubscriptions/Unsubscribe_succeeds_even_with_no_subscription"}
|
||||
{"Action":"fail","Test":"TestThreadedReceipts"}
|
||||
{"Action":"fail","Test":"TestThreadsEndpoint"}
|
||||
{"Action":"pass","Test":"TestToDeviceMessages"}
|
||||
{"Action":"fail","Test":"TestToDeviceMessagesOverFederation"}
|
||||
{"Action":"pass","Test":"TestToDeviceMessagesOverFederation/good_connectivity"}
|
||||
{"Action":"pass","Test":"TestToDeviceMessagesOverFederation/interrupted_connectivity"}
|
||||
{"Action":"fail","Test":"TestToDeviceMessagesOverFederation/interrupted_connectivity"}
|
||||
{"Action":"fail","Test":"TestToDeviceMessagesOverFederation/stopped_server"}
|
||||
{"Action":"fail","Test":"TestTxnIdWithRefreshToken"}
|
||||
{"Action":"fail","Test":"TestTxnIdempotency"}
|
||||
@@ -617,6 +704,7 @@
|
||||
{"Action":"pass","Test":"TestTxnScopeOnLocalEcho"}
|
||||
{"Action":"pass","Test":"TestTyping"}
|
||||
{"Action":"pass","Test":"TestTyping/Typing_can_be_explicitly_stopped"}
|
||||
{"Action":"pass","Test":"TestTyping/Typing_events_DO_NOT_include_a_`room_id`_field"}
|
||||
{"Action":"pass","Test":"TestTyping/Typing_notification_sent_to_local_room_members"}
|
||||
{"Action":"fail","Test":"TestUnknownEndpoints"}
|
||||
{"Action":"pass","Test":"TestUnknownEndpoints/Client-server_endpoints"}
|
||||
@@ -624,7 +712,7 @@
|
||||
{"Action":"pass","Test":"TestUnknownEndpoints/Media_endpoints"}
|
||||
{"Action":"pass","Test":"TestUnknownEndpoints/Server-server_endpoints"}
|
||||
{"Action":"pass","Test":"TestUnknownEndpoints/Unknown_prefix"}
|
||||
{"Action":"fail","Test":"TestUnrejectRejectedEvents"}
|
||||
{"Action":"pass","Test":"TestUnrejectRejectedEvents"}
|
||||
{"Action":"fail","Test":"TestUploadKey"}
|
||||
{"Action":"fail","Test":"TestUploadKey/Parallel"}
|
||||
{"Action":"fail","Test":"TestUploadKey/Parallel/Can_claim_one_time_key_using_POST"}
|
||||
@@ -637,7 +725,7 @@
|
||||
{"Action":"pass","Test":"TestUploadKeyIdempotency"}
|
||||
{"Action":"pass","Test":"TestUploadKeyIdempotencyOverlap"}
|
||||
{"Action":"fail","Test":"TestUrlPreview"}
|
||||
{"Action":"pass","Test":"TestUserAppearsInChangedDeviceListOnJoinOverFederation"}
|
||||
{"Action":"fail","Test":"TestUserAppearsInChangedDeviceListOnJoinOverFederation"}
|
||||
{"Action":"pass","Test":"TestVersionStructure"}
|
||||
{"Action":"pass","Test":"TestVersionStructure/Version_responds_200_OK_with_valid_structure"}
|
||||
{"Action":"pass","Test":"TestWithoutOwnedState"}
|
||||
|
||||
Reference in New Issue
Block a user