Compare commits

...

11 Commits

Author SHA1 Message Date
timedout
49ce6b4072 fix: Partially pervert botched previous commit 2025-12-24 01:40:28 +00:00
timedout
f6ad1787a0 fix: Don't treat every create event as unstripped 2025-12-24 01:39:31 +00:00
timedout
81ff8f1bd3 feat: Allow using legacy, less secure validation 2025-12-24 01:34:08 +00:00
timedout
04980b3ee7 feat: Enhance invite security checks & do away with stripped state 2025-12-23 19:50:37 +00:00
timedout
1237e60aaf Revert "feat(ci): Allow running manual workflows against specific commits"
This reverts commit 9b4845bf8d.
2025-12-22 13:45:45 +00:00
timedout
9b4845bf8d feat(ci): Allow running manual workflows against specific commits 2025-12-22 13:29:40 +00:00
aviac
fb5b515f96 chore: update flake lock 2025-12-22 04:11:41 +00:00
Jade Ellis
e6336d694a chore: Fix escape 2025-12-22 02:42:21 +00:00
Jade Ellis
b7841280d9 chore: Security announcement 2025-12-22 02:36:31 +00:00
Jade Ellis
f4ccb81913 chore: Release 2025-12-22 00:23:20 +00:00
Jade Ellis
710cdfeadb chore: Update mailmap 2025-12-21 20:34:11 +00:00
15 changed files with 606 additions and 241 deletions

View File

@@ -2,6 +2,7 @@ AlexPewMaster <git@alex.unbox.at> <68469103+AlexPewMaster@users.noreply.github.c
Daniel Wiesenberg <weasy@hotmail.de> <weasy666@gmail.com>
Devin Ragotzy <devin.ragotzy@gmail.com> <d6ragotzy@wmich.edu>
Devin Ragotzy <devin.ragotzy@gmail.com> <dragotzy7460@mail.kvcc.edu>
Ginger <ginger@gingershaped.computer> <75683114+gingershaped@users.noreply.github.com>
Jonas Platte <jplatte+git@posteo.de> <jplatte+gitlab@posteo.de>
Jonas Zohren <git-pbkyr@jzohren.de> <gitlab-jfowl-0ux98@sh14.de>
Jonathan de Jong <jonathan@automatia.nl> <jonathandejong02@gmail.com>
@@ -12,5 +13,6 @@ Olivia Lee <olivia@computer.surgery> <benjamin@computer.surgery>
Rudi Floren <rudi.floren@gmail.com> <rudi.floren@googlemail.com>
Tamara Schmitz <tamara.zoe.schmitz@posteo.de> <15906939+tamara-schmitz@users.noreply.github.com>
Timo Kösters <timo@koesters.xyz>
nexy7574 <git@nexy7574.co.uk> <nex@noreply.forgejo.ellis.link>
nexy7574 <git@nexy7574.co.uk> <nex@noreply.localhost>
x4u <xi.zhu@protonmail.ch> <14617923-x4u@users.noreply.gitlab.com>
Ginger <ginger@gingershaped.computer> <75683114+gingershaped@users.noreply.github.com>

46
Cargo.lock generated
View File

@@ -940,7 +940,7 @@ dependencies = [
[[package]]
name = "conduwuit"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"clap",
"conduwuit_admin",
@@ -972,7 +972,7 @@ dependencies = [
[[package]]
name = "conduwuit_admin"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"clap",
"conduwuit_api",
@@ -994,7 +994,7 @@ dependencies = [
[[package]]
name = "conduwuit_api"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"async-trait",
"axum 0.7.9",
@@ -1027,14 +1027,14 @@ dependencies = [
[[package]]
name = "conduwuit_build_metadata"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"built",
]
[[package]]
name = "conduwuit_core"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"argon2",
"arrayvec",
@@ -1095,7 +1095,7 @@ dependencies = [
[[package]]
name = "conduwuit_database"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"async-channel",
"conduwuit_core",
@@ -1114,7 +1114,7 @@ dependencies = [
[[package]]
name = "conduwuit_macros"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"itertools 0.14.0",
"proc-macro2",
@@ -1124,7 +1124,7 @@ dependencies = [
[[package]]
name = "conduwuit_router"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"axum 0.7.9",
"axum-client-ip",
@@ -1159,7 +1159,7 @@ dependencies = [
[[package]]
name = "conduwuit_service"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"async-trait",
"base64 0.22.1",
@@ -1200,7 +1200,7 @@ dependencies = [
[[package]]
name = "conduwuit_web"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"askama",
"axum 0.7.9",
@@ -4063,7 +4063,7 @@ checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
[[package]]
name = "ruma"
version = "0.10.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"assign",
"js_int",
@@ -4083,7 +4083,7 @@ dependencies = [
[[package]]
name = "ruma-appservice-api"
version = "0.10.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"js_int",
"ruma-common",
@@ -4095,7 +4095,7 @@ dependencies = [
[[package]]
name = "ruma-client-api"
version = "0.18.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"as_variant",
"assign",
@@ -4118,7 +4118,7 @@ dependencies = [
[[package]]
name = "ruma-common"
version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"as_variant",
"base64 0.22.1",
@@ -4150,7 +4150,7 @@ dependencies = [
[[package]]
name = "ruma-events"
version = "0.28.1"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"as_variant",
"indexmap",
@@ -4175,7 +4175,7 @@ dependencies = [
[[package]]
name = "ruma-federation-api"
version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"bytes",
"headers",
@@ -4197,7 +4197,7 @@ dependencies = [
[[package]]
name = "ruma-identifiers-validation"
version = "0.9.5"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"js_int",
"thiserror 2.0.17",
@@ -4206,7 +4206,7 @@ dependencies = [
[[package]]
name = "ruma-identity-service-api"
version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"js_int",
"ruma-common",
@@ -4216,7 +4216,7 @@ dependencies = [
[[package]]
name = "ruma-macros"
version = "0.13.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"cfg-if",
"proc-macro-crate",
@@ -4231,7 +4231,7 @@ dependencies = [
[[package]]
name = "ruma-push-gateway-api"
version = "0.9.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"js_int",
"ruma-common",
@@ -4243,7 +4243,7 @@ dependencies = [
[[package]]
name = "ruma-signatures"
version = "0.15.0"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=27abe0dcd33fd4056efc94bab3582646b31b6ce9#27abe0dcd33fd4056efc94bab3582646b31b6ce9"
source = "git+https://forgejo.ellis.link/continuwuation/ruwuma?rev=3a6f29fda2c3ccf07282c746dc0e2021defc50bb#3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
dependencies = [
"base64 0.22.1",
"ed25519-dalek",
@@ -6204,7 +6204,7 @@ dependencies = [
[[package]]
name = "xtask"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"clap",
"serde",
@@ -6213,7 +6213,7 @@ dependencies = [
[[package]]
name = "xtask-generate-commands"
version = "0.5.0-rc.8.1"
version = "0.5.0"
dependencies = [
"clap-markdown",
"clap_builder",

View File

@@ -21,7 +21,7 @@ license = "Apache-2.0"
readme = "README.md"
repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
rust-version = "1.86.0"
version = "0.5.0-rc.8.1"
version = "0.5.0"
[workspace.metadata.crane]
name = "conduwuit"
@@ -33,11 +33,11 @@ features = ["serde"]
[workspace.dependencies.smallvec]
version = "1.14.0"
features = [
"const_generics",
"const_new",
"serde",
"union",
"write",
"const_generics",
"const_new",
"serde",
"union",
"write",
]
[workspace.dependencies.smallstr]
@@ -96,13 +96,13 @@ version = "1.11.1"
version = "0.7.9"
default-features = false
features = [
"form",
"http1",
"http2",
"json",
"matched-path",
"tokio",
"tracing",
"form",
"http1",
"http2",
"json",
"matched-path",
"tokio",
"tracing",
]
[workspace.dependencies.axum-extra]
@@ -149,10 +149,10 @@ features = ["aws_lc_rs"]
version = "0.12.15"
default-features = false
features = [
"rustls-tls-native-roots",
"socks",
"hickory-dns",
"http2",
"rustls-tls-native-roots",
"socks",
"hickory-dns",
"http2",
]
[workspace.dependencies.serde]
@@ -188,18 +188,18 @@ default-features = false
version = "0.25.5"
default-features = false
features = [
"jpeg",
"png",
"gif",
"webp",
"jpeg",
"png",
"gif",
"webp",
]
[workspace.dependencies.blurhash]
version = "0.2.3"
default-features = false
features = [
"fast-linear-to-srgb",
"image",
"fast-linear-to-srgb",
"image",
]
# logging
@@ -229,13 +229,13 @@ default-features = false
version = "4.5.35"
default-features = false
features = [
"derive",
"env",
"error-context",
"help",
"std",
"string",
"usage",
"derive",
"env",
"error-context",
"help",
"std",
"string",
"usage",
]
[workspace.dependencies.futures]
@@ -247,15 +247,15 @@ features = ["std", "async-await"]
version = "1.44.2"
default-features = false
features = [
"fs",
"net",
"macros",
"sync",
"signal",
"time",
"rt-multi-thread",
"io-util",
"tracing",
"fs",
"net",
"macros",
"sync",
"signal",
"time",
"rt-multi-thread",
"io-util",
"tracing",
]
[workspace.dependencies.tokio-metrics]
@@ -280,18 +280,18 @@ default-features = false
version = "1.6.0"
default-features = false
features = [
"server",
"http1",
"http2",
"server",
"http1",
"http2",
]
[workspace.dependencies.hyper-util]
version = "=0.1.17"
default-features = false
features = [
"server-auto",
"server-graceful",
"tokio",
"server-auto",
"server-graceful",
"tokio",
]
# to support multiple variations of setting a config option
@@ -310,9 +310,9 @@ features = ["env", "toml"]
version = "0.25.1"
default-features = false
features = [
"serde",
"system-config",
"tokio",
"serde",
"system-config",
"tokio",
]
# Used for conduwuit::Error type
@@ -351,7 +351,7 @@ version = "0.1.2"
# Used for matrix spec type definitions and helpers
[workspace.dependencies.ruma]
git = "https://forgejo.ellis.link/continuwuation/ruwuma"
rev = "27abe0dcd33fd4056efc94bab3582646b31b6ce9"
rev = "3a6f29fda2c3ccf07282c746dc0e2021defc50bb"
features = [
"compat",
"rand",
@@ -381,13 +381,13 @@ features = [
"unstable-msc4095",
"unstable-msc4121",
"unstable-msc4125",
"unstable-msc4155",
"unstable-msc4155",
"unstable-msc4186",
"unstable-msc4203", # sending to-device events to appservices
"unstable-msc4210", # remove legacy mentions
"unstable-extensible-events",
"unstable-pdu",
"unstable-msc4155"
"unstable-msc4155"
]
[workspace.dependencies.rust-rocksdb]
@@ -395,11 +395,11 @@ git = "https://forgejo.ellis.link/continuwuation/rust-rocksdb-zaidoon1"
rev = "61d9d23872197e9ace4a477f2617d5c9f50ecb23"
default-features = false
features = [
"multi-threaded-cf",
"mt_static",
"lz4",
"zstd",
"bzip2",
"multi-threaded-cf",
"mt_static",
"lz4",
"zstd",
"bzip2",
]
[workspace.dependencies.sha2]
@@ -458,16 +458,16 @@ git = "https://forgejo.ellis.link/continuwuation/jemallocator"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false
features = [
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
]
[workspace.dependencies.tikv-jemallocator]
git = "https://forgejo.ellis.link/continuwuation/jemallocator"
rev = "82af58d6a13ddd5dcdc7d4e91eae3b63292995b8"
default-features = false
features = [
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
"background_threads_runtime_support",
"unprefixed_malloc_on_supported_platforms",
]
[workspace.dependencies.tikv-jemalloc-ctl]
git = "https://forgejo.ellis.link/continuwuation/jemallocator"
@@ -491,9 +491,9 @@ default-features = false
version = "0.1.2"
default-features = false
features = [
"static",
"gcc",
"light",
"static",
"gcc",
"light",
]
[workspace.dependencies.rustyline-async]

View File

@@ -1515,16 +1515,11 @@
#
#block_non_admin_invites = false
# Enable or disable making requests to MSC4284 Policy Servers.
# It is recommended you keep this enabled unless you experience frequent
# connectivity issues, such as in a restricted networking environment.
# This item is undocumented. Please contribute documentation for it.
#
#enable_msc4284_policy_servers = true
# Enable running locally generated events through configured MSC4284
# policy servers. You may wish to disable this if your server is
# single-user for a slight speed benefit in some rooms, but otherwise
# should leave it enabled.
# This item is undocumented. Please contribute documentation for it.
#
#policy_server_check_own_events = true
@@ -1739,6 +1734,12 @@
#
#ldap = false
# Configuration for protocol experiments that enable experimental
# features. Each one is associated with a matrix spec proposal, a list of
# which are published at https://spec.matrix.org/proposals/
#
#experiments = false
[global.tls]
# Path to a valid TLS certificate file.

View File

@@ -6,12 +6,10 @@
"message": "Welcome to Continuwuity! Important announcements about the project will appear here."
},
{
"id": 3,
"message": "_taps microphone_ The Continuwuity 0.5.0-rc.7 release is now available, and it's better than ever! **177 commits**, **35 pull requests**, **11 contributors,** and a lot of new stuff!\n\nFor highlights, we've got:\n\n* 🕵️ Full Policy Server support to fight spam!\n* 🚀 Smarter room & space upgrades.\n* 🚫 User suspension tools for better moderation.\n* 🤖 reCaptcha support for safer open registration.\n* 🔍 Ability to disable read receipts & typing indicators.\n* ⚡ Sweeping performance improvements!\n\nGet the [full changelog and downloads on our Forgejo](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v0.5.0-rc.7) - and make sure you're in the [Announcements room](https://matrix.to/#/!releases:continuwuity.org/$hN9z6L2_dTAlPxFLAoXVfo_g8DyYXu4cpvWsSrWhmB0) to get stuff like this sooner."
},
{
"id": 5,
"message": "It's a bird! It's a plane! No, it's 0.5.0-rc.8.1!\n\nThis is a minor bugfix update to the rc8 which backports some important fixes from the latest main branch. If you still haven't updated to rc8, you should skip to main. Otherwise, you should upgrade to this bugfix release as soon as possible.\n\nBugfixes backported to this version:\n\n- Resolved several issues with state resolution v2.1 (room version 12)\n- Fixed issues with the `restricted` and `knock_restricted` join rules that would sometimes incorrectly disallow a valid join\n- Fixed the automatic support contact listing being a no-op\n- Fixed upgrading pre-v12 rooms to v12 rooms\n- Fixed policy servers sending the incorrect JSON objects (resulted in false positives)\n- Fixed debug build panic during MSC4133 migration\n\nIt is recommended, if you can and are comfortable with doing so, following updates to the main branch - we're in the run up to the full 0.5.0 release, and more and more bugfixes and new features are being pushed constantly. Please don't forget to join [#announcements:continuwuity.org](https://matrix.to/#/#announcements:continuwuity.org) to receive this news faster and be alerted to other important updates!"
"id": 6,
"mention_room": true,
"date": "2025-12-22",
"message": "Continuwuity v0.5.0 has been released. **The release contains a fix for the critical vulnerability [GHSA-22fw-4jq7-g8r8](https://github.com/continuwuity/continuwuity/security/advisories/GHSA-22fw-4jq7-g8r8). Update as soon as possible.**\n\nThis has been *actively exploited* to create fake leave events in the Continuwuity rooms. Please leave and rejoin the rooms to fix any issues this may have caused. \n\n - [Continuwuity (space)](https://matrix.to/#/!PxtzompFuodlyzdCDtV5lzjXs10XIHeOOaq_FYodHyk?via=ellis.link&via=gingershaped.computer&via=continuwuity.org)\n - [Continuwuity](https://matrix.to/#/!kn3VQSLcgWGUFm0FFRid4MinJ_aeZPjHQ0irXbHa3bU?via=ellis.link&via=gingershaped.computer&via=continuwuity.org)\n - [Continuwuity Announcements](https://matrix.to/#/!d7zDZg1Vu5nhkCi50jNfOIObD5fpfGhfl48SZWZek7k?via=ellis.link)\n - [Continuwuity Offtopic](https://matrix.to/#/!QlOomq-suHC9rJHfDFVdbcGg4HS2ojSQ0bo4W2JOGMM?via=ellis.link&via=gingershaped.computer&via=continuwuity.org)\n - [Continuwuity Development](https://matrix.to/#/!aAvealFbgiKTJGzumNbjuwDgt1tOkBKwiyfYqE3ouk0?via=ellis.link&via=explodie.org&via=continuwuity.org)\n"
}
]
}

54
flake.lock generated
View File

@@ -3,11 +3,11 @@
"advisory-db": {
"flake": false,
"locked": {
"lastModified": 1761112158,
"narHash": "sha256-RIXu/7eyKpQHjsPuAUODO81I4ni8f+WYSb7K4mTG6+0=",
"lastModified": 1766324728,
"narHash": "sha256-9C+WyE5U3y5w4WQXxmb0ylRyMMsPyzxielWXSHrcDpE=",
"owner": "rustsec",
"repo": "advisory-db",
"rev": "58f3aaec0e1776f4a900737be8cd7cb00972210d",
"rev": "c88b88c62bda077be8aa621d4e89d8701e39cb5d",
"type": "github"
},
"original": {
@@ -18,11 +18,11 @@
},
"crane": {
"locked": {
"lastModified": 1760924934,
"narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=",
"lastModified": 1766194365,
"narHash": "sha256-4AFsUZ0kl6MXSm4BaQgItD0VGlEKR3iq7gIaL7TjBvc=",
"owner": "ipetkov",
"repo": "crane",
"rev": "c6b4d5308293d0d04fcfeee92705017537cad02f",
"rev": "7d8ec2c71771937ab99790b45e6d9b93d15d9379",
"type": "github"
},
"original": {
@@ -39,11 +39,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1761115517,
"narHash": "sha256-Fev/ag/c3Fp3JBwHfup3lpA5FlNXfkoshnQ7dssBgJ0=",
"lastModified": 1766299592,
"narHash": "sha256-7u+q5hexu2eAxL2VjhskHvaUKg+GexmelIR2ve9Nbb4=",
"owner": "nix-community",
"repo": "fenix",
"rev": "320433651636186ea32b387cff05d6bbfa30cea7",
"rev": "381579dee168d5ced412e2990e9637ecc7cf1c5d",
"type": "github"
},
"original": {
@@ -55,11 +55,11 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1747046372,
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
"lastModified": 1765121682,
"narHash": "sha256-4VBOP18BFeiPkyhy9o4ssBNQEvfvv1kXkasAYd0+rrA=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
"type": "github"
},
"original": {
@@ -74,11 +74,11 @@
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1760948891,
"narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
"lastModified": 1765835352,
"narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
"rev": "a34fae9c08a15ad73f295041fec82323541400a9",
"type": "github"
},
"original": {
@@ -89,11 +89,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1760878510,
"narHash": "sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs=",
"lastModified": 1766070988,
"narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5e2a59a5b1a82f89f2c7e598302a9cacebb72a67",
"rev": "c6245e83d836d0433170a16eb185cefe0572f8b8",
"type": "github"
},
"original": {
@@ -105,11 +105,11 @@
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1754788789,
"narHash": "sha256-x2rJ+Ovzq0sCMpgfgGaaqgBSwY+LST+WbZ6TytnT9Rk=",
"lastModified": 1765674936,
"narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "a73b9c743612e4244d865a2fdee11865283c04e6",
"rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
"type": "github"
},
"original": {
@@ -132,11 +132,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1761077270,
"narHash": "sha256-O1uTuvI/rUlubJ8AXKyzh1WSWV3qCZX0huTFUvWLN4E=",
"lastModified": 1766253897,
"narHash": "sha256-ChK07B1aOlJ4QzWXpJo+y8IGAxp1V9yQ2YloJ+RgHRw=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "39990a923c8bca38f5bd29dc4c96e20ee7808d5d",
"rev": "765b7bdb432b3740f2d564afccfae831d5a972e4",
"type": "github"
},
"original": {
@@ -153,11 +153,11 @@
]
},
"locked": {
"lastModified": 1760945191,
"narHash": "sha256-ZRVs8UqikBa4Ki3X4KCnMBtBW0ux1DaT35tgsnB1jM4=",
"lastModified": 1766000401,
"narHash": "sha256-+cqN4PJz9y0JQXfAK5J1drd0U05D5fcAGhzhfVrDlsI=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "f56b1934f5f8fcab8deb5d38d42fd692632b47c2",
"rev": "42d96e75aa56a3f70cab7e7dc4a32868db28e8fd",
"type": "github"
},
"original": {

View File

@@ -13,6 +13,7 @@
room::member::{MembershipState, RoomMemberEventContent},
},
};
use serde_json::value::RawValue;
use service::Services;
use super::banned_room_check;
@@ -146,7 +147,17 @@ pub(crate) async fn invite_helper(
)
.await?;
let invite_room_state = services.rooms.state.summary_stripped(&pdu, room_id).await;
let invite_room_state = services
.rooms
.state
.summary(&pdu, room_id)
.await
.into_iter()
.map(|evt| RawValue::from_string(evt.json().get().to_owned()))
.collect::<std::result::Result<Vec<_>, _>>()
.map_err(|e| {
err!(Request(BadJson(warn!("Could not clone invite state event: {e}"))))
})?;
drop(state_lock);

View File

@@ -1,30 +1,327 @@
use std::collections::HashMap;
use axum::extract::State;
use axum_client_ip::InsecureClientIp;
use base64::{Engine as _, engine::general_purpose};
use conduwuit::{
Err, Error, PduEvent, Result, err,
matrix::{Event, event::gen_event_id},
Err, Error, EventTypeExt, PduEvent, Result, RoomVersion, debug, debug_warn, err,
matrix::{Event, StateKey, event::gen_event_id},
trace,
utils::{self, hash::sha256},
warn,
};
use ruma::{
CanonicalJsonValue, OwnedUserId, UserId,
CanonicalJsonValue, OwnedUserId, RoomId, RoomVersionId, ServerName, UserId,
api::{client::error::ErrorKind, federation::membership::create_invite},
events::room::member::{MembershipState, RoomMemberEventContent},
serde::JsonObject,
events::{
StateEventType,
room::{
create::RoomCreateEventContent,
member::{MembershipState, RoomMemberEventContent},
},
},
};
use serde_json::value::RawValue;
use service::{Services, rooms::timeline::pdu_fits};
use crate::Ruma;
/// Ensures that the state received from the invite endpoint is sane, correct,
/// and complies with the room version's requirements.
async fn check_invite_state(
services: &Services,
stripped_state: &Vec<Box<RawValue>>,
room_id: &RoomId,
room_version_id: &RoomVersionId,
) -> Result<()> {
let room_version = RoomVersion::new(room_version_id).map_err(|e| {
err!(Request(UnsupportedRoomVersion("Invalid room version provided: {e}")))
})?;
let mut room_state: HashMap<(StateEventType, StateKey), PduEvent> = HashMap::new();
// Build the room state from the provided state events,
// ensuring that there's no duplicates. We need to check that m.room.create is
// present and lines up with the other things we've been told, and then verify
// any signatures present to ensure this isn't forged.
for raw_event in stripped_state {
trace!("Processing invite state event: {:?}", raw_event);
let canonical = utils::to_canonical_object(raw_event)?;
let event_id = gen_event_id(&canonical, room_version_id)?;
let event = PduEvent::from_id_val(&event_id, canonical.clone())
.map_err(|e| err!(Request(InvalidParam("Invite state event is invalid: {e}"))))?;
if event.state_key().is_none() {
return Err!(Request(InvalidParam("Invite state event missing event type.")));
}
let key = event
.event_type()
.with_state_key(event.state_key().unwrap());
if room_state.contains_key(&key) {
return Err!(Request(InvalidParam("Duplicate state event found for {key:?}")));
}
// verify the event
if !pdu_fits(&canonical) {
return Err!(Request(InvalidParam(
"An invite state event ({event_id}) is too large"
)));
}
services
.server_keys
.verify_event(&canonical, Some(room_version_id))
.await
.map_err(|e| {
err!(Request(InvalidParam(
"Signature failed verification on event {event_id}: {e}"
)))
})?;
// Ensure all events are in the same room
if event.room_id_or_hash() != room_id {
return Err!(Request(InvalidParam(
"State event room ID for {} does not match the expected room ID {}.",
event.event_id,
room_id,
)));
}
room_state.insert(key, event);
}
// verify m.room.create is present, has a matching room ID, and a matching room
// version.
let create_event = room_state
.get(&(StateEventType::RoomCreate, "".into()))
.ok_or_else(|| err!(Request(MissingParam("Missing m.room.create in stripped state."))))?;
let create_event_content: RoomCreateEventContent = create_event
.get_content()
.map_err(|e| err!(Request(InvalidParam("Invalid m.room.create content: {e}"))))?;
// Room v12 removed room IDs over federation, so we'll need to see if the event
// ID matches the room ID instead.
if room_version.room_ids_as_hashes {
let given_room_id = create_event.event_id().as_str().replace('$', "!");
if given_room_id != room_id.as_str() {
return Err!(Request(InvalidParam(
"m.room.create event ID does not match the room ID."
)));
}
} else if create_event.room_id().unwrap() != room_id {
return Err!(Request(InvalidParam("m.room.create room ID does not match the room ID.")));
}
// Make sure the room version matches
if &create_event_content.room_version != room_version_id {
return Err!(Request(InvalidParam(
"m.room.create room version does not match the given room version."
)));
}
// Looks solid
Ok(())
}
/// Ensures that the invite event received from the invite endpoint is sane,
/// correct, and complies with the room version's requirements.
/// Returns the invited user ID on success.
async fn check_invite_event(
services: &Services,
invite_event: &PduEvent,
origin: &ServerName,
room_id: &RoomId,
room_version_id: &RoomVersionId,
) -> Result<OwnedUserId> {
// Check: The event sender is not a user ID on the origin server.
if invite_event.sender.server_name() != origin {
return Err!(Request(InvalidParam(
"Invite event sender's server does not match the origin server."
)));
}
// Check: The `state_key` is not a user ID on the receiving server.
let state_key: &UserId = invite_event
.state_key()
.ok_or_else(|| err!(Request(MissingParam("Invite event missing state_key."))))?
.try_into()
.map_err(|e| err!(Request(InvalidParam("Invalid state_key property: {e}"))))?;
if !services.globals.server_is_ours(state_key.server_name()) {
return Err!(Request(InvalidParam(
"Invite event state_key does not belong to this homeserver."
)));
}
// Check: The event's room ID matches the expected room ID.
if let Some(evt_room_id) = invite_event.room_id() {
if evt_room_id != room_id {
return Err!(Request(InvalidParam(
"Invite event room ID does not match the expected room ID."
)));
}
} else {
return Err!(Request(MissingParam("Invite event missing room ID.")));
}
// Check: the membership really is "invite"
let content = invite_event.get_content::<RoomMemberEventContent>()?;
if content.membership != MembershipState::Invite {
return Err!(Request(InvalidParam("Invite event is not a membership invite.")));
}
// Check: signature is valid
let as_obj = &mut utils::to_canonical_object(invite_event)?;
// remove the event_id before verification
as_obj.remove("event_id");
services
.server_keys
.verify_event(as_obj, Some(room_version_id))
.await
.map_err(|e| {
err!(Request(InvalidParam("Invite event signature failed verification: {e}")))
})?;
Ok(state_key.to_owned())
}
/// Performs only legacy checks on the invite, for use when the requesting
/// server doesn't support matrix v1.16 invites.
/// This is significantly less secure than the full checks and should only be
/// used if the user has allowed it.
async fn legacy_check_invite(
services: &Services,
origin: &ServerName,
invite_event: &PduEvent,
stripped_state: &Vec<Box<RawValue>>,
room_id: &RoomId,
room_version_id: &RoomVersionId,
) -> Result<OwnedUserId> {
// Ensure the sender is from origin, the state key is a user ID that points at a
// local user, the event type is m.room.member with membership "invite", and
// the room ID matches.
if invite_event.sender().server_name() != origin {
return Err!(Request(InvalidParam(
"Invite event sender's server does not match the origin server."
)));
}
let state_key: &UserId = invite_event
.state_key()
.ok_or_else(|| err!(Request(MissingParam("Invite event missing state_key."))))?
.try_into()
.map_err(|e| err!(Request(InvalidParam("Invalid state_key property: {e}"))))?;
if !services.globals.server_is_ours(state_key.server_name()) {
return Err!(Request(InvalidParam(
"Invite event state_key does not belong to this homeserver."
)));
}
if let Some(evt_room_id) = invite_event.room_id() {
if evt_room_id != room_id {
return Err!(Request(InvalidParam(
"Invite event room ID does not match the expected room ID."
)));
}
} else {
return Err!(Request(MissingParam("Invite event missing room ID.")));
}
let content = invite_event.get_content::<RoomMemberEventContent>()?;
if content.membership != MembershipState::Invite {
return Err!(Request(InvalidParam("Invite event is not a membership invite.")));
}
// We can also opportunistically check that the m.room.create event is present
// and matches the room version, to avoid accepting invites to rooms that
// don't match.
let mut has_create = false;
for raw_event in stripped_state {
let canonical = utils::to_canonical_object(raw_event)?;
if canonical.get("room_id").is_none() {
// This is a stripped event, skip
continue;
}
if let Some(event_type) = canonical.get("type") {
if event_type.as_str().unwrap_or_default() == "m.room.create" {
has_create = true;
let event_id = gen_event_id(&canonical, room_version_id)?;
let event = PduEvent::from_id_val(&event_id, canonical.clone()).map_err(|e| {
err!(Request(InvalidParam("Invite state event is invalid: {e}")))
})?;
// We can verify that the room ID is correct now
let version = RoomVersion::new(room_version_id)?;
if version.room_ids_as_hashes {
let given_room_id = event.event_id().as_str().replace('$', "!");
if given_room_id != room_id.as_str() {
return Err!(Request(InvalidParam(
"m.room.create event ID does not match the room ID."
)));
}
} else if event.room_id().unwrap() != room_id {
return Err!(Request(InvalidParam(
"m.room.create room ID does not match the room ID."
)));
}
// Everything's as fine as we're getting with this event
break;
}
}
}
if !has_create {
warn!(
"federated invite is missing m.room.create event in stripped state, the remote \
server is either outdated or trying something fishy."
);
}
Ok(state_key.to_owned())
}
/// Checks the incoming event is allowed and not forged.
/// If the MSC4311 enforcement experiment is enabled, performs full checks,
/// otherwise performs legacy checks only.
async fn check_invite(
services: &Services,
invite_event: &PduEvent,
stripped_state: &Vec<Box<RawValue>>,
origin: &ServerName,
room_id: &RoomId,
room_version_id: &RoomVersionId,
) -> Result<OwnedUserId> {
if services.config.experiments.enforce_msc4311 {
debug!("Checking invite event validity");
let user = check_invite_event(services, invite_event, origin, room_id, room_version_id)
.await
.inspect_err(|e| {
debug_warn!("Invite event validity check failed: {e}");
})?;
debug!("Checking invite state validity");
check_invite_state(services, stripped_state, room_id, room_version_id)
.await
.inspect_err(|e| {
debug_warn!("Invite state validity check failed: {e}");
})?;
Ok(user)
} else {
debug!("Performing legacy invite checks");
legacy_check_invite(
services,
origin,
invite_event,
stripped_state,
room_id,
room_version_id,
)
.await
.inspect_err(|e| {
debug_warn!("Legacy invite validity check failed: {e}");
})
}
}
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
///
/// Invites a remote user to a room.
#[tracing::instrument(skip_all, fields(%client), name = "invite")]
#[tracing::instrument(skip_all, fields(%client, room_id=?body.room_id), name = "invite")]
pub(crate) async fn create_invite_route(
State(services): State<crate::State>,
InsecureClientIp(client): InsecureClientIp,
body: Ruma<create_invite::v2::Request>,
) -> Result<create_invite::v2::Response> {
debug!("Received invite request from {}: {:?}", body.room_id, body.origin());
// ACL check origin
services
.rooms
@@ -33,6 +330,7 @@ pub(crate) async fn create_invite_route(
.await?;
if !services.server.supported_room_version(&body.room_version) {
debug_warn!("Unsupported room version: {}", body.room_version);
return Err(Error::BadRequest(
ErrorKind::IncompatibleRoomVersion { room_version: body.room_version.clone() },
"Server does not support this room version.",
@@ -41,6 +339,7 @@ pub(crate) async fn create_invite_route(
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
warn!("Received invite to room created by a banned server: {}. Rejecting.", server);
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
}
@@ -50,7 +349,7 @@ pub(crate) async fn create_invite_route(
.is_remote_server_forbidden(body.origin())
{
warn!(
"Received federated/remote invite from banned server {} for room ID {}. Rejecting.",
"Received invite from banned server {} for room ID {}. Rejecting.",
body.origin(),
body.room_id
);
@@ -61,57 +360,42 @@ pub(crate) async fn create_invite_route(
let mut signed_event = utils::to_canonical_object(&body.event)
.map_err(|_| err!(Request(InvalidParam("Invite event is invalid."))))?;
// Ensure this is a membership event
if signed_event
.get("type")
.expect("event must have a type")
.as_str()
.expect("type must be a string")
!= "m.room.member"
{
return Err!(Request(BadJson(
"Not allowed to send non-membership event to invite endpoint."
)));
// We need to hash and sign the event before we can generate the event ID.
// It is important that this signed event does not get sent back to the caller
// until we've verified this isn't incorrect.
trace!(event=?signed_event, "Hashing & signing invite event");
services
.server_keys
.hash_and_sign_event(&mut signed_event, &body.room_version)
.map_err(|e| err!(Request(InvalidParam("Failed to sign event: {e}"))))?;
let event_id = gen_event_id(&signed_event.clone(), &body.room_version)?;
if event_id != body.event_id {
warn!("Event ID mismatch: expected {}, got {}", event_id, body.event_id);
return Err!(Request(InvalidParam("Event ID does not match the generated event ID.")));
}
let content: RoomMemberEventContent = serde_json::from_value(
signed_event
.get("content")
.ok_or_else(|| err!(Request(BadJson("Event missing content property"))))?
.clone()
.into(),
let pdu = PduEvent::from_id_val(&event_id, signed_event.clone())
.map_err(|e| err!(Request(InvalidParam("Invite event is invalid: {e}"))))?;
let recipient_user = check_invite(
&services,
&pdu,
&body.invite_room_state,
body.origin(),
&body.room_id,
&body.room_version,
)
.map_err(|e| err!(Request(BadJson(warn!("Event content is empty or invalid: {e}")))))?;
.await?;
// Ensure this is an invite membership event
if content.membership != MembershipState::Invite {
return Err!(Request(BadJson(
"Not allowed to send a non-invite membership event to invite endpoint."
)));
}
// Ensure the sending user isn't a lying bozo
let sender_server = signed_event
.get("sender")
.try_into()
.map(UserId::server_name)
.map_err(|e| err!(Request(InvalidParam("Invalid sender property: {e}"))))?;
if sender_server != body.origin() {
return Err!(Request(Forbidden("Sender's server does not match the origin server.",)));
}
// Ensure the target user belongs to this server
let recipient_user: OwnedUserId = signed_event
.get("state_key")
.try_into()
.map(UserId::to_owned)
.map_err(|e| err!(Request(InvalidParam("Invalid state_key property: {e}"))))?;
if !services
.globals
.server_is_ours(recipient_user.server_name())
// Make sure the room isn't banned and we allow invites
if services.config.block_non_admin_invites && !services.users.is_admin(&recipient_user).await
{
return Err!(Request(InvalidParam("User does not belong to this homeserver.")));
return Err!(Request(Forbidden("This server does not allow room invites.")));
}
if services.rooms.metadata.is_banned(&body.room_id).await
&& !services.users.is_admin(&recipient_user).await
{
return Err!(Request(Forbidden("This room is banned on this homeserver.")));
}
// Make sure we're not ACL'ed from their room.
@@ -121,45 +405,9 @@ pub(crate) async fn create_invite_route(
.acl_check(recipient_user.server_name(), &body.room_id)
.await?;
services
.server_keys
.hash_and_sign_event(&mut signed_event, &body.room_version)
.map_err(|e| err!(Request(InvalidParam("Failed to sign event: {e}"))))?;
// Generate event id
let event_id = gen_event_id(&signed_event, &body.room_version)?;
// Add event_id back
signed_event.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.to_string()));
let sender_user: &UserId = signed_event
.get("sender")
.try_into()
.map_err(|e| err!(Request(InvalidParam("Invalid sender property: {e}"))))?;
if services.rooms.metadata.is_banned(&body.room_id).await
&& !services.users.is_admin(&recipient_user).await
{
return Err!(Request(Forbidden("This room is banned on this homeserver.")));
}
if services.config.block_non_admin_invites && !services.users.is_admin(&recipient_user).await
{
return Err!(Request(Forbidden("This server does not allow room invites.")));
}
let mut invite_state = body.invite_room_state.clone();
let mut event: JsonObject = serde_json::from_str(body.event.get())
.map_err(|e| err!(Request(BadJson("Invalid invite event PDU: {e}"))))?;
event.insert("event_id".to_owned(), "$placeholder".into());
let pdu: PduEvent = serde_json::from_value(event.into())
.map_err(|e| err!(Request(BadJson("Invalid invite event PDU: {e}"))))?;
invite_state.push(pdu.to_format());
// If we are active in the room, the remote server will notify us about the
// join/invite through /send. If we are not in the room, we need to manually
// record the invited state for client /sync through update_membership(), and
@@ -170,6 +418,19 @@ pub(crate) async fn create_invite_route(
.server_in_room(services.globals.server_name(), &body.room_id)
.await
{
let mut invite_state: Vec<CanonicalJsonValue> = body
.invite_room_state
.clone()
.into_iter()
.map(|v| utils::to_canonical_object(&v).unwrap().into())
.collect();
invite_state.push(pdu.to_canonical_object().into());
let sender_user: &UserId = signed_event
.get("sender")
.try_into()
.map_err(|e| err!(Request(InvalidParam("Invalid sender property: {e}"))))?;
debug!("Marking user {} as invited to remote room {}", recipient_user, body.room_id);
services
.rooms
.state_cache
@@ -208,6 +469,7 @@ pub(crate) async fn create_invite_route(
}
}
debug!("Invite is valid, returning signed event");
Ok(create_invite::v2::Response {
event: services
.sending

View File

@@ -175,11 +175,7 @@ pub(crate) async fn create_knock_event_v1_route(
.send_pdu_room(&body.room_id, &pdu_id)
.await?;
let knock_room_state = services
.rooms
.state
.summary_stripped(&pdu, &body.room_id)
.await;
let knock_room_state = services.rooms.state.summary(&pdu, &body.room_id).await;
Ok(send_knock::v1::Response { knock_room_state })
}

View File

@@ -0,0 +1,25 @@
mod msc4284_policy_servers;
use conduwuit_macros::config_example_generator;
use serde::Deserialize;
#[derive(Clone, Debug, Default, Deserialize)]
#[config_example_generator(filename = "conduwuit-example.toml", section = "global.experiments")]
pub struct Experiments {
/// Enforce MSC4311's updated requirements on all incoming invites.
///
/// This drastically increases the security and filtering capabilities
/// when processing invites over federation, at the cost of compatibility.
/// Servers that do not implement MSC4311 will be unable to send invites
/// to your server when this is enabled, including continuwuity 0.5.0 and
/// below.
///
/// default: false
/// Introduced in: (unreleased)
#[serde(default)]
pub enforce_msc4311: bool,
/// MSC4284 Policy Server support configuration.
#[serde(default)]
pub msc4284: msc4284_policy_servers::MSC4248,
}

View File

@@ -0,0 +1,58 @@
use conduwuit_macros::config_example_generator;
use serde::Deserialize;
fn true_fn() -> bool { true }
fn default_federation_timeout() -> u64 { 25 }
#[derive(Clone, Debug, Default, Deserialize)]
#[config_example_generator(
filename = "conduwuit-example.toml",
section = "global.experiments.msc4284"
)]
pub struct MSC4248 {
/// Enable or disable making requests to MSC4284 Policy Servers.
/// It is recommended you keep this enabled unless you experience frequent
/// connectivity issues, such as in a restricted networking environment.
///
/// default: true
/// Introduced in: 0.5.0
#[serde(default = "true_fn")]
pub enabled: bool,
/// Enable running locally generated events through configured MSC4284
/// policy servers. You may wish to disable this if your server is
/// single-user for a slight speed benefit in some rooms, but otherwise
/// should leave it enabled.
///
/// If the room's policy server configuration requires event signatures,
/// this option is effectively ignored, as otherwise local events would
/// be rejected for missing the policy server's signature.
///
/// default: true
/// Introduced in: 0.5.0
#[serde(default = "true_fn")]
pub check_own_events: bool,
/// MSC4284 Policy server request timeout (seconds). Generally policy
/// servers should respond near instantly, however may slow down under
/// load. If a policy server doesn't respond in a short amount of time, the
/// room it is configured in may become unusable if this limit is set too
/// high. 25 seconds is a good default, however should be raised if you
/// experience too many connection issues.
///
/// Please be aware that policy requests are *NOT* currently re-tried, so if
/// a spam check request fails, the event will be assumed to be not spam,
/// which in some cases may result in spam being sent to or received from
/// the room that would typically be prevented.
///
/// If your request timeout is too low, and the policy server requires
/// signatures, you may find that you are unable to send events that are
/// accepted regardless.
///
/// About policy servers: https://matrix.org/blog/2025/04/introducing-policy-servers/
/// default: 25
/// Introduced in: 0.5.0
#[serde(default = "default_federation_timeout")]
pub request_timeout: u64,
}

View File

@@ -1,5 +1,6 @@
#![allow(clippy::doc_link_with_quotes)]
pub mod check;
pub mod experiments;
pub mod manager;
pub mod proxy;
@@ -1734,16 +1735,9 @@ pub struct Config {
#[serde(default)]
pub block_non_admin_invites: bool,
/// Enable or disable making requests to MSC4284 Policy Servers.
/// It is recommended you keep this enabled unless you experience frequent
/// connectivity issues, such as in a restricted networking environment.
#[serde(default = "true_fn")]
pub enable_msc4284_policy_servers: bool,
/// Enable running locally generated events through configured MSC4284
/// policy servers. You may wish to disable this if your server is
/// single-user for a slight speed benefit in some rooms, but otherwise
/// should leave it enabled.
#[serde(default = "true_fn")]
pub policy_server_check_own_events: bool,
@@ -2003,6 +1997,13 @@ pub struct Config {
// external structure; separate section
#[serde(default)]
pub blurhashing: BlurhashConfig,
/// Configuration for protocol experiments that enable experimental
/// features. Each one is associated with a matrix spec proposal, a list of
/// which are published at https://spec.matrix.org/proposals/
#[serde(default)]
pub experiments: experiments::Experiments,
#[serde(flatten)]
#[allow(clippy::zero_sized_map_values)]
// this is a catchall, the map shouldn't be zero at runtime
@@ -2216,7 +2217,7 @@ struct ListeningAddr {
addrs: Either<IpAddr, Vec<IpAddr>>,
}
const DEPRECATED_KEYS: &[&str; 9] = &[
const DEPRECATED_KEYS: &[&str; 11] = &[
"cache_capacity",
"conduit_cache_capacity_modifier",
"max_concurrent_requests",
@@ -2226,6 +2227,8 @@ struct ListeningAddr {
"well_known_support_role",
"well_known_support_email",
"well_known_support_mxid",
"enable_msc4284_policy_servers",
"policy_server_check_own_events",
];
impl Config {

View File

@@ -19,8 +19,7 @@
use ruma::{
EventId, OwnedEventId, OwnedRoomId, RoomId, RoomVersionId, UserId,
events::{
AnyStrippedStateEvent, StateEventType, TimelineEventType,
room::create::RoomCreateEventContent,
AnyStateEvent, StateEventType, TimelineEventType, room::create::RoomCreateEventContent,
},
serde::Raw,
};
@@ -307,12 +306,22 @@ pub async fn append_to_state(&self, new_pdu: &PduEvent, room_id: &RoomId) -> Res
}
}
/// Get a summary of the room state for invites and knock responses.
///
/// This used to return stripped state, but now returns complete events.
///
/// Returns:
///
/// - m.room.create
/// - m.room.join_rules
/// - m.room.canonical_alias
/// - m.room.name
/// - m.room.avatar
/// - m.room.member (of the event sender)
/// - m.room.encryption
/// - m.room.topic
#[tracing::instrument(skip_all, level = "debug")]
pub async fn summary_stripped<'a, E>(
&self,
event: &'a E,
room_id: &RoomId,
) -> Vec<Raw<AnyStrippedStateEvent>>
pub async fn summary<'a, E>(&self, event: &'a E, room_id: &RoomId) -> Vec<Raw<AnyStateEvent>>
where
E: Event + Send + Sync,
&'a E: Event + Send,

View File

@@ -1,10 +1,10 @@
use std::collections::HashSet;
use conduwuit::{Err, Event, Pdu, Result, implement, is_not_empty, utils::ReadyExt, warn};
use conduwuit::{Err, Event, Pdu, Result, implement, is_not_empty, utils::ReadyExt};
use database::{Json, serialize_key};
use futures::StreamExt;
use ruma::{
OwnedServerName, RoomId, UserId,
CanonicalJsonValue, OwnedServerName, RoomId, UserId,
events::{
AnyStrippedStateEvent, GlobalAccountDataEventType, RoomAccountDataEventType,
StateEventType,
@@ -334,7 +334,7 @@ pub async fn mark_as_invited(
user_id: &UserId,
room_id: &RoomId,
sender_user: &UserId,
last_state: Option<Vec<Raw<AnyStrippedStateEvent>>>,
last_state: Option<Vec<CanonicalJsonValue>>,
invite_via: Option<Vec<OwnedServerName>>,
) -> Result<()> {
// return an error for blocked invites. ignored invites aren't handled here

View File

@@ -23,7 +23,7 @@
use super::RoomMutexGuard;
pub fn pdu_fits(owned_obj: &mut CanonicalJsonObject) -> bool {
pub fn pdu_fits(owned_obj: &CanonicalJsonObject) -> bool {
// room IDs, event IDs, senders, types, and state keys must all be <= 255 bytes
if let Some(CanonicalJsonValue::String(room_id)) = owned_obj.get("room_id") {
if room_id.len() > 255 {