Compare commits

..
Author SHA1 Message Date
Ginger ec863bc08d fix: Properly handle appservice device creation 2026-07-11 16:20:08 -04:00
54 changed files with 884 additions and 950 deletions
+1 -1
View File
@@ -71,7 +71,7 @@ runs:
- name: Install timelord-cli and git-warp-time - name: Install timelord-cli and git-warp-time
if: steps.check-binaries.outputs.need-install == 'true' if: steps.check-binaries.outputs.need-install == 'true'
uses: https://github.com/taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 # v2 uses: https://github.com/taiki-e/install-action@50414676f9f5d50a65992c6dd2ed02641263226c # v2
with: with:
tool: git-warp-time,timelord-cli@3.0.1 tool: git-warp-time,timelord-cli@3.0.1
+1 -1
View File
@@ -65,7 +65,7 @@ jobs:
path: binaries path: binaries
merge-multiple: true merge-multiple: true
- name: Create Release and Upload - name: Create Release and Upload
uses: https://github.com/softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3 uses: https://github.com/softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3
with: with:
draft: true draft: true
files: binaries/* files: binaries/*
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20' if: steps.runner-env.outputs.node_major == '' || steps.runner-env.outputs.node_major < '20'
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 uses: https://github.com/actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version: 22 node-version: 22
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
steps: steps:
- name: 📦 Setup Node.js - name: 📦 Setup Node.js
uses: https://github.com/actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 uses: https://github.com/actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with: with:
node-version: "22" node-version: "22"
+1 -1
View File
@@ -218,7 +218,7 @@ jobs:
path: binaries path: binaries
merge-multiple: true merge-multiple: true
- name: Create Release and Upload - name: Create Release and Upload
uses: https://github.com/softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3 uses: https://github.com/softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3
with: with:
draft: true draft: true
files: binaries/* files: binaries/*
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
name: Renovate name: Renovate
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/renovatebot/renovate:43.260.2@sha256:60d830108d9ff6408d11a55d5f110ee0976bed78a6b82b08211e3ddb72f72952 image: ghcr.io/renovatebot/renovate:43.252.1@sha256:121eb04ef758537019fb58f587aa53c99e5fda4e703993ce2ca01bd4b3926bd4
options: --tmpfs /tmp:exec options: --tmpfs /tmp:exec
steps: steps:
- name: Checkout - name: Checkout
-24
View File
@@ -1,27 +1,3 @@
# Continuwuity 26.6.2 (2026-07-12)
## Bugfixes
- Fixed the server returning 500 errors if `admin_console_automatic` is enabled and no TTY is available. Contributed by @s1lv3r. (#1975)
- Fixed `global.oauth.compatibility_mode` being required, despite being ignored, when the `[global.oauth.oidc]` config section is provided.
- Fixed an issue with a migration that could cause user accounts imported from an identity provider to be marked as deactivated when the server started. If you have accounts affected by this issue, use `!admin users reset-password --convert-to-local-account` to reactivate them.
# Continuwuity 26.6.1 (2026-07-12)
## Features
- Added enforcement for new federated invite checks and corrected a bunch of related spec compliance issues along the way. Contributed by @nex. (#1952)
## Bugfixes
- Fixed existing accounts failing to link when logging in with OIDC if `prompt_for_localpart` was `false`. (#1942)
- Authentication is no longer required on the `/_matrix/client/v3/account/3pid/email/requestToken` endpoint. (#1953)
- Fixed newly created rooms failing to sync properly in clients using legacy sync.
- Stopped appservice users from being erroneously marked as deactivated during a 26.6 database migration.
- Whitespace will now automatically be trimmed from the start and end of the `global.oauth.oidc.client_secret_file`.
# Continuwuity 26.6.0 (2026-07-10) # Continuwuity 26.6.0 (2026-07-10)
## Features ## Features
+2 -2
View File
@@ -26,7 +26,7 @@ ### Pre-commit Checks
```bash ```bash
# Install prek using cargo-binstall https://github.com/cargo-bins/cargo-binstall # Install prek using cargo-binstall
cargo binstall prek cargo binstall prek
# Install git hooks to run checks automatically # Install git hooks to run checks automatically
@@ -155,7 +155,7 @@ ### Creating pull requests
Before submitting a pull request, please ensure: Before submitting a pull request, please ensure:
1. Your code passes all CI checks (formatting, linting, typo detection, etc.) 1. Your code passes all CI checks (formatting, linting, typo detection, etc.)
2. Your code follows the [code style guide](docs/development/code_style.mdx) 2. Your code follows the [code style guide](/development/code_style.md)
3. Your commit messages follow the conventional commits format 3. Your commit messages follow the conventional commits format
4. Tests are added for new functionality 4. Tests are added for new functionality
5. Documentation is updated if needed 5. Documentation is updated if needed
Generated
+234 -137
View File
@@ -259,9 +259,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]] [[package]]
name = "aws-lc-rs" name = "aws-lc-rs"
version = "1.17.1" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad" checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00"
dependencies = [ dependencies = [
"aws-lc-sys", "aws-lc-sys",
"zeroize", "zeroize",
@@ -269,15 +269,14 @@ dependencies = [
[[package]] [[package]]
name = "aws-lc-sys" name = "aws-lc-sys"
version = "0.42.0" version = "0.41.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444" checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4"
dependencies = [ dependencies = [
"cc", "cc",
"cmake", "cmake",
"dunce", "dunce",
"fs_extra", "fs_extra",
"pkg-config",
] ]
[[package]] [[package]]
@@ -558,9 +557,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.25.1" version = "1.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424" checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@@ -576,9 +575,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.12.1" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
[[package]] [[package]]
name = "bytesize" name = "bytesize"
@@ -642,9 +641,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.67" version = "1.2.65"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@@ -827,7 +826,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit" name = "conduwuit"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"aws-lc-rs", "aws-lc-rs",
"clap", "clap",
@@ -865,7 +864,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_admin" name = "conduwuit_admin"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"assign", "assign",
"clap", "clap",
@@ -891,7 +890,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_api" name = "conduwuit_api"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"assign", "assign",
"async-trait", "async-trait",
@@ -929,7 +928,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_build_metadata" name = "conduwuit_build_metadata"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"built", "built",
"cargo_metadata", "cargo_metadata",
@@ -937,7 +936,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_core" name = "conduwuit_core"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"argon2", "argon2",
"arrayvec", "arrayvec",
@@ -1005,7 +1004,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_database" name = "conduwuit_database"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"async-channel", "async-channel",
"conduwuit_core", "conduwuit_core",
@@ -1026,7 +1025,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_macros" name = "conduwuit_macros"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"cargo_toml", "cargo_toml",
"itertools 0.15.0", "itertools 0.15.0",
@@ -1037,7 +1036,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_router" name = "conduwuit_router"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"assign", "assign",
"axum", "axum",
@@ -1075,7 +1074,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_service" name = "conduwuit_service"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"askama", "askama",
"assign", "assign",
@@ -1127,7 +1126,7 @@ dependencies = [
[[package]] [[package]]
name = "conduwuit_web" name = "conduwuit_web"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"askama", "askama",
"assign", "assign",
@@ -1362,18 +1361,18 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.16" version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.7" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [ dependencies = [
"crossbeam-epoch", "crossbeam-epoch",
"crossbeam-utils", "crossbeam-utils",
@@ -1381,27 +1380,27 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.20" version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.3.13" version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "803d13fb3b09d88be9f4dbc29062c66b19bf7170867ceb746d2a8689bf6c7a26" checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.22" version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]] [[package]]
name = "crossterm" name = "crossterm"
@@ -1464,9 +1463,9 @@ dependencies = [
[[package]] [[package]]
name = "ctor" name = "ctor"
version = "1.0.8" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb22e947478ccf9dc44d8922042c677a63fbb88f2cb468521d1145816e5087cb" checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a"
dependencies = [ dependencies = [
"link-section", "link-section",
"linktime-proc-macro", "linktime-proc-macro",
@@ -1514,14 +1513,38 @@ version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "817fa642fb0ee7fe42e95783e00e0969927b96091bdd4b9b1af082acd943913b" checksum = "817fa642fb0ee7fe42e95783e00e0969927b96091bdd4b9b1af082acd943913b"
[[package]]
name = "darling"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
dependencies = [
"darling_core 0.20.11",
"darling_macro 0.20.11",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.23.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
dependencies = [ dependencies = [
"darling_core", "darling_core 0.23.0",
"darling_macro", "darling_macro 0.23.0",
]
[[package]]
name = "darling_core"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
] ]
[[package]] [[package]]
@@ -1537,13 +1560,24 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "darling_macro"
version = "0.20.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core 0.20.11",
"quote",
"syn",
]
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.23.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
dependencies = [ dependencies = [
"darling_core", "darling_core 0.23.0",
"quote", "quote",
"syn", "syn",
] ]
@@ -2088,11 +2122,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys",
"libc", "libc",
"r-efi 6.0.0", "r-efi 6.0.0",
"rand_core 0.10.1", "rand_core 0.10.1",
"wasm-bindgen",
] ]
[[package]] [[package]]
@@ -2258,7 +2290,7 @@ dependencies = [
"http", "http",
"httpdate", "httpdate",
"mime", "mime",
"sha1 0.10.7", "sha1 0.10.6",
] ]
[[package]] [[package]]
@@ -2443,9 +2475,9 @@ dependencies = [
[[package]] [[package]]
name = "http-body-util" name = "http-body-util"
version = "0.1.4" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
@@ -2874,11 +2906,11 @@ dependencies = [
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.35" version = "0.1.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
dependencies = [ dependencies = [
"getrandom 0.4.3", "getrandom 0.3.4",
"libc", "libc",
] ]
@@ -3028,9 +3060,9 @@ dependencies = [
[[package]] [[package]]
name = "link-section" name = "link-section"
version = "0.19.0" version = "0.18.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e333fe507b738576d6da5bb3f1a7d7a1c80307ed9ef31624c057d844c19c93e9" checksum = "24670b639492630905459a6c7d47f063d33c2d4fcd5362f6e5827c5613976c9f"
[[package]] [[package]]
name = "linked-hash-map" name = "linked-hash-map"
@@ -3167,20 +3199,19 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.3" version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]] [[package]]
name = "memory-serve" name = "memory-serve"
version = "2.3.0" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18718e8f7eefb3194d346474ac95f50ada065ff043e0074e5b8e85b85148122f" checksum = "81b5bbad2035f57b1e95f66da606832edd935b47d82312e38e1ccffbcfb8a427"
dependencies = [ dependencies = [
"axum", "axum",
"brotli", "brotli",
"flate2", "flate2",
"fs-err",
"mime_guess", "mime_guess",
"sha256", "sha256",
"tracing", "tracing",
@@ -3364,9 +3395,9 @@ dependencies = [
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.8" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" checksum = "c863e9ab5e7bf9c99ba75e1050f1e4d624ae87ed3532d6238ffbdc7b585dbbe6"
dependencies = [ dependencies = [
"num-integer", "num-integer",
"num-traits", "num-traits",
@@ -3383,7 +3414,7 @@ dependencies = [
"num-integer", "num-integer",
"num-iter", "num-iter",
"num-traits", "num-traits",
"rand 0.8.7", "rand 0.8.6",
"smallvec", "smallvec",
"zeroize", "zeroize",
] ]
@@ -3414,10 +3445,11 @@ dependencies = [
[[package]] [[package]]
name = "num-iter" name = "num-iter"
version = "0.1.46" version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [ dependencies = [
"autocfg",
"num-integer", "num-integer",
"num-traits", "num-traits",
] ]
@@ -3463,7 +3495,7 @@ dependencies = [
"chrono", "chrono",
"getrandom 0.2.17", "getrandom 0.2.17",
"http", "http",
"rand 0.8.7", "rand 0.8.6",
"reqwest 0.12.28", "reqwest 0.12.28",
"serde", "serde",
"serde_json", "serde_json",
@@ -3668,7 +3700,7 @@ dependencies = [
"oauth2", "oauth2",
"p256", "p256",
"p384", "p384",
"rand 0.8.7", "rand 0.8.6",
"rsa", "rsa",
"serde", "serde",
"serde-value", "serde-value",
@@ -3759,7 +3791,7 @@ dependencies = [
"opentelemetry", "opentelemetry",
"percent-encoding", "percent-encoding",
"portable-atomic", "portable-atomic",
"rand 0.9.5", "rand 0.9.4",
"thiserror 2.0.18", "thiserror 2.0.18",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
@@ -3936,7 +3968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [ dependencies = [
"phf_shared", "phf_shared",
"rand 0.8.7", "rand 0.8.6",
] ]
[[package]] [[package]]
@@ -4080,22 +4112,22 @@ dependencies = [
] ]
[[package]] [[package]]
name = "proc-macro-error-attr3" name = "proc-macro-error-attr2"
version = "3.0.2" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34e4dd828515431dd6c4a030d26f7eaed7dd4778226e9d2bb968d65ca4ec3d4d" checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
] ]
[[package]] [[package]]
name = "proc-macro-error3" name = "proc-macro-error2"
version = "3.0.2" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee475e440453418ff1335189eddf7101ba502cd818ab7ae04209bc83aa925aa" checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
dependencies = [ dependencies = [
"proc-macro-error-attr3", "proc-macro-error-attr2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@@ -4175,9 +4207,9 @@ checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
[[package]] [[package]]
name = "pxfm" name = "pxfm"
version = "0.1.30" version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
[[package]] [[package]]
name = "quick-error" name = "quick-error"
@@ -4208,16 +4240,15 @@ dependencies = [
[[package]] [[package]]
name = "quinn-proto" name = "quinn-proto"
version = "0.11.16" version = "0.11.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e"
dependencies = [ dependencies = [
"aws-lc-rs", "aws-lc-rs",
"bytes", "bytes",
"getrandom 0.4.3", "getrandom 0.3.4",
"lru-slab", "lru-slab",
"rand 0.10.2", "rand 0.9.4",
"rand_pcg",
"ring", "ring",
"rustc-hash", "rustc-hash",
"rustls", "rustls",
@@ -4231,16 +4262,16 @@ dependencies = [
[[package]] [[package]]
name = "quinn-udp" name = "quinn-udp"
version = "0.5.15" version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
dependencies = [ dependencies = [
"cfg_aliases", "cfg_aliases",
"libc", "libc",
"once_cell", "once_cell",
"socket2", "socket2",
"tracing", "tracing",
"windows-sys 0.61.2", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@@ -4272,9 +4303,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.8.7" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
dependencies = [ dependencies = [
"libc", "libc",
"rand_chacha 0.3.1", "rand_chacha 0.3.1",
@@ -4283,9 +4314,9 @@ dependencies = [
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.9.5" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
dependencies = [ dependencies = [
"rand_chacha 0.9.0", "rand_chacha 0.9.0",
"rand_core 0.9.5", "rand_core 0.9.5",
@@ -4346,15 +4377,6 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rand_pcg"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a"
dependencies = [
"rand_core 0.10.1",
]
[[package]] [[package]]
name = "recaptcha-verify" name = "recaptcha-verify"
version = "0.2.0" version = "0.2.0"
@@ -4397,9 +4419,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.13.0" version = "1.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -4409,9 +4431,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.4.15" version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -4517,9 +4539,9 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
[[package]] [[package]]
name = "resolvematrix" name = "resolvematrix"
version = "1.2.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a68b9735d8c1096d8152d4dfb5a705c0135dd14d181542fd87301f8d3cb4ed03" checksum = "a574e37f06e219dcfdb14a4f0abf56e806c4551e030aae53802d2c42b29aea33"
dependencies = [ dependencies = [
"futures", "futures",
"hickory-resolver", "hickory-resolver",
@@ -4777,7 +4799,7 @@ dependencies = [
[[package]] [[package]]
name = "ruminuwuity" name = "ruminuwuity"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"assign", "assign",
"ruma", "ruma",
@@ -4815,9 +4837,9 @@ dependencies = [
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.28" version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
@@ -4849,9 +4871,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.42" version = "0.23.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f"
dependencies = [ dependencies = [
"aws-lc-rs", "aws-lc-rs",
"log", "log",
@@ -4926,9 +4948,9 @@ dependencies = [
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.23" version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]] [[package]]
name = "rustyline-async" name = "rustyline-async"
@@ -5114,7 +5136,7 @@ version = "0.48.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8c44ee52fa3d30581f951b57aec754ef9cd70186df5fb788367804360c48097" checksum = "b8c44ee52fa3d30581f951b57aec754ef9cd70186df5fb788367804360c48097"
dependencies = [ dependencies = [
"rand 0.9.5", "rand 0.9.4",
"sentry-types", "sentry-types",
"serde", "serde",
"serde_json", "serde_json",
@@ -5187,7 +5209,7 @@ checksum = "1be93ef0435a5ab91f88178fb7681249437e875d004f996ecb35be94dc99a0e0"
dependencies = [ dependencies = [
"debugid", "debugid",
"hex", "hex",
"rand 0.9.5", "rand 0.9.4",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 2.0.18", "thiserror 2.0.18",
@@ -5367,7 +5389,7 @@ version = "3.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660"
dependencies = [ dependencies = [
"darling", "darling 0.23.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@@ -5375,9 +5397,9 @@ dependencies = [
[[package]] [[package]]
name = "sha1" name = "sha1"
version = "0.10.7" version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures 0.2.17", "cpufeatures 0.2.17",
@@ -5700,9 +5722,9 @@ dependencies = [
[[package]] [[package]]
name = "termimad" name = "termimad"
version = "0.35.1" version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53d4b1294b87e81925b7ae7f8f4d000376e3a5b3349d978429665428a793fcb" checksum = "903906afabf58273a7a90b47e0e60701cbd01731ca72ba88508b38b5539647f4"
dependencies = [ dependencies = [
"coolor", "coolor",
"crokey", "crokey",
@@ -5766,9 +5788,9 @@ dependencies = [
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "1.1.10" version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@@ -5843,9 +5865,9 @@ dependencies = [
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.12.0" version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
dependencies = [ dependencies = [
"tinyvec_macros", "tinyvec_macros",
] ]
@@ -6208,7 +6230,7 @@ dependencies = [
"futures", "futures",
"http", "http",
"parking_lot", "parking_lot",
"rand 0.9.5", "rand 0.9.4",
"serde", "serde",
"serde_json", "serde_json",
"thiserror 2.0.18", "thiserror 2.0.18",
@@ -6422,9 +6444,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.23.5" version = "1.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea5fab0d6c3c01ae70085a09cb03d4c7a1d6314e2b3e075392783396d724ca0a" checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53"
dependencies = [ dependencies = [
"getrandom 0.4.3", "getrandom 0.4.3",
"js-sys", "js-sys",
@@ -6450,12 +6472,13 @@ dependencies = [
[[package]] [[package]]
name = "validator_derive" name = "validator_derive"
version = "0.20.1" version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240e4b81c20a1d6d50d1d7265c658dfbd204e8b9ac4d80f3c931f39462196335" checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca"
dependencies = [ dependencies = [
"darling", "darling 0.20.11",
"proc-macro-error3", "once_cell",
"proc-macro-error2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@@ -6756,7 +6779,16 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.5",
] ]
[[package]] [[package]]
@@ -6774,14 +6806,31 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.52.6",
"windows_i686_gnu", "windows_i686_gnu 0.52.6",
"windows_i686_gnullvm", "windows_i686_gnullvm 0.52.6",
"windows_i686_msvc", "windows_i686_msvc 0.52.6",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
] ]
[[package]] [[package]]
@@ -6790,48 +6839,96 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]] [[package]]
name = "windows_i686_gnullvm" name = "windows_i686_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.7.15" version = "0.7.15"
@@ -6875,7 +6972,7 @@ dependencies = [
[[package]] [[package]]
name = "xtask" name = "xtask"
version = "26.6.2" version = "26.6.0"
dependencies = [ dependencies = [
"askama", "askama",
"cargo_metadata", "cargo_metadata",
@@ -6915,18 +7012,18 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.8.54" version = "0.8.52"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.8.54" version = "0.8.52"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -6995,9 +7092,9 @@ dependencies = [
[[package]] [[package]]
name = "zmij" name = "zmij"
version = "1.0.22" version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd2f034a4bebf216c9e4b7083603e024cf930873fd67830cfb083c9fa33129d9" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
[[package]] [[package]]
name = "zstd" name = "zstd"
+8 -2
View File
@@ -12,7 +12,7 @@ license = "Apache-2.0"
# See also `rust-toolchain.toml` # See also `rust-toolchain.toml`
readme = "README.md" readme = "README.md"
repository = "https://forgejo.ellis.link/continuwuation/continuwuity" repository = "https://forgejo.ellis.link/continuwuation/continuwuity"
version = "26.6.2" version = "26.6.0"
[workspace.metadata.crane] [workspace.metadata.crane]
name = "conduwuit" name = "conduwuit"
@@ -141,6 +141,12 @@ features = [
version = "0.23.25" version = "0.23.25"
default-features = false default-features = false
[workspace.dependencies.aws-lc-sys]
version = "0.41.0"
[workspace.dependencies.aws-lc-rs]
version = "1.17.0"
[workspace.dependencies.reqwest] [workspace.dependencies.reqwest]
version = "0.13.2" version = "0.13.2"
default-features = false default-features = false
@@ -564,7 +570,7 @@ features = ["std"]
version = "0.3.0" version = "0.3.0"
[workspace.dependencies.resolvematrix] [workspace.dependencies.resolvematrix]
version = "1.2.0" version = "1.1.0"
[workspace.dependencies.serde_urlencoded] [workspace.dependencies.serde_urlencoded]
version = "0.7.1" version = "0.7.1"
+1
View File
@@ -0,0 +1 @@
Stopped appservice users from being erroneously marked as deactivated during a 26.6 database migration.
-1
View File
@@ -1 +0,0 @@
Appservices may now specify both the unstable and stable `device_id` query parameters in a request. The stable parameter will take priority. Contributed by @ginger.
+1
View File
@@ -0,0 +1 @@
Fixed existing accounts failing to link when logging in with OIDC if `prompt_for_localpart` was `false`.
+1
View File
@@ -0,0 +1 @@
Authentication is no longer required on the `/_matrix/client/v3/account/3pid/email/requestToken` endpoint.
-1
View File
@@ -1 +0,0 @@
Fixed the deeplink redirect for deleting devices. Contributed by @koen
-1
View File
@@ -1 +0,0 @@
Fix status code for oauth registration. Contributed by @n00byking
-1
View File
@@ -1 +0,0 @@
Exempt m.room.create from auth_events check. Contributed by @eleboucher
@@ -6,10 +6,10 @@
"message": "Welcome to Continuwuity! Important announcements about the project will appear here." "message": "Welcome to Continuwuity! Important announcements about the project will appear here."
}, },
{ {
"id": 16, "id": 15,
"mention_room": true, "mention_room": true,
"date": "2026-07-13", "date": "2026-07-10",
"message": "[Continuwuity 26.6.2](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v26.6.1) has just been released! This release fixes a severe bug with OIDC that could cause users' accounts to be flagged as deactivated. If you use OIDC, please update as soon as possible." "message": "[Continuwuity 26.6.0](https://forgejo.ellis.link/continuwuation/continuwuity/releases/tag/v26.6.0) is finally out! This is by far our largest release yet, and it wouldn't have been possible without our community. Thank you so much for all of your patience, support, and/or development time over the last three months <3"
} }
] ]
} }
Generated
+21 -21
View File
@@ -3,11 +3,11 @@
"advisory-db": { "advisory-db": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1783840254, "lastModified": 1781566179,
"narHash": "sha256-XjyvZk0f3YiinVHmkGOotmLBAzvK+LwEJYj2QqJ5pn8=", "narHash": "sha256-Tqv8I586fYzWpEW/Smq/JqESFa3DVVzVWsnAMtvhy/I=",
"owner": "rustsec", "owner": "rustsec",
"repo": "advisory-db", "repo": "advisory-db",
"rev": "6e3286f4efa8c142fb33e5ea4342c8db6693cf34", "rev": "74e084413d979d52d2f93b1d93b1ab7b9ee648f5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -18,11 +18,11 @@
}, },
"crane": { "crane": {
"locked": { "locked": {
"lastModified": 1783203018, "lastModified": 1780532242,
"narHash": "sha256-G6R9IT/xwFuu+CYBWDUAok6AdC4ERC4ZfPPFtEpxnZE=", "narHash": "sha256-D+BsdpxmtUwtqGoY0IXPhHgTlmqgcZKCEo1oMyn7ep0=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "80db5bdc391be8a1794f6d8a2d56e3a84ebcede2", "rev": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -39,11 +39,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1783844668, "lastModified": 1781527054,
"narHash": "sha256-3MOpw4y3reoErRLvFBDz0t9aG6FWXUj7leKvUns5eQA=", "narHash": "sha256-1fX9ev2Fh5QoKQ41G9dYutjo5j/jywu6tZse5Eb1Ck4=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "4e49ef62eedaa5c149d62b63b3f53844e1cc45d7", "rev": "8c2e51dffefc040a21975da7abf6f252c8c9b783",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -74,11 +74,11 @@
"nixpkgs-lib": "nixpkgs-lib" "nixpkgs-lib": "nixpkgs-lib"
}, },
"locked": { "locked": {
"lastModified": 1782949081, "lastModified": 1778716662,
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=", "narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e", "rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -89,11 +89,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1783776592, "lastModified": 1781074563,
"narHash": "sha256-UgCQzxeWI75XM8G+hPrPh+MKzEPjG3SpAj7dtqSbksA=", "narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e7a3ca8092b61ff85b6a45bf863ea2b2d6a661b3", "rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -105,11 +105,11 @@
}, },
"nixpkgs-lib": { "nixpkgs-lib": {
"locked": { "locked": {
"lastModified": 1782614948, "lastModified": 1777168982,
"narHash": "sha256-ePjCwr1sNm9NYUqywL7QfK3JnlS015msC+eBu2zKlp8=", "narHash": "sha256-GOkGPcboWE9BmGCRMLX3worL4EMnsnG8MyKmXNeYuhQ=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixpkgs.lib", "repo": "nixpkgs.lib",
"rev": "db3f255737b94216eb71cce308e2912cf6bc2d7c", "rev": "f5901329dade4a6ea039af1433fb087bd9c1fe14",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -132,11 +132,11 @@
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1783779020, "lastModified": 1781453968,
"narHash": "sha256-vpm418WZa9l1KUl6HRs+Ga+SIfE+D2/sV4olwTlilYc=", "narHash": "sha256-+V3nK4pCngbmgyVGXY6Kkrlevp4ocPkJJLf2aqwkDNA=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "5be5e89cf0145d73a85c805726821b4adfc3af48", "rev": "cc272809a173c2c11d0e479d639c811c1eacf049",
"type": "github" "type": "github"
}, },
"original": { "original": {
+2 -2
View File
@@ -43,8 +43,8 @@ let
env = { env = {
CARGO_PROFILE = profile; CARGO_PROFILE = profile;
RUSTFLAGS = rustflags; RUSTFLAGS = rustflags;
GIT_COMMIT_HASH = self.rev or self.dirtyRev or ""; GIT_COMMIT_HASH = self.rev or self.dirtyRev;
GIT_COMMIT_HASH_SHORT = self.shortRev or self.dirtyShortRev or ""; GIT_COMMIT_HASH_SHORT = self.shortRev or self.dirtyShortRev;
} }
// (lib.optionalAttrs (rocksdb != null) { // (lib.optionalAttrs (rocksdb != null) {
ROCKSDB_INCLUDE_DIR = "${rocksdb}/include"; ROCKSDB_INCLUDE_DIR = "${rocksdb}/include";
+48 -48
View File
@@ -510,14 +510,14 @@
} }
}, },
"node_modules/@shikijs/core": { "node_modules/@shikijs/core": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.2.0.tgz",
"integrity": "sha512-ANMDxuaPsNMdDC1m4vfvhlDmJweMwkE5XitTwrq2rWHx5jM+dlm4MmHt2PP6t0uejfR77SuhrhJ0zEijIF/uhA==", "integrity": "sha512-Hc87Ab1Ld/vEbZRCbwx344I5v+4RU8CVToUTRkqXL1+TjbuOp9U5Xa0M23V4GEWHxVn+yO5otb+HkQVm3ptWQQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/primitive": "4.3.1", "@shikijs/primitive": "4.2.0",
"@shikijs/types": "4.3.1", "@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2", "@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"hast-util-to-html": "^9.0.5" "hast-util-to-html": "^9.0.5"
@@ -527,13 +527,13 @@
} }
}, },
"node_modules/@shikijs/engine-javascript": { "node_modules/@shikijs/engine-javascript": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.2.0.tgz",
"integrity": "sha512-JBItcnPuYq7jVJdZo/vMj94r+szT7XEjHFX+mvFDGSEIbVAXAGyHAHzhbWzpGOwYidCZrErJLLgn2PVeiokHnQ==", "integrity": "sha512-fjETeq1k5ffyXqRgS6+3hpvqseLalp1kjNfRbXpUgWR8FpZ1CmQfiNHovc5lncYjt/Vg5JK/WJEmLahjwMa0og==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "4.3.1", "@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2", "@shikijs/vscode-textmate": "^10.0.2",
"oniguruma-to-es": "^4.3.6" "oniguruma-to-es": "^4.3.6"
}, },
@@ -542,13 +542,13 @@
} }
}, },
"node_modules/@shikijs/engine-oniguruma": { "node_modules/@shikijs/engine-oniguruma": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.2.0.tgz",
"integrity": "sha512-OXyNMzg0pews+msMj4cHeqT4xiYKKvbnn6VbdAXxfoFl3SSx4fJTc8FadECuc5/H9p3BzhNAoAUXKwAu9rWYhg==", "integrity": "sha512-hTorK1dffPkpbMUk6Z+828PgRo7d07HbnizoP0hNPFjhxMHctj0Px/qoHeGMYafc6ju+u9iMldN4JbVzNQM++g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "4.3.1", "@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2" "@shikijs/vscode-textmate": "^10.0.2"
}, },
"engines": { "engines": {
@@ -556,26 +556,26 @@
} }
}, },
"node_modules/@shikijs/langs": { "node_modules/@shikijs/langs": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.2.0.tgz",
"integrity": "sha512-m0l9nsDqgBHvbZbk7A0/kXz/impK3uB/c6rAn6Gpg/uPtdZRQ+alsN/17MU5thb68XTj/4DxkZAotrM0GGSpDQ==", "integrity": "sha512-bwrVRlJ0wUhZxAbVdvBbv2TTC9yLsh4C/IO5Ofz0T8MQntgDvyVnkbjw9vi50r1kx7RCIJdnJnjZAwmAsXFLZQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "4.3.1" "@shikijs/types": "4.2.0"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"
} }
}, },
"node_modules/@shikijs/primitive": { "node_modules/@shikijs/primitive": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.2.0.tgz",
"integrity": "sha512-CXQRQOYy1leqQ8ceTeJdmXv/bsUY++6QyLpXJ94LZAAYj5X2SKRdc5ipguv4NPyGVKItB2PPwUpRNe0Sjh5S1A==", "integrity": "sha512-NOq+DtUkVBJtZMVXL5A0vI0Xk8nvDYaXetFHSJFlOqjDZIVhIPRYFdGkSoElDqNuegikcc3A76SNUa8dTqtAYA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "4.3.1", "@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2", "@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4" "@types/hast": "^3.0.4"
}, },
@@ -584,16 +584,16 @@
} }
}, },
"node_modules/@shikijs/rehype": { "node_modules/@shikijs/rehype": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/rehype/-/rehype-4.2.0.tgz",
"integrity": "sha512-oshrlfUF3VPUJfnp5K1lLwsS/SRBKrIxONpdWebSKZXdBE3UsZnxgqpvRUA8UsofS7vmjFOCAHIT71ECbmOxTw==", "integrity": "sha512-ST3EWye/dwF1gWskczJNBnwFtDzEQ9ceytXZtyc/GfwR5V0qJrkoSGZO55O3SAKDDsXkTDcsfwd9pVe7ROlAHg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "4.3.1", "@shikijs/types": "4.2.0",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"hast-util-to-string": "^3.0.1", "hast-util-to-string": "^3.0.1",
"shiki": "4.3.1", "shiki": "4.2.0",
"unified": "^11.0.5", "unified": "^11.0.5",
"unist-util-visit": "^5.1.0" "unist-util-visit": "^5.1.0"
}, },
@@ -602,22 +602,22 @@
} }
}, },
"node_modules/@shikijs/themes": { "node_modules/@shikijs/themes": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.2.0.tgz",
"integrity": "sha512-dgpoJ4WqNi2yTmizQHBJ5zcX6j2lE6icN/0yt4l1kkf16jrY/pwPLoTb1ETsWMz0OBLf9ZNvwmxft+cH+N9qSA==", "integrity": "sha512-RX8IHYeLv8Cu2W6ruc3RxUqWn0IYCqSrMBzi/uRGAmfyDNOnNO5BF/Px7o97n4XTpmFTo5GbRaazuOWj+2ak2w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "4.3.1" "@shikijs/types": "4.2.0"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"
} }
}, },
"node_modules/@shikijs/types": { "node_modules/@shikijs/types": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.2.0.tgz",
"integrity": "sha512-CHFxE0jztBIZRHH6gxXE7DXUCFXjReEGxZ/j0rfSLGKZuwp2xBYycEP14875DSa9KLL/6700oxIq6oO6ef9K2g==", "integrity": "sha512-VT/MKtlpOhEPZloSH3Pb9WCZEBDoQVMa9jedp5UAwmJOar1DVc9DRODAxmYPW9M93IK4ryuqRejFfmlvlVDemw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -684,9 +684,9 @@
} }
}, },
"node_modules/@types/hast": { "node_modules/@types/hast": {
"version": "3.0.5", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
"integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -1076,9 +1076,9 @@
} }
}, },
"node_modules/@ungap/structured-clone": { "node_modules/@ungap/structured-clone": {
"version": "1.3.3", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz",
"integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
@@ -3589,18 +3589,18 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/shiki": { "node_modules/shiki": {
"version": "4.3.1", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-4.3.1.tgz", "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.2.0.tgz",
"integrity": "sha512-oR+qDVi2OjX1tmDpyv+3KviX01KzO6Af+0NNnKnsp9491UEGz2YpxTuJboS/6VhYpTdqzmuJBuiTlrAWWJAssw==", "integrity": "sha512-hjNax6o/ylDy9lefQEaSDtzaT3iVNtZ3WmpQnbuQNoG4xvnSKf2kSKbihZVO4JRG1TTMejs7CmNRYlWgAL66pQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/core": "4.3.1", "@shikijs/core": "4.2.0",
"@shikijs/engine-javascript": "4.3.1", "@shikijs/engine-javascript": "4.2.0",
"@shikijs/engine-oniguruma": "4.3.1", "@shikijs/engine-oniguruma": "4.2.0",
"@shikijs/langs": "4.3.1", "@shikijs/langs": "4.2.0",
"@shikijs/themes": "4.3.1", "@shikijs/themes": "4.2.0",
"@shikijs/types": "4.3.1", "@shikijs/types": "4.2.0",
"@shikijs/vscode-textmate": "^10.0.2", "@shikijs/vscode-textmate": "^10.0.2",
"@types/hast": "^3.0.4" "@types/hast": "^3.0.4"
}, },
+3 -3
View File
@@ -486,7 +486,7 @@ pub(super) async fn get_remote_pdu(
.services .services
.rooms .rooms
.event_handler .event_handler
.parse_incoming_pdu(&response.pdu, None) .parse_incoming_pdu(&response.pdu)
.boxed() .boxed()
.await; .await;
@@ -832,7 +832,7 @@ pub(super) async fn force_set_room_state_from_server(
.services .services
.rooms .rooms
.event_handler .event_handler
.parse_incoming_pdu(&pdu, Some(&room_version_rules)) .parse_incoming_pdu(&pdu)
.await .await
{ {
| Ok(t) => t, | Ok(t) => t,
@@ -1014,7 +1014,7 @@ pub(super) async fn resolve_true_destination(
let resolver: &MatrixResolver = if no_cache { let resolver: &MatrixResolver = if no_cache {
&MatrixResolverBuilder::new() &MatrixResolverBuilder::new()
.dangerous_tls_accept_invalid_certs(self.services.server.config.allow_invalid_tls_certificates_yes_i_know_what_the_fuck_i_am_doing_with_this_and_i_know_this_is_insecure) .dangerous_tls_accept_invalid_certs(self.services.server.config.allow_invalid_tls_certificates_yes_i_know_what_the_fuck_i_am_doing_with_this_and_i_know_this_is_insecure)
.http_client(self.services.client.dns.clone()) .http_client(self.services.client.default.clone())
.build()? .build()?
} else { } else {
&self.services.client.matrix_resolver &self.services.client.matrix_resolver
+1 -1
View File
@@ -54,7 +54,7 @@ pub(super) async fn fetch_support_well_known(&self, server_name: OwnedServerName
let response = self let response = self
.services .services
.client .client
.external_resource .default
.get(format!("https://{server_name}/.well-known/matrix/support")) .get(format!("https://{server_name}/.well-known/matrix/support"))
.send() .send()
.await?; .await?;
+2 -3
View File
@@ -3,7 +3,7 @@
use conduwuit::{ use conduwuit::{
Err, Result, debug_error, err, info, Err, Result, debug_error, err, info,
matrix::{event::gen_event_id_canonical_json, pdu::PartialPdu}, matrix::{event::gen_event_id_canonical_json, pdu::PartialPdu},
trace, warn, warn,
}; };
use futures::FutureExt; use futures::FutureExt;
use ruma::{ use ruma::{
@@ -166,7 +166,7 @@ pub(crate) async fn invite_helper(
let invite_room_state = services let invite_room_state = services
.rooms .rooms
.state .state
.summary_stripped(&pdu, room_id, recipient_user, true) .summary_stripped(&pdu, room_id, recipient_user)
.await; .await;
drop(state_lock); drop(state_lock);
@@ -193,7 +193,6 @@ pub(crate) async fn invite_helper(
.await .await
.ok(); .ok();
trace!(?request, "Sending invite");
let response = services let response = services
.sending .sending
.send_federation_request(recipient_user.server_name(), request) .send_federation_request(recipient_user.server_name(), request)
+1 -1
View File
@@ -24,5 +24,5 @@ pub(crate) async fn register_client_route(
.await .await
.map_err(|err| (StatusCode::BAD_REQUEST, Json(err)).into_response())?; .map_err(|err| (StatusCode::BAD_REQUEST, Json(err)).into_response())?;
Ok((StatusCode::CREATED, Json(RegisteredClient { client_id, metadata })).into_response()) Ok(Json(RegisteredClient { client_id, metadata }).into_response())
} }
+3 -2
View File
@@ -15,9 +15,10 @@
#[derive(Deserialize)] #[derive(Deserialize)]
pub(crate) struct AuthQueryParams { pub(crate) struct AuthQueryParams {
pub(super) user_id: Option<String>, pub(super) user_id: Option<String>,
/// Device ID for appservice device masquerading (MSC3202/MSC4190).
/// Can be provided as `device_id` or `org.matrix.msc3202.device_id`.
#[serde(alias = "org.matrix.msc3202.device_id")]
pub(super) device_id: Option<String>, pub(super) device_id: Option<String>,
#[serde(rename = "org.matrix.msc3202.device_id")]
pub(super) legacy_device_id: Option<String>,
} }
/// Extractor for Ruma request structs /// Extractor for Ruma request structs
+18 -22
View File
@@ -219,29 +219,25 @@ async fn verify<B: AsRef<[u8]> + Sync>(
// MSC3202/MSC4190: Handle device_id masquerading for appservices. // MSC3202/MSC4190: Handle device_id masquerading for appservices.
// The device_id can be provided via `device_id` or // The device_id can be provided via `device_id` or
// `org.matrix.msc3202.device_id` query parameter. // `org.matrix.msc3202.device_id` query parameter.
let sender_device = if let Some(device_id) = query let sender_device =
.device_id if let Some(device_id) = query.device_id.as_deref().map(Into::into) {
.or(query.legacy_device_id) // Verify the device exists for this user
.as_deref() if services
.map(Into::into) .users
{ .get_device_metadata(&sender_user, device_id)
// Verify the device exists for this user .await
if services .is_err()
.users {
.get_device_metadata(&sender_user, device_id) return Err!(Request(Forbidden(
.await "Device does not exist for user or appservice cannot masquerade as \
.is_err() this device."
{ )));
return Err!(Request(Forbidden( }
"Device does not exist for user or appservice cannot masquerade as this \
device."
)));
}
Some(device_id.to_owned()) Some(device_id.to_owned())
} else { } else {
None None
}; };
Ok(ClientIdentity::Appservice { Ok(ClientIdentity::Appservice {
sender_user, sender_user,
+116 -300
View File
@@ -1,29 +1,23 @@
use std::collections::{HashMap, hash_map::Entry};
use axum::extract::State; use axum::extract::State;
use axum_client_ip::ClientIp; use axum_client_ip::ClientIp;
use base64::{Engine as _, engine::general_purpose}; use base64::{Engine as _, engine::general_purpose};
use conduwuit::{ use conduwuit::{
Err, Error, EventTypeExt, PduEvent, Result, debug, err, error, Err, Error, PduEvent, Result, err, error,
matrix::{Event, StateKey}, matrix::{Event, event::gen_event_id},
result::FlatOk, utils::{self, hash::sha256},
state_res, trace,
utils::hash::sha256,
warn, warn,
}; };
use ruma::{ use ruma::{
CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedUserId, ServerName, CanonicalJsonValue, UserId,
UserId,
api::{ api::{
error::{ErrorKind, IncompatibleRoomVersionErrorData}, error::{ErrorKind, IncompatibleRoomVersionErrorData},
federation::membership::{RawStrippedState, create_invite}, federation::membership::{RawStrippedState, create_invite},
}, },
events::{StateEventType, room::member::MembershipState}, events::room::member::{MembershipState, RoomMemberEventContent},
room_version_rules::RoomVersionRules, serde::JsonObject,
}; };
use serde::Deserialize;
use crate::{Ruma, server::utils::validate_any_membership_event}; use crate::Ruma;
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}` /// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
/// ///
@@ -34,16 +28,30 @@ pub(crate) async fn create_invite_route(
ClientIp(client): ClientIp, ClientIp(client): ClientIp,
body: Ruma<create_invite::v2::Request>, body: Ruma<create_invite::v2::Request>,
) -> Result<create_invite::v2::Response> { ) -> Result<create_invite::v2::Response> {
// ACL check origin
services
.rooms
.event_handler
.acl_check(&body.identity, &body.room_id)
.await?;
if !services.server.supported_room_version(&body.room_version) { if !services.server.supported_room_version(&body.room_version) {
return Err(Error::BadRequest( return Err(Error::BadRequest(
ErrorKind::IncompatibleRoomVersion(IncompatibleRoomVersionErrorData::new( ErrorKind::IncompatibleRoomVersion(IncompatibleRoomVersionErrorData::new(
body.room_version.clone(), body.room_version.clone(),
)), )),
"This server does not support that room version", "Server does not support this room version.",
)); ));
} }
let room_version_rules = body.room_version.rules().unwrap(); let room_version_rules = body.room_version.rules().unwrap();
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
}
if services if services
.moderation .moderation
.is_remote_server_forbidden(&body.identity) .is_remote_server_forbidden(&body.identity)
@@ -53,61 +61,90 @@ pub(crate) async fn create_invite_route(
body.identity, body.room_id body.identity, body.room_id
); );
return Err!(Request(Forbidden("Federation denied with {}", body.identity)));
}
// First, validate the invite room state, so we can compare with the create
// event.
debug!(
event_id=%body.event_id,
room_id=%body.room_id,
room_version=?body.room_version,
via=?body.via,
"Validating invite room state for invite request"
);
let (create_event_id, state) = validate_invite_state(
&services,
&body.invite_room_state,
&room_version_rules,
body.room_id.clone(),
)
.await?;
let create_event_json = state
.get(&StateEventType::RoomCreate.with_state_key(""))
.expect("must have create event in invite state by this point");
// We can now perform the banned remote server check with the create event.
// N.B. this checks the sender field, which is technically incorrect for rooms
// v10 and below. This usually isn't the case though so sue me
let creator = create_event_json
.get("sender")
.and_then(|v| v.as_str())
.map(UserId::parse)
.flat_ok()
.expect("must have valid sender in create event");
if services
.moderation
.is_remote_server_forbidden(creator.server_name())
{
return Err!(Request(Forbidden("Server is banned on this homeserver."))); return Err!(Request(Forbidden("Server is banned on this homeserver.")));
} }
// And then we can validate the member event itself let mut signed_event = utils::to_canonical_object(&body.event)
let (mut signed_event, sender_user, recipient_user) = validate_invite_membership_event( .map_err(|_| err!(Request(InvalidParam("Invite event is invalid."))))?;
&services,
&body.event, // Ensure this is a membership event
&room_version_rules, if signed_event
&body.identity, .get("type")
create_event_id.clone(), .expect("event must have a type")
body.room_id.clone(), .as_str()
body.event_id.clone(), .expect("type must be a string")
!= "m.room.member"
{
return Err!(Request(BadJson(
"Not allowed to send non-membership event to invite endpoint."
)));
}
let content: RoomMemberEventContent = serde_json::from_value(
signed_event
.get("content")
.ok_or_else(|| err!(Request(BadJson("Event missing content property"))))?
.clone()
.into(),
) )
.await?; .map_err(|e| err!(Request(BadJson(warn!("Event content is empty or invalid: {e}")))))?;
// 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_user = signed_event
.get("sender")
.and_then(|v| v.as_str())
.map(UserId::parse)
.and_then(Result::ok)
.ok_or_else(|| err!(Request(InvalidParam("Invalid sender property"))))?;
if sender_user.server_name() != body.identity {
return Err!(Request(Forbidden("Sender's server does not match the origin server.",)));
}
// Ensure the target user belongs to this server
let recipient_user = signed_event
.get("state_key")
.and_then(|v| v.as_str())
.map(UserId::parse)
.and_then(Result::ok)
.ok_or_else(|| err!(Request(InvalidParam("Invalid state_key property"))))?;
if !services
.globals
.server_is_ours(recipient_user.server_name())
{
return Err!(Request(InvalidParam("User does not belong to this homeserver.")));
}
// Make sure we're not ACL'ed from their room.
services
.rooms
.event_handler
.acl_check(recipient_user.server_name(), &body.room_id)
.await?;
services
.server_keys
.hash_and_sign_event(&mut signed_event, &room_version_rules)
.map_err(|e| err!(Request(InvalidParam("Failed to sign event: {e}"))))?;
// Generate event id
let event_id = gen_event_id(&signed_event, &room_version_rules)?;
// Add event_id back
signed_event.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.to_string()));
if services.rooms.metadata.is_banned(&body.room_id).await if services.rooms.metadata.is_banned(&body.room_id).await
&& !services.users.is_admin(&recipient_user).await && !services.users.is_admin(&recipient_user).await
{ {
return Err!(Request(Forbidden("That room is banned on this homeserver."))); 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 if services.config.block_non_admin_invites && !services.users.is_admin(&recipient_user).await
@@ -124,57 +161,30 @@ pub(crate) async fn create_invite_route(
return Err!(Request(Forbidden("Invite rejected by antispam service."))); return Err!(Request(Forbidden("Invite rejected by antispam service.")));
} }
// If we're already in the room, ensure that neither the origin nor ourselves
// are ACL'd.
let resident = services
.rooms
.state_cache
.server_in_room(services.globals.server_name(), &body.room_id)
.await;
if resident {
services
.rooms
.event_handler
.acl_check(&body.identity, &body.room_id)
.await?;
services
.rooms
.event_handler
.acl_check(recipient_user.server_name(), &body.room_id)
.await
.map_err(|_| err!(Request(Forbidden("This server is ACL'd from that room"))))?;
}
services
.server_keys
.hash_and_sign_event(&mut signed_event, &room_version_rules)
.map_err(|e| err!(Request(InvalidParam("Failed to sign event: {e}"))))?;
// Add event_id back
signed_event
.insert("event_id".to_owned(), CanonicalJsonValue::String(body.event_id.to_string()));
let mut invite_state = body.invite_room_state.clone(); let mut invite_state = body.invite_room_state.clone();
let pdu = PduEvent::from_id_val(&body.event_id, signed_event.clone())
.expect("must be able to create PDU object"); let mut event: JsonObject = serde_json::from_str(body.event.get())
invite_state.push(RawStrippedState::Pdu(serde_json::value::to_raw_value(&signed_event)?)); .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(RawStrippedState::Pdu(
serde_json::value::to_raw_value(&pdu).expect("PDU was just created, it must be valid"),
));
// If we are active in the room, the remote server will notify us about the // 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 // 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 // record the invited state for client /sync through update_membership(), and
// send the invite PDU to the relevant appservices. // send the invite PDU to the relevant appservices.
if !resident { if !services
// We will start by recording the room's create event as an outlier. .rooms
// This will allow us to recognise it later in case the sender revokes the .state_cache
// invite over federation later. We could store more state from the invite .server_in_room(services.globals.server_name(), &body.room_id)
// request, but we will get that during send_join anyway. .await
// This is safe to just add directly as an outlier as we already auth checked it {
// during validation.
services
.rooms
.outlier
.add_pdu_outlier(&create_event_id, create_event_json);
services services
.rooms .rooms
.state_cache .state_cache
@@ -230,197 +240,3 @@ pub(crate) async fn create_invite_route(
.await, .await,
)) ))
} }
/// Validates the *membership event* in the invite request, per the steps listed
/// under the invite endpoint's [spec].
///
/// Returns the validated JSON body, sender user ID, and recipient user ID.
///
/// Since this function performs a PDU format check, the create event must be
/// known ahead of time. This implies validating the invite state before the
/// invite event itself.
///
/// [spec]: https://spec.matrix.org/v1.19/server-server-api/#put_matrixfederationv2inviteroomideventid
async fn validate_invite_membership_event(
services: &crate::State,
body: &serde_json::value::RawValue,
room_version_rules: &RoomVersionRules,
origin: &ServerName,
create_event_id: OwnedEventId,
room_id: OwnedRoomId,
event_id: OwnedEventId,
) -> Result<(CanonicalJsonObject, OwnedUserId, OwnedUserId)> {
trace!(?body, "Invite membership event");
let (pdu, target_membership, sender_user, recipient_user) = validate_any_membership_event(
services,
body,
room_version_rules,
create_event_id,
room_id,
event_id,
)
.await?;
// Ensure the sender belongs to the remote that is sending the invite
if sender_user.server_name() != origin {
return Err!(Request(Forbidden("Sender belongs to a different server")));
}
// Ensure the target user belongs to this server
if !services
.globals
.server_is_ours(recipient_user.server_name())
{
return Err!(Request(InvalidParam("Recipient does not belong to this homeserver")));
}
if target_membership != MembershipState::Invite {
return Err!(Request(BadJson("Invalid membership (expected `invite`)")));
}
Ok((pdu, sender_user, recipient_user))
}
/// Validates the *invite state* of an invite request, per the steps listed
/// under the endpoint's [spec].
///
/// Returns the create event's event ID, and the partial state map.
///
/// [spec]: https://spec.matrix.org/v1.19/server-server-api/#put_matrixfederationv2inviteroomideventid
async fn validate_invite_state(
services: &crate::State,
invite_state: &[RawStrippedState],
room_version_rules: &RoomVersionRules,
room_id: OwnedRoomId,
) -> Result<(OwnedEventId, HashMap<(StateEventType, StateKey), CanonicalJsonObject>)> {
trace!(?invite_state, "Raw invite state");
let mut invite_state_map: HashMap<(StateEventType, StateKey), _> =
HashMap::with_capacity(invite_state.len());
let mut create_event_id: Option<OwnedEventId> = None;
for (idx, invite_state_event) in invite_state.iter().cloned().enumerate() {
trace!(%idx, ?invite_state_event, "Invite state event");
// Stripped state hasn't been sent over federation since v1.16.
let RawStrippedState::Pdu(raw_pdu) = invite_state_event else {
debug!(%idx, "Invite state event is not a PDU");
return Err!(Request(InvalidParam(
"PDU in invite state (index {idx}) violates the room event format"
)));
};
let (state_event_room_id, state_event_id, state_event_json) = services
.rooms
.event_handler
.parse_incoming_pdu(&raw_pdu, Some(room_version_rules))
.await
.map_err(|e| {
err!(Request(InvalidParam(debug_warn!("Invalid PDU in invite state: {e}"))))
})?;
if state_event_room_id != room_id {
return Err!(Request(InvalidParam(debug_warn!(
%state_event_room_id,
%room_id,
"PDU in invite state ({state_event_id}) belongs to the wrong room"
))));
}
services
.server_keys
.verify_event(&state_event_json, room_version_rules)
.await
.map_err(|e| {
err!(Request(InvalidParam("Signature verification failed on invite event: {e}")))
})?;
let Some(state_key) = state_event_json.get("state_key").and_then(|k| k.as_str()) else {
return Err!(Request(InvalidParam(debug_info!(
"PDU in invite state ({state_event_id}) is not a state event"
))));
};
let Some(event_type) = state_event_json.get("type").and_then(|k| k.as_str()) else {
return Err!(Request(InvalidParam(debug_warn!(
"PDU in invite state ({state_event_id}) is not an event?"
))));
};
let key = StateEventType::from(event_type).with_state_key(state_key);
match invite_state_map.entry(key) {
| Entry::Occupied(entry) =>
return Err!(Request(InvalidParam(
"Duplicate state events in invite state for state key: {:?}",
entry.key(),
))),
| Entry::Vacant(entry) => {
if entry.key().0 == StateEventType::RoomCreate {
// Ensure this is a legal create event.
let pdu_event =
PduEvent::from_id_val(&state_event_id, state_event_json.clone())
.expect("must be able to create pdu event from event json");
debug!("Validating discovered create event in invite room state");
validate_invite_create_event(&pdu_event, room_version_rules).await?;
create_event_id = Some(state_event_id);
}
entry.insert(state_event_json);
},
}
}
let Some(create_event_id) = create_event_id else {
return Err!(Request(InvalidParam(debug_warn!(
parsed_state=?invite_state_map,
"Invite state does not contain the m.room.create event"
))));
};
invite_state_map.iter().try_for_each(|(key, event_json)| {
service::rooms::event_handler::Service::pdu_format_check_1(
event_json,
room_version_rules,
&create_event_id,
)
.map_err(|e| {
err!(Request(InvalidParam(
"PDU in invite state for {key:?} violates the room event format: {e}"
)))
})
})?;
Ok((create_event_id, invite_state_map))
}
#[derive(Deserialize)]
struct MFederate {
#[serde(rename = "m.federate")]
mfederate: Option<bool>,
}
/// Validates that a create event is suitable for the invite, namely:
///
/// 1. It passes auth checks (aka is valid)
/// 2. The room is federated (there's no point persisting unfederated rooms)
async fn validate_invite_create_event(
pdu: &PduEvent,
room_version_rules: &RoomVersionRules,
) -> Result {
if !state_res::auth_check(
room_version_rules,
pdu,
None,
|_, _| async {
unreachable!("No state should be fetched when processing a lone create event");
},
pdu,
)
.await
.unwrap_or_default()
{
return Err!(Request(InvalidParam("m.room.create event fails auth check")));
}
let can_federate = pdu.get_content::<MFederate>()?.mfederate;
if !can_federate.unwrap_or(true) {
return Err!(Request(InvalidParam(
"Cannot receive invites to a room with m.federate=false"
)));
}
Ok(())
}
+8
View File
@@ -75,6 +75,14 @@ pub(crate) async fn create_join_event_template_route(
return Err!(Request(Forbidden("Server is banned on this homeserver."))); return Err!(Request(Forbidden("Server is banned on this homeserver.")));
} }
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
return Err!(Request(Forbidden(warn!(
"Room ID server name {server} is banned on this homeserver."
))));
}
}
let room_version = services.rooms.state.get_room_version(&body.room_id).await?; let room_version = services.rooms.state.get_room_version(&body.room_id).await?;
let room_version_rules = room_version.rules().unwrap(); let room_version_rules = room_version.rules().unwrap();
if !body.ver.contains(&room_version) { if !body.ver.contains(&room_version) {
+6
View File
@@ -58,6 +58,12 @@ pub(crate) async fn create_knock_event_template_route(
return Err!(Request(Forbidden("Server is banned on this homeserver."))); return Err!(Request(Forbidden("Server is banned on this homeserver.")));
} }
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
}
let room_version = services.rooms.state.get_room_version(&body.room_id).await?; let room_version = services.rooms.state.get_room_version(&body.room_id).await?;
let room_version_rules = room_version.rules().unwrap(); let room_version_rules = room_version.rules().unwrap();
-1
View File
@@ -27,7 +27,6 @@ pub(crate) async fn create_leave_event_template_route(
{ {
info!( info!(
origin = body.identity.as_str(), origin = body.identity.as_str(),
room_id = %body.room_id,
"Refusing to serve make_leave for room we aren't participating in" "Refusing to serve make_leave for room we aren't participating in"
); );
return Err!(Request(NotFound("This server is not participating in that room."))); return Err!(Request(NotFound("This server is not participating in that room.")));
+1 -1
View File
@@ -150,7 +150,7 @@ async fn process_inbound_transaction(
.pdus .pdus
.iter() .iter()
.stream() .stream()
.broad_then(|pdu| services.rooms.event_handler.parse_incoming_pdu(pdu, None)) .broad_then(|pdu| services.rooms.event_handler.parse_incoming_pdu(pdu))
.inspect_err(|e| warn!("Could not parse incoming PDU: {e}")) .inspect_err(|e| warn!("Could not parse incoming PDU: {e}"))
.ready_filter_map(Result::ok); .ready_filter_map(Result::ok);
+115 -67
View File
@@ -2,36 +2,34 @@
use axum::extract::State; use axum::extract::State;
use conduwuit::{ use conduwuit::{
Err, Event, Result, at, debug, err, info, trace, Err, Event, Result, at, debug, err, info,
matrix::event::gen_event_id_canonical_json,
trace,
utils::stream::{BroadbandExt, IterStream, TryBroadbandExt}, utils::stream::{BroadbandExt, IterStream, TryBroadbandExt},
warn, warn,
}; };
use conduwuit_service::Services; use conduwuit_service::Services;
use futures::{FutureExt, StreamExt, TryStreamExt}; use futures::{FutureExt, StreamExt, TryStreamExt};
use ruma::{ use ruma::{
CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, RoomId, ServerName, UserId, CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, ServerName,
api::federation::membership::create_join_event, api::federation::membership::create_join_event,
assign, assign,
events::{ events::{
TimelineEventType, StateEventType, TimelineEventType,
room::member::{MembershipState, RoomMemberEventContent}, room::member::{MembershipState, RoomMemberEventContent},
}, },
room_version_rules::RoomVersionRules,
}; };
use serde_json::value::to_raw_value; use serde_json::value::{RawValue as RawJsonValue, to_raw_value};
use crate::{Ruma, server::utils::validate_any_membership_event}; use crate::Ruma;
/// Creates a join membership event for the target, returning a computed /// helper method for /send_join v1 and v2
/// response with room state, auth chains, etc.
#[tracing::instrument(skip(services, pdu, omit_members), fields(room_id = room_id.as_str(), origin = origin.as_str()), level = "info")] #[tracing::instrument(skip(services, pdu, omit_members), fields(room_id = room_id.as_str(), origin = origin.as_str()), level = "info")]
async fn create_join_event( async fn create_join_event(
services: &Services, services: &Services,
origin: &ServerName, origin: &ServerName,
room_id: &RoomId, room_id: &RoomId,
event_id: &EventId, pdu: &RawJsonValue,
room_version_rules: &RoomVersionRules,
mut pdu: CanonicalJsonObject,
omit_members: bool, omit_members: bool,
) -> Result<create_join_event::v2::RoomState> { ) -> Result<create_join_event::v2::RoomState> {
if !services.rooms.metadata.exists(room_id).await { if !services.rooms.metadata.exists(room_id).await {
@@ -45,7 +43,6 @@ async fn create_join_event(
{ {
info!( info!(
origin = origin.as_str(), origin = origin.as_str(),
room_id = %room_id,
"Refusing to serve send_join for room we aren't participating in" "Refusing to serve send_join for room we aren't participating in"
); );
return Err!(Request(NotFound("This server is not participating in that room."))); return Err!(Request(NotFound("This server is not participating in that room.")));
@@ -67,25 +64,94 @@ async fn create_join_event(
.await .await
.map_err(|e| err!(Request(NotFound(error!("Room has no state: {e}")))))?; .map_err(|e| err!(Request(NotFound(error!("Room has no state: {e}")))))?;
let sender = pdu // We do not add the event_id field to the pdu here because of signature and
.get("sender") // hashes checks
.and_then(|v| v.as_str()) trace!("Getting room version");
.map(UserId::parse) let room_version = services.rooms.state.get_room_version(room_id).await?;
.and_then(Result::ok) let room_version_rules = room_version.rules().unwrap();
.expect("sender was already validated");
trace!("Generating event ID and converting to canonical json");
let Ok((event_id, mut value)) = gen_event_id_canonical_json(pdu, &room_version_rules) else {
// Event could not be converted to canonical json
return Err!(Request(BadJson("Could not convert event to canonical json.")));
};
let event_room_id: OwnedRoomId = serde_json::from_value(
value
.get("room_id")
.ok_or_else(|| err!(Request(BadJson("Event missing room_id property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("room_id field is not a valid room ID: {e}")))))?;
if event_room_id != room_id {
return Err!(Request(BadJson("Event room_id does not match request path room ID.")));
}
let event_type: StateEventType = serde_json::from_value(
value
.get("type")
.ok_or_else(|| err!(Request(BadJson("Event missing type property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("Event has invalid state event type: {e}")))))?;
if event_type != StateEventType::RoomMember {
return Err!(Request(BadJson(
"Not allowed to send non-membership state event to join endpoint."
)));
}
let content: RoomMemberEventContent = serde_json::from_value( let content: RoomMemberEventContent = serde_json::from_value(
pdu.get("content") value
.get("content")
.ok_or_else(|| err!(Request(BadJson("Event missing content property"))))? .ok_or_else(|| err!(Request(BadJson("Event missing content property"))))?
.clone() .clone()
.into(), .into(),
) )
.map_err(|e| err!(Request(BadJson(warn!("Event content is empty or invalid: {e}")))))?; .map_err(|e| err!(Request(BadJson(warn!("Event content is empty or invalid: {e}")))))?;
if content.membership != MembershipState::Join {
return Err!(Request(BadJson(
"Not allowed to send a non-join membership event to join endpoint."
)));
}
let sender: OwnedUserId = serde_json::from_value(
value
.get("sender")
.ok_or_else(|| err!(Request(BadJson("Event missing sender property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("sender property is not a valid user ID: {e}")))))?;
// check if origin server is trying to send for another server
if sender.server_name() != origin {
return Err!(Request(Forbidden("Not allowed to join on behalf of another server.")));
}
let state_key: OwnedUserId = serde_json::from_value(
value
.get("state_key")
.ok_or_else(|| err!(Request(BadJson("Event missing state_key property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("State key is not a valid user ID: {e}")))))?;
if state_key != sender {
return Err!(Request(BadJson("State key does not match sender user.")));
}
if let Some(authorising_user) = content.join_authorized_via_users_server { if let Some(authorising_user) = content.join_authorized_via_users_server {
if !room_version_rules.authorization.restricted_join_rule { use ruma::RoomVersionId::*;
if matches!(room_version, V1 | V2 | V3 | V4 | V5 | V6 | V7) {
return Err!(Request(InvalidParam( return Err!(Request(InvalidParam(
"Room version does not support restricted rooms but \ "Room version {room_version} does not support restricted rooms but \
join_authorised_via_users_server ({authorising_user}) was found in the event." join_authorised_via_users_server ({authorising_user}) was found in the event."
))); )));
} }
@@ -108,7 +174,8 @@ async fn create_join_event(
they cannot authorise your join." they cannot authorise your join."
))); )));
} }
if !super::user_can_perform_restricted_join(services, &sender, room_id).await? {
if !super::user_can_perform_restricted_join(services, &state_key, room_id).await? {
return Err!(Request(UnableToAuthorizeJoin( return Err!(Request(UnableToAuthorizeJoin(
"Joining user did not pass restricted room's rules." "Joining user did not pass restricted room's rules."
))); )));
@@ -116,7 +183,7 @@ async fn create_join_event(
services services
.server_keys .server_keys
.hash_and_sign_event(&mut pdu, room_version_rules) .hash_and_sign_event(&mut value, &room_version_rules)
.map_err(|e| { .map_err(|e| {
err!(Request(InvalidParam(warn!("Failed to sign send_join event: {e}")))) err!(Request(InvalidParam(warn!("Failed to sign send_join event: {e}"))))
})?; })?;
@@ -133,7 +200,7 @@ async fn create_join_event(
let pdu_id = services let pdu_id = services
.rooms .rooms
.event_handler .event_handler
.handle_incoming_pdu(sender.server_name(), room_id, event_id, pdu.clone(), false) .handle_incoming_pdu(sender.server_name(), room_id, &event_id, value.clone(), false)
.boxed() .boxed()
.await? .await?
.ok_or_else(|| err!(Request(InvalidParam("Could not accept as timeline event."))))?; .ok_or_else(|| err!(Request(InvalidParam("Could not accept as timeline event."))))?;
@@ -153,12 +220,14 @@ async fn create_join_event(
.iter() .iter()
.try_stream() .try_stream()
.broad_filter_map(|event_id| async move { .broad_filter_map(|event_id| async move {
if omit_members && let Ok(e) = event_id.as_ref() { if omit_members {
let pdu = services.rooms.timeline.get_pdu(e).await; if let Ok(e) = event_id.as_ref() {
if pdu.is_ok_and(|p| *p.kind() == TimelineEventType::RoomMember) { let pdu = services.rooms.timeline.get_pdu(e).await;
trace!("omitting member event {e:?} from returned state"); if pdu.is_ok_and(|p| *p.kind() == TimelineEventType::RoomMember) {
// skip members trace!("omitting member event {e:?} from returned state");
return None; // skip members
return None;
}
} }
} }
Some(event_id) Some(event_id)
@@ -220,7 +289,7 @@ async fn create_join_event(
Ok(assign!(create_join_event::v2::RoomState::new(), { Ok(assign!(create_join_event::v2::RoomState::new(), {
auth_chain, auth_chain,
state, state,
event: to_raw_value(&CanonicalJsonValue::Object(pdu)).ok(), event: to_raw_value(&CanonicalJsonValue::Object(value)).ok(),
members_omitted: omit_members, members_omitted: omit_members,
servers_in_room, servers_in_room,
})) }))
@@ -240,45 +309,24 @@ pub(crate) async fn create_join_event_v2_route(
return Err!(Request(Forbidden("Server is banned on this homeserver."))); return Err!(Request(Forbidden("Server is banned on this homeserver.")));
} }
let room_version = services.rooms.state.get_room_version(&body.room_id).await?; if let Some(server) = body.room_id.server_name() {
let create_event = services if services.moderation.is_remote_server_forbidden(server) {
.rooms warn!(
.state_accessor "Server {} tried joining room ID {} through us which has a server name that is \
.get_room_create_event(&body.room_id) globally forbidden. Rejecting.",
.await; body.identity, &body.room_id,
let room_version_rules = room_version.rules().unwrap(); );
return Err!(Request(Forbidden(warn!(
let (value, membership, sender, target) = validate_any_membership_event( "Room ID server name {server} is banned on this homeserver."
&services, ))));
&body.pdu, }
&room_version_rules,
create_event.event_id.clone(),
body.room_id.clone(),
body.event_id.clone(),
)
.await?;
if membership != MembershipState::Join {
return Err!(Request(InvalidParam("Invalid membership (expected `join`)")));
}
if sender.server_name() != body.identity {
return Err!(Request(InvalidParam("Sender belongs to a different server")));
}
if sender != target {
return Err!(Request(InvalidParam("Sender does not match state key")));
} }
let now = Instant::now(); let now = Instant::now();
let room_state = create_join_event( let room_state =
&services, create_join_event(&services, &body.identity, &body.room_id, &body.pdu, body.omit_members)
&body.identity, .boxed()
&body.room_id, .await?;
&body.event_id,
&room_version_rules,
value,
body.omit_members,
)
.boxed()
.await?;
info!( info!(
"Finished sending a join for {} in {} in {:?}", "Finished sending a join for {} in {} in {:?}",
body.identity, body.identity,
+97 -29
View File
@@ -1,11 +1,21 @@
use axum::extract::State; use axum::extract::State;
use conduwuit::{Err, Event, Result, debug_info, err, matrix::pdu::PduEvent, warn}; use conduwuit::{
Err, Result, err, info,
matrix::{event::gen_event_id_canonical_json, pdu::PduEvent},
warn,
};
use futures::FutureExt; use futures::FutureExt;
use ruma::{ use ruma::{
api::federation::membership::create_knock_event, events::room::member::MembershipState, OwnedUserId,
api::federation::membership::create_knock_event,
events::{
StateEventType,
room::member::{MembershipState, RoomMemberEventContent},
},
serde::JsonObject,
}; };
use crate::{Ruma, server::utils::validate_any_membership_event}; use crate::Ruma;
/// # `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}` /// # `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}`
/// ///
@@ -23,7 +33,18 @@ pub(crate) async fn create_knock_event_v1_route(
forbidden. Rejecting.", forbidden. Rejecting.",
body.identity, &body.room_id, body.identity, &body.room_id,
); );
return Err!(Request(Forbidden("Federation denied with {}", body.identity))); return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
if let Some(server) = body.room_id.server_name() {
if services.moderation.is_remote_server_forbidden(server) {
warn!(
"Server {} tried knocking room ID {} which has a server name that is globally \
forbidden. Rejecting.",
body.identity, &body.room_id,
);
return Err!(Request(Forbidden("Server is banned on this homeserver.")));
}
} }
if !services.rooms.metadata.exists(&body.room_id).await { if !services.rooms.metadata.exists(&body.room_id).await {
@@ -36,9 +57,8 @@ pub(crate) async fn create_knock_event_v1_route(
.server_in_room(services.globals.server_name(), &body.room_id) .server_in_room(services.globals.server_name(), &body.room_id)
.await .await
{ {
debug_info!( info!(
origin = body.identity.as_str(), origin = body.identity.as_str(),
room_id = %body.room_id,
"Refusing to serve send_knock for room we aren't participating in" "Refusing to serve send_knock for room we aren't participating in"
); );
return Err!(Request(NotFound("This server is not participating in that room."))); return Err!(Request(NotFound("This server is not participating in that room.")));
@@ -52,40 +72,88 @@ pub(crate) async fn create_knock_event_v1_route(
.await?; .await?;
let room_version = services.rooms.state.get_room_version(&body.room_id).await?; let room_version = services.rooms.state.get_room_version(&body.room_id).await?;
let create_event = services
.rooms
.state_accessor
.get_room_create_event(&body.room_id)
.await;
let room_version_rules = room_version.rules().unwrap(); let room_version_rules = room_version.rules().unwrap();
if !room_version_rules.authorization.knocking { if !room_version_rules.authorization.knocking {
return Err!(Request(Forbidden("Room version does not support knocking."))); return Err!(Request(Forbidden("Room version does not support knocking.")));
} }
let (mut event, target_membership, sender, target) = validate_any_membership_event( let Ok((event_id, value)) = gen_event_id_canonical_json(&body.pdu, &room_version_rules)
&services, else {
&body.pdu, // Event could not be converted to canonical json
&room_version_rules, return Err!(Request(InvalidParam("Could not convert event to canonical json.")));
create_event.event_id().to_owned(), };
body.room_id.clone(),
body.event_id.clone(), let event_type: StateEventType = serde_json::from_value(
value
.get("type")
.ok_or_else(|| err!(Request(InvalidParam("Event has no event type."))))?
.clone()
.into(),
) )
.await?; .map_err(|e| err!(Request(InvalidParam("Event has invalid event type: {e}"))))?;
if target_membership != MembershipState::Knock { if event_type != StateEventType::RoomMember {
return Err!(Request(InvalidParam("Invalid membership (expected `knock`)"))); return Err!(Request(InvalidParam(
"Not allowed to send non-membership state event to knock endpoint.",
)));
} }
let content: RoomMemberEventContent = serde_json::from_value(
value
.get("content")
.ok_or_else(|| err!(Request(InvalidParam("Membership event has no content"))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(InvalidParam("Event has invalid membership content: {e}"))))?;
if content.membership != MembershipState::Knock {
return Err!(Request(InvalidParam(
"Not allowed to send a non-knock membership event to knock endpoint."
)));
}
// ACL check sender server name
let sender: OwnedUserId = serde_json::from_value(
value
.get("sender")
.ok_or_else(|| err!(Request(InvalidParam("Event has no sender user ID."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson("Event sender is not a valid user ID: {e}"))))?;
services
.rooms
.event_handler
.acl_check(sender.server_name(), &body.room_id)
.await?;
// check if origin server is trying to send for another server
if sender.server_name() != body.identity { if sender.server_name() != body.identity {
return Err!(Request(InvalidParam("Sender belongs to a different server"))); return Err!(Request(BadJson("Not allowed to knock on behalf of another server/user.")));
}
if sender != target {
return Err!(Request(InvalidParam("Sender does not match state key")));
} }
event.insert("event_id".to_owned(), body.event_id.as_str().into()); let state_key: OwnedUserId = serde_json::from_value(
value
.get("state_key")
.ok_or_else(|| err!(Request(InvalidParam("Event does not have a state_key"))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson("Event does not have a valid state_key: {e}"))))?;
let pdu = PduEvent::from_id_val(&body.event_id, event.clone()) if state_key != sender {
return Err!(Request(InvalidParam("state_key does not match sender user of event.")));
}
let mut event: JsonObject = serde_json::from_str(body.pdu.get())
.map_err(|e| err!(Request(InvalidParam("Invalid knock 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(InvalidParam("Invalid knock event PDU: {e}"))))?; .map_err(|e| err!(Request(InvalidParam("Invalid knock event PDU: {e}"))))?;
let mutex_lock = services let mutex_lock = services
@@ -98,7 +166,7 @@ pub(crate) async fn create_knock_event_v1_route(
let pdu_id = services let pdu_id = services
.rooms .rooms
.event_handler .event_handler
.handle_incoming_pdu(sender.server_name(), &body.room_id, &body.event_id, event, false) .handle_incoming_pdu(sender.server_name(), &body.room_id, &event_id, value.clone(), false)
.boxed() .boxed()
.await? .await?
.ok_or_else(|| err!(Request(InvalidParam("Could not accept as timeline event."))))?; .ok_or_else(|| err!(Request(InvalidParam("Could not accept as timeline event."))))?;
@@ -113,7 +181,7 @@ pub(crate) async fn create_knock_event_v1_route(
let knock_room_state = services let knock_room_state = services
.rooms .rooms
.state .state
.summary_stripped(&pdu, &body.room_id, &sender, true) .summary_stripped(&pdu, &body.room_id, &sender)
.await; .await;
Ok(create_knock_event::v1::Response::new(knock_room_state)) Ok(create_knock_event::v1::Response::new(knock_room_state))
+104 -31
View File
@@ -1,11 +1,18 @@
use axum::extract::State; use axum::extract::State;
use conduwuit::{Err, Result, debug_info, err}; use conduwuit::{Err, Result, err, info, matrix::event::gen_event_id_canonical_json};
use conduwuit_service::Services;
use futures::FutureExt; use futures::FutureExt;
use ruma::{ use ruma::{
api::federation::membership::create_leave_event, events::room::member::MembershipState, OwnedRoomId, OwnedUserId, RoomId, ServerName,
api::federation::membership::create_leave_event,
events::{
StateEventType,
room::member::{MembershipState, RoomMemberEventContent},
},
}; };
use serde_json::value::RawValue as RawJsonValue;
use crate::{Ruma, server::utils::validate_any_membership_event}; use crate::Ruma;
/// # `PUT /_matrix/federation/v2/send_leave/{roomId}/{eventId}` /// # `PUT /_matrix/federation/v2/send_leave/{roomId}/{eventId}`
/// ///
@@ -14,8 +21,17 @@ pub(crate) async fn create_leave_event_v2_route(
State(services): State<crate::State>, State(services): State<crate::State>,
body: Ruma<create_leave_event::v2::Request>, body: Ruma<create_leave_event::v2::Request>,
) -> Result<create_leave_event::v2::Response> { ) -> Result<create_leave_event::v2::Response> {
let room_id = body.room_id.as_ref(); create_leave_event(&services, &body.identity, &body.room_id, &body.pdu).await?;
let origin = &body.identity;
Ok(create_leave_event::v2::Response::new())
}
async fn create_leave_event(
services: &Services,
origin: &ServerName,
room_id: &RoomId,
pdu: &RawJsonValue,
) -> Result {
if !services.rooms.metadata.exists(room_id).await { if !services.rooms.metadata.exists(room_id).await {
return Err!(Request(NotFound("Room is unknown to this server."))); return Err!(Request(NotFound("Room is unknown to this server.")));
} }
@@ -26,10 +42,9 @@ pub(crate) async fn create_leave_event_v2_route(
.server_in_room(services.globals.server_name(), room_id) .server_in_room(services.globals.server_name(), room_id)
.await .await
{ {
debug_info!( info!(
origin = origin.as_str(), origin = origin.as_str(),
room_id = %room_id, "Refusing to serve backfill for room we aren't participating in"
"Refusing to send_leave for room we aren't participating in"
); );
return Err!(Request(NotFound("This server is not participating in that room."))); return Err!(Request(NotFound("This server is not participating in that room.")));
} }
@@ -41,31 +56,91 @@ pub(crate) async fn create_leave_event_v2_route(
.acl_check(origin, room_id) .acl_check(origin, room_id)
.await?; .await?;
// We do not add the event_id field to the pdu here because of signature and
// hashes checks
let room_version = services.rooms.state.get_room_version(room_id).await?; let room_version = services.rooms.state.get_room_version(room_id).await?;
let create_event = services
.rooms
.state_accessor
.get_room_create_event(room_id)
.await;
let room_version_rules = room_version.rules().unwrap(); let room_version_rules = room_version.rules().unwrap();
let (value, membership, sender, target) = validate_any_membership_event( let Ok((event_id, value)) = gen_event_id_canonical_json(pdu, &room_version_rules) else {
&services, // Event could not be converted to canonical json
&body.pdu, return Err!(Request(BadJson("Could not convert event to canonical json.")));
&room_version_rules, };
create_event.event_id.clone(),
body.room_id.clone(), let event_room_id: OwnedRoomId = serde_json::from_value(
body.event_id.clone(), serde_json::to_value(
value
.get("room_id")
.ok_or_else(|| err!(Request(BadJson("Event missing room_id property."))))?,
)
.expect("CanonicalJson is valid json value"),
) )
.await?; .map_err(|e| err!(Request(BadJson(warn!("room_id field is not a valid room ID: {e}")))))?;
if membership != MembershipState::Leave {
return Err!(Request(InvalidParam("Invalid membership (expected `leave`)"))); if event_room_id != room_id {
return Err!(Request(BadJson("Event room_id does not match request path room ID.")));
} }
if sender.server_name() != body.identity {
return Err!(Request(InvalidParam("Sender belongs to a different server"))); let content: RoomMemberEventContent = serde_json::from_value(
value
.get("content")
.ok_or_else(|| err!(Request(BadJson("Event missing content property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("Event content is empty or invalid: {e}")))))?;
if content.membership != MembershipState::Leave {
return Err!(Request(BadJson(
"Not allowed to send a non-leave membership event to leave endpoint."
)));
} }
if sender != target {
return Err!(Request(InvalidParam("Sender does not match state key"))); let event_type: StateEventType = serde_json::from_value(
value
.get("type")
.ok_or_else(|| err!(Request(BadJson("Event missing type property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("Event has invalid state event type: {e}")))))?;
if event_type != StateEventType::RoomMember {
return Err!(Request(BadJson(
"Not allowed to send non-membership state event to leave endpoint."
)));
}
// ACL check sender server name
let sender: OwnedUserId = serde_json::from_value(
value
.get("sender")
.ok_or_else(|| err!(Request(BadJson("Event missing sender property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("sender property is not a valid user ID: {e}")))))?;
services
.rooms
.event_handler
.acl_check(sender.server_name(), room_id)
.await?;
if sender.server_name() != origin {
return Err!(Request(BadJson("Not allowed to leave on behalf of another server/user.")));
}
let state_key: OwnedUserId = serde_json::from_value(
value
.get("state_key")
.ok_or_else(|| err!(Request(BadJson("Event missing state_key property."))))?
.clone()
.into(),
)
.map_err(|e| err!(Request(BadJson(warn!("State key is not a valid user ID: {e}")))))?;
if state_key != sender {
return Err!(Request(BadJson("State key does not match sender user.")));
} }
let mutex_lock = services let mutex_lock = services
@@ -78,7 +153,7 @@ pub(crate) async fn create_leave_event_v2_route(
let pdu_id = services let pdu_id = services
.rooms .rooms
.event_handler .event_handler
.handle_incoming_pdu(origin, room_id, &body.event_id, value, false) .handle_incoming_pdu(origin, room_id, &event_id, value, false)
.boxed() .boxed()
.await? .await?
.ok_or_else(|| err!(Request(InvalidParam("Could not accept as timeline event."))))?; .ok_or_else(|| err!(Request(InvalidParam("Could not accept as timeline event."))))?;
@@ -89,7 +164,5 @@ pub(crate) async fn create_leave_event_v2_route(
.sending .sending
.send_pdu_room(room_id, &pdu_id) .send_pdu_room(room_id, &pdu_id)
.boxed() .boxed()
.await?; .await
Ok(create_leave_event::v2::Response::new())
} }
+2 -105
View File
@@ -1,10 +1,7 @@
use conduwuit::{Err, Result, err, is_false}; use conduwuit::{Err, Result, is_false};
use conduwuit_service::Services; use conduwuit_service::Services;
use futures::{FutureExt, future::OptionFuture, join}; use futures::{FutureExt, future::OptionFuture, join};
use ruma::{ use ruma::{EventId, RoomId, ServerName};
CanonicalJsonObject, EventId, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, ServerName,
UserId, events::room::member::MembershipState, room_version_rules::RoomVersionRules,
};
pub(super) struct AccessCheck<'a> { pub(super) struct AccessCheck<'a> {
pub(super) services: &'a Services, pub(super) services: &'a Services,
@@ -66,103 +63,3 @@ pub(super) async fn assert(&self) -> Result {
Ok(()) Ok(())
} }
} }
/// Performs validation on a membership event that should be run on any event a
/// remote is trying to send via us.
///
/// ## Checks performed
///
/// 1. PDU room ID matches request path room ID
/// 2. PDU event ID matches request path event ID
/// 3. Signature check
/// 4. Event type check
/// 5. `sender` field presence (and parsing)
/// 6. `state_key` field presence (and parsing)
/// 7. PDU room format check (PDU check 1)
///
/// ## Returns
///
/// A resulting tuple of (PDU JSON, target membership state, sender, recipient).
pub(crate) async fn validate_any_membership_event(
services: &crate::State,
body: &serde_json::value::RawValue,
room_version_rules: &RoomVersionRules,
create_event_id: OwnedEventId,
expected_room_id: OwnedRoomId,
expected_event_id: OwnedEventId,
) -> Result<(CanonicalJsonObject, MembershipState, OwnedUserId, OwnedUserId)> {
let (template_room_id, template_event_id, pdu) = services
.rooms
.event_handler
.parse_incoming_pdu(body, Some(room_version_rules))
.await
.map_err(|e| err!(Request(BadJson("Invalid membership PDU: {e}"))))?;
if template_room_id != expected_room_id {
return Err!(Request(InvalidParam("Membership event does not belong to requested room")));
}
if template_event_id != expected_event_id {
return Err!(Request(InvalidParam(debug_warn!(
%template_event_id,
%expected_event_id,
"Membership event ID does not match provided event ID"
))));
}
services
.server_keys
.verify_event(&pdu, room_version_rules)
.await
.map_err(|e| {
err!(Request(InvalidParam("Signature verification failed on membership event: {e}")))
})?;
// Ensure this is a membership event
if pdu
.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 this endpoint"
)));
}
let membership = pdu
.get("content")
.ok_or_else(|| err!(Request(BadJson("Event missing content property"))))?
.as_object()
.ok_or_else(|| err!(Request(BadJson("Event content is not an object"))))?
.get("membership")
.ok_or_else(|| err!(Request(BadJson("Event missing membership property"))))?
.as_str()
.ok_or_else(|| err!(Request(BadJson("Event is not a string"))))?
.to_owned();
let sender_user = pdu
.get("sender")
.and_then(|v| v.as_str())
.map(UserId::parse)
.and_then(Result::ok)
.ok_or_else(|| err!(Request(InvalidParam("Invalid sender property"))))?;
let recipient_user = pdu
.get("state_key")
.and_then(|v| v.as_str())
.map(UserId::parse)
.and_then(Result::ok)
.ok_or_else(|| err!(Request(InvalidParam("Invalid state_key property"))))?;
// Do a quick format check. The spec doesn't suggest this, but it's probably
// a good idea nonetheless.
service::rooms::event_handler::Service::pdu_format_check_1(
&pdu,
room_version_rules,
&create_event_id,
)
.map_err(|e| {
err!(Request(InvalidParam("Membership event violates the room event format: {e}")))
})?;
Ok((pdu, membership.into(), sender_user, recipient_user))
}
-1
View File
@@ -2442,7 +2442,6 @@ pub struct OauthConfig {
/// legacy authentication will be unable to log in. /// legacy authentication will be unable to log in.
/// ///
/// default: "hybrid" /// default: "hybrid"
#[serde(default)]
compatibility_mode: OAuthMode, compatibility_mode: OAuthMode,
/// display: hidden /// display: hidden
+2 -10
View File
@@ -1,6 +1,4 @@
use std::io::IsTerminal; use conduwuit::{Err, Result, debug, debug_info, error, info};
use conduwuit::{Err, Result, debug, debug_info, error, info, warn};
use ruma::events::room::message::RoomMessageEventContent; use ruma::events::room::message::RoomMessageEventContent;
use tokio::time::{Duration, sleep}; use tokio::time::{Duration, sleep};
@@ -9,16 +7,10 @@
pub(super) const SIGNAL: &str = "SIGUSR2"; pub(super) const SIGNAL: &str = "SIGUSR2";
impl super::Service { impl super::Service {
/// Possibly spawn the terminal console at startup if configured and a TTY /// Possibly spawn the terminal console at startup if configured.
/// is available.
pub(super) async fn console_auto_start(&self) { pub(super) async fn console_auto_start(&self) {
#[cfg(feature = "console")] #[cfg(feature = "console")]
if self.services.server.config.admin_console_automatic { if self.services.server.config.admin_console_automatic {
if !std::io::stdin().is_terminal() {
warn!("Console enabled without a tty available; Not enabling console");
return;
}
// Allow more of the startup sequence to execute before spawning // Allow more of the startup sequence to execute before spawning
tokio::task::yield_now().await; tokio::task::yield_now().await;
self.console.start().await; self.console.start().await;
+1 -1
View File
@@ -134,7 +134,7 @@ async fn check(&self) -> Result<()> {
let response = self let response = self
.services .services
.client .client
.external_resource .default
.get(CHECK_FOR_ANNOUNCEMENTS_URL) .get(CHECK_FOR_ANNOUNCEMENTS_URL)
.send() .send()
.await? .await?
+19 -14
View File
@@ -16,9 +16,9 @@ pub struct Service {
pub matrix_resolver: Arc<MatrixResolver>, pub matrix_resolver: Arc<MatrixResolver>,
pub dns_resolver: Arc<TokioResolver>, pub dns_resolver: Arc<TokioResolver>,
pub dns: reqwest::Client, pub default: reqwest::Client,
pub url_preview: reqwest::Client, pub url_preview: reqwest::Client,
pub external_resource: reqwest::Client, pub extern_media: reqwest::Client,
pub federation: reqwest::Client, pub federation: reqwest::Client,
pub federation_slow: reqwest::Client, pub federation_slow: reqwest::Client,
pub sender: reqwest::Client, pub sender: reqwest::Client,
@@ -35,17 +35,17 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
let dns_resolver = get_dns_resolver(args.server)?; let dns_resolver = get_dns_resolver(args.server)?;
let dns_client = base(&args.server.config)?
.connect_timeout(Duration::from_secs(args.server.config.well_known_conn_timeout))
.read_timeout(Duration::from_secs(args.server.config.well_known_timeout))
.timeout(Duration::from_secs(args.server.config.well_known_timeout))
.pool_max_idle_per_host(0)
.redirect(redirect::Policy::limited(4))
.build()?;
let matrix_resolver = Arc::new(MatrixResolverBuilder::new() let matrix_resolver = Arc::new(MatrixResolverBuilder::new()
.dangerous_tls_accept_invalid_certs(args.server.config.allow_invalid_tls_certificates_yes_i_know_what_the_fuck_i_am_doing_with_this_and_i_know_this_is_insecure) .dangerous_tls_accept_invalid_certs(args.server.config.allow_invalid_tls_certificates_yes_i_know_what_the_fuck_i_am_doing_with_this_and_i_know_this_is_insecure)
.http_client(dns_client.clone()) .http_client(
base(&args.server.config)?
.connect_timeout(Duration::from_secs(args.server.config.well_known_conn_timeout))
.read_timeout(Duration::from_secs(args.server.config.well_known_timeout))
.timeout(Duration::from_secs(args.server.config.well_known_timeout))
.pool_max_idle_per_host(0)
.redirect(redirect::Policy::limited(4))
.build()?
)
.dns_resolver(dns_resolver.clone()) .dns_resolver(dns_resolver.clone())
.build()?); .build()?);
let matrix_dns_resolver = matrix_resolver.create_dns_resolver(); let matrix_dns_resolver = matrix_resolver.create_dns_resolver();
@@ -69,19 +69,23 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
matrix_resolver, matrix_resolver,
dns_resolver, dns_resolver,
dns: dns_client, default: base(config)?
.dns_resolver(matrix_dns_resolver.clone())
.build()?,
url_preview: base(config) url_preview: base(config)
.and_then(|builder| { .and_then(|builder| {
builder_interface(builder, url_preview_bind_iface.as_deref()) builder_interface(builder, url_preview_bind_iface.as_deref())
})? })?
.local_address(url_preview_bind_addr) .local_address(url_preview_bind_addr)
.dns_resolver(matrix_dns_resolver.clone())
.timeout(Duration::from_secs(config.url_preview_timeout)) .timeout(Duration::from_secs(config.url_preview_timeout))
.redirect(redirect::Policy::limited(3)) .redirect(redirect::Policy::limited(3))
.user_agent(url_preview_user_agent) .user_agent(url_preview_user_agent)
.build()?, .build()?,
external_resource: base(config)? extern_media: base(config)?
.dns_resolver(matrix_dns_resolver.clone())
.redirect(redirect::Policy::limited(3)) .redirect(redirect::Policy::limited(3))
.build()?, .build()?,
@@ -124,7 +128,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
.build()?, .build()?,
appservice: base(config)? appservice: base(config)?
.dns_resolver(matrix_dns_resolver) .dns_resolver(matrix_dns_resolver.clone())
.connect_timeout(Duration::from_secs(5)) .connect_timeout(Duration::from_secs(5))
.read_timeout(Duration::from_secs(config.appservice_timeout)) .read_timeout(Duration::from_secs(config.appservice_timeout))
.timeout(Duration::from_secs(config.appservice_timeout)) .timeout(Duration::from_secs(config.appservice_timeout))
@@ -134,6 +138,7 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
.build()?, .build()?,
pusher: base(config)? pusher: base(config)?
.dns_resolver(matrix_dns_resolver)
.connect_timeout(Duration::from_secs(config.pusher_conn_timeout)) .connect_timeout(Duration::from_secs(config.pusher_conn_timeout))
.timeout(Duration::from_secs(config.pusher_timeout)) .timeout(Duration::from_secs(config.pusher_timeout))
.pool_max_idle_per_host(1) .pool_max_idle_per_host(1)
+1 -1
View File
@@ -260,7 +260,7 @@ async fn location_request(&self, location: &str) -> Result<FileMeta> {
let response = self let response = self
.services .services
.client .client
.external_resource .extern_media
.get(location) .get(location)
.send() .send()
.await?; .await?;
+2 -4
View File
@@ -829,7 +829,7 @@ async fn fix_local_invite_state(services: &Services) -> Result {
&& services.globals.user_is_local(&membership_event.sender) { && services.globals.user_is_local(&membership_event.sender) {
// build and save stripped state for their invite in the database // build and save stripped state for their invite in the database
let stripped_state = services.rooms.state.summary_stripped(&membership_event, &room_id, &user_id, false).await; let stripped_state = services.rooms.state.summary_stripped(&membership_event, &room_id, &user_id).await;
userroomid_invitestate.put((&user_id, &room_id), Json(stripped_state)); userroomid_invitestate.put((&user_id, &room_id), Json(stripped_state));
fixed = fixed.saturating_add(1); fixed = fixed.saturating_add(1);
} }
@@ -882,7 +882,7 @@ async fn split_userid_password(services: &Services) -> Result {
drop(cork); drop(cork);
info!(?remote_users, "Split userid_password."); info!(?remote_users, "Split userid_password.");
db["global"].insert(SPLIT_USERID_PASSWORD, []); db["global"].insert(FIXED_LOCAL_INVITE_STATE_MARKER, []);
db.db.sort()?; db.db.sort()?;
Ok(()) Ok(())
} }
@@ -895,7 +895,5 @@ async fn obliterate_roomsynctoken_shortstatehash_with_extreme_prejudice(
info!("Cleared roomsynctoken_shortstatehash."); info!("Cleared roomsynctoken_shortstatehash.");
services.db["global"].insert(DROP_ROOMSYNCTOKEN_SHORTSTATEHASH, []);
Ok(()) Ok(())
} }
-1
View File
@@ -151,7 +151,6 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
config: config.clone(), config: config.clone(),
client_secret: if let Some(client_secret_file) = &config.client_secret_file { client_secret: if let Some(client_secret_file) = &config.client_secret_file {
std::fs::read_to_string(client_secret_file) std::fs::read_to_string(client_secret_file)
.map(|client_secret| client_secret.trim().to_owned())
.map(ClientSecret::new) .map(ClientSecret::new)
.map_err(|err| err!("Failed to read OIDC client secret file: {err}"))? .map_err(|err| err!("Failed to read OIDC client secret file: {err}"))?
} else if let Some(client_secret) = &config.client_secret { } else if let Some(client_secret) = &config.client_secret {
@@ -241,7 +241,7 @@ pub async fn get_missing_events(
latest_events.clear(); latest_events.clear();
for raw_event in response.events { for raw_event in response.events {
let (_, event_id, pdu_json) = self.parse_incoming_pdu(&raw_event, None).await?; let (_, event_id, pdu_json) = self.parse_incoming_pdu(&raw_event).await?;
let pdu = PduEvent::from_id_val(&event_id, pdu_json).map_err(|e| { let pdu = PduEvent::from_id_val(&event_id, pdu_json).map_err(|e| {
err!(Request(BadJson("Failed to parse gapfilled event {event_id}: {e}"))) err!(Request(BadJson("Failed to parse gapfilled event {event_id}: {e}")))
})?; })?;
@@ -384,9 +384,8 @@ async fn fetch_event_via(
.send_federation_request(&remote, get_event::v1::Request::new(event_id.clone())) .send_federation_request(&remote, get_event::v1::Request::new(event_id.clone()))
.await?; .await?;
let (_, calculated_event_id, value) = self let (calculated_event_id, value) =
.parse_incoming_pdu(&res.pdu, Some(room_version_rules)) Self::parse_incoming_pdu_with_known_room(&res.pdu, room_version_rules)?;
.await?;
if calculated_event_id != event_id { if calculated_event_id != event_id {
Err!(Request(BadJson(warn!( Err!(Request(BadJson(warn!(
+8 -10
View File
@@ -48,16 +48,14 @@ pub(super) async fn fetch_and_persist_event_auth<Pdu>(
let mut auth_chain_map = HashMap::with_capacity(event_auth.auth_chain.len()); let mut auth_chain_map = HashMap::with_capacity(event_auth.auth_chain.len());
for auth_pdu_json in event_auth.auth_chain { for auth_pdu_json in event_auth.auth_chain {
let (auth_event_room_id, auth_event_id, auth_pdu_json) = match self let (auth_event_room_id, auth_event_id, auth_pdu_json) =
.parse_incoming_pdu(&auth_pdu_json, Some(room_version_rules)) match self.parse_incoming_pdu(&auth_pdu_json).await {
.await | Ok(parsed) => parsed,
{ | Err(e) => {
| Ok(parsed) => parsed, warn!(error=?e, "Dropping auth chain event as it could not be parsed");
| Err(e) => { continue;
warn!(error=?e, "Dropping auth chain event as it could not be parsed"); },
continue; };
},
};
if let Err(e) = Self::pdu_format_check_1( if let Err(e) = Self::pdu_format_check_1(
&auth_pdu_json, &auth_pdu_json,
room_version_rules, room_version_rules,
@@ -314,7 +314,7 @@ pub(super) async fn fetch_full_state(
.iter() .iter()
.stream() .stream()
.broad_filter_map(|raw_event_json| async { .broad_filter_map(|raw_event_json| async {
if let Some(parsed) = self.parse_incoming_pdu(raw_event_json, None).await.ok() if let Some(parsed) = self.parse_incoming_pdu(raw_event_json).await.ok()
&& parsed.0 == room_id && parsed.0 == room_id
{ {
Some(parsed) Some(parsed)
@@ -351,7 +351,7 @@ pub(super) async fn fetch_full_state(
.iter() .iter()
.stream() .stream()
.broad_filter_map(|raw_event_json| async { .broad_filter_map(|raw_event_json| async {
if let Some(parsed) = self.parse_incoming_pdu(raw_event_json, None).await.ok() if let Some(parsed) = self.parse_incoming_pdu(raw_event_json).await.ok()
&& parsed.0 == room_id && parsed.0 == room_id
{ {
Some(parsed) Some(parsed)
@@ -14,12 +14,10 @@ impl super::Service {
/// This performs steps 1 through 4 of [S-S section 5.1][spec], returning /// This performs steps 1 through 4 of [S-S section 5.1][spec], returning
/// the parsed PDU and modified JSON object. /// the parsed PDU and modified JSON object.
/// ///
/// **External callers likely want `handle_incoming_pdu` instead.**
///
/// [spec]: https://spec.matrix.org/v1.19/server-server-api/#checks-performed-on-receipt-of-a-pdu /// [spec]: https://spec.matrix.org/v1.19/server-server-api/#checks-performed-on-receipt-of-a-pdu
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[tracing::instrument(name = "handle_outlier", skip_all)] #[tracing::instrument(name = "handle_outlier", skip_all)]
pub async fn handle_outlier_pdu<'a, Pdu>( pub(super) async fn handle_outlier_pdu<'a, Pdu>(
&self, &self,
origin: &'a ServerName, origin: &'a ServerName,
create_event: &'a Pdu, create_event: &'a Pdu,
@@ -56,6 +54,7 @@ pub async fn handle_outlier_pdu<'a, Pdu>(
})?; })?;
value.remove("unsigned"); value.remove("unsigned");
let room_version_rules = get_room_version_rules(create_event)?;
// 2. Check signatures, otherwise drop. // 2. Check signatures, otherwise drop.
// 3. Check content hash, redacting the event if it fails. // 3. Check content hash, redacting the event if it fails.
@@ -82,14 +82,25 @@ pub(super) fn expect_event_id_array(
} }
impl super::Service { impl super::Service {
/// Parses an incoming PDU JSON object, generating an event ID for it. Does
/// not insert the event ID into the returned object. Does not discover the
/// room ID.
pub(super) fn parse_incoming_pdu_with_known_room(
pdu: &RawJsonValue,
room_version_rules: &RoomVersionRules,
) -> Result<(OwnedEventId, CanonicalJsonObject)> {
let (event_id, value) =
gen_event_id_canonical_json(pdu, room_version_rules).map_err(|e| {
err!(Request(InvalidParam("Could not convert event to canonical json: {e}")))
})?;
// NOTE: validation checks are now performed by `pdu_format_check_1`.
Ok((event_id, value))
}
/// Parses an incoming PDU JSON object, generating an event ID for it and /// Parses an incoming PDU JSON object, generating an event ID for it and
/// attempts to discover the associated room ID. Does not insert the event /// attempts to discover the associated room ID. Does not insert the event
/// ID into the returned object. /// ID into the returned object.
pub async fn parse_incoming_pdu( pub async fn parse_incoming_pdu(&self, pdu: &RawJsonValue) -> Result<Parsed> {
&self,
pdu: &RawJsonValue,
room_version_rules: Option<&RoomVersionRules>,
) -> Result<Parsed> {
let value = serde_json::from_str::<CanonicalJsonObject>(pdu.get()).map_err(|e| { let value = serde_json::from_str::<CanonicalJsonObject>(pdu.get()).map_err(|e| {
err!(BadServerResponse(debug_warn!("Error parsing incoming event {e:?}"))) err!(BadServerResponse(debug_warn!("Error parsing incoming event {e:?}")))
})?; })?;
@@ -100,20 +111,17 @@ pub async fn parse_incoming_pdu(
let room_id = extract_room_id(event_type, &value)?; let room_id = extract_room_id(event_type, &value)?;
let room_version_rules = match room_version_rules { let room_version_rules = self
| Some(r) => r, .services
| None => &self .state
.services .get_room_version(&room_id)
.state .await
.get_room_version(&room_id) .unwrap_or(RoomVersionId::V1)
.await .rules()
.unwrap_or(RoomVersionId::V1) .unwrap();
.rules()
.expect("room version must be supported"),
};
let (event_id, value) = let (event_id, value) =
gen_event_id_canonical_json(pdu, room_version_rules).map_err(|e| { gen_event_id_canonical_json(pdu, &room_version_rules).map_err(|e| {
err!(Request(InvalidParam("Could not convert event to canonical json: {e}"))) err!(Request(InvalidParam("Could not convert event to canonical json: {e}")))
})?; })?;
// NOTE: validation checks are now performed by `pdu_format_check_1`. // NOTE: validation checks are now performed by `pdu_format_check_1`.
+8 -27
View File
@@ -6,9 +6,8 @@
}; };
use futures::future::ready; use futures::future::ready;
use ruma::{ use ruma::{
CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, ServerName, CanonicalJsonObject, EventId, OwnedEventId, ServerName, api::error::ErrorKind,
api::error::ErrorKind, canonical_json::redact, events::StateEventType, canonical_json::redact, events::StateEventType, room_version_rules::RoomVersionRules,
room_version_rules::RoomVersionRules,
}; };
use crate::rooms::{ use crate::rooms::{
@@ -19,7 +18,7 @@ impl super::Service {
/// Checks that the PDU conforms to the PDU format (check 1). This is /// Checks that the PDU conforms to the PDU format (check 1). This is
/// already mostly done during deserialisation, so this function just checks /// already mostly done during deserialisation, so this function just checks
/// that the PDU isn't a too large. /// that the PDU isn't a too large.
pub fn pdu_format_check_1( pub(super) fn pdu_format_check_1(
pdu_json: &CanonicalJsonObject, pdu_json: &CanonicalJsonObject,
room_version_rules: &RoomVersionRules, room_version_rules: &RoomVersionRules,
create_event_id: &EventId, create_event_id: &EventId,
@@ -43,27 +42,9 @@ pub fn pdu_format_check_1(
return Err!(Request(BadJson("PDU has too many auth events"))); return Err!(Request(BadJson("PDU has too many auth events")));
} }
// The m.room.create event is the genesis event and has empty auth_events let create_event_in_auth_events = auth_events.iter().any(|id| id == create_event_id);
// by definition, so it is exempt from the checks below requiring or if !event_format.allow_room_create_in_auth_events && create_event_in_auth_events {
// forbidding the create event in auth_events (it cannot reference itself). return Err!(Request(BadJson("PDU references a create event")));
let Some(event_type) = pdu_json.get("type").and_then(CanonicalJsonValue::as_str) else {
return Err!(Request(BadJson("PDU is missing a type")));
};
let state_key = pdu_json
.get("state_key")
.and_then(CanonicalJsonValue::as_str);
let is_create_event = event_type == "m.room.create" && state_key == Some("");
if !is_create_event {
let create_event_in_auth_events = auth_events.iter().any(|id| id == create_event_id);
if !event_format.allow_room_create_in_auth_events && create_event_in_auth_events {
return Err!(Request(BadJson("PDU references a create event")));
} else if event_format.allow_room_create_in_auth_events
&& !create_event_in_auth_events
{
return Err!(Request(BadJson("PDU does not reference the room create event")));
}
} }
let prev_events = expect_event_id_array(pdu_json, "prev_events")?; let prev_events = expect_event_id_array(pdu_json, "prev_events")?;
@@ -78,7 +59,7 @@ pub fn pdu_format_check_1(
/// the content hash verification fails (check 3), returning the /// the content hash verification fails (check 3), returning the
/// potentially modified JSON. Returns an error if the PDU cannot be /// potentially modified JSON. Returns an error if the PDU cannot be
/// redacted, or fails signature verification. /// redacted, or fails signature verification.
pub async fn signature_hash_check_2_3( pub(super) async fn signature_hash_check_2_3(
&self, &self,
pdu_json: CanonicalJsonObject, pdu_json: CanonicalJsonObject,
room_version_rules: &RoomVersionRules, room_version_rules: &RoomVersionRules,
@@ -111,7 +92,7 @@ pub async fn signature_hash_check_2_3(
/// If the auth check fails, false is returned, otherwise true. /// If the auth check fails, false is returned, otherwise true.
/// ///
/// [spec]: https://spec.matrix.org/v1.19/server-server-api/#checks-performed-on-receipt-of-a-pdu /// [spec]: https://spec.matrix.org/v1.19/server-server-api/#checks-performed-on-receipt-of-a-pdu
pub async fn auth_state_check_4( pub(super) async fn auth_state_check_4(
&self, &self,
pdu: &PduEvent, pdu: &PduEvent,
room_version_rules: &RoomVersionRules, room_version_rules: &RoomVersionRules,
+3 -18
View File
@@ -1,7 +1,7 @@
use std::{collections::HashMap, fmt::Write, sync::Arc}; use std::{collections::HashMap, fmt::Write, sync::Arc};
use async_trait::async_trait; use async_trait::async_trait;
use conduwuit::{debug, utils::stream::WidebandExt}; use conduwuit::debug;
use conduwuit_core::{ use conduwuit_core::{
Event, PduEvent, Result, err, Event, PduEvent, Result, err,
result::FlatOk, result::FlatOk,
@@ -30,7 +30,7 @@
short::{ShortEventId, ShortStateHash}, short::{ShortEventId, ShortStateHash},
state_compressor::{CompressedState, parse_compressed_state_event}, state_compressor::{CompressedState, parse_compressed_state_event},
}, },
sending, sync, sync,
}; };
pub struct Service { pub struct Service {
@@ -45,7 +45,6 @@ struct Services {
state_cache: Dep<rooms::state_cache::Service>, state_cache: Dep<rooms::state_cache::Service>,
state_accessor: Dep<rooms::state_accessor::Service>, state_accessor: Dep<rooms::state_accessor::Service>,
state_compressor: Dep<rooms::state_compressor::Service>, state_compressor: Dep<rooms::state_compressor::Service>,
sending: Dep<sending::Service>,
sync: Dep<sync::Service>, sync: Dep<sync::Service>,
timeline: Dep<rooms::timeline::Service>, timeline: Dep<rooms::timeline::Service>,
} }
@@ -72,7 +71,6 @@ fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
.depend::<rooms::state_accessor::Service>("rooms::state_accessor"), .depend::<rooms::state_accessor::Service>("rooms::state_accessor"),
state_compressor: args state_compressor: args
.depend::<rooms::state_compressor::Service>("rooms::state_compressor"), .depend::<rooms::state_compressor::Service>("rooms::state_compressor"),
sending: args.depend::<sending::Service>("sending"),
sync: args.depend::<sync::Service>("sync"), sync: args.depend::<sync::Service>("sync"),
timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"), timeline: args.depend::<rooms::timeline::Service>("rooms::timeline"),
}, },
@@ -309,7 +307,6 @@ pub async fn summary_stripped(
event: &PduEvent, event: &PduEvent,
room_id: &RoomId, room_id: &RoomId,
target_user: &UserId, target_user: &UserId,
federation: bool,
) -> Vec<RawStrippedState> { ) -> Vec<RawStrippedState> {
let mut state_events = [ let mut state_events = [
(&StateEventType::RoomCreate, ""), (&StateEventType::RoomCreate, ""),
@@ -346,20 +343,8 @@ pub async fn summary_stripped(
.await .await
.into_iter() .into_iter()
.filter_map(Result::ok) .filter_map(Result::ok)
.stream() .map(|pdu| RawStrippedState::Pdu(serde_json::value::to_raw_value(&pdu).unwrap()))
.wide_then(async |pdu| {
let formatted = if federation {
self.services
.sending
.convert_to_outgoing_federation_event(pdu.to_canonical_object())
.await
} else {
serde_json::value::to_raw_value(&pdu).unwrap()
};
RawStrippedState::Pdu(formatted)
})
.collect() .collect()
.await
} }
/// Set the state hash to a new version, but does not update state_cache. /// Set the state hash to a new version, but does not update state_cache.
+1 -1
View File
@@ -114,7 +114,7 @@ pub async fn update_membership(
let invite_state = if is_local { let invite_state = if is_local {
self.services self.services
.state .state
.summary_stripped(pdu, room_id, user_id, false) .summary_stripped(pdu, room_id, user_id)
.await .await
} else { } else {
vec![] vec![]
+2 -5
View File
@@ -166,11 +166,8 @@ pub async fn get_remote_pdu(&self, room_id: &RoomId, event_id: &EventId) -> Resu
/// Backfills a single PDU. /// Backfills a single PDU.
#[tracing::instrument(skip(self, pdu), level = "debug")] #[tracing::instrument(skip(self, pdu), level = "debug")]
pub async fn backfill_pdu(&self, origin: &ServerName, pdu: Box<RawJsonValue>) -> Result<()> { pub async fn backfill_pdu(&self, origin: &ServerName, pdu: Box<RawJsonValue>) -> Result<()> {
let (room_id, event_id, value) = self let (room_id, event_id, value) =
.services self.services.event_handler.parse_incoming_pdu(&pdu).await?;
.event_handler
.parse_incoming_pdu(&pdu, None)
.await?;
// Lock so we cannot backfill the same pdu twice at the same time // Lock so we cannot backfill the same pdu twice at the same time
let mutex_lock = self let mutex_lock = self
-15
View File
@@ -308,21 +308,6 @@ pub async fn create_hash_and_sign_event(
| _ => Err!(Request(Unknown(warn!("Signing event failed: {e}")))), | _ => Err!(Request(Unknown(warn!("Signing event failed: {e}")))),
}; };
} }
// Evil hack because only the PDU JSON gets signed
pdu.hashes = serde_json::from_value(serde_json::to_value(
pdu_json
.get("hashes")
.expect("must have hashes after signing")
.clone(),
)?)?;
pdu.signatures = serde_json::from_value(serde_json::to_value(
pdu_json
.get("signatures")
.expect("must have signatures after signing")
.clone(),
)?)?;
// Generate event id // Generate event id
pdu.event_id = gen_event_id(&pdu_json, &room_version_rules)?; pdu.event_id = gen_event_id(&pdu_json, &room_version_rules)?;
pdu_json pdu_json
+1 -1
View File
@@ -155,7 +155,7 @@ async fn get_account_deeplink(
)); ));
}; };
format!("device/{device_id}/remove") format!("device/{device_id}/delete")
}, },
| AccountManagementAction::DeviceView => { | AccountManagementAction::DeviceView => {
let Some(device_id) = query.device_id else { let Some(device_id) = query.device_id else {