From 3a8321f9adcb575370fa2c606c2a212c1f6f03f3 Mon Sep 17 00:00:00 2001 From: AndSDev Date: Mon, 29 Aug 2022 14:09:08 +0000 Subject: feat(db/rooms): encryption is not allowed in the admins room --- src/service/rooms/timeline/mod.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 619dca2..32781f2 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -22,6 +22,7 @@ use ruma::{ }, push::{Action, Ruleset, Tweak}, state_res, + state_res::Event, state_res::RoomVersion, uint, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, OwnedServerName, RoomAliasId, RoomId, UserId, @@ -683,6 +684,22 @@ impl Service { let (pdu, pdu_json) = self.create_hash_and_sign_event(pdu_builder, sender, room_id, state_lock)?; + let admin_room = services().rooms.alias.resolve_local_alias( + <&RoomAliasId>::try_from( + format!("#admins:{}", services().globals.server_name()).as_str(), + ) + .expect("#admins:server_name is a valid room alias"), + )?; + if admin_room.filter(|v| v == room_id).is_some() { + if pdu.event_type() == &RoomEventType::RoomEncryption { + warn!("Encryption is not allowed in the admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Encryption is not allowed in the admins room.", + )); + } + } + // We append to state before appending the pdu, so we don't have a moment in time with the // pdu without it's state. This is okay because append_pdu can't fail. let statehashid = services().rooms.state.append_to_state(&pdu)?; -- cgit v1.2.3 From c67f95ebffd60a9efe222816c742b1522e06578e Mon Sep 17 00:00:00 2001 From: AndSDev Date: Wed, 31 Aug 2022 07:10:54 +0000 Subject: feat(db/rooms): disable leaving from admin room for conduit user --- src/service/rooms/timeline/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 32781f2..2f56fea 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -698,6 +698,26 @@ impl Service { "Encryption is not allowed in the admins room.", )); } + if pdu.event_type() == &RoomEventType::RoomMember { + #[derive(Deserialize)] + struct ExtractMembership { + membership: MembershipState, + } + + let content = serde_json::from_str::(pdu.content.get()) + .map_err(|_| Error::bad_database("Invalid content in pdu."))?; + + if content.membership == MembershipState::Leave { + let server_user = format!("@conduit:{}", services().globals.server_name()); + if sender == &server_user { + warn!("Conduit user cannot leave from admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Conduit user cannot leave from admins room.", + )); + } + } + } } // We append to state before appending the pdu, so we don't have a moment in time with the -- cgit v1.2.3 From da2dbd2877d3b7b1edc2a05bb5593759d8072794 Mon Sep 17 00:00:00 2001 From: AndSDev Date: Wed, 31 Aug 2022 07:11:28 +0000 Subject: feat(db/rooms): disable leaving from admin room for last user --- src/service/rooms/timeline/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 2f56fea..5d28628 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -716,6 +716,21 @@ impl Service { "Conduit user cannot leave from admins room.", )); } + + let count = services() + .rooms + .state_cache + .room_members(room_id) + .filter_map(|m| m.ok()) + .filter(|m| m.server_name() == services().globals.server_name()) + .count(); + if count < 3 { + warn!("Last admin cannot leave from admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Last admin cannot leave from admins room.", + )); + } } } } -- cgit v1.2.3 From 912491cb28f88fb0ed9cdd1aac4a76a307cbec03 Mon Sep 17 00:00:00 2001 From: AndSDev Date: Wed, 31 Aug 2022 08:22:45 +0000 Subject: style(db/rooms): refactor admin room pdu validating --- src/service/rooms/timeline/mod.rs | 73 ++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 5d28628..9ededd2 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -691,47 +691,50 @@ impl Service { .expect("#admins:server_name is a valid room alias"), )?; if admin_room.filter(|v| v == room_id).is_some() { - if pdu.event_type() == &RoomEventType::RoomEncryption { - warn!("Encryption is not allowed in the admins room"); - return Err(Error::BadRequest( - ErrorKind::Forbidden, - "Encryption is not allowed in the admins room.", - )); - } - if pdu.event_type() == &RoomEventType::RoomMember { - #[derive(Deserialize)] - struct ExtractMembership { - membership: MembershipState, + match pdu.event_type() { + RoomEventType::RoomEncryption => { + warn!("Encryption is not allowed in the admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Encryption is not allowed in the admins room.", + )); } + RoomEventType::RoomMember => { + #[derive(Deserialize)] + struct ExtractMembership { + membership: MembershipState, + } - let content = serde_json::from_str::(pdu.content.get()) - .map_err(|_| Error::bad_database("Invalid content in pdu."))?; + let content = serde_json::from_str::(pdu.content.get()) + .map_err(|_| Error::bad_database("Invalid content in pdu."))?; - if content.membership == MembershipState::Leave { - let server_user = format!("@conduit:{}", services().globals.server_name()); - if sender == &server_user { - warn!("Conduit user cannot leave from admins room"); - return Err(Error::BadRequest( - ErrorKind::Forbidden, - "Conduit user cannot leave from admins room.", - )); - } + if content.membership == MembershipState::Leave { + let server_user = format!("@conduit:{}", services().globals.server_name()); + if sender == &server_user { + warn!("Conduit user cannot leave from admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Conduit user cannot leave from admins room.", + )); + } - let count = services() - .rooms - .state_cache - .room_members(room_id) - .filter_map(|m| m.ok()) - .filter(|m| m.server_name() == services().globals.server_name()) - .count(); - if count < 3 { - warn!("Last admin cannot leave from admins room"); - return Err(Error::BadRequest( - ErrorKind::Forbidden, - "Last admin cannot leave from admins room.", - )); + let count = services() + .rooms + .state_cache + .room_members(room_id) + .filter_map(|m| m.ok()) + .filter(|m| m.server_name() == services().globals.server_name()) + .count(); + if count < 3 { + warn!("Last admin cannot leave from admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Last admin cannot leave from admins room.", + )); + } } } + _ => {} } } -- cgit v1.2.3 From 76f81ac2010746c5cba1105a37187ce2e59d2ffe Mon Sep 17 00:00:00 2001 From: AndSDev Date: Tue, 6 Sep 2022 11:32:33 +0000 Subject: feat(db/rooms): disable banning for last user and conduit user in admins room --- src/service/rooms/timeline/mod.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 9ededd2..66a8196 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -733,6 +733,32 @@ impl Service { )); } } + + if content.membership == MembershipState::Ban && pdu.state_key().is_some() { + let server_user = format!("@conduit:{}", services().globals.server_name()); + if pdu.state_key().as_ref().unwrap() == &server_user { + warn!("Conduit user cannot be banned in admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Conduit user cannot be banned in admins room.", + )); + } + + let count = services() + .rooms + .state_cache + .room_members(room_id) + .filter_map(|m| m.ok()) + .filter(|m| m.server_name() == services().globals.server_name()) + .count(); + if count < 3 { + warn!("Last admin cannot be banned in admins room"); + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Last admin cannot be banned in admins room.", + )); + } + } } _ => {} } -- cgit v1.2.3 From d755a96c2c3422849fdac8792e5d91141f837a18 Mon Sep 17 00:00:00 2001 From: AndSDev Date: Thu, 13 Oct 2022 11:19:51 +0000 Subject: refactor(service/rooms/timeline): add cache for server_name --- src/service/rooms/timeline/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 66a8196..9494f67 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -705,11 +705,12 @@ impl Service { membership: MembershipState, } + let server_name = services().globals.server_name(); let content = serde_json::from_str::(pdu.content.get()) .map_err(|_| Error::bad_database("Invalid content in pdu."))?; if content.membership == MembershipState::Leave { - let server_user = format!("@conduit:{}", services().globals.server_name()); + let server_user = format!("@conduit:{}", server_name); if sender == &server_user { warn!("Conduit user cannot leave from admins room"); return Err(Error::BadRequest( @@ -723,7 +724,7 @@ impl Service { .state_cache .room_members(room_id) .filter_map(|m| m.ok()) - .filter(|m| m.server_name() == services().globals.server_name()) + .filter(|m| m.server_name() == server_name) .count(); if count < 3 { warn!("Last admin cannot leave from admins room"); @@ -735,7 +736,7 @@ impl Service { } if content.membership == MembershipState::Ban && pdu.state_key().is_some() { - let server_user = format!("@conduit:{}", services().globals.server_name()); + let server_user = format!("@conduit:{}", server_name); if pdu.state_key().as_ref().unwrap() == &server_user { warn!("Conduit user cannot be banned in admins room"); return Err(Error::BadRequest( @@ -749,7 +750,7 @@ impl Service { .state_cache .room_members(room_id) .filter_map(|m| m.ok()) - .filter(|m| m.server_name() == services().globals.server_name()) + .filter(|m| m.server_name() == server_name) .count(); if count < 3 { warn!("Last admin cannot be banned in admins room"); -- cgit v1.2.3 From e923f63c4919a9eb65f074c8099fc7bc115925ee Mon Sep 17 00:00:00 2001 From: AndSDev Date: Fri, 14 Oct 2022 14:45:05 +0300 Subject: fix(service/rooms/timeline): fix validating for non-joined members --- src/service/rooms/timeline/mod.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 9494f67..403b400 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -705,13 +705,17 @@ impl Service { membership: MembershipState, } + let target = pdu + .state_key() + .filter(|v| v.starts_with("@")) + .unwrap_or(sender.as_str()); let server_name = services().globals.server_name(); + let server_user = format!("@conduit:{}", server_name); let content = serde_json::from_str::(pdu.content.get()) .map_err(|_| Error::bad_database("Invalid content in pdu."))?; if content.membership == MembershipState::Leave { - let server_user = format!("@conduit:{}", server_name); - if sender == &server_user { + if target == &server_user { warn!("Conduit user cannot leave from admins room"); return Err(Error::BadRequest( ErrorKind::Forbidden, @@ -725,8 +729,9 @@ impl Service { .room_members(room_id) .filter_map(|m| m.ok()) .filter(|m| m.server_name() == server_name) + .filter(|m| m != target) .count(); - if count < 3 { + if count < 2 { warn!("Last admin cannot leave from admins room"); return Err(Error::BadRequest( ErrorKind::Forbidden, @@ -736,8 +741,7 @@ impl Service { } if content.membership == MembershipState::Ban && pdu.state_key().is_some() { - let server_user = format!("@conduit:{}", server_name); - if pdu.state_key().as_ref().unwrap() == &server_user { + if target == &server_user { warn!("Conduit user cannot be banned in admins room"); return Err(Error::BadRequest( ErrorKind::Forbidden, @@ -751,8 +755,9 @@ impl Service { .room_members(room_id) .filter_map(|m| m.ok()) .filter(|m| m.server_name() == server_name) + .filter(|m| m != target) .count(); - if count < 3 { + if count < 2 { warn!("Last admin cannot be banned in admins room"); return Err(Error::BadRequest( ErrorKind::Forbidden, -- cgit v1.2.3 From ada15ceacc4a18d53b40a7d84216404ae79aa888 Mon Sep 17 00:00:00 2001 From: Jonathan de Jong Date: Mon, 17 Oct 2022 18:41:45 +0200 Subject: Complement improvements --- .gitignore | 1 + complement/Dockerfile | 47 +++++++++++++++++++++++++++++ complement/caddy.json | 72 +++++++++++++++++++++++++++++++++++++++++++++ tests/Complement.Dockerfile | 48 ------------------------------ 4 files changed, 120 insertions(+), 48 deletions(-) create mode 100644 complement/Dockerfile create mode 100644 complement/caddy.json delete mode 100644 tests/Complement.Dockerfile diff --git a/.gitignore b/.gitignore index f5e9505..f5cbfaa 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,4 @@ conduit.db # Etc. **/*.rs.bk +cached_target \ No newline at end of file diff --git a/complement/Dockerfile b/complement/Dockerfile new file mode 100644 index 0000000..43416fa --- /dev/null +++ b/complement/Dockerfile @@ -0,0 +1,47 @@ +# For use in our CI only. This requires a build artifact created by a previous run pipline stage to be placed in cached_target/release/conduit +FROM registry.gitlab.com/jfowl/conduit-containers/rust-with-tools:commit-16a08e9b as builder +#FROM rust:latest as builder + +WORKDIR /workdir + +ARG RUSTC_WRAPPER +ARG AWS_ACCESS_KEY_ID +ARG AWS_SECRET_ACCESS_KEY +ARG SCCACHE_BUCKET +ARG SCCACHE_ENDPOINT +ARG SCCACHE_S3_USE_SSL + +COPY . . +RUN mkdir -p target/release +RUN test -e cached_target/release/conduit && cp cached_target/release/conduit target/release/conduit || cargo build --release + +## Actual image +FROM debian:bullseye +WORKDIR /workdir + +# Install caddy +RUN apt-get update && apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-testing-archive-keyring.gpg && curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-testing.list && apt-get update && apt-get install -y caddy + +COPY conduit-example.toml conduit.toml +COPY complement/caddy.json caddy.json + +ENV SERVER_NAME=localhost +ENV CONDUIT_CONFIG=/workdir/conduit.toml + +RUN sed -i "s/port = 6167/port = 8008/g" conduit.toml +RUN echo "allow_federation = true" >> conduit.toml +RUN echo "allow_encryption = true" >> conduit.toml +RUN echo "allow_registration = true" >> conduit.toml +RUN echo "log = \"warn,_=off,sled=off\"" >> conduit.toml +RUN sed -i "s/address = \"127.0.0.1\"/address = \"0.0.0.0\"/g" conduit.toml + +COPY --from=builder /workdir/target/release/conduit /workdir/conduit +RUN chmod +x /workdir/conduit + +EXPOSE 8008 8448 + +CMD uname -a && \ + sed -i "s/#server_name = \"your.server.name\"/server_name = \"${SERVER_NAME}\"/g" conduit.toml && \ + sed -i "s/your.server.name/${SERVER_NAME}/g" caddy.json && \ + caddy start --config caddy.json > /dev/null && \ + /workdir/conduit diff --git a/complement/caddy.json b/complement/caddy.json new file mode 100644 index 0000000..ea52c2c --- /dev/null +++ b/complement/caddy.json @@ -0,0 +1,72 @@ +{ + "logging": { + "logs": { + "default": { + "level": "WARN" + } + } + }, + "apps": { + "http": { + "https_port": 8448, + "servers": { + "srv0": { + "listen": [":8448"], + "routes": [{ + "match": [{ + "host": ["your.server.name"] + }], + "handle": [{ + "handler": "subroute", + "routes": [{ + "handle": [{ + "handler": "reverse_proxy", + "upstreams": [{ + "dial": "127.0.0.1:8008" + }] + }] + }] + }], + "terminal": true + }], + "tls_connection_policies": [{ + "match": { + "sni": ["your.server.name"] + } + }] + } + } + }, + "pki": { + "certificate_authorities": { + "local": { + "name": "Complement CA", + "root": { + "certificate": "/complement/ca/ca.crt", + "private_key": "/complement/ca/ca.key" + }, + "intermediate": { + "certificate": "/complement/ca/ca.crt", + "private_key": "/complement/ca/ca.key" + } + } + } + }, + "tls": { + "automation": { + "policies": [{ + "subjects": ["your.server.name"], + "issuers": [{ + "module": "internal" + }], + "on_demand": true + }, { + "issuers": [{ + "module": "internal", + "ca": "local" + }] + }] + } + } + } +} \ No newline at end of file diff --git a/tests/Complement.Dockerfile b/tests/Complement.Dockerfile deleted file mode 100644 index b9d0f8c..0000000 --- a/tests/Complement.Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -# For use in our CI only. This requires a build artifact created by a previous run pipline stage to be placed in cached_target/release/conduit -FROM valkum/docker-rust-ci:latest as builder -WORKDIR /workdir - -ARG RUSTC_WRAPPER -ARG AWS_ACCESS_KEY_ID -ARG AWS_SECRET_ACCESS_KEY -ARG SCCACHE_BUCKET -ARG SCCACHE_ENDPOINT -ARG SCCACHE_S3_USE_SSL - -COPY . . -RUN mkdir -p target/release -RUN test -e cached_target/release/conduit && cp cached_target/release/conduit target/release/conduit || cargo build --release - - -FROM valkum/docker-rust-ci:latest -WORKDIR /workdir - -RUN curl -OL "https://github.com/caddyserver/caddy/releases/download/v2.2.1/caddy_2.2.1_linux_amd64.tar.gz" -RUN tar xzf caddy_2.2.1_linux_amd64.tar.gz - -COPY cached_target/release/conduit /workdir/conduit -RUN chmod +x /workdir/conduit -RUN chmod +x /workdir/caddy - -COPY conduit-example.toml conduit.toml - -ENV SERVER_NAME=localhost -ENV CONDUIT_CONFIG=/workdir/conduit.toml - -RUN sed -i "s/port = 6167/port = 8008/g" conduit.toml -RUN echo "allow_federation = true" >> conduit.toml -RUN echo "allow_encryption = true" >> conduit.toml -RUN echo "allow_registration = true" >> conduit.toml -RUN echo "log = \"warn,_=off,sled=off\"" >> conduit.toml -RUN sed -i "s/address = \"127.0.0.1\"/address = \"0.0.0.0\"/g" conduit.toml - -# Enabled Caddy auto cert generation for complement provided CA. -RUN echo '{"logging":{"logs":{"default":{"level":"WARN"}}}, "apps":{"http":{"https_port":8448,"servers":{"srv0":{"listen":[":8448"],"routes":[{"match":[{"host":["your.server.name"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"127.0.0.1:8008"}]}]}]}],"terminal":true}],"tls_connection_policies": [{"match": {"sni": ["your.server.name"]}}]}}},"pki": {"certificate_authorities": {"local": {"name": "Complement CA","root": {"certificate": "/ca/ca.crt","private_key": "/ca/ca.key"},"intermediate": {"certificate": "/ca/ca.crt","private_key": "/ca/ca.key"}}}},"tls":{"automation":{"policies":[{"subjects":["your.server.name"],"issuer":{"module":"internal"},"on_demand":true},{"issuer":{"module":"internal", "ca": "local"}}]}}}}' > caddy.json - -EXPOSE 8008 8448 - -CMD ([ -z "${COMPLEMENT_CA}" ] && echo "Error: Need Complement PKI support" && true) || \ - sed -i "s/#server_name = \"your.server.name\"/server_name = \"${SERVER_NAME}\"/g" conduit.toml && \ - sed -i "s/your.server.name/${SERVER_NAME}/g" caddy.json && \ - /workdir/caddy start --config caddy.json > /dev/null && \ - /workdir/conduit -- cgit v1.2.3 From 215d909e5986600b8b9eeb07edfff7a90d8f75bb Mon Sep 17 00:00:00 2001 From: Jonathan de Jong Date: Mon, 17 Oct 2022 18:41:59 +0200 Subject: More debug info when try_from_http_request fails --- src/api/ruma_wrapper/axum.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/ruma_wrapper/axum.rs b/src/api/ruma_wrapper/axum.rs index d056f3f..3870250 100644 --- a/src/api/ruma_wrapper/axum.rs +++ b/src/api/ruma_wrapper/axum.rs @@ -281,7 +281,10 @@ where debug!("{:?}", http_request); let body = T::try_from_http_request(http_request, &path_params).map_err(|e| { - warn!("{:?}\n{:?}", e, json_body); + warn!( + "try_from_http_request failed: {:?}\nJSON body: {:?}", + e, json_body + ); Error::BadRequest(ErrorKind::BadJson, "Failed to deserialize request.") })?; -- cgit v1.2.3 From 2a66ad4329c012e482b80deeaf750eb9360d758d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 21 Dec 2022 16:08:05 +0100 Subject: Bump version to 0.6.0-alpha --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7dc6448..019f9ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = ["timokoesters "] homepage = "https://conduit.rs" repository = "https://gitlab.com/famedly/conduit" readme = "README.md" -version = "0.5.0" +version = "0.6.0-alpha" rust-version = "1.64" edition = "2021" -- cgit v1.2.3 From 19156c7bbf8dab7267db235807ea80255ee91e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 21 Dec 2022 16:15:56 +0100 Subject: Update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index e773892..505c71c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,7 +378,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "conduit" -version = "0.5.0" +version = "0.6.0-alpha" dependencies = [ "async-trait", "axum", -- cgit v1.2.3 From 0a4e8e59094b5ace727262820d05899ffa1be3bd Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Fri, 16 Dec 2022 13:06:59 -0800 Subject: update rust toolchain hash --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 924300c..5db8168 100644 --- a/flake.nix +++ b/flake.nix @@ -34,7 +34,7 @@ # This will need to be updated when `package.rust-version` is changed in # `Cargo.toml` - sha256 = "sha256-KXx+ID0y4mg2B3LHp7IyaiMrdexF6octADnAtFIOjrY="; + sha256 = "sha256-8len3i8oTwJSOJZMosGGXHBL5BVuGQnWOT2St5YAUFU="; }; builder = (pkgs.callPackage naersk { -- cgit v1.2.3 From 9f74555c88a7705f393c3175e9bda60aaf438c62 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Fri, 16 Dec 2022 13:09:35 -0800 Subject: update flake.lock --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index 9217ff2..bfe0a9b 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1665815894, - "narHash": "sha256-Vboo1L4NMGLKZKVLnOPi9OHlae7uoNyfgvyIUm+SVXE=", + "lastModified": 1671776618, + "narHash": "sha256-myjhExbKIzZy+kqqFyqvX59KErqYZVNTPsCfgByTOKo=", "owner": "nix-community", "repo": "fenix", - "rev": "2348450241a5f945f0ba07e44ecbfac2f541d7f4", + "rev": "64d1607710b99e72d9afb2cde11bd1c2cea7cb91", "type": "github" }, "original": { @@ -23,11 +23,11 @@ }, "flake-utils": { "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", "owner": "numtide", "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", "type": "github" }, "original": { @@ -43,11 +43,11 @@ ] }, "locked": { - "lastModified": 1662220400, - "narHash": "sha256-9o2OGQqu4xyLZP9K6kNe1pTHnyPz0Wr3raGYnr9AIgY=", + "lastModified": 1671096816, + "narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=", "owner": "nix-community", "repo": "naersk", - "rev": "6944160c19cb591eb85bbf9b2f2768a935623ed3", + "rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114", "type": "github" }, "original": { @@ -58,11 +58,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1665856037, - "narHash": "sha256-/RvIWnGKdTSoIq5Xc2HwPIL0TzRslzU6Rqk4Img6UNg=", + "lastModified": 1671780662, + "narHash": "sha256-Tsc64sN8LLHa7eqDZVVeubI8CyqIjs9l5tQ5EeRlgvM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c95ebc5125ffffcd431df0ad8620f0926b8125b8", + "rev": "339063a22409514cb2baea677b329e618faa6a08", "type": "github" }, "original": { @@ -82,11 +82,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1665765556, - "narHash": "sha256-w9L5j0TIB5ay4aRwzGCp8mgvGsu5dVJQvbEFutwr6xE=", + "lastModified": 1671750139, + "narHash": "sha256-xbL8BZU87rHfQkF3tuFXduNGPW8fDwFI+0fFmRJx66E=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "018b8429cf3fa9d8aed916704e41dfedeb0f4f78", + "rev": "a06525517b0b69cd97f2c39a4012d96f44bf0776", "type": "github" }, "original": { -- cgit v1.2.3 From 315944968b4f84c31f7f1396a8409b4a13e52709 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Fri, 23 Dec 2022 00:20:05 -0800 Subject: remind people to update the hash And offer help since it's pretty easy but impossible if you don't have Nix installed. --- Cargo.toml | 6 +++++- flake.nix | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 019f9ce..16c04bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,13 @@ homepage = "https://conduit.rs" repository = "https://gitlab.com/famedly/conduit" readme = "README.md" version = "0.6.0-alpha" -rust-version = "1.64" edition = "2021" +# When changing this, change the hash near the text "THE rust-version HASH" in +# `/flake.nix` too. If you don't have Nix installed or otherwise don't know how +# to do this, ping `@charles:computer.surgery` in the matrix room. +rust-version = "1.64" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/flake.nix b/flake.nix index 5db8168..e10e8bb 100644 --- a/flake.nix +++ b/flake.nix @@ -32,8 +32,7 @@ # Use the Rust version defined in `Cargo.toml` channel = cargoToml.package.rust-version; - # This will need to be updated when `package.rust-version` is changed in - # `Cargo.toml` + # THE rust-version HASH sha256 = "sha256-8len3i8oTwJSOJZMosGGXHBL5BVuGQnWOT2St5YAUFU="; }; -- cgit v1.2.3 From 112b76b1c134be7514986e30e72c2be5ebda5323 Mon Sep 17 00:00:00 2001 From: r3g_5z Date: Sun, 8 Jan 2023 02:44:25 -0500 Subject: Add Contributor's Covenant Code of Conduct Signed-off-by: r3g_5z --- CODE_OF_CONDUCT.md | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..1b06035 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,134 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement over email at +coc@koesters.xyz or over Matrix at @timo:conduit.rs. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + -- cgit v1.2.3 From 391beddaf4034e114020c707198414fd6e4d141a Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Sun, 8 Jan 2023 12:44:59 -0800 Subject: fix nix docs I made some silly copy paste errors while writing this... --- nix/README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/nix/README.md b/nix/README.md index d92f910..77bad0f 100644 --- a/nix/README.md +++ b/nix/README.md @@ -107,7 +107,7 @@ in recommendedProxySettings = true; virtualHosts = { - "${server_name}" = { + "${matrix_hostname}" = { forceSSL = true; enableACME = true; @@ -124,14 +124,6 @@ in } ]; - extraConfig = '' - merge_slashes off; - ''; - - "${matrix_hostname}" = { - forceSSL = true; - enableACME = true; - locations."/_matrix/" = { proxyPass = "http://backend_conduit$request_uri"; proxyWebsockets = true; @@ -141,6 +133,15 @@ in ''; }; + extraConfig = '' + merge_slashes off; + ''; + }; + + "${server_name}" = { + forceSSL = true; + enableACME = true; + locations."=/.well-known/matrix/server" = { # Use the contents of the derivation built previously alias = "${well_known_server}"; -- cgit v1.2.3 From 844508bc482f0bafab61111b8fad70684368bd8d Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Mon, 9 Jan 2023 08:09:41 -0800 Subject: document `trusted_servers` option --- conduit-example.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/conduit-example.toml b/conduit-example.toml index 0549030..6089aa5 100644 --- a/conduit-example.toml +++ b/conduit-example.toml @@ -43,6 +43,10 @@ allow_federation = true # Enable the display name lightning bolt on registration. enable_lightning_bolt = true +# Servers listed here will be used to gather public keys of other servers. +# Generally, copying this exactly should be enough. (Currently, Conduit doesn't +# support batched key requests, so this list should only contain Synapse +# servers.) trusted_servers = ["matrix.org"] #max_concurrent_requests = 100 # How many requests Conduit sends to other servers at the same time -- cgit v1.2.3 From 809c9b44817faa4b4c4126a11d9bb9e5486ba3c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sat, 14 Jan 2023 21:20:16 +0100 Subject: Maybe fix room joins This is a workaround for https://github.com/hyperium/hyper/issues/2312 --- src/service/globals/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index bb823e2..cd3be08 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -345,6 +345,7 @@ impl Service { fn reqwest_client_builder(config: &Config) -> Result { let mut reqwest_client_builder = reqwest::Client::builder() + .pool_max_idle_per_host(0) .connect_timeout(Duration::from_secs(30)) .timeout(Duration::from_secs(60 * 3)); -- cgit v1.2.3 From 4d589d9788d4c8d038bef243e97035e7ab4aa01b Mon Sep 17 00:00:00 2001 From: digital Date: Wed, 18 Jan 2023 23:21:23 +0100 Subject: feat: support end to bridge encryption by implementing appservice logins --- src/api/client_server/session.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/api/client_server/session.rs b/src/api/client_server/session.rs index 64c0072..f8fc7f1 100644 --- a/src/api/client_server/session.rs +++ b/src/api/client_server/session.rs @@ -26,6 +26,7 @@ pub async fn get_login_types_route( ) -> Result { Ok(get_login_types::v3::Response::new(vec![ get_login_types::v3::LoginType::Password(Default::default()), + get_login_types::v3::LoginType::ApplicationService(Default::default()), ])) } @@ -103,6 +104,27 @@ pub async fn login_route(body: Ruma) -> Result { + info!("hi"); + if !body.from_appservice { + return Err(Error::BadRequest( + ErrorKind::Forbidden, + // TODO: is this the correct response + "Wrong username or password.", + )); + }; + let username = if let UserIdentifier::UserIdOrLocalpart(user_id) = identifier { + user_id.to_lowercase() + } else { + return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type.")); + }; + let user_id = + UserId::parse_with_server_name(username, services().globals.server_name()) + .map_err(|_| { + Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.") + })?; + user_id + } _ => { return Err(Error::BadRequest( ErrorKind::Unknown, -- cgit v1.2.3 From f01b96588dae3ffbfca267a1ff51477decba998a Mon Sep 17 00:00:00 2001 From: The one with the braid Date: Thu, 19 Jan 2023 07:21:04 +0100 Subject: fix: adjust CI config to runner requirements - make use of more stable BTRFS driver - set default pull policy to `if-not-present` Signed-off-by: The one with the braid --- .gitlab-ci.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 91258ea..d05bb89 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,14 +16,17 @@ variables: .docker-shared-settings: stage: "build docker image" - image: jdrouet/docker-with-buildx:20.10.21-0.9.1 + image: + name: jdrouet/docker-with-buildx:20.10.21-0.9.1 + pull_policy: if-not-present needs: [] - tags: ["docker"] + tags: [ "docker" ] variables: # Docker in Docker: DOCKER_HOST: tcp://docker:2375/ DOCKER_TLS_CERTDIR: "" - DOCKER_DRIVER: overlay2 + # Famedly runners use BTRFS, overlayfs and overlay2 often break jobs + DOCKER_DRIVER: btrfs services: - docker:dind script: -- cgit v1.2.3 From e13dc7c14a0c5b318a57e47b37fddd92203d32a6 Mon Sep 17 00:00:00 2001 From: Jonathan de Jong Date: Thu, 26 Jan 2023 18:28:33 +0100 Subject: add little readme --- complement/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 complement/README.md diff --git a/complement/README.md b/complement/README.md new file mode 100644 index 0000000..b86aab3 --- /dev/null +++ b/complement/README.md @@ -0,0 +1,13 @@ +# Running Conduit on Complement + +This assumes that you're familiar with complement, if not, please readme +[their readme](https://github.com/matrix-org/complement#running). + +Complement works with "base images", this directory (and Dockerfile) helps build the conduit complement-ready docker +image. + +To build, `cd` to the base directory of the workspace, and run this: + +`docker build -t complement-conduit:dev -f complement/Dockerfile .` + +Then use `complement-conduit:dev` as a base image for running complement tests. -- cgit v1.2.3 From 5d913f701083e1519a3595190e63193c519fbc6b Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 28 Jan 2023 00:10:21 +0300 Subject: build(nix): fix flake builds --- Cargo.toml | 2 +- flake.lock | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- flake.nix | 124 +++++++++------------ 3 files changed, 398 insertions(+), 100 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16c04bc..e0e3e32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" # When changing this, change the hash near the text "THE rust-version HASH" in # `/flake.nix` too. If you don't have Nix installed or otherwise don't know how # to do this, ping `@charles:computer.surgery` in the matrix room. -rust-version = "1.64" +rust-version = "1.64.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/flake.lock b/flake.lock index bfe0a9b..1bb1123 100644 --- a/flake.lock +++ b/flake.lock @@ -1,18 +1,124 @@ { "nodes": { + "alejandra": { + "inputs": { + "fenix": "fenix", + "flakeCompat": "flakeCompat", + "nixpkgs": [ + "d2n", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1658427149, + "narHash": "sha256-ToD/1z/q5VHsLMrS2h96vjJoLho59eNRtknOUd19ey8=", + "owner": "kamadorueda", + "repo": "alejandra", + "rev": "f5a22afd2adfb249b4e68e0b33aa1f0fb73fb1be", + "type": "github" + }, + "original": { + "owner": "kamadorueda", + "repo": "alejandra", + "type": "github" + } + }, + "all-cabal-json": { + "flake": false, + "locked": { + "lastModified": 1665552503, + "narHash": "sha256-r14RmRSwzv5c+bWKUDaze6pXM7nOsiz1H8nvFHJvufc=", + "owner": "nix-community", + "repo": "all-cabal-json", + "rev": "d7c0434eebffb305071404edcf9d5cd99703878e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "hackage", + "repo": "all-cabal-json", + "type": "github" + } + }, + "crane": { + "flake": false, + "locked": { + "lastModified": 1670900067, + "narHash": "sha256-VXVa+KBfukhmWizaiGiHRVX/fuk66P8dgSFfkVN4/MY=", + "owner": "ipetkov", + "repo": "crane", + "rev": "59b31b41a589c0a65e4a1f86b0e5eac68081468b", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "d2n": { + "inputs": { + "alejandra": "alejandra", + "all-cabal-json": "all-cabal-json", + "crane": "crane", + "devshell": "devshell", + "flake-parts": "flake-parts", + "flake-utils-pre-commit": "flake-utils-pre-commit", + "ghc-utils": "ghc-utils", + "gomod2nix": "gomod2nix", + "mach-nix": "mach-nix", + "nix-pypi-fetcher": "nix-pypi-fetcher", + "nixpkgs": [ + "nixpkgs" + ], + "poetry2nix": "poetry2nix", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1674848374, + "narHash": "sha256-1+xlsmUWzpptK8mLjznwqOLogeicLkxB8tV6XUZbobc=", + "owner": "nix-community", + "repo": "dream2nix", + "rev": "d91e7381fa303be02f70e472207e05b26ce35b41", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "dream2nix", + "type": "github" + } + }, + "devshell": { + "flake": false, + "locked": { + "lastModified": 1663445644, + "narHash": "sha256-+xVlcK60x7VY1vRJbNUEAHi17ZuoQxAIH4S4iUFUGBA=", + "owner": "numtide", + "repo": "devshell", + "rev": "e3dc3e21594fe07bdb24bdf1c8657acaa4cb8f66", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, "fenix": { "inputs": { "nixpkgs": [ + "d2n", + "alejandra", "nixpkgs" ], "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1671776618, - "narHash": "sha256-myjhExbKIzZy+kqqFyqvX59KErqYZVNTPsCfgByTOKo=", + "lastModified": 1657607339, + "narHash": "sha256-HaqoAwlbVVZH2n4P3jN2FFPMpVuhxDy1poNOR7kzODc=", "owner": "nix-community", "repo": "fenix", - "rev": "64d1607710b99e72d9afb2cde11bd1c2cea7cb91", + "rev": "b814c83d9e6aa5a28d0cf356ecfdafb2505ad37d", "type": "github" }, "original": { @@ -21,13 +127,31 @@ "type": "github" } }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1668450977, + "narHash": "sha256-cfLhMhnvXn6x1vPm+Jow3RiFAUSCw/l1utktCw5rVA4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "d591857e9d7dd9ddbfba0ea02b43b927c3c0f1fa", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", "type": "github" }, "original": { @@ -36,57 +160,228 @@ "type": "github" } }, - "naersk": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] + "flake-utils-pre-commit": { + "locked": { + "lastModified": 1644229661, + "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", + "type": "github" }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flakeCompat": { + "flake": false, "locked": { - "lastModified": 1671096816, - "narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=", - "owner": "nix-community", - "repo": "naersk", - "rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114", + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", "type": "github" }, "original": { - "owner": "nix-community", - "repo": "naersk", + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "ghc-utils": { + "flake": false, + "locked": { + "lastModified": 1662774800, + "narHash": "sha256-1Rd2eohGUw/s1tfvkepeYpg8kCEXiIot0RijapUjAkE=", + "ref": "refs/heads/master", + "rev": "bb3a2d3dc52ff0253fb9c2812bd7aa2da03e0fea", + "revCount": 1072, + "type": "git", + "url": "https://gitlab.haskell.org/bgamari/ghc-utils" + }, + "original": { + "type": "git", + "url": "https://gitlab.haskell.org/bgamari/ghc-utils" + } + }, + "gomod2nix": { + "flake": false, + "locked": { + "lastModified": 1627572165, + "narHash": "sha256-MFpwnkvQpauj799b4QTBJQFEddbD02+Ln5k92QyHOSk=", + "owner": "tweag", + "repo": "gomod2nix", + "rev": "67f22dd738d092c6ba88e420350ada0ed4992ae8", + "type": "github" + }, + "original": { + "owner": "tweag", + "repo": "gomod2nix", + "type": "github" + } + }, + "mach-nix": { + "flake": false, + "locked": { + "lastModified": 1634711045, + "narHash": "sha256-m5A2Ty88NChLyFhXucECj6+AuiMZPHXNbw+9Kcs7F6Y=", + "owner": "DavHau", + "repo": "mach-nix", + "rev": "4433f74a97b94b596fa6cd9b9c0402104aceef5d", + "type": "github" + }, + "original": { + "id": "mach-nix", + "type": "indirect" + } + }, + "nix-pypi-fetcher": { + "flake": false, + "locked": { + "lastModified": 1669065297, + "narHash": "sha256-UStjXjNIuIm7SzMOWvuYWIHBkPUKQ8Id63BMJjnIDoA=", + "owner": "DavHau", + "repo": "nix-pypi-fetcher", + "rev": "a9885ac6a091576b5195d547ac743d45a2a615ac", + "type": "github" + }, + "original": { + "owner": "DavHau", + "repo": "nix-pypi-fetcher", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1671780662, - "narHash": "sha256-Tsc64sN8LLHa7eqDZVVeubI8CyqIjs9l5tQ5EeRlgvM=", + "lastModified": 1674641431, + "narHash": "sha256-qfo19qVZBP4qn5M5gXc/h1MDgAtPA5VxJm9s8RUAkVk=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9b97ad7b4330aacda9b2343396eb3df8a853b4fc", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1665349835, + "narHash": "sha256-UK4urM3iN80UXQ7EaOappDzcisYIuEURFRoGQ/yPkug=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "34c5293a71ffdb2fe054eb5288adc1882c1eb0b1", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib_2": { + "locked": { + "dir": "lib", + "lastModified": 1672350804, + "narHash": "sha256-jo6zkiCabUBn3ObuKXHGqqORUMH27gYDIFFfLq5P4wg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "339063a22409514cb2baea677b329e618faa6a08", + "rev": "677ed08a50931e38382dbef01cba08a8f7eac8f6", "type": "github" }, "original": { + "dir": "lib", "owner": "NixOS", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, + "parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib_2" + }, + "locked": { + "lastModified": 1674771137, + "narHash": "sha256-Zpk1GbEsYrqKmuIZkx+f+8pU0qcCYJoSUwNz1Zk+R00=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "7c7a8bce3dffe71203dcd4276504d1cb49dfe05f", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "poetry2nix": { + "flake": false, + "locked": { + "lastModified": 1666918719, + "narHash": "sha256-BkK42fjAku+2WgCOv2/1NrPa754eQPV7gPBmoKQBWlc=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "289efb187123656a116b915206e66852f038720e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "1.36.0", + "repo": "poetry2nix", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-utils": [ + "d2n", + "flake-utils-pre-commit" + ], + "nixpkgs": [ + "d2n", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1646153636, + "narHash": "sha256-AlWHMzK+xJ1mG267FdT8dCq/HvLCA6jwmx2ZUy5O8tY=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "b6bc0b21e1617e2b07d8205e7fae7224036dfa4b", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { - "fenix": "fenix", - "flake-utils": "flake-utils", - "naersk": "naersk", - "nixpkgs": "nixpkgs" + "d2n": "d2n", + "nixpkgs": "nixpkgs", + "parts": "parts", + "rust-overlay": "rust-overlay" } }, "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1671750139, - "narHash": "sha256-xbL8BZU87rHfQkF3tuFXduNGPW8fDwFI+0fFmRJx66E=", + "lastModified": 1657557289, + "narHash": "sha256-PRW+nUwuqNTRAEa83SfX+7g+g8nQ+2MMbasQ9nt6+UM=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "a06525517b0b69cd97f2c39a4012d96f44bf0776", + "rev": "caf23f29144b371035b864a1017dbc32573ad56d", "type": "github" }, "original": { @@ -95,6 +390,27 @@ "repo": "rust-analyzer", "type": "github" } + }, + "rust-overlay": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1674786480, + "narHash": "sha256-n25V3Ug/dJewbJaxj1gL0cUMBdOonrVkIQCHd9yHHvw=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "296dd673b46aaebe1c8355f1848ceb7c905dda35", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index e10e8bb..f4db253 100644 --- a/flake.nix +++ b/flake.nix @@ -1,74 +1,56 @@ { - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs"; - flake-utils.url = "github:numtide/flake-utils"; - - fenix = { - url = "github:nix-community/fenix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - naersk = { - url = "github:nix-community/naersk"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - }; - - outputs = - { self - , nixpkgs - , flake-utils - - , fenix - , naersk - }: flake-utils.lib.eachDefaultSystem (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - - # Nix-accessible `Cargo.toml` - cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); - - # The Rust toolchain to use - toolchain = fenix.packages.${system}.toolchainOf { - # Use the Rust version defined in `Cargo.toml` - channel = cargoToml.package.rust-version; - - # THE rust-version HASH - sha256 = "sha256-8len3i8oTwJSOJZMosGGXHBL5BVuGQnWOT2St5YAUFU="; + inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + inputs.d2n.url = "github:nix-community/dream2nix"; + inputs.d2n.inputs.nixpkgs.follows = "nixpkgs"; + inputs.parts.url = "github:hercules-ci/flake-parts"; + inputs.rust-overlay.url = "github:oxalica/rust-overlay"; + inputs.rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; + + outputs = inp: + inp.parts.lib.mkFlake {inputs = inp;} { + systems = ["x86_64-linux"]; + imports = [inp.d2n.flakeModuleBeta]; + perSystem = { + config, + system, + pkgs, + ... + }: let + cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); + pkgsWithToolchain = pkgs.appendOverlays [inp.rust-overlay.overlays.default]; + + toolchains = pkgsWithToolchain.rust-bin.stable."${cargoToml.package.rust-version}"; + # toolchain to use when building conduit, includes only cargo and rustc to reduce closure size + buildToolchain = toolchains.minimal; + # toolchain to use in development shell + # the "default" component set of toolchain adds rustfmt, clippy etc. + devToolchain = toolchains.default.override { + extensions = ["rust-src"]; + }; + + # flake outputs for conduit project + conduitOutputs = config.dream2nix.outputs.conduit; + in { + dream2nix.inputs.conduit = { + source = inp.self; + projects.conduit = { + name = "conduit"; + subsystem = "rust"; + translator = "cargo-lock"; + }; + packageOverrides = { + "^.*".set-toolchain.overrideRustToolchain = _: { + cargo = buildToolchain; + rustc = buildToolchain; + }; + }; + }; + devShells.conduit = conduitOutputs.devShells.conduit.overrideAttrs (old: { + # export default crate sources for rust-analyzer to read + RUST_SRC_PATH = "${devToolchain}/lib/rustlib/src/rust/library"; + nativeBuildInputs = (old.nativeBuildInputs or []) ++ [devToolchain]; + }); + devShells.default = config.devShells.conduit; }; - - builder = (pkgs.callPackage naersk { - inherit (toolchain) rustc cargo; - }).buildPackage; - in - { - packages.default = builder { - src = ./.; - - nativeBuildInputs = (with pkgs.rustPlatform; [ - bindgenHook - ]); - }; - - devShells.default = pkgs.mkShell { - # Rust Analyzer needs to be able to find the path to default crate - # sources, and it can read this environment variable to do so - RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library"; - - # Development tools - nativeBuildInputs = (with pkgs.rustPlatform; [ - bindgenHook - ]) ++ (with toolchain; [ - cargo - clippy - rust-src - rustc - rustfmt - ]); - }; - - checks = { - packagesDefault = self.packages.${system}.default; - devShellsDefault = self.devShells.${system}.default; - }; - }); + }; } -- cgit v1.2.3 From 11b9cfad5e326e0abbd9b05758e2e72abb3be93c Mon Sep 17 00:00:00 2001 From: Yusuf Bera Ertan Date: Sat, 28 Jan 2023 00:14:58 +0300 Subject: docs: update nix comment for rust-version in Cargo.toml --- Cargo.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e0e3e32..36ffb13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,9 +9,10 @@ readme = "README.md" version = "0.6.0-alpha" edition = "2021" -# When changing this, change the hash near the text "THE rust-version HASH" in -# `/flake.nix` too. If you don't have Nix installed or otherwise don't know how -# to do this, ping `@charles:computer.surgery` in the matrix room. +# When changing this, make sure to update the `flake.lock` file by running +# `nix flake update`. If you don't have Nix installed or otherwise don't know +# how to do this, ping `@charles:computer.surgery` or `@dusk:gaze.systems` in +# the matrix room. rust-version = "1.64.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -- cgit v1.2.3 From cfcc9086ff4890131d498ed434d7934e23c5f060 Mon Sep 17 00:00:00 2001 From: Moritz Heiber Date: Fri, 27 Jan 2023 22:43:04 +0000 Subject: Add a dynamic address resolution to the Docker healthcheck --- docker/healthcheck.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docker/healthcheck.sh b/docker/healthcheck.sh index 42b2e10..62f2f98 100644 --- a/docker/healthcheck.sh +++ b/docker/healthcheck.sh @@ -6,9 +6,14 @@ if [ -z "${CONDUIT_PORT}" ]; then CONDUIT_PORT=$(ss -tlpn | grep conduit | grep -m1 -o ':[0-9]*' | grep -m1 -o '[0-9]*') fi +# If CONDUIT_ADDRESS is not set try to get the address from the process list +if [ -z "${CONDUIT_ADDRESS}" ]; then + CONDUIT_ADDRESS=$(ss -tlpn | awk -F ' +|:' '/conduit/ { print $4 }') +fi + # The actual health check. # We try to first get a response on HTTP and when that fails on HTTPS and when that fails, we exit with code 1. # TODO: Change this to a single wget call. Do we have a config value that we can check for that? -wget --no-verbose --tries=1 --spider "http://localhost:${CONDUIT_PORT}/_matrix/client/versions" || \ - wget --no-verbose --tries=1 --spider "https://localhost:${CONDUIT_PORT}/_matrix/client/versions" || \ +wget --no-verbose --tries=1 --spider "http://${CONDUIT_ADDRESS}:${CONDUIT_PORT}/_matrix/client/versions" || \ + wget --no-verbose --tries=1 --spider "https://${CONDUIT_ADDRESS}:${CONDUIT_PORT}/_matrix/client/versions" || \ exit 1 -- cgit v1.2.3 From a4f18f99ad2d02635fb72a0053d551878339ffca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 7 Feb 2023 15:26:34 +0100 Subject: fix: ignore bad user ids --- src/database/mod.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index 78bb358..46ba5b3 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -800,10 +800,17 @@ impl KeyValueDatabase { } if services().globals.database_version()? < 12 { - for username in services().users.list_local_users().unwrap() { - let user = - UserId::parse_with_server_name(username, services().globals.server_name()) - .unwrap(); + for username in services().users.list_local_users()? { + let user = match UserId::parse_with_server_name( + username.clone(), + services().globals.server_name(), + ) { + Ok(u) => u, + Err(e) => { + warn!("Invalid username {username}: {e}"); + continue; + } + }; let raw_rules_list = services() .account_data -- cgit v1.2.3 From fc0aff20cfcc30350d87994ee518fd1bec7ce088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sat, 11 Feb 2023 12:43:41 +0100 Subject: fix: allow reactivation of users using reset-password admin command --- src/service/admin/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index 77f351a..b6609e1 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -556,7 +556,6 @@ impl Service { // Check if the specified user is valid if !services().users.exists(&user_id)? - || services().users.is_deactivated(&user_id)? || user_id == UserId::parse_with_server_name( "conduit", @@ -565,7 +564,7 @@ impl Service { .expect("conduit user exists") { return Ok(RoomMessageEventContent::text_plain( - "The specified user does not exist or is deactivated!", + "The specified user does not exist!", )); } @@ -600,12 +599,12 @@ impl Service { }; if user_id.is_historical() { return Ok(RoomMessageEventContent::text_plain(format!( - "userid {user_id} is not allowed due to historical" + "Userid {user_id} is not allowed due to historical" ))); } if services().users.exists(&user_id)? { return Ok(RoomMessageEventContent::text_plain(format!( - "userid {user_id} already exists" + "Userid {user_id} already exists" ))); } // Create user -- cgit v1.2.3 From 23b18d71eef78544148746d30d8b9630998a3a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sat, 18 Feb 2023 13:20:20 +0100 Subject: feat: handle backfill requests Based on https://gitlab.com/famedly/conduit/-/merge_requests/421 --- src/api/server_server.rs | 83 ++++++++++++++++++++++- src/main.rs | 1 + src/service/mod.rs | 7 +- src/service/rooms/state_accessor/mod.rs | 114 +++++++++++++++++++++++++++++++- 4 files changed, 199 insertions(+), 6 deletions(-) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index fc3e2c0..11a6cbf 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -12,6 +12,7 @@ use ruma::{ client::error::{Error as RumaError, ErrorKind}, federation::{ authorization::get_event_authorization, + backfill::get_backfill, device::get_devices::{self, v1::UserDevice}, directory::{get_public_rooms, get_public_rooms_filtered}, discovery::{get_server_keys, get_server_version, ServerSigningKeys, VerifyKey}, @@ -42,8 +43,9 @@ use ruma::{ }, serde::{Base64, JsonObject, Raw}, to_device::DeviceIdOrAllDevices, - CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, - OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, RoomId, ServerName, + uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, + OwnedEventId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, RoomId, + ServerName, }; use serde_json::value::{to_raw_value, RawValue as RawJsonValue}; use std::{ @@ -950,6 +952,83 @@ pub async fn get_event_route( }) } +/// # `GET /_matrix/federation/v1/backfill/` +/// +/// Retrieves events from before the sender joined the room, if the room's +/// history visibility allows. +pub async fn get_backfill_route( + body: Ruma, +) -> Result { + if !services().globals.allow_federation() { + return Err(Error::bad_config("Federation is disabled.")); + } + + let sender_servername = body + .sender_servername + .as_ref() + .expect("server is authenticated"); + + info!("Got backfill request from: {}", sender_servername); + + if !services() + .rooms + .state_cache + .server_in_room(sender_servername, &body.room_id)? + { + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Server is not in room.", + )); + } + + services() + .rooms + .event_handler + .acl_check(sender_servername, &body.room_id)?; + + let until = body + .v + .iter() + .map(|eventid| services().rooms.timeline.get_pdu_count(eventid)) + .filter_map(|r| r.ok().flatten()) + .max() + .ok_or(Error::BadRequest( + ErrorKind::InvalidParam, + "No known eventid in v", + ))?; + + let limit = body.limit.min(uint!(100)); + + let all_events = services() + .rooms + .timeline + .pdus_until(&user_id!("@doesntmatter:conduit.rs"), &body.room_id, until)? + .take(limit.try_into().unwrap()); + + let events = all_events + .filter_map(|r| r.ok()) + .filter(|(_, e)| { + matches!( + services().rooms.state_accessor.server_can_see_event( + sender_servername, + &e.room_id, + &e.event_id, + ), + Ok(true), + ) + }) + .map(|(pdu_id, _)| services().rooms.timeline.get_pdu_json_from_id(&pdu_id)) + .filter_map(|r| r.ok().flatten()) + .map(|pdu| PduEvent::convert_to_outgoing_federation_event(pdu)) + .collect(); + + Ok(get_backfill::v1::Response { + origin: services().globals.server_name().to_owned(), + origin_server_ts: MilliSecondsSinceUnixEpoch::now(), + pdus: events, + }) +} + /// # `POST /_matrix/federation/v1/get_missing_events/{roomId}` /// /// Retrieves events that the sender is missing. diff --git a/src/main.rs b/src/main.rs index da80507..fe6cfc0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -390,6 +390,7 @@ fn routes() -> Router { .ruma_route(server_server::get_public_rooms_filtered_route) .ruma_route(server_server::send_transaction_message_route) .ruma_route(server_server::get_event_route) + .ruma_route(server_server::get_backfill_route) .ruma_route(server_server::get_missing_events_route) .ruma_route(server_server::get_event_authorization_route) .ruma_route(server_server::get_room_state_route) diff --git a/src/service/mod.rs b/src/service/mod.rs index 385dcc6..07d80a1 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -77,7 +77,12 @@ impl Services { search: rooms::search::Service { db }, short: rooms::short::Service { db }, state: rooms::state::Service { db }, - state_accessor: rooms::state_accessor::Service { db }, + state_accessor: rooms::state_accessor::Service { + db, + server_visibility_cache: Mutex::new(LruCache::new( + (100.0 * config.conduit_cache_capacity_modifier) as usize, + )), + }, state_cache: rooms::state_cache::Service { db }, state_compressor: rooms::state_compressor::Service { db, diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index 87d9936..e940ffa 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -1,13 +1,28 @@ mod data; -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; pub use data::Data; -use ruma::{events::StateEventType, EventId, RoomId}; +use lru_cache::LruCache; +use ruma::{ + events::{ + room::{ + history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, + member::{MembershipState, RoomMemberEventContent}, + }, + StateEventType, + }, + EventId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId, +}; +use tracing::error; -use crate::{PduEvent, Result}; +use crate::{services, Error, PduEvent, Result}; pub struct Service { pub db: &'static dyn Data, + pub server_visibility_cache: Mutex>, } impl Service { @@ -46,6 +61,99 @@ impl Service { self.db.state_get(shortstatehash, event_type, state_key) } + /// Get membership for given user in state + fn user_membership(&self, shortstatehash: u64, user_id: &UserId) -> Result { + self.state_get( + shortstatehash, + &StateEventType::RoomMember, + user_id.as_str(), + )? + .map_or(Ok(MembershipState::Leave), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomMemberEventContent| c.membership) + .map_err(|_| Error::bad_database("Invalid room membership event in database.")) + }) + } + + /// The user was a joined member at this state (potentially in the past) + fn user_was_joined(&self, shortstatehash: u64, user_id: &UserId) -> bool { + self.user_membership(shortstatehash, user_id) + .map(|s| s == MembershipState::Join) + .unwrap_or_default() // Return sensible default, i.e. false + } + + /// The user was an invited or joined room member at this state (potentially + /// in the past) + fn user_was_invited(&self, shortstatehash: u64, user_id: &UserId) -> bool { + self.user_membership(shortstatehash, user_id) + .map(|s| s == MembershipState::Join || s == MembershipState::Invite) + .unwrap_or_default() // Return sensible default, i.e. false + } + + /// Whether a server is allowed to see an event through federation, based on + /// the room's history_visibility at that event's state. + #[tracing::instrument(skip(self))] + pub fn server_can_see_event( + &self, + origin: &ServerName, + room_id: &RoomId, + event_id: &EventId, + ) -> Result { + let shortstatehash = match self.pdu_shortstatehash(event_id)? { + Some(shortstatehash) => shortstatehash, + None => return Ok(false), + }; + + if let Some(visibility) = self + .server_visibility_cache + .lock() + .unwrap() + .get_mut(&(origin.to_owned(), shortstatehash)) + { + return Ok(*visibility); + } + + let history_visibility = self + .state_get(shortstatehash, &StateEventType::RoomHistoryVisibility, "")? + .map_or(Ok(HistoryVisibility::Shared), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomHistoryVisibilityEventContent| c.history_visibility) + .map_err(|_| { + Error::bad_database("Invalid history visibility event in database.") + }) + })?; + + let mut current_server_members = services() + .rooms + .state_cache + .room_members(room_id) + .filter_map(|r| r.ok()) + .filter(|member| member.server_name() == origin); + + let visibility = match history_visibility { + HistoryVisibility::WorldReadable | HistoryVisibility::Shared => true, + HistoryVisibility::Invited => { + // Allow if any member on requesting server was AT LEAST invited, else deny + current_server_members.any(|member| self.user_was_invited(shortstatehash, &member)) + } + HistoryVisibility::Joined => { + // Allow if any member on requested server was joined, else deny + current_server_members.any(|member| self.user_was_joined(shortstatehash, &member)) + } + _ => { + error!("Unknown history visibility {history_visibility}"); + false + } + }; + + self.server_visibility_cache + .lock() + .unwrap() + .insert((origin.to_owned(), shortstatehash), visibility); + + Ok(visibility) + } + /// Returns the state hash for this pdu. pub fn pdu_shortstatehash(&self, event_id: &EventId) -> Result> { self.db.pdu_shortstatehash(event_id) -- cgit v1.2.3 From 7bdd9660aa51b2d3d0d39b35b14e49c3e4d6a23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 20 Feb 2023 22:59:45 +0100 Subject: feat: ask for backfill --- src/api/client_server/context.rs | 33 ++--- src/api/client_server/membership.rs | 6 +- src/api/client_server/message.rs | 52 +++---- src/api/client_server/read_marker.rs | 60 +++++--- src/api/client_server/sync.rs | 34 ++--- src/api/server_server.rs | 64 +++++---- src/database/key_value/rooms/timeline.rs | 237 +++++++++++++++++++------------ src/database/mod.rs | 11 +- src/service/rooms/lazy_loading/mod.rs | 8 +- src/service/rooms/state_accessor/mod.rs | 2 +- src/service/rooms/timeline/data.rs | 36 ++--- src/service/rooms/timeline/mod.rs | 228 ++++++++++++++++++++++++----- 12 files changed, 502 insertions(+), 269 deletions(-) diff --git a/src/api/client_server/context.rs b/src/api/client_server/context.rs index 1e62f91..fa3c754 100644 --- a/src/api/client_server/context.rs +++ b/src/api/client_server/context.rs @@ -27,25 +27,24 @@ pub async fn get_context_route( let mut lazy_loaded = HashSet::new(); - let base_pdu_id = services() + let base_token = services() .rooms .timeline - .get_pdu_id(&body.event_id)? + .get_pdu_count(&body.event_id)? .ok_or(Error::BadRequest( ErrorKind::NotFound, "Base event id not found.", ))?; - let base_token = services().rooms.timeline.pdu_count(&base_pdu_id)?; - - let base_event = services() - .rooms - .timeline - .get_pdu_from_id(&base_pdu_id)? - .ok_or(Error::BadRequest( - ErrorKind::NotFound, - "Base event not found.", - ))?; + let base_event = + services() + .rooms + .timeline + .get_pdu(&body.event_id)? + .ok_or(Error::BadRequest( + ErrorKind::NotFound, + "Base event not found.", + ))?; let room_id = base_event.room_id.clone(); @@ -97,10 +96,7 @@ pub async fn get_context_route( } } - let start_token = events_before - .last() - .and_then(|(pdu_id, _)| services().rooms.timeline.pdu_count(pdu_id).ok()) - .map(|count| count.to_string()); + let start_token = events_before.last().map(|(count, _)| count.stringify()); let events_before: Vec<_> = events_before .into_iter() @@ -151,10 +147,7 @@ pub async fn get_context_route( .state_full_ids(shortstatehash) .await?; - let end_token = events_after - .last() - .and_then(|(pdu_id, _)| services().rooms.timeline.pdu_count(pdu_id).ok()) - .map(|count| count.to_string()); + let end_token = events_after.last().map(|(count, _)| count.stringify()); let events_after: Vec<_> = events_after .into_iter() diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index 61c67cb..cd0cc7a 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -714,8 +714,10 @@ async fn join_room_by_id_helper( .ok()? }, ) - .map_err(|_e| Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed"))? - { + .map_err(|e| { + warn!("Auth check failed: {e}"); + Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed") + })? { return Err(Error::BadRequest( ErrorKind::InvalidParam, "Auth check failed", diff --git a/src/api/client_server/message.rs b/src/api/client_server/message.rs index 6ad0751..a0c9571 100644 --- a/src/api/client_server/message.rs +++ b/src/api/client_server/message.rs @@ -1,4 +1,7 @@ -use crate::{service::pdu::PduBuilder, services, utils, Error, Result, Ruma}; +use crate::{ + service::{pdu::PduBuilder, rooms::timeline::PduCount}, + services, utils, Error, Result, Ruma, +}; use ruma::{ api::client::{ error::ErrorKind, @@ -122,17 +125,17 @@ pub async fn get_message_events_route( } let from = match body.from.clone() { - Some(from) => from - .parse() - .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from` value."))?, - + Some(from) => PduCount::try_from_string(&from)?, None => match body.dir { - ruma::api::client::Direction::Forward => 0, - ruma::api::client::Direction::Backward => u64::MAX, + ruma::api::client::Direction::Forward => PduCount::min(), + ruma::api::client::Direction::Backward => PduCount::max(), }, }; - let to = body.to.as_ref().map(|t| t.parse()); + let to = body + .to + .as_ref() + .and_then(|t| PduCount::try_from_string(&t).ok()); services().rooms.lazy_loading.lazy_load_confirm_delivery( sender_user, @@ -158,15 +161,7 @@ pub async fn get_message_events_route( .pdus_after(sender_user, &body.room_id, from)? .take(limit) .filter_map(|r| r.ok()) // Filter out buggy events - .filter_map(|(pdu_id, pdu)| { - services() - .rooms - .timeline - .pdu_count(&pdu_id) - .map(|pdu_count| (pdu_count, pdu)) - .ok() - }) - .take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to` + .take_while(|&(k, _)| Some(k) != to) // Stop at `to` .collect(); for (_, event) in &events_after { @@ -192,26 +187,23 @@ pub async fn get_message_events_route( .map(|(_, pdu)| pdu.to_room_event()) .collect(); - resp.start = from.to_string(); - resp.end = next_token.map(|count| count.to_string()); + resp.start = from.stringify(); + resp.end = next_token.map(|count| count.stringify()); resp.chunk = events_after; } ruma::api::client::Direction::Backward => { + services() + .rooms + .timeline + .backfill_if_required(&body.room_id, from) + .await?; let events_before: Vec<_> = services() .rooms .timeline .pdus_until(sender_user, &body.room_id, from)? .take(limit) .filter_map(|r| r.ok()) // Filter out buggy events - .filter_map(|(pdu_id, pdu)| { - services() - .rooms - .timeline - .pdu_count(&pdu_id) - .map(|pdu_count| (pdu_count, pdu)) - .ok() - }) - .take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to` + .take_while(|&(k, _)| Some(k) != to) // Stop at `to` .collect(); for (_, event) in &events_before { @@ -237,8 +229,8 @@ pub async fn get_message_events_route( .map(|(_, pdu)| pdu.to_room_event()) .collect(); - resp.start = from.to_string(); - resp.end = next_token.map(|count| count.to_string()); + resp.start = from.stringify(); + resp.end = next_token.map(|count| count.stringify()); resp.chunk = events_before; } } diff --git a/src/api/client_server/read_marker.rs b/src/api/client_server/read_marker.rs index b12468a..a5553d2 100644 --- a/src/api/client_server/read_marker.rs +++ b/src/api/client_server/read_marker.rs @@ -1,4 +1,4 @@ -use crate::{services, Error, Result, Ruma}; +use crate::{service::rooms::timeline::PduCount, services, Error, Result, Ruma}; use ruma::{ api::client::{error::ErrorKind, read_marker::set_read_marker, receipt::create_receipt}, events::{ @@ -42,18 +42,28 @@ pub async fn set_read_marker_route( } if let Some(event) = &body.private_read_receipt { - services().rooms.edus.read_receipt.private_read_set( - &body.room_id, - sender_user, - services() - .rooms - .timeline - .get_pdu_count(event)? - .ok_or(Error::BadRequest( + let count = services() + .rooms + .timeline + .get_pdu_count(event)? + .ok_or(Error::BadRequest( + ErrorKind::InvalidParam, + "Event does not exist.", + ))?; + let count = match count { + PduCount::Backfilled(_) => { + return Err(Error::BadRequest( ErrorKind::InvalidParam, - "Event does not exist.", - ))?, - )?; + "Read receipt is in backfilled timeline", + )) + } + PduCount::Normal(c) => c, + }; + services() + .rooms + .edus + .read_receipt + .private_read_set(&body.room_id, sender_user, count)?; } if let Some(event) = &body.read_receipt { @@ -142,17 +152,27 @@ pub async fn create_receipt_route( )?; } create_receipt::v3::ReceiptType::ReadPrivate => { + let count = services() + .rooms + .timeline + .get_pdu_count(&body.event_id)? + .ok_or(Error::BadRequest( + ErrorKind::InvalidParam, + "Event does not exist.", + ))?; + let count = match count { + PduCount::Backfilled(_) => { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Read receipt is in backfilled timeline", + )) + } + PduCount::Normal(c) => c, + }; services().rooms.edus.read_receipt.private_read_set( &body.room_id, sender_user, - services() - .rooms - .timeline - .get_pdu_count(&body.event_id)? - .ok_or(Error::BadRequest( - ErrorKind::InvalidParam, - "Event does not exist.", - ))?, + count, )?; } _ => return Err(Error::bad_database("Unsupported receipt type")), diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 568a23c..834438c 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -1,4 +1,4 @@ -use crate::{services, Error, Result, Ruma, RumaResponse}; +use crate::{service::rooms::timeline::PduCount, services, Error, Result, Ruma, RumaResponse}; use ruma::{ api::client::{ filter::{FilterDefinition, LazyLoadOptions}, @@ -172,6 +172,7 @@ async fn sync_helper( let watcher = services().globals.watch(&sender_user, &sender_device); let next_batch = services().globals.current_count()?; + let next_batchcount = PduCount::Normal(next_batch); let next_batch_string = next_batch.to_string(); // Load filter @@ -197,6 +198,7 @@ async fn sync_helper( .clone() .and_then(|string| string.parse().ok()) .unwrap_or(0); + let sincecount = PduCount::Normal(since); let mut presence_updates = HashMap::new(); let mut left_encrypted_users = HashSet::new(); // Users that have left any encrypted rooms the sender was in @@ -241,12 +243,12 @@ async fn sync_helper( .rooms .timeline .last_timeline_count(&sender_user, &room_id)? - > since + > sincecount { let mut non_timeline_pdus = services() .rooms .timeline - .pdus_until(&sender_user, &room_id, u64::MAX)? + .pdus_until(&sender_user, &room_id, PduCount::max())? .filter_map(|r| { // Filter out buggy events if r.is_err() { @@ -254,13 +256,7 @@ async fn sync_helper( } r.ok() }) - .take_while(|(pduid, _)| { - services() - .rooms - .timeline - .pdu_count(pduid) - .map_or(false, |count| count > since) - }); + .take_while(|(pducount, _)| pducount > &sincecount); // Take the last 10 events for the timeline timeline_pdus = non_timeline_pdus @@ -295,7 +291,7 @@ async fn sync_helper( &sender_user, &sender_device, &room_id, - since, + sincecount, )?; // Database queries: @@ -492,7 +488,7 @@ async fn sync_helper( &sender_device, &room_id, lazy_loaded, - next_batch, + next_batchcount, ); ( @@ -582,7 +578,7 @@ async fn sync_helper( &sender_device, &room_id, lazy_loaded, - next_batch, + next_batchcount, ); let encrypted_room = services() @@ -711,10 +707,14 @@ async fn sync_helper( let prev_batch = timeline_pdus .first() - .map_or(Ok::<_, Error>(None), |(pdu_id, _)| { - Ok(Some( - services().rooms.timeline.pdu_count(pdu_id)?.to_string(), - )) + .map_or(Ok::<_, Error>(None), |(pdu_count, _)| { + Ok(Some(match pdu_count { + PduCount::Backfilled(_) => { + error!("timeline in backfill state?!"); + "0".to_owned() + } + PduCount::Normal(c) => c.to_string(), + })) })?; let room_events: Vec<_> = timeline_pdus diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 11a6cbf..e95a560 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -629,6 +629,37 @@ pub async fn get_public_rooms_route( }) } +pub fn parse_incoming_pdu( + pdu: &RawJsonValue, +) -> Result<(OwnedEventId, CanonicalJsonObject, OwnedRoomId)> { + let value: CanonicalJsonObject = serde_json::from_str(pdu.get()).map_err(|e| { + warn!("Error parsing incoming event {:?}: {:?}", pdu, e); + Error::BadServerResponse("Invalid PDU in server response") + })?; + + let room_id: OwnedRoomId = value + .get("room_id") + .and_then(|id| RoomId::parse(id.as_str()?).ok()) + .ok_or(Error::BadRequest( + ErrorKind::InvalidParam, + "Invalid room id in pdu", + ))?; + + let room_version_id = services().rooms.state.get_room_version(&room_id)?; + + let (event_id, value) = match gen_event_id_canonical_json(&pdu, &room_version_id) { + Ok(t) => t, + Err(_) => { + // Event could not be converted to canonical json + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Could not convert event to canonical json.", + )); + } + }; + Ok((event_id, value, room_id)) +} + /// # `PUT /_matrix/federation/v1/send/{txnId}` /// /// Push EDUs and PDUs to this server. @@ -657,36 +688,7 @@ pub async fn send_transaction_message_route( // let mut auth_cache = EventMap::new(); for pdu in &body.pdus { - let value: CanonicalJsonObject = serde_json::from_str(pdu.get()).map_err(|e| { - warn!("Error parsing incoming event {:?}: {:?}", pdu, e); - Error::BadServerResponse("Invalid PDU in server response") - })?; - - let room_id: OwnedRoomId = match value - .get("room_id") - .and_then(|id| RoomId::parse(id.as_str()?).ok()) - { - Some(id) => id, - None => { - // Event is invalid - continue; - } - }; - - let room_version_id = match services().rooms.state.get_room_version(&room_id) { - Ok(v) => v, - Err(_) => { - continue; - } - }; - - let (event_id, value) = match gen_event_id_canonical_json(pdu, &room_version_id) { - Ok(t) => t, - Err(_) => { - // Event could not be converted to canonical json - continue; - } - }; + let (event_id, value, room_id) = parse_incoming_pdu(&pdu)?; // We do not add the event_id field to the pdu here because of signature and hashes checks services() @@ -1017,7 +1019,7 @@ pub async fn get_backfill_route( Ok(true), ) }) - .map(|(pdu_id, _)| services().rooms.timeline.get_pdu_json_from_id(&pdu_id)) + .map(|(_, pdu)| services().rooms.timeline.get_pdu_json(&pdu.event_id)) .filter_map(|r| r.ok().flatten()) .map(|pdu| PduEvent::convert_to_outgoing_federation_event(pdu)) .collect(); diff --git a/src/database/key_value/rooms/timeline.rs b/src/database/key_value/rooms/timeline.rs index 336317d..9f2c607 100644 --- a/src/database/key_value/rooms/timeline.rs +++ b/src/database/key_value/rooms/timeline.rs @@ -7,6 +7,8 @@ use tracing::error; use crate::{database::KeyValueDatabase, service, services, utils, Error, PduEvent, Result}; +use service::rooms::timeline::PduCount; + impl service::rooms::timeline::Data for KeyValueDatabase { fn first_pdu_in_room(&self, room_id: &RoomId) -> Result>> { let prefix = services() @@ -30,7 +32,7 @@ impl service::rooms::timeline::Data for KeyValueDatabase { .transpose() } - fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result { + fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result { match self .lasttimelinecount_cache .lock() @@ -39,20 +41,18 @@ impl service::rooms::timeline::Data for KeyValueDatabase { { hash_map::Entry::Vacant(v) => { if let Some(last_count) = self - .pdus_until(sender_user, room_id, u64::MAX)? - .filter_map(|r| { + .pdus_until(sender_user, room_id, PduCount::max())? + .find_map(|r| { // Filter out buggy events if r.is_err() { error!("Bad pdu in pdus_since: {:?}", r); } r.ok() }) - .map(|(pduid, _)| self.pdu_count(&pduid)) - .next() { - Ok(*v.insert(last_count?)) + Ok(*v.insert(last_count.0)) } else { - Ok(0) + Ok(PduCount::Normal(0)) } } hash_map::Entry::Occupied(o) => Ok(*o.get()), @@ -60,11 +60,23 @@ impl service::rooms::timeline::Data for KeyValueDatabase { } /// Returns the `count` of this pdu's id. - fn get_pdu_count(&self, event_id: &EventId) -> Result> { - self.eventid_pduid + fn get_pdu_count(&self, event_id: &EventId) -> Result> { + Ok(self + .eventid_pduid .get(event_id.as_bytes())? - .map(|pdu_id| self.pdu_count(&pdu_id)) - .transpose() + .map(|pdu_id| Ok::<_, Error>(PduCount::Normal(pdu_count(&pdu_id)?))) + .transpose()? + .map_or_else( + || { + Ok::<_, Error>( + self.eventid_backfillpduid + .get(event_id.as_bytes())? + .map(|pdu_id| Ok::<_, Error>(PduCount::Backfilled(pdu_count(&pdu_id)?))) + .transpose()?, + ) + }, + |x| Ok(Some(x)), + )?) } /// Returns the json of a pdu. @@ -182,12 +194,6 @@ impl service::rooms::timeline::Data for KeyValueDatabase { }) } - /// Returns the `count` of this pdu's id. - fn pdu_count(&self, pdu_id: &[u8]) -> Result { - utils::u64_from_bytes(&pdu_id[pdu_id.len() - size_of::()..]) - .map_err(|_| Error::bad_database("PDU has invalid count bytes.")) - } - fn append_pdu( &self, pdu_id: &[u8], @@ -203,7 +209,7 @@ impl service::rooms::timeline::Data for KeyValueDatabase { self.lasttimelinecount_cache .lock() .unwrap() - .insert(pdu.room_id.clone(), count); + .insert(pdu.room_id.clone(), PduCount::Normal(count)); self.eventid_pduid.insert(pdu.event_id.as_bytes(), pdu_id)?; self.eventid_outlierpdu.remove(pdu.event_id.as_bytes())?; @@ -211,6 +217,24 @@ impl service::rooms::timeline::Data for KeyValueDatabase { Ok(()) } + fn prepend_backfill_pdu( + &self, + pdu_id: &[u8], + event_id: &EventId, + json: &CanonicalJsonObject, + ) -> Result<()> { + self.pduid_backfillpdu.insert( + pdu_id, + &serde_json::to_vec(json).expect("CanonicalJsonObject is always a valid"), + )?; + + self.eventid_backfillpduid + .insert(event_id.as_bytes(), pdu_id)?; + self.eventid_outlierpdu.remove(event_id.as_bytes())?; + + Ok(()) + } + /// Removes a pdu and creates a new one with the same id. fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()> { if self.pduid_pdu.get(pdu_id)?.is_some() { @@ -227,51 +251,14 @@ impl service::rooms::timeline::Data for KeyValueDatabase { } } - /// Returns an iterator over all events in a room that happened after the event with id `since` - /// in chronological order. - fn pdus_since<'a>( - &'a self, - user_id: &UserId, - room_id: &RoomId, - since: u64, - ) -> Result, PduEvent)>> + 'a>> { - let prefix = services() - .rooms - .short - .get_shortroomid(room_id)? - .expect("room exists") - .to_be_bytes() - .to_vec(); - - // Skip the first pdu if it's exactly at since, because we sent that last time - let mut first_pdu_id = prefix.clone(); - first_pdu_id.extend_from_slice(&(since + 1).to_be_bytes()); - - let user_id = user_id.to_owned(); - - Ok(Box::new( - self.pduid_pdu - .iter_from(&first_pdu_id, false) - .take_while(move |(k, _)| k.starts_with(&prefix)) - .map(move |(pdu_id, v)| { - let mut pdu = serde_json::from_slice::(&v) - .map_err(|_| Error::bad_database("PDU in db is invalid."))?; - if pdu.sender != user_id { - pdu.remove_transaction_id()?; - } - Ok((pdu_id, pdu)) - }), - )) - } - /// Returns an iterator over all events and their tokens in a room that happened before the /// event with id `until` in reverse-chronological order. fn pdus_until<'a>( &'a self, user_id: &UserId, room_id: &RoomId, - until: u64, - ) -> Result, PduEvent)>> + 'a>> { + until: PduCount, + ) -> Result> + 'a>> { // Create the first part of the full pdu id let prefix = services() .rooms @@ -281,34 +268,63 @@ impl service::rooms::timeline::Data for KeyValueDatabase { .to_be_bytes() .to_vec(); - let mut current = prefix.clone(); - current.extend_from_slice(&(until.saturating_sub(1)).to_be_bytes()); // -1 because we don't want event at `until` - - let current: &[u8] = ¤t; + let mut current_backfill = prefix.clone(); + // +1 so we don't send the base event + let backfill_count = match until { + PduCount::Backfilled(x) => x + 1, + PduCount::Normal(_) => 0, + }; + current_backfill.extend_from_slice(&backfill_count.to_be_bytes()); let user_id = user_id.to_owned(); + let user_id2 = user_id.to_owned(); + let prefix2 = prefix.clone(); + + let backfill_iter = self + .pduid_backfillpdu + .iter_from(¤t_backfill, false) + .take_while(move |(k, _)| k.starts_with(&prefix)) + .map(move |(pdu_id, v)| { + let mut pdu = serde_json::from_slice::(&v) + .map_err(|_| Error::bad_database("PDU in db is invalid."))?; + if pdu.sender != user_id { + pdu.remove_transaction_id()?; + } + let count = PduCount::Backfilled(pdu_count(&pdu_id)?); + Ok((count, pdu)) + }); + + match until { + PduCount::Backfilled(_) => Ok(Box::new(backfill_iter)), + PduCount::Normal(x) => { + let mut current_normal = prefix2.clone(); + // -1 so we don't send the base event + current_normal.extend_from_slice(&x.saturating_sub(1).to_be_bytes()); + let normal_iter = self + .pduid_pdu + .iter_from(¤t_normal, true) + .take_while(move |(k, _)| k.starts_with(&prefix2)) + .map(move |(pdu_id, v)| { + let mut pdu = serde_json::from_slice::(&v) + .map_err(|_| Error::bad_database("PDU in db is invalid."))?; + if pdu.sender != user_id2 { + pdu.remove_transaction_id()?; + } + let count = PduCount::Normal(pdu_count(&pdu_id)?); + Ok((count, pdu)) + }); - Ok(Box::new( - self.pduid_pdu - .iter_from(current, true) - .take_while(move |(k, _)| k.starts_with(&prefix)) - .map(move |(pdu_id, v)| { - let mut pdu = serde_json::from_slice::(&v) - .map_err(|_| Error::bad_database("PDU in db is invalid."))?; - if pdu.sender != user_id { - pdu.remove_transaction_id()?; - } - Ok((pdu_id, pdu)) - }), - )) + Ok(Box::new(normal_iter.chain(backfill_iter))) + } + } } fn pdus_after<'a>( &'a self, user_id: &UserId, room_id: &RoomId, - from: u64, - ) -> Result, PduEvent)>> + 'a>> { + from: PduCount, + ) -> Result> + 'a>> { // Create the first part of the full pdu id let prefix = services() .rooms @@ -318,26 +334,55 @@ impl service::rooms::timeline::Data for KeyValueDatabase { .to_be_bytes() .to_vec(); - let mut current = prefix.clone(); - current.extend_from_slice(&(from + 1).to_be_bytes()); // +1 so we don't send the base event - - let current: &[u8] = ¤t; + let mut current_normal = prefix.clone(); + // +1 so we don't send the base event + let normal_count = match from { + PduCount::Normal(x) => x + 1, + PduCount::Backfilled(_) => 0, + }; + current_normal.extend_from_slice(&normal_count.to_be_bytes()); let user_id = user_id.to_owned(); + let user_id2 = user_id.to_owned(); + let prefix2 = prefix.clone(); + + let normal_iter = self + .pduid_pdu + .iter_from(¤t_normal, false) + .take_while(move |(k, _)| k.starts_with(&prefix)) + .map(move |(pdu_id, v)| { + let mut pdu = serde_json::from_slice::(&v) + .map_err(|_| Error::bad_database("PDU in db is invalid."))?; + if pdu.sender != user_id { + pdu.remove_transaction_id()?; + } + let count = PduCount::Normal(pdu_count(&pdu_id)?); + Ok((count, pdu)) + }); + + match from { + PduCount::Normal(_) => Ok(Box::new(normal_iter)), + PduCount::Backfilled(x) => { + let mut current_backfill = prefix2.clone(); + // -1 so we don't send the base event + current_backfill.extend_from_slice(&x.saturating_sub(1).to_be_bytes()); + let backfill_iter = self + .pduid_backfillpdu + .iter_from(¤t_backfill, true) + .take_while(move |(k, _)| k.starts_with(&prefix2)) + .map(move |(pdu_id, v)| { + let mut pdu = serde_json::from_slice::(&v) + .map_err(|_| Error::bad_database("PDU in db is invalid."))?; + if pdu.sender != user_id2 { + pdu.remove_transaction_id()?; + } + let count = PduCount::Backfilled(pdu_count(&pdu_id)?); + Ok((count, pdu)) + }); - Ok(Box::new( - self.pduid_pdu - .iter_from(current, false) - .take_while(move |(k, _)| k.starts_with(&prefix)) - .map(move |(pdu_id, v)| { - let mut pdu = serde_json::from_slice::(&v) - .map_err(|_| Error::bad_database("PDU in db is invalid."))?; - if pdu.sender != user_id { - pdu.remove_transaction_id()?; - } - Ok((pdu_id, pdu)) - }), - )) + Ok(Box::new(backfill_iter.chain(normal_iter))) + } + } } fn increment_notification_counts( @@ -368,3 +413,9 @@ impl service::rooms::timeline::Data for KeyValueDatabase { Ok(()) } } + +/// Returns the `count` of this pdu's id. +fn pdu_count(pdu_id: &[u8]) -> Result { + utils::u64_from_bytes(&pdu_id[pdu_id.len() - size_of::()..]) + .map_err(|_| Error::bad_database("PDU has invalid count bytes.")) +} diff --git a/src/database/mod.rs b/src/database/mod.rs index 46ba5b3..f07ad87 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -1,7 +1,10 @@ pub mod abstraction; pub mod key_value; -use crate::{services, utils, Config, Error, PduEvent, Result, Services, SERVICES}; +use crate::{ + service::rooms::timeline::PduCount, services, utils, Config, Error, PduEvent, Result, Services, + SERVICES, +}; use abstraction::{KeyValueDatabaseEngine, KvTree}; use directories::ProjectDirs; use lru_cache::LruCache; @@ -71,7 +74,9 @@ pub struct KeyValueDatabase { //pub rooms: rooms::Rooms, pub(super) pduid_pdu: Arc, // PduId = ShortRoomId + Count + pub(super) pduid_backfillpdu: Arc, // PduId = ShortRoomId + Count pub(super) eventid_pduid: Arc, + pub(super) eventid_backfillpduid: Arc, pub(super) roomid_pduleaves: Arc, pub(super) alias_roomid: Arc, pub(super) aliasid_alias: Arc, // AliasId = RoomId + Count @@ -161,7 +166,7 @@ pub struct KeyValueDatabase { pub(super) shortstatekey_cache: Mutex>, pub(super) our_real_users_cache: RwLock>>>, pub(super) appservice_in_room_cache: RwLock>>, - pub(super) lasttimelinecount_cache: Mutex>, + pub(super) lasttimelinecount_cache: Mutex>, } impl KeyValueDatabase { @@ -292,7 +297,9 @@ impl KeyValueDatabase { presenceid_presence: builder.open_tree("presenceid_presence")?, userid_lastpresenceupdate: builder.open_tree("userid_lastpresenceupdate")?, pduid_pdu: builder.open_tree("pduid_pdu")?, + pduid_backfillpdu: builder.open_tree("pduid_backfillpdu")?, eventid_pduid: builder.open_tree("eventid_pduid")?, + eventid_backfillpduid: builder.open_tree("eventid_backfillpduid")?, roomid_pduleaves: builder.open_tree("roomid_pduleaves")?, alias_roomid: builder.open_tree("alias_roomid")?, diff --git a/src/service/rooms/lazy_loading/mod.rs b/src/service/rooms/lazy_loading/mod.rs index 701a734..e6e4f89 100644 --- a/src/service/rooms/lazy_loading/mod.rs +++ b/src/service/rooms/lazy_loading/mod.rs @@ -9,11 +9,13 @@ use ruma::{DeviceId, OwnedDeviceId, OwnedRoomId, OwnedUserId, RoomId, UserId}; use crate::Result; +use super::timeline::PduCount; + pub struct Service { pub db: &'static dyn Data, pub lazy_load_waiting: - Mutex>>, + Mutex>>, } impl Service { @@ -36,7 +38,7 @@ impl Service { device_id: &DeviceId, room_id: &RoomId, lazy_load: HashSet, - count: u64, + count: PduCount, ) { self.lazy_load_waiting.lock().unwrap().insert( ( @@ -55,7 +57,7 @@ impl Service { user_id: &UserId, device_id: &DeviceId, room_id: &RoomId, - since: u64, + since: PduCount, ) -> Result<()> { if let Some(user_ids) = self.lazy_load_waiting.lock().unwrap().remove(&( user_id.to_owned(), diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index e940ffa..bd9ef88 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -14,7 +14,7 @@ use ruma::{ }, StateEventType, }, - EventId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId, + EventId, OwnedServerName, RoomId, ServerName, UserId, }; use tracing::error; diff --git a/src/service/rooms/timeline/data.rs b/src/service/rooms/timeline/data.rs index 9377af0..c802105 100644 --- a/src/service/rooms/timeline/data.rs +++ b/src/service/rooms/timeline/data.rs @@ -4,12 +4,14 @@ use ruma::{CanonicalJsonObject, EventId, OwnedUserId, RoomId, UserId}; use crate::{PduEvent, Result}; +use super::PduCount; + pub trait Data: Send + Sync { fn first_pdu_in_room(&self, room_id: &RoomId) -> Result>>; - fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result; + fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result; /// Returns the `count` of this pdu's id. - fn get_pdu_count(&self, event_id: &EventId) -> Result>; + fn get_pdu_count(&self, event_id: &EventId) -> Result>; /// Returns the json of a pdu. fn get_pdu_json(&self, event_id: &EventId) -> Result>; @@ -38,9 +40,6 @@ pub trait Data: Send + Sync { /// Returns the pdu as a `BTreeMap`. fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result>; - /// Returns the `count` of this pdu's id. - fn pdu_count(&self, pdu_id: &[u8]) -> Result; - /// Adds a new pdu to the timeline fn append_pdu( &self, @@ -50,33 +49,34 @@ pub trait Data: Send + Sync { count: u64, ) -> Result<()>; + // Adds a new pdu to the backfilled timeline + fn prepend_backfill_pdu( + &self, + pdu_id: &[u8], + event_id: &EventId, + json: &CanonicalJsonObject, + ) -> Result<()>; + /// Removes a pdu and creates a new one with the same id. fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()>; - /// Returns an iterator over all events in a room that happened after the event with id `since` - /// in chronological order. - fn pdus_since<'a>( - &'a self, - user_id: &UserId, - room_id: &RoomId, - since: u64, - ) -> Result, PduEvent)>> + 'a>>; - /// Returns an iterator over all events and their tokens in a room that happened before the /// event with id `until` in reverse-chronological order. fn pdus_until<'a>( &'a self, user_id: &UserId, room_id: &RoomId, - until: u64, - ) -> Result, PduEvent)>> + 'a>>; + until: PduCount, + ) -> Result> + 'a>>; + /// Returns an iterator over all events in a room that happened after the event with id `from` + /// in chronological order. fn pdus_after<'a>( &'a self, user_id: &UserId, room_id: &RoomId, - from: u64, - ) -> Result, PduEvent)>> + 'a>>; + from: PduCount, + ) -> Result> + 'a>>; fn increment_notification_counts( &self, diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index cc58e6f..b407dfd 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -1,7 +1,9 @@ mod data; -use std::collections::HashMap; +use std::cmp::Ordering; +use std::collections::{BTreeMap, HashMap}; +use std::sync::RwLock; use std::{ collections::HashSet, sync::{Arc, Mutex}, @@ -9,6 +11,8 @@ use std::{ pub use data::Data; use regex::Regex; +use ruma::api::federation; +use ruma::serde::Base64; use ruma::{ api::client::error::ErrorKind, canonical_json::to_canonical_value, @@ -27,11 +31,13 @@ use ruma::{ uint, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, OwnedServerName, RoomAliasId, RoomId, UserId, }; +use ruma::{user_id, ServerName}; use serde::Deserialize; -use serde_json::value::to_raw_value; +use serde_json::value::{to_raw_value, RawValue as RawJsonValue}; use tokio::sync::MutexGuard; -use tracing::{error, warn}; +use tracing::{error, info, warn}; +use crate::api::server_server; use crate::{ service::pdu::{EventHash, PduBuilder}, services, utils, Error, PduEvent, Result, @@ -39,10 +45,70 @@ use crate::{ use super::state_compressor::CompressedStateEvent; +#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] +pub enum PduCount { + Backfilled(u64), + Normal(u64), +} + +impl PduCount { + pub fn min() -> Self { + Self::Backfilled(u64::MAX) + } + pub fn max() -> Self { + Self::Normal(u64::MAX) + } + + pub fn try_from_string(token: &str) -> Result { + if token.starts_with('-') { + token[1..].parse().map(PduCount::Backfilled) + } else { + token.parse().map(PduCount::Normal) + } + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid pagination token.")) + } + + pub fn stringify(&self) -> String { + match self { + PduCount::Backfilled(x) => format!("-{x}"), + PduCount::Normal(x) => x.to_string(), + } + } +} + +impl PartialOrd for PduCount { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for PduCount { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (PduCount::Normal(s), PduCount::Normal(o)) => s.cmp(o), + (PduCount::Backfilled(s), PduCount::Backfilled(o)) => o.cmp(s), + (PduCount::Normal(_), PduCount::Backfilled(_)) => Ordering::Greater, + (PduCount::Backfilled(_), PduCount::Normal(_)) => Ordering::Less, + } + } +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn comparisons() { + assert!(PduCount::Normal(1) < PduCount::Normal(2)); + assert!(PduCount::Backfilled(2) < PduCount::Backfilled(1)); + assert!(PduCount::Normal(1) > PduCount::Backfilled(1)); + assert!(PduCount::Backfilled(1) < PduCount::Normal(1)); + } +} + pub struct Service { pub db: &'static dyn Data, - pub lasttimelinecount_cache: Mutex>, + pub lasttimelinecount_cache: Mutex>, } impl Service { @@ -52,10 +118,15 @@ impl Service { } #[tracing::instrument(skip(self))] - pub fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result { + pub fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result { self.db.last_timeline_count(sender_user, room_id) } + /// Returns the `count` of this pdu's id. + pub fn get_pdu_count(&self, event_id: &EventId) -> Result> { + self.db.get_pdu_count(event_id) + } + // TODO Is this the same as the function above? /* #[tracing::instrument(skip(self))] @@ -79,11 +150,6 @@ impl Service { } */ - /// Returns the `count` of this pdu's id. - pub fn get_pdu_count(&self, event_id: &EventId) -> Result> { - self.db.get_pdu_count(event_id) - } - /// Returns the json of a pdu. pub fn get_pdu_json(&self, event_id: &EventId) -> Result> { self.db.get_pdu_json(event_id) @@ -128,11 +194,6 @@ impl Service { self.db.get_pdu_json_from_id(pdu_id) } - /// Returns the `count` of this pdu's id. - pub fn pdu_count(&self, pdu_id: &[u8]) -> Result { - self.db.pdu_count(pdu_id) - } - /// Removes a pdu and creates a new one with the same id. #[tracing::instrument(skip(self))] fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()> { @@ -863,19 +924,8 @@ impl Service { &'a self, user_id: &UserId, room_id: &RoomId, - ) -> Result, PduEvent)>> + 'a> { - self.pdus_since(user_id, room_id, 0) - } - - /// Returns an iterator over all events in a room that happened after the event with id `since` - /// in chronological order. - pub fn pdus_since<'a>( - &'a self, - user_id: &UserId, - room_id: &RoomId, - since: u64, - ) -> Result, PduEvent)>> + 'a> { - self.db.pdus_since(user_id, room_id, since) + ) -> Result> + 'a> { + self.pdus_after(user_id, room_id, PduCount::min()) } /// Returns an iterator over all events and their tokens in a room that happened before the @@ -885,8 +935,8 @@ impl Service { &'a self, user_id: &UserId, room_id: &RoomId, - until: u64, - ) -> Result, PduEvent)>> + 'a> { + until: PduCount, + ) -> Result> + 'a> { self.db.pdus_until(user_id, room_id, until) } @@ -897,8 +947,8 @@ impl Service { &'a self, user_id: &UserId, room_id: &RoomId, - from: u64, - ) -> Result, PduEvent)>> + 'a> { + from: PduCount, + ) -> Result> + 'a> { self.db.pdus_after(user_id, room_id, from) } @@ -915,4 +965,118 @@ impl Service { // If event does not exist, just noop Ok(()) } + + #[tracing::instrument(skip(self, room_id))] + pub async fn backfill_if_required(&self, room_id: &RoomId, from: PduCount) -> Result<()> { + let first_pdu = self + .all_pdus(&user_id!("@doesntmatter:conduit.rs"), &room_id)? + .next() + .expect("Room is not empty")?; + + if first_pdu.0 < from { + // No backfill required, there are still events between them + return Ok(()); + } + + let power_levels: RoomPowerLevelsEventContent = services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomPowerLevels, "")? + .map(|ev| { + serde_json::from_str(ev.content.get()) + .map_err(|_| Error::bad_database("invalid m.room.power_levels event")) + }) + .transpose()? + .unwrap_or_default(); + let mut admin_servers = power_levels + .users + .iter() + .filter(|(_, level)| **level > power_levels.users_default) + .map(|(user_id, _)| user_id.server_name()) + .collect::>(); + admin_servers.remove(services().globals.server_name()); + + // Request backfill + for backfill_server in admin_servers { + info!("Asking {backfill_server} for backfill"); + let response = services() + .sending + .send_federation_request( + backfill_server, + federation::backfill::get_backfill::v1::Request { + room_id: room_id.to_owned(), + v: vec![first_pdu.1.event_id.as_ref().to_owned()], + limit: uint!(100), + }, + ) + .await; + match response { + Ok(response) => { + let mut pub_key_map = RwLock::new(BTreeMap::new()); + for pdu in response.pdus { + if let Err(e) = self + .backfill_pdu(backfill_server, pdu, &mut pub_key_map) + .await + { + warn!("Failed to add backfilled pdu: {e}"); + } + } + return Ok(()); + } + Err(e) => { + warn!("{backfill_server} could not provide backfill: {e}"); + } + } + } + + info!("No servers could backfill"); + Ok(()) + } + + #[tracing::instrument(skip(self, pdu))] + pub async fn backfill_pdu( + &self, + origin: &ServerName, + pdu: Box, + pub_key_map: &RwLock>>, + ) -> Result<()> { + let (event_id, value, room_id) = server_server::parse_incoming_pdu(&pdu)?; + + services() + .rooms + .event_handler + .handle_incoming_pdu(origin, &event_id, &room_id, value, false, &pub_key_map) + .await?; + + let value = self.get_pdu_json(&event_id)?.expect("We just created it"); + + let shortroomid = services() + .rooms + .short + .get_shortroomid(&room_id)? + .expect("room exists"); + + let mutex_insert = Arc::clone( + services() + .globals + .roomid_mutex_insert + .write() + .unwrap() + .entry(room_id.clone()) + .or_default(), + ); + let insert_lock = mutex_insert.lock().unwrap(); + + let count = services().globals.next_count()?; + let mut pdu_id = shortroomid.to_be_bytes().to_vec(); + pdu_id.extend_from_slice(&count.to_be_bytes()); + + // Insert pdu + self.db.prepend_backfill_pdu(&pdu_id, &event_id, &value)?; + + drop(insert_lock); + + info!("Appended incoming pdu"); + Ok(()) + } } -- cgit v1.2.3 From fcfb06ffa65c84de3253dbebae98faa5b6025d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 21 Feb 2023 00:56:05 +0100 Subject: fix: allow handling create event itself --- src/service/rooms/event_handler/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index bc67f7a..66c6394 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -392,11 +392,12 @@ impl Service { } // The original create event must be in the auth events - if auth_events - .get(&(StateEventType::RoomCreate, "".to_owned())) - .map(|a| a.as_ref()) - != Some(create_event) - { + if !matches!( + auth_events + .get(&(StateEventType::RoomCreate, "".to_owned())) + .map(|a| a.as_ref()), + Some(_) | None + ) { return Err(Error::BadRequest( ErrorKind::InvalidParam, "Incoming event refers to wrong create event.", -- cgit v1.2.3 From 17a6431f5f145f1c28977bda344639f6e93b9699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 21 Feb 2023 00:56:26 +0100 Subject: fix: make backfilled events reachable --- src/database/key_value/rooms/timeline.rs | 137 +++++++++++++++++-------------- src/service/rooms/timeline/data.rs | 1 - src/service/rooms/timeline/mod.rs | 5 +- 3 files changed, 79 insertions(+), 64 deletions(-) diff --git a/src/database/key_value/rooms/timeline.rs b/src/database/key_value/rooms/timeline.rs index 9f2c607..7a33e5d 100644 --- a/src/database/key_value/rooms/timeline.rs +++ b/src/database/key_value/rooms/timeline.rs @@ -10,28 +10,6 @@ use crate::{database::KeyValueDatabase, service, services, utils, Error, PduEven use service::rooms::timeline::PduCount; impl service::rooms::timeline::Data for KeyValueDatabase { - fn first_pdu_in_room(&self, room_id: &RoomId) -> Result>> { - let prefix = services() - .rooms - .short - .get_shortroomid(room_id)? - .expect("room exists") - .to_be_bytes() - .to_vec(); - - // Look for PDUs in that room. - self.pduid_pdu - .iter_from(&prefix, false) - .filter(|(k, _)| k.starts_with(&prefix)) - .map(|(_, pdu)| { - serde_json::from_slice(&pdu) - .map_err(|_| Error::bad_database("Invalid first PDU in db.")) - .map(Arc::new) - }) - .next() - .transpose() - } - fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result { match self .lasttimelinecount_cache @@ -81,20 +59,18 @@ impl service::rooms::timeline::Data for KeyValueDatabase { /// Returns the json of a pdu. fn get_pdu_json(&self, event_id: &EventId) -> Result> { - self.eventid_pduid - .get(event_id.as_bytes())? - .map_or_else( - || self.eventid_outlierpdu.get(event_id.as_bytes()), - |pduid| { - Ok(Some(self.pduid_pdu.get(&pduid)?.ok_or_else(|| { - Error::bad_database("Invalid pduid in eventid_pduid.") - })?)) - }, - )? - .map(|pdu| { - serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db.")) - }) - .transpose() + self.get_non_outlier_pdu_json(event_id)?.map_or_else( + || { + self.eventid_outlierpdu + .get(event_id.as_bytes())? + .map(|pdu| { + serde_json::from_slice(&pdu) + .map_err(|_| Error::bad_database("Invalid PDU in db.")) + }) + .transpose() + }, + |x| Ok(Some(x)), + ) } /// Returns the json of a pdu. @@ -107,6 +83,21 @@ impl service::rooms::timeline::Data for KeyValueDatabase { .ok_or_else(|| Error::bad_database("Invalid pduid in eventid_pduid.")) }) .transpose()? + .map_or_else( + || { + Ok::<_, Error>( + self.eventid_backfillpduid + .get(event_id.as_bytes())? + .map(|pduid| { + self.pduid_backfillpdu.get(&pduid)?.ok_or_else(|| { + Error::bad_database("Invalid pduid in eventid_pduid.") + }) + }) + .transpose()?, + ) + }, + |x| Ok(Some(x)), + )? .map(|pdu| { serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db.")) }) @@ -115,7 +106,10 @@ impl service::rooms::timeline::Data for KeyValueDatabase { /// Returns the pdu's id. fn get_pdu_id(&self, event_id: &EventId) -> Result>> { - self.eventid_pduid.get(event_id.as_bytes()) + Ok(self.eventid_pduid.get(event_id.as_bytes())?.map_or_else( + || self.eventid_backfillpduid.get(event_id.as_bytes()), + |x| Ok(Some(x)), + )?) } /// Returns the pdu. @@ -130,6 +124,21 @@ impl service::rooms::timeline::Data for KeyValueDatabase { .ok_or_else(|| Error::bad_database("Invalid pduid in eventid_pduid.")) }) .transpose()? + .map_or_else( + || { + Ok::<_, Error>( + self.eventid_backfillpduid + .get(event_id.as_bytes())? + .map(|pduid| { + self.pduid_backfillpdu.get(&pduid)?.ok_or_else(|| { + Error::bad_database("Invalid pduid in eventid_pduid.") + }) + }) + .transpose()?, + ) + }, + |x| Ok(Some(x)), + )? .map(|pdu| { serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db.")) }) @@ -145,22 +154,20 @@ impl service::rooms::timeline::Data for KeyValueDatabase { } if let Some(pdu) = self - .eventid_pduid - .get(event_id.as_bytes())? + .get_non_outlier_pdu(event_id)? .map_or_else( - || self.eventid_outlierpdu.get(event_id.as_bytes()), - |pduid| { - Ok(Some(self.pduid_pdu.get(&pduid)?.ok_or_else(|| { - Error::bad_database("Invalid pduid in eventid_pduid.") - })?)) + || { + self.eventid_outlierpdu + .get(event_id.as_bytes())? + .map(|pdu| { + serde_json::from_slice(&pdu) + .map_err(|_| Error::bad_database("Invalid PDU in db.")) + }) + .transpose() }, + |x| Ok(Some(x)), )? - .map(|pdu| { - serde_json::from_slice(&pdu) - .map_err(|_| Error::bad_database("Invalid PDU in db.")) - .map(Arc::new) - }) - .transpose()? + .map(Arc::new) { self.pdu_cache .lock() @@ -176,22 +183,28 @@ impl service::rooms::timeline::Data for KeyValueDatabase { /// /// This does __NOT__ check the outliers `Tree`. fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result> { - self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| { - Ok(Some( - serde_json::from_slice(&pdu) - .map_err(|_| Error::bad_database("Invalid PDU in db."))?, - )) - }) + self.pduid_pdu + .get(pdu_id)? + .map_or_else(|| self.pduid_backfillpdu.get(pdu_id), |x| Ok(Some(x)))? + .map_or(Ok(None), |pdu| { + Ok(Some( + serde_json::from_slice(&pdu) + .map_err(|_| Error::bad_database("Invalid PDU in db."))?, + )) + }) } /// Returns the pdu as a `BTreeMap`. fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result> { - self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| { - Ok(Some( - serde_json::from_slice(&pdu) - .map_err(|_| Error::bad_database("Invalid PDU in db."))?, - )) - }) + self.pduid_pdu + .get(pdu_id)? + .map_or_else(|| self.pduid_backfillpdu.get(pdu_id), |x| Ok(Some(x)))? + .map_or(Ok(None), |pdu| { + Ok(Some( + serde_json::from_slice(&pdu) + .map_err(|_| Error::bad_database("Invalid PDU in db."))?, + )) + }) } fn append_pdu( diff --git a/src/service/rooms/timeline/data.rs b/src/service/rooms/timeline/data.rs index c802105..193f384 100644 --- a/src/service/rooms/timeline/data.rs +++ b/src/service/rooms/timeline/data.rs @@ -7,7 +7,6 @@ use crate::{PduEvent, Result}; use super::PduCount; pub trait Data: Send + Sync { - fn first_pdu_in_room(&self, room_id: &RoomId) -> Result>>; fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result; /// Returns the `count` of this pdu's id. diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index b407dfd..dcf04be 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -114,7 +114,10 @@ pub struct Service { impl Service { #[tracing::instrument(skip(self))] pub fn first_pdu_in_room(&self, room_id: &RoomId) -> Result>> { - self.db.first_pdu_in_room(room_id) + self.all_pdus(&user_id!("@doesntmatter:conduit.rs"), &room_id)? + .next() + .map(|o| o.map(|(_, p)| Arc::new(p))) + .transpose() } #[tracing::instrument(skip(self))] -- cgit v1.2.3 From eae0989c4048152729a5369ed6cb252d87f8b2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 21 Feb 2023 16:38:50 +0100 Subject: fix: refactor backfill and add support for search --- src/api/client_server/search.rs | 14 +- src/database/key_value/rooms/search.rs | 16 +- src/database/key_value/rooms/timeline.rs | 282 +++++++++++-------------------- src/database/mod.rs | 4 - src/service/rooms/timeline/mod.rs | 45 ++++- 5 files changed, 157 insertions(+), 204 deletions(-) diff --git a/src/api/client_server/search.rs b/src/api/client_server/search.rs index 51255d5..5d760db 100644 --- a/src/api/client_server/search.rs +++ b/src/api/client_server/search.rs @@ -81,6 +81,14 @@ pub async fn search_events_route( let results: Vec<_> = results .iter() + .filter_map(|result| { + services() + .rooms + .timeline + .get_pdu_from_id(result) + .ok()? + .map(|pdu| pdu.to_room_event()) + }) .map(|result| { Ok::<_, Error>(SearchResult { context: EventContextResult { @@ -91,11 +99,7 @@ pub async fn search_events_route( start: None, }, rank: None, - result: services() - .rooms - .timeline - .get_pdu_from_id(result)? - .map(|pdu| pdu.to_room_event()), + result: Some(result), }) }) .filter_map(|r| r.ok()) diff --git a/src/database/key_value/rooms/search.rs b/src/database/key_value/rooms/search.rs index 19ae57b..ad573f0 100644 --- a/src/database/key_value/rooms/search.rs +++ b/src/database/key_value/rooms/search.rs @@ -1,5 +1,3 @@ -use std::mem::size_of; - use ruma::RoomId; use crate::{database::KeyValueDatabase, service, services, utils, Result}; @@ -15,7 +13,7 @@ impl service::rooms::search::Data for KeyValueDatabase { let mut key = shortroomid.to_be_bytes().to_vec(); key.extend_from_slice(word.as_bytes()); key.push(0xff); - key.extend_from_slice(pdu_id); + key.extend_from_slice(pdu_id); // TODO: currently we save the room id a second time here (key, Vec::new()) }); @@ -34,7 +32,6 @@ impl service::rooms::search::Data for KeyValueDatabase { .expect("room exists") .to_be_bytes() .to_vec(); - let prefix_clone = prefix.clone(); let words: Vec<_> = search_string .split_terminator(|c: char| !c.is_alphanumeric()) @@ -46,6 +43,7 @@ impl service::rooms::search::Data for KeyValueDatabase { let mut prefix2 = prefix.clone(); prefix2.extend_from_slice(word.as_bytes()); prefix2.push(0xff); + let prefix3 = prefix2.clone(); let mut last_possible_id = prefix2.clone(); last_possible_id.extend_from_slice(&u64::MAX.to_be_bytes()); @@ -53,7 +51,7 @@ impl service::rooms::search::Data for KeyValueDatabase { self.tokenids .iter_from(&last_possible_id, true) // Newest pdus first .take_while(move |(k, _)| k.starts_with(&prefix2)) - .map(|(key, _)| key[key.len() - size_of::()..].to_vec()) + .map(move |(key, _)| key[prefix3.len()..].to_vec()) }); let common_elements = match utils::common_elements(iterators, |a, b| { @@ -64,12 +62,6 @@ impl service::rooms::search::Data for KeyValueDatabase { None => return Ok(None), }; - let mapped = common_elements.map(move |id| { - let mut pduid = prefix_clone.clone(); - pduid.extend_from_slice(&id); - pduid - }); - - Ok(Some((Box::new(mapped), words))) + Ok(Some((Box::new(common_elements), words))) } } diff --git a/src/database/key_value/rooms/timeline.rs b/src/database/key_value/rooms/timeline.rs index 7a33e5d..d9c4423 100644 --- a/src/database/key_value/rooms/timeline.rs +++ b/src/database/key_value/rooms/timeline.rs @@ -42,19 +42,8 @@ impl service::rooms::timeline::Data for KeyValueDatabase { Ok(self .eventid_pduid .get(event_id.as_bytes())? - .map(|pdu_id| Ok::<_, Error>(PduCount::Normal(pdu_count(&pdu_id)?))) - .transpose()? - .map_or_else( - || { - Ok::<_, Error>( - self.eventid_backfillpduid - .get(event_id.as_bytes())? - .map(|pdu_id| Ok::<_, Error>(PduCount::Backfilled(pdu_count(&pdu_id)?))) - .transpose()?, - ) - }, - |x| Ok(Some(x)), - )?) + .map(|pdu_id| pdu_count(&pdu_id)) + .transpose()?) } /// Returns the json of a pdu. @@ -83,21 +72,6 @@ impl service::rooms::timeline::Data for KeyValueDatabase { .ok_or_else(|| Error::bad_database("Invalid pduid in eventid_pduid.")) }) .transpose()? - .map_or_else( - || { - Ok::<_, Error>( - self.eventid_backfillpduid - .get(event_id.as_bytes())? - .map(|pduid| { - self.pduid_backfillpdu.get(&pduid)?.ok_or_else(|| { - Error::bad_database("Invalid pduid in eventid_pduid.") - }) - }) - .transpose()?, - ) - }, - |x| Ok(Some(x)), - )? .map(|pdu| { serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db.")) }) @@ -106,10 +80,7 @@ impl service::rooms::timeline::Data for KeyValueDatabase { /// Returns the pdu's id. fn get_pdu_id(&self, event_id: &EventId) -> Result>> { - Ok(self.eventid_pduid.get(event_id.as_bytes())?.map_or_else( - || self.eventid_backfillpduid.get(event_id.as_bytes()), - |x| Ok(Some(x)), - )?) + Ok(self.eventid_pduid.get(event_id.as_bytes())?) } /// Returns the pdu. @@ -124,21 +95,6 @@ impl service::rooms::timeline::Data for KeyValueDatabase { .ok_or_else(|| Error::bad_database("Invalid pduid in eventid_pduid.")) }) .transpose()? - .map_or_else( - || { - Ok::<_, Error>( - self.eventid_backfillpduid - .get(event_id.as_bytes())? - .map(|pduid| { - self.pduid_backfillpdu.get(&pduid)?.ok_or_else(|| { - Error::bad_database("Invalid pduid in eventid_pduid.") - }) - }) - .transpose()?, - ) - }, - |x| Ok(Some(x)), - )? .map(|pdu| { serde_json::from_slice(&pdu).map_err(|_| Error::bad_database("Invalid PDU in db.")) }) @@ -183,28 +139,22 @@ impl service::rooms::timeline::Data for KeyValueDatabase { /// /// This does __NOT__ check the outliers `Tree`. fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result> { - self.pduid_pdu - .get(pdu_id)? - .map_or_else(|| self.pduid_backfillpdu.get(pdu_id), |x| Ok(Some(x)))? - .map_or(Ok(None), |pdu| { - Ok(Some( - serde_json::from_slice(&pdu) - .map_err(|_| Error::bad_database("Invalid PDU in db."))?, - )) - }) + self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| { + Ok(Some( + serde_json::from_slice(&pdu) + .map_err(|_| Error::bad_database("Invalid PDU in db."))?, + )) + }) } /// Returns the pdu as a `BTreeMap`. fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result> { - self.pduid_pdu - .get(pdu_id)? - .map_or_else(|| self.pduid_backfillpdu.get(pdu_id), |x| Ok(Some(x)))? - .map_or(Ok(None), |pdu| { - Ok(Some( - serde_json::from_slice(&pdu) - .map_err(|_| Error::bad_database("Invalid PDU in db."))?, - )) - }) + self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| { + Ok(Some( + serde_json::from_slice(&pdu) + .map_err(|_| Error::bad_database("Invalid PDU in db."))?, + )) + }) } fn append_pdu( @@ -236,13 +186,12 @@ impl service::rooms::timeline::Data for KeyValueDatabase { event_id: &EventId, json: &CanonicalJsonObject, ) -> Result<()> { - self.pduid_backfillpdu.insert( + self.pduid_pdu.insert( pdu_id, &serde_json::to_vec(json).expect("CanonicalJsonObject is always a valid"), )?; - self.eventid_backfillpduid - .insert(event_id.as_bytes(), pdu_id)?; + self.eventid_pduid.insert(event_id.as_bytes(), pdu_id)?; self.eventid_outlierpdu.remove(event_id.as_bytes())?; Ok(()) @@ -272,64 +221,24 @@ impl service::rooms::timeline::Data for KeyValueDatabase { room_id: &RoomId, until: PduCount, ) -> Result> + 'a>> { - // Create the first part of the full pdu id - let prefix = services() - .rooms - .short - .get_shortroomid(room_id)? - .expect("room exists") - .to_be_bytes() - .to_vec(); - - let mut current_backfill = prefix.clone(); - // +1 so we don't send the base event - let backfill_count = match until { - PduCount::Backfilled(x) => x + 1, - PduCount::Normal(_) => 0, - }; - current_backfill.extend_from_slice(&backfill_count.to_be_bytes()); + let (prefix, current) = count_to_id(&room_id, until, 1, true)?; let user_id = user_id.to_owned(); - let user_id2 = user_id.to_owned(); - let prefix2 = prefix.clone(); - - let backfill_iter = self - .pduid_backfillpdu - .iter_from(¤t_backfill, false) - .take_while(move |(k, _)| k.starts_with(&prefix)) - .map(move |(pdu_id, v)| { - let mut pdu = serde_json::from_slice::(&v) - .map_err(|_| Error::bad_database("PDU in db is invalid."))?; - if pdu.sender != user_id { - pdu.remove_transaction_id()?; - } - let count = PduCount::Backfilled(pdu_count(&pdu_id)?); - Ok((count, pdu)) - }); - - match until { - PduCount::Backfilled(_) => Ok(Box::new(backfill_iter)), - PduCount::Normal(x) => { - let mut current_normal = prefix2.clone(); - // -1 so we don't send the base event - current_normal.extend_from_slice(&x.saturating_sub(1).to_be_bytes()); - let normal_iter = self - .pduid_pdu - .iter_from(¤t_normal, true) - .take_while(move |(k, _)| k.starts_with(&prefix2)) - .map(move |(pdu_id, v)| { - let mut pdu = serde_json::from_slice::(&v) - .map_err(|_| Error::bad_database("PDU in db is invalid."))?; - if pdu.sender != user_id2 { - pdu.remove_transaction_id()?; - } - let count = PduCount::Normal(pdu_count(&pdu_id)?); - Ok((count, pdu)) - }); - Ok(Box::new(normal_iter.chain(backfill_iter))) - } - } + Ok(Box::new( + self.pduid_pdu + .iter_from(¤t, true) + .take_while(move |(k, _)| k.starts_with(&prefix)) + .map(move |(pdu_id, v)| { + let mut pdu = serde_json::from_slice::(&v) + .map_err(|_| Error::bad_database("PDU in db is invalid."))?; + if pdu.sender != user_id { + pdu.remove_transaction_id()?; + } + let count = pdu_count(&pdu_id)?; + Ok((count, pdu)) + }), + )) } fn pdus_after<'a>( @@ -338,64 +247,24 @@ impl service::rooms::timeline::Data for KeyValueDatabase { room_id: &RoomId, from: PduCount, ) -> Result> + 'a>> { - // Create the first part of the full pdu id - let prefix = services() - .rooms - .short - .get_shortroomid(room_id)? - .expect("room exists") - .to_be_bytes() - .to_vec(); - - let mut current_normal = prefix.clone(); - // +1 so we don't send the base event - let normal_count = match from { - PduCount::Normal(x) => x + 1, - PduCount::Backfilled(_) => 0, - }; - current_normal.extend_from_slice(&normal_count.to_be_bytes()); + let (prefix, current) = count_to_id(&room_id, from, 1, false)?; let user_id = user_id.to_owned(); - let user_id2 = user_id.to_owned(); - let prefix2 = prefix.clone(); - - let normal_iter = self - .pduid_pdu - .iter_from(¤t_normal, false) - .take_while(move |(k, _)| k.starts_with(&prefix)) - .map(move |(pdu_id, v)| { - let mut pdu = serde_json::from_slice::(&v) - .map_err(|_| Error::bad_database("PDU in db is invalid."))?; - if pdu.sender != user_id { - pdu.remove_transaction_id()?; - } - let count = PduCount::Normal(pdu_count(&pdu_id)?); - Ok((count, pdu)) - }); - - match from { - PduCount::Normal(_) => Ok(Box::new(normal_iter)), - PduCount::Backfilled(x) => { - let mut current_backfill = prefix2.clone(); - // -1 so we don't send the base event - current_backfill.extend_from_slice(&x.saturating_sub(1).to_be_bytes()); - let backfill_iter = self - .pduid_backfillpdu - .iter_from(¤t_backfill, true) - .take_while(move |(k, _)| k.starts_with(&prefix2)) - .map(move |(pdu_id, v)| { - let mut pdu = serde_json::from_slice::(&v) - .map_err(|_| Error::bad_database("PDU in db is invalid."))?; - if pdu.sender != user_id2 { - pdu.remove_transaction_id()?; - } - let count = PduCount::Backfilled(pdu_count(&pdu_id)?); - Ok((count, pdu)) - }); - Ok(Box::new(backfill_iter.chain(normal_iter))) - } - } + Ok(Box::new( + self.pduid_pdu + .iter_from(¤t, false) + .take_while(move |(k, _)| k.starts_with(&prefix)) + .map(move |(pdu_id, v)| { + let mut pdu = serde_json::from_slice::(&v) + .map_err(|_| Error::bad_database("PDU in db is invalid."))?; + if pdu.sender != user_id { + pdu.remove_transaction_id()?; + } + let count = pdu_count(&pdu_id)?; + Ok((count, pdu)) + }), + )) } fn increment_notification_counts( @@ -428,7 +297,58 @@ impl service::rooms::timeline::Data for KeyValueDatabase { } /// Returns the `count` of this pdu's id. -fn pdu_count(pdu_id: &[u8]) -> Result { - utils::u64_from_bytes(&pdu_id[pdu_id.len() - size_of::()..]) - .map_err(|_| Error::bad_database("PDU has invalid count bytes.")) +fn pdu_count(pdu_id: &[u8]) -> Result { + let last_u64 = utils::u64_from_bytes(&pdu_id[pdu_id.len() - size_of::()..]) + .map_err(|_| Error::bad_database("PDU has invalid count bytes."))?; + let second_last_u64 = utils::u64_from_bytes( + &pdu_id[pdu_id.len() - 2 * size_of::()..pdu_id.len() - size_of::()], + ); + + if matches!(second_last_u64, Ok(0)) { + Ok(PduCount::Backfilled(u64::MAX - last_u64)) + } else { + Ok(PduCount::Normal(last_u64)) + } +} + +fn count_to_id( + room_id: &RoomId, + count: PduCount, + offset: u64, + subtract: bool, +) -> Result<(Vec, Vec)> { + let prefix = services() + .rooms + .short + .get_shortroomid(room_id)? + .expect("room exists") + .to_be_bytes() + .to_vec(); + let mut pdu_id = prefix.clone(); + // +1 so we don't send the base event + let count_raw = match count { + PduCount::Normal(x) => { + if subtract { + x - offset + } else { + x + offset + } + } + PduCount::Backfilled(x) => { + pdu_id.extend_from_slice(&0_u64.to_be_bytes()); + let num = u64::MAX - x; + if subtract { + if num > 0 { + num - offset + } else { + num + } + } else { + num + offset + } + } + }; + pdu_id.extend_from_slice(&count_raw.to_be_bytes()); + + Ok((prefix, pdu_id)) } diff --git a/src/database/mod.rs b/src/database/mod.rs index f07ad87..e05991d 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -74,9 +74,7 @@ pub struct KeyValueDatabase { //pub rooms: rooms::Rooms, pub(super) pduid_pdu: Arc, // PduId = ShortRoomId + Count - pub(super) pduid_backfillpdu: Arc, // PduId = ShortRoomId + Count pub(super) eventid_pduid: Arc, - pub(super) eventid_backfillpduid: Arc, pub(super) roomid_pduleaves: Arc, pub(super) alias_roomid: Arc, pub(super) aliasid_alias: Arc, // AliasId = RoomId + Count @@ -297,9 +295,7 @@ impl KeyValueDatabase { presenceid_presence: builder.open_tree("presenceid_presence")?, userid_lastpresenceupdate: builder.open_tree("userid_lastpresenceupdate")?, pduid_pdu: builder.open_tree("pduid_pdu")?, - pduid_backfillpdu: builder.open_tree("pduid_backfillpdu")?, eventid_pduid: builder.open_tree("eventid_pduid")?, - eventid_backfillpduid: builder.open_tree("eventid_backfillpduid")?, roomid_pduleaves: builder.open_tree("roomid_pduleaves")?, alias_roomid: builder.open_tree("alias_roomid")?, diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index dcf04be..47f4c65 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -1045,6 +1045,24 @@ impl Service { ) -> Result<()> { let (event_id, value, room_id) = server_server::parse_incoming_pdu(&pdu)?; + // Lock so we cannot backfill the same pdu twice at the same time + let mutex = Arc::clone( + services() + .globals + .roomid_mutex_federation + .write() + .unwrap() + .entry(room_id.to_owned()) + .or_default(), + ); + let mutex_lock = mutex.lock().await; + + // Skip the PDU if we already have it as a timeline event + if let Some(pdu_id) = services().rooms.timeline.get_pdu_id(&event_id)? { + info!("We already know {event_id} at {pdu_id:?}"); + return Ok(()); + } + services() .rooms .event_handler @@ -1052,6 +1070,7 @@ impl Service { .await?; let value = self.get_pdu_json(&event_id)?.expect("We just created it"); + let pdu = self.get_pdu(&event_id)?.expect("We just created it"); let shortroomid = services() .rooms @@ -1072,14 +1091,36 @@ impl Service { let count = services().globals.next_count()?; let mut pdu_id = shortroomid.to_be_bytes().to_vec(); - pdu_id.extend_from_slice(&count.to_be_bytes()); + pdu_id.extend_from_slice(&0_u64.to_be_bytes()); + pdu_id.extend_from_slice(&(u64::MAX - count).to_be_bytes()); // Insert pdu self.db.prepend_backfill_pdu(&pdu_id, &event_id, &value)?; drop(insert_lock); - info!("Appended incoming pdu"); + match pdu.kind { + RoomEventType::RoomMessage => { + #[derive(Deserialize)] + struct ExtractBody { + body: Option, + } + + let content = serde_json::from_str::(pdu.content.get()) + .map_err(|_| Error::bad_database("Invalid content in pdu."))?; + + if let Some(body) = content.body { + services() + .rooms + .search + .index_pdu(shortroomid, &pdu_id, &body)?; + } + } + _ => {} + } + drop(mutex_lock); + + info!("Prepended backfill pdu"); Ok(()) } } -- cgit v1.2.3 From d39003ffc084eb61a017827d9b985ce6fdeefad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 21 Feb 2023 17:43:39 +0100 Subject: Allow backfilling create event itself --- src/service/rooms/state_accessor/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index bd9ef88..154c189 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -101,7 +101,7 @@ impl Service { ) -> Result { let shortstatehash = match self.pdu_shortstatehash(event_id)? { Some(shortstatehash) => shortstatehash, - None => return Ok(false), + None => return Ok(true), }; if let Some(visibility) = self -- cgit v1.2.3 From 2aa0a2474b9f2f7b9c091b70e48ce3b37d52ab85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 22 Feb 2023 09:32:47 +0100 Subject: fix: ignore unparsable pdus in /send --- src/api/server_server.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index e95a560..adf4bc2 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -688,7 +688,14 @@ pub async fn send_transaction_message_route( // let mut auth_cache = EventMap::new(); for pdu in &body.pdus { - let (event_id, value, room_id) = parse_incoming_pdu(&pdu)?; + let r = parse_incoming_pdu(&pdu); + let (event_id, value, room_id) = match r { + Ok(t) => t, + Err(e) => { + warn!("Could not parse pdu: {e}"); + continue; + } + }; // We do not add the event_id field to the pdu here because of signature and hashes checks services() -- cgit v1.2.3 From 2a16a5e967ff15052fe03313711dda89d0f95232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 22 Feb 2023 13:12:19 +0100 Subject: fix: don't send nulls as unsigned content --- src/service/pdu.rs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/service/pdu.rs b/src/service/pdu.rs index 554f3be..5b5cbd0 100644 --- a/src/service/pdu.rs +++ b/src/service/pdu.rs @@ -111,9 +111,11 @@ impl PduEvent { "event_id": self.event_id, "sender": self.sender, "origin_server_ts": self.origin_server_ts, - "unsigned": self.unsigned, }); + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } if let Some(state_key) = &self.state_key { json["state_key"] = json!(state_key); } @@ -133,10 +135,12 @@ impl PduEvent { "event_id": self.event_id, "sender": self.sender, "origin_server_ts": self.origin_server_ts, - "unsigned": self.unsigned, "room_id": self.room_id, }); + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } if let Some(state_key) = &self.state_key { json["state_key"] = json!(state_key); } @@ -155,10 +159,12 @@ impl PduEvent { "event_id": self.event_id, "sender": self.sender, "origin_server_ts": self.origin_server_ts, - "unsigned": self.unsigned, "room_id": self.room_id, }); + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } if let Some(state_key) = &self.state_key { json["state_key"] = json!(state_key); } @@ -171,32 +177,38 @@ impl PduEvent { #[tracing::instrument(skip(self))] pub fn to_state_event(&self) -> Raw { - let json = json!({ + let mut json = json!({ "content": self.content, "type": self.kind, "event_id": self.event_id, "sender": self.sender, "origin_server_ts": self.origin_server_ts, - "unsigned": self.unsigned, "room_id": self.room_id, "state_key": self.state_key, }); + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + serde_json::from_value(json).expect("Raw::from_value always works") } #[tracing::instrument(skip(self))] pub fn to_sync_state_event(&self) -> Raw { - let json = json!({ + let mut json = json!({ "content": self.content, "type": self.kind, "event_id": self.event_id, "sender": self.sender, "origin_server_ts": self.origin_server_ts, - "unsigned": self.unsigned, "state_key": self.state_key, }); + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + serde_json::from_value(json).expect("Raw::from_value always works") } @@ -214,18 +226,21 @@ impl PduEvent { #[tracing::instrument(skip(self))] pub fn to_member_event(&self) -> Raw> { - let json = json!({ + let mut json = json!({ "content": self.content, "type": self.kind, "event_id": self.event_id, "sender": self.sender, "origin_server_ts": self.origin_server_ts, "redacts": self.redacts, - "unsigned": self.unsigned, "room_id": self.room_id, "state_key": self.state_key, }); + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + serde_json::from_value(json).expect("Raw::from_value always works") } -- cgit v1.2.3 From 10fa686c77637ed2837ff6348ccbdebeff9dcae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 22 Feb 2023 15:49:55 +0100 Subject: feat: respect history visibility --- src/api/client_server/context.rs | 20 ++++++-- src/api/client_server/message.rs | 25 +++++----- src/api/client_server/room.rs | 23 ++++----- src/api/client_server/search.rs | 7 +++ src/api/client_server/state.rs | 81 ++++--------------------------- src/api/server_server.rs | 21 +++++++++ src/service/mod.rs | 3 ++ src/service/rooms/state_accessor/mod.rs | 84 ++++++++++++++++++++++++++++++++- 8 files changed, 166 insertions(+), 98 deletions(-) diff --git a/src/api/client_server/context.rs b/src/api/client_server/context.rs index fa3c754..5a3013b 100644 --- a/src/api/client_server/context.rs +++ b/src/api/client_server/context.rs @@ -50,12 +50,12 @@ pub async fn get_context_route( if !services() .rooms - .state_cache - .is_joined(sender_user, &room_id)? + .state_accessor + .user_can_see_event(sender_user, &room_id, &body.event_id)? { return Err(Error::BadRequest( ErrorKind::Forbidden, - "You don't have permission to view this room.", + "You don't have permission to view this event.", )); } @@ -82,6 +82,13 @@ pub async fn get_context_route( / 2, ) .filter_map(|r| r.ok()) // Remove buggy events + .filter(|(_, pdu)| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &room_id, &pdu.event_id) + .unwrap_or(false) + }) .collect(); for (_, event) in &events_before { @@ -114,6 +121,13 @@ pub async fn get_context_route( / 2, ) .filter_map(|r| r.ok()) // Remove buggy events + .filter(|(_, pdu)| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &room_id, &pdu.event_id) + .unwrap_or(false) + }) .collect(); for (_, event) in &events_after { diff --git a/src/api/client_server/message.rs b/src/api/client_server/message.rs index a0c9571..f7c77f6 100644 --- a/src/api/client_server/message.rs +++ b/src/api/client_server/message.rs @@ -113,17 +113,6 @@ pub async fn get_message_events_route( let sender_user = body.sender_user.as_ref().expect("user is authenticated"); let sender_device = body.sender_device.as_ref().expect("user is authenticated"); - if !services() - .rooms - .state_cache - .is_joined(sender_user, &body.room_id)? - { - return Err(Error::BadRequest( - ErrorKind::Forbidden, - "You don't have permission to view this room.", - )); - } - let from = match body.from.clone() { Some(from) => PduCount::try_from_string(&from)?, None => match body.dir { @@ -161,6 +150,13 @@ pub async fn get_message_events_route( .pdus_after(sender_user, &body.room_id, from)? .take(limit) .filter_map(|r| r.ok()) // Filter out buggy events + .filter(|(_, pdu)| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &body.room_id, &pdu.event_id) + .unwrap_or(false) + }) .take_while(|&(k, _)| Some(k) != to) // Stop at `to` .collect(); @@ -203,6 +199,13 @@ pub async fn get_message_events_route( .pdus_until(sender_user, &body.room_id, from)? .take(limit) .filter_map(|r| r.ok()) // Filter out buggy events + .filter(|(_, pdu)| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &body.room_id, &pdu.event_id) + .unwrap_or(false) + }) .take_while(|&(k, _)| Some(k) != to) // Stop at `to` .collect(); diff --git a/src/api/client_server/room.rs b/src/api/client_server/room.rs index 830e085..aa6fa5f 100644 --- a/src/api/client_server/room.rs +++ b/src/api/client_server/room.rs @@ -425,24 +425,25 @@ pub async fn get_room_event_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - if !services() + let event = services() .rooms - .state_cache - .is_joined(sender_user, &body.room_id)? - { + .timeline + .get_pdu(&body.event_id)? + .ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?; + + if !services().rooms.state_accessor.user_can_see_event( + sender_user, + &event.room_id, + &body.event_id, + )? { return Err(Error::BadRequest( ErrorKind::Forbidden, - "You don't have permission to view this room.", + "You don't have permission to view this event.", )); } Ok(get_room_event::v3::Response { - event: services() - .rooms - .timeline - .get_pdu(&body.event_id)? - .ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))? - .to_room_event(), + event: event.to_room_event(), }) } diff --git a/src/api/client_server/search.rs b/src/api/client_server/search.rs index 5d760db..fe69e7c 100644 --- a/src/api/client_server/search.rs +++ b/src/api/client_server/search.rs @@ -87,6 +87,13 @@ pub async fn search_events_route( .timeline .get_pdu_from_id(result) .ok()? + .filter(|pdu| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &pdu.room_id, &pdu.event_id) + .unwrap_or(false) + }) .map(|pdu| pdu.to_room_event()) }) .map(|result| { diff --git a/src/api/client_server/state.rs b/src/api/client_server/state.rs index d9c1464..e2abe48 100644 --- a/src/api/client_server/state.rs +++ b/src/api/client_server/state.rs @@ -7,11 +7,7 @@ use ruma::{ state::{get_state_events, get_state_events_for_key, send_state_event}, }, events::{ - room::{ - canonical_alias::RoomCanonicalAliasEventContent, - history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, - }, - AnyStateEventContent, StateEventType, + room::canonical_alias::RoomCanonicalAliasEventContent, AnyStateEventContent, StateEventType, }, serde::Raw, EventId, RoomId, UserId, @@ -85,29 +81,10 @@ pub async fn get_state_events_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - #[allow(clippy::blocks_in_if_conditions)] - // Users not in the room should not be able to access the state unless history_visibility is - // WorldReadable - if !services() + if services() .rooms - .state_cache - .is_joined(sender_user, &body.room_id)? - && !matches!( - services() - .rooms - .state_accessor - .room_state_get(&body.room_id, &StateEventType::RoomHistoryVisibility, "")? - .map(|event| { - serde_json::from_str(event.content.get()) - .map(|e: RoomHistoryVisibilityEventContent| e.history_visibility) - .map_err(|_| { - Error::bad_database( - "Invalid room history visibility event in database.", - ) - }) - }), - Some(Ok(HistoryVisibility::WorldReadable)) - ) + .state_accessor + .user_can_see_state_events(&sender_user, &body.room_id)? { return Err(Error::BadRequest( ErrorKind::Forbidden, @@ -137,29 +114,10 @@ pub async fn get_state_events_for_key_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - #[allow(clippy::blocks_in_if_conditions)] - // Users not in the room should not be able to access the state unless history_visibility is - // WorldReadable - if !services() + if services() .rooms - .state_cache - .is_joined(sender_user, &body.room_id)? - && !matches!( - services() - .rooms - .state_accessor - .room_state_get(&body.room_id, &StateEventType::RoomHistoryVisibility, "")? - .map(|event| { - serde_json::from_str(event.content.get()) - .map(|e: RoomHistoryVisibilityEventContent| e.history_visibility) - .map_err(|_| { - Error::bad_database( - "Invalid room history visibility event in database.", - ) - }) - }), - Some(Ok(HistoryVisibility::WorldReadable)) - ) + .state_accessor + .user_can_see_state_events(&sender_user, &body.room_id)? { return Err(Error::BadRequest( ErrorKind::Forbidden, @@ -192,29 +150,10 @@ pub async fn get_state_events_for_empty_key_route( ) -> Result> { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - #[allow(clippy::blocks_in_if_conditions)] - // Users not in the room should not be able to access the state unless history_visibility is - // WorldReadable - if !services() + if services() .rooms - .state_cache - .is_joined(sender_user, &body.room_id)? - && !matches!( - services() - .rooms - .state_accessor - .room_state_get(&body.room_id, &StateEventType::RoomHistoryVisibility, "")? - .map(|event| { - serde_json::from_str(event.content.get()) - .map(|e: RoomHistoryVisibilityEventContent| e.history_visibility) - .map_err(|_| { - Error::bad_database( - "Invalid room history visibility event in database.", - ) - }) - }), - Some(Ok(HistoryVisibility::WorldReadable)) - ) + .state_accessor + .user_can_see_state_events(&sender_user, &body.room_id)? { return Err(Error::BadRequest( ErrorKind::Forbidden, diff --git a/src/api/server_server.rs b/src/api/server_server.rs index adf4bc2..0247369 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -954,6 +954,17 @@ pub async fn get_event_route( )); } + if !services().rooms.state_accessor.server_can_see_event( + sender_servername, + &room_id, + &body.event_id, + )? { + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "Server is not allowed to see event.", + )); + } + Ok(get_event::v1::Response { origin: services().globals.server_name().to_owned(), origin_server_ts: MilliSecondsSinceUnixEpoch::now(), @@ -1098,6 +1109,16 @@ pub async fn get_missing_events_route( i += 1; continue; } + + if !services().rooms.state_accessor.server_can_see_event( + sender_servername, + &body.room_id, + &queued_events[i], + )? { + i += 1; + continue; + } + queued_events.extend_from_slice( &serde_json::from_value::>( serde_json::to_value(pdu.get("prev_events").cloned().ok_or_else(|| { diff --git a/src/service/mod.rs b/src/service/mod.rs index 07d80a1..eea397f 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -82,6 +82,9 @@ impl Services { server_visibility_cache: Mutex::new(LruCache::new( (100.0 * config.conduit_cache_capacity_modifier) as usize, )), + user_visibility_cache: Mutex::new(LruCache::new( + (100.0 * config.conduit_cache_capacity_modifier) as usize, + )), }, state_cache: rooms::state_cache::Service { db }, state_compressor: rooms::state_compressor::Service { diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index 154c189..a25a8b5 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -14,7 +14,7 @@ use ruma::{ }, StateEventType, }, - EventId, OwnedServerName, RoomId, ServerName, UserId, + EventId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId, }; use tracing::error; @@ -23,6 +23,7 @@ use crate::{services, Error, PduEvent, Result}; pub struct Service { pub db: &'static dyn Data, pub server_visibility_cache: Mutex>, + pub user_visibility_cache: Mutex>, } impl Service { @@ -92,7 +93,7 @@ impl Service { /// Whether a server is allowed to see an event through federation, based on /// the room's history_visibility at that event's state. - #[tracing::instrument(skip(self))] + #[tracing::instrument(skip(self, origin, room_id, event_id))] pub fn server_can_see_event( &self, origin: &ServerName, @@ -154,6 +155,85 @@ impl Service { Ok(visibility) } + /// Whether a user is allowed to see an event, based on + /// the room's history_visibility at that event's state. + #[tracing::instrument(skip(self, user_id, room_id, event_id))] + pub fn user_can_see_event( + &self, + user_id: &UserId, + room_id: &RoomId, + event_id: &EventId, + ) -> Result { + let shortstatehash = match self.pdu_shortstatehash(event_id)? { + Some(shortstatehash) => shortstatehash, + None => return Ok(true), + }; + + if let Some(visibility) = self + .user_visibility_cache + .lock() + .unwrap() + .get_mut(&(user_id.to_owned(), shortstatehash)) + { + return Ok(*visibility); + } + + let currently_member = services().rooms.state_cache.is_joined(&user_id, &room_id)?; + + let history_visibility = self + .state_get(shortstatehash, &StateEventType::RoomHistoryVisibility, "")? + .map_or(Ok(HistoryVisibility::Shared), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomHistoryVisibilityEventContent| c.history_visibility) + .map_err(|_| { + Error::bad_database("Invalid history visibility event in database.") + }) + })?; + + let visibility = match history_visibility { + HistoryVisibility::WorldReadable => true, + HistoryVisibility::Shared => currently_member, + HistoryVisibility::Invited => { + // Allow if any member on requesting server was AT LEAST invited, else deny + self.user_was_invited(shortstatehash, &user_id) + } + HistoryVisibility::Joined => { + // Allow if any member on requested server was joined, else deny + self.user_was_joined(shortstatehash, &user_id) + } + _ => { + error!("Unknown history visibility {history_visibility}"); + false + } + }; + + self.user_visibility_cache + .lock() + .unwrap() + .insert((user_id.to_owned(), shortstatehash), visibility); + + Ok(visibility) + } + + /// Whether a user is allowed to see an event, based on + /// the room's history_visibility at that event's state. + #[tracing::instrument(skip(self, user_id, room_id))] + pub fn user_can_see_state_events(&self, user_id: &UserId, room_id: &RoomId) -> Result { + let currently_member = services().rooms.state_cache.is_joined(&user_id, &room_id)?; + + let history_visibility = self + .room_state_get(&room_id, &StateEventType::RoomHistoryVisibility, "")? + .map_or(Ok(HistoryVisibility::Shared), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomHistoryVisibilityEventContent| c.history_visibility) + .map_err(|_| { + Error::bad_database("Invalid history visibility event in database.") + }) + })?; + + Ok(currently_member || history_visibility == HistoryVisibility::WorldReadable) + } + /// Returns the state hash for this pdu. pub fn pdu_shortstatehash(&self, event_id: &EventId) -> Result> { self.db.pdu_shortstatehash(event_id) -- cgit v1.2.3 From 4617ee2b6b763f66bfc6a018471dfdb2170db5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 22 Feb 2023 21:07:47 +0100 Subject: More logging for remote joins --- src/api/client_server/membership.rs | 31 +++++++++++++++++++++++++++---- src/service/rooms/event_handler/mod.rs | 8 ++++++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index cd0cc7a..965c618 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -29,7 +29,7 @@ use std::{ sync::{Arc, RwLock}, time::{Duration, Instant}, }; -use tracing::{debug, error, warn}; +use tracing::{debug, error, info, warn}; use crate::{ service::pdu::{gen_event_id_canonical_json, PduBuilder}, @@ -491,9 +491,13 @@ async fn join_room_by_id_helper( .state_cache .server_in_room(services().globals.server_name(), room_id)? { + info!("Joining {room_id} over federation."); + let (make_join_response, remote_server) = make_join_request(sender_user, room_id, servers).await?; + info!("make_join finished"); + let room_version_id = match make_join_response.room_version { Some(room_version) if services() @@ -578,6 +582,7 @@ async fn join_room_by_id_helper( // It has enough fields to be called a proper event now let mut join_event = join_event_stub; + info!("Asking {remote_server} for send_join"); let send_join_response = services() .sending .send_federation_request( @@ -590,7 +595,10 @@ async fn join_room_by_id_helper( ) .await?; + info!("send_join finished"); + if let Some(signed_raw) = &send_join_response.room_state.event { + info!("There is a signed event. This room is probably using restricted joins"); let (signed_event_id, signed_value) = match gen_event_id_canonical_json(signed_raw, &room_version_id) { Ok(t) => t, @@ -630,24 +638,29 @@ async fn join_room_by_id_helper( .expect("we created a valid pdu") .insert(remote_server.to_string(), signature.clone()); } else { - warn!("Server {} sent invalid sendjoin event", remote_server); + warn!( + "Server {remote_server} sent invalid signature in sendjoin signatures for event {signed_value:?}", + ); } } services().rooms.short.get_or_create_shortroomid(room_id)?; + info!("Parsing join event"); let parsed_join_pdu = PduEvent::from_id_val(event_id, join_event.clone()) .map_err(|_| Error::BadServerResponse("Invalid join event PDU."))?; let mut state = HashMap::new(); let pub_key_map = RwLock::new(BTreeMap::new()); + info!("Fetching join signing keys"); services() .rooms .event_handler .fetch_join_signing_keys(&send_join_response, &room_version_id, &pub_key_map) .await?; + info!("Going through send_join response room_state"); for result in send_join_response .room_state .state @@ -677,6 +690,7 @@ async fn join_room_by_id_helper( } } + info!("Going through send_join response auth_chain"); for result in send_join_response .room_state .auth_chain @@ -694,6 +708,7 @@ async fn join_room_by_id_helper( .add_pdu_outlier(&event_id, &value)?; } + info!("Running send_join auth check"); if !state_res::event_auth::auth_check( &state_res::RoomVersion::new(&room_version_id).expect("room version is supported"), &parsed_join_pdu, @@ -724,6 +739,7 @@ async fn join_room_by_id_helper( )); } + info!("Saving state from send_join"); let (statehash_before_join, new, removed) = services().rooms.state_compressor.save_state( room_id, state @@ -743,12 +759,14 @@ async fn join_room_by_id_helper( .force_state(room_id, statehash_before_join, new, removed, &state_lock) .await?; + info!("Updating joined counts for new room"); services().rooms.state_cache.update_joined_count(room_id)?; // We append to state before appending the pdu, so we don't have a moment in time with the // pdu without it's state. This is okay because append_pdu can't fail. let statehash_after_join = services().rooms.state.append_to_state(&parsed_join_pdu)?; + info!("Appending new room join event"); services().rooms.timeline.append_pdu( &parsed_join_pdu, join_event, @@ -756,6 +774,7 @@ async fn join_room_by_id_helper( &state_lock, )?; + info!("Setting final room state for new room"); // We set the room state after inserting the pdu, so that we never have a moment in time // where events in the current room state do not exist services() @@ -763,6 +782,8 @@ async fn join_room_by_id_helper( .state .set_room_state(room_id, statehash_after_join, &state_lock)?; } else { + info!("We can join locally"); + let join_rules_event = services().rooms.state_accessor.room_state_get( room_id, &StateEventType::RoomJoinRules, @@ -881,8 +902,9 @@ async fn join_room_by_id_helper( }; if !restriction_rooms.is_empty() { - // We couldn't do the join locally, maybe federation can help to satisfy the restricted - // join requirements + info!( + "We couldn't do the join locally, maybe federation can help to satisfy the restricted join requirements" + ); let (make_join_response, remote_server) = make_join_request(sender_user, room_id, servers).await?; @@ -1040,6 +1062,7 @@ async fn make_join_request( if remote_server == services().globals.server_name() { continue; } + info!("Asking {remote_server} for make_join"); let make_join_response = services() .sending .send_federation_request( diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index 66c6394..63301b8 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -1460,12 +1460,12 @@ impl Service { } if servers.is_empty() { - // We had all keys locally + info!("We had all keys locally"); return Ok(()); } for server in services().globals.trusted_servers() { - trace!("Asking batch signing keys from trusted server {}", server); + info!("Asking batch signing keys from trusted server {}", server); if let Ok(keys) = services() .sending .send_federation_request( @@ -1508,10 +1508,12 @@ impl Service { } if servers.is_empty() { + info!("Trusted server supplied all signing keys"); return Ok(()); } } + info!("Asking individual servers for signing keys"); let mut futures: FuturesUnordered<_> = servers .into_keys() .map(|server| async move { @@ -1541,6 +1543,8 @@ impl Service { } } + info!("Search for signing keys done"); + Ok(()) } -- cgit v1.2.3 From 8b648d0d3f1e6bb4f9299ddaaa5502b1b5815718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 22 Feb 2023 22:09:15 +0100 Subject: fix: force abort federation requests after 2 minutes --- src/service/sending/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/service/sending/mod.rs b/src/service/sending/mod.rs index 1861feb..e0e2f54 100644 --- a/src/service/sending/mod.rs +++ b/src/service/sending/mod.rs @@ -684,7 +684,15 @@ impl Service { T: Debug, { let permit = self.maximum_requests.acquire().await; - let response = server_server::send_request(destination, request).await; + let response = tokio::time::timeout( + Duration::from_secs(2 * 60), + server_server::send_request(destination, request), + ) + .await + .map_err(|_| { + warn!("Timeout waiting for server response of {destination}"); + Error::BadServerResponse("Timeout waiting for server response") + })?; drop(permit); response -- cgit v1.2.3 From bde4880c1d169066e22e4c04288f8bce6c84b32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 22 Feb 2023 23:49:49 +0100 Subject: fix: don't unwrap server keys --- src/service/rooms/event_handler/mod.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index 63301b8..e3502e6 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -1529,17 +1529,18 @@ impl Service { while let Some(result) = futures.next().await { if let (Ok(get_keys_response), origin) = result { - let result: BTreeMap<_, _> = services() - .globals - .add_signing_key(&origin, get_keys_response.server_key.deserialize().unwrap())? - .into_iter() - .map(|(k, v)| (k.to_string(), v.key)) - .collect(); - - pub_key_map - .write() - .map_err(|_| Error::bad_database("RwLock is poisoned."))? - .insert(origin.to_string(), result); + if let Ok(key) = get_keys_response.server_key.deserialize() { + let result: BTreeMap<_, _> = services() + .globals + .add_signing_key(&origin, key)? + .into_iter() + .map(|(k, v)| (k.to_string(), v.key)) + .collect(); + pub_key_map + .write() + .map_err(|_| Error::bad_database("RwLock is poisoned."))? + .insert(origin.to_string(), result); + } } } -- cgit v1.2.3 From 2316d89048f78043af95a055f8c8cd45fae894f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 23 Feb 2023 11:20:40 +0100 Subject: Even more logging --- src/api/server_server.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 0247369..3bdbdef 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -125,6 +125,8 @@ where return Err(Error::bad_config("Federation is disabled.")); } + info!("Preparing to send request to {destination}"); + let mut write_destination_to_cache = false; let cached_result = services() @@ -231,11 +233,13 @@ where let url = reqwest_request.url().clone(); + info!("Sending request to {destination} at {url}"); let response = services() .globals .federation_client() .execute(reqwest_request) .await; + info!("Received response from {destination} at {url}"); match response { Ok(mut response) => { @@ -251,10 +255,12 @@ where .expect("http::response::Builder is usable"), ); + info!("Getting response bytes from {destination}"); let body = response.bytes().await.unwrap_or_else(|e| { warn!("server error {}", e); Vec::new().into() }); // TODO: handle timeout + info!("Got response bytes from {destination}"); if status != 200 { warn!( @@ -273,6 +279,7 @@ where .expect("reqwest body is valid http body"); if status == 200 { + info!("Parsing response bytes from {destination}"); let response = T::IncomingResponse::try_from_http_response(http_response); if response.is_ok() && write_destination_to_cache { services() @@ -294,6 +301,7 @@ where Error::BadServerResponse("Server returned bad 200 response.") }) } else { + info!("Returning error from {destination}"); Err(Error::FederationError( destination.to_owned(), RumaError::from_http_response(http_response), -- cgit v1.2.3 From b7c99788e46a4e3c0e25f38742dfac67b72a7b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 23 Feb 2023 11:49:35 +0100 Subject: All the logs --- src/service/rooms/event_handler/mod.rs | 4 +++- src/service/sending/mod.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index e3502e6..da40e6f 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -1513,7 +1513,7 @@ impl Service { } } - info!("Asking individual servers for signing keys"); + info!("Asking individual servers for signing keys: {servers:?}"); let mut futures: FuturesUnordered<_> = servers .into_keys() .map(|server| async move { @@ -1528,6 +1528,7 @@ impl Service { .collect(); while let Some(result) = futures.next().await { + info!("Received new result"); if let (Ok(get_keys_response), origin) = result { if let Ok(key) = get_keys_response.server_key.deserialize() { let result: BTreeMap<_, _> = services() @@ -1542,6 +1543,7 @@ impl Service { .insert(origin.to_string(), result); } } + info!("Done handling result"); } info!("Search for signing keys done"); diff --git a/src/service/sending/mod.rs b/src/service/sending/mod.rs index e0e2f54..b0d9b4b 100644 --- a/src/service/sending/mod.rs +++ b/src/service/sending/mod.rs @@ -40,7 +40,7 @@ use tokio::{ select, sync::{mpsc, Mutex, Semaphore}, }; -use tracing::{error, warn}; +use tracing::{error, info, warn}; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum OutgoingKind { @@ -683,7 +683,9 @@ impl Service { where T: Debug, { + info!("Waiting for permit"); let permit = self.maximum_requests.acquire().await; + info!("Got permit"); let response = tokio::time::timeout( Duration::from_secs(2 * 60), server_server::send_request(destination, request), -- cgit v1.2.3 From cb0ce5b08f8d9e68aad51478d745730e92b2cdba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 23 Feb 2023 12:28:15 +0100 Subject: Logs for server resolution --- src/api/server_server.rs | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 3bdbdef..422da47 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -340,36 +340,38 @@ fn add_port_to_hostname(destination_str: &str) -> FedDest { /// Implemented according to the specification at https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names /// Numbers in comments below refer to bullet points in linked section of specification async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDest) { + info!("Finding actual destination for {destination}"); let destination_str = destination.as_str().to_owned(); let mut hostname = destination_str.clone(); let actual_destination = match get_ip_with_port(&destination_str) { Some(host_port) => { - // 1: IP literal with provided or default port + info!("1: IP literal with provided or default port"); host_port } None => { if let Some(pos) = destination_str.find(':') { - // 2: Hostname with included port + info!("2: Hostname with included port"); let (host, port) = destination_str.split_at(pos); FedDest::Named(host.to_owned(), port.to_owned()) } else { + info!("Requesting well known for {destination}"); match request_well_known(destination.as_str()).await { - // 3: A .well-known file is available Some(delegated_hostname) => { + info!("3: A .well-known file is available"); hostname = add_port_to_hostname(&delegated_hostname).into_uri_string(); match get_ip_with_port(&delegated_hostname) { Some(host_and_port) => host_and_port, // 3.1: IP literal in .well-known file None => { if let Some(pos) = delegated_hostname.find(':') { - // 3.2: Hostname with port in .well-known file + info!("3.2: Hostname with port in .well-known file"); let (host, port) = delegated_hostname.split_at(pos); FedDest::Named(host.to_owned(), port.to_owned()) } else { - // Delegated hostname has no port in this branch + info!("Delegated hostname has no port in this branch"); if let Some(hostname_override) = query_srv_record(&delegated_hostname).await { - // 3.3: SRV lookup successful + info!("3.3: SRV lookup successful"); let force_port = hostname_override.port(); if let Ok(override_ip) = services() @@ -400,18 +402,18 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe add_port_to_hostname(&delegated_hostname) } } else { - // 3.4: No SRV records, just use the hostname from .well-known + info!("3.4: No SRV records, just use the hostname from .well-known"); add_port_to_hostname(&delegated_hostname) } } } } } - // 4: No .well-known or an error occured None => { + info!("4: No .well-known or an error occured"); match query_srv_record(&destination_str).await { - // 4: SRV record found Some(hostname_override) => { + info!("4: SRV record found"); let force_port = hostname_override.port(); if let Ok(override_ip) = services() @@ -442,14 +444,17 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe add_port_to_hostname(&hostname) } } - // 5: No SRV record found - None => add_port_to_hostname(&destination_str), + None => { + info!("5: No SRV record found"); + add_port_to_hostname(&destination_str) + } } } } } } }; + info!("Actual destination: {actual_destination:?}"); // Can't use get_ip_with_port here because we don't want to add a port // to an IP address if it wasn't specified @@ -488,19 +493,16 @@ async fn query_srv_record(hostname: &'_ str) -> Option { } async fn request_well_known(destination: &str) -> Option { - let body: serde_json::Value = serde_json::from_str( - &services() - .globals - .default_client() - .get(&format!("https://{destination}/.well-known/matrix/server")) - .send() - .await - .ok()? - .text() - .await - .ok()?, - ) - .ok()?; + let response = services() + .globals + .default_client() + .get(&format!("https://{destination}/.well-known/matrix/server")) + .send() + .await; + info!("Got well known response"); + let text = response.ok()?.text().await; + info!("Got well known response text"); + let body: serde_json::Value = serde_json::from_str(&text.ok()?).ok()?; Some(body.get("m.server")?.as_str()?.to_owned()) } -- cgit v1.2.3 From 27f29ba69911fc2de240bafe165024fc8ce5ea5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 23 Feb 2023 16:12:58 +0100 Subject: fix: SRV lookups should end with a period --- src/api/server_server.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 422da47..3a6da4f 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -472,10 +472,11 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe } async fn query_srv_record(hostname: &'_ str) -> Option { + let hostname = hostname.trim_end_matches('.'); if let Ok(Some(host_port)) = services() .globals .dns_resolver() - .srv_lookup(format!("_matrix._tcp.{hostname}")) + .srv_lookup(format!("_matrix._tcp.{hostname}.")) .await .map(|srv| { srv.iter().next().map(|result| { -- cgit v1.2.3 From a1bd348977357e55508fc5510d24c8bdc9115c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 7 Mar 2023 17:58:55 +0100 Subject: fix: history visibility --- src/api/client_server/account.rs | 2 +- src/api/client_server/membership.rs | 11 +++++------ src/api/client_server/state.rs | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/api/client_server/account.rs b/src/api/client_server/account.rs index 7459254..1d7480a 100644 --- a/src/api/client_server/account.rs +++ b/src/api/client_server/account.rs @@ -129,7 +129,7 @@ pub async fn register_route(body: Ruma) -> Result Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - // TODO: check history visibility? if !services() .rooms - .state_cache - .is_joined(sender_user, &body.room_id)? + .state_accessor + .user_can_see_state_events(&sender_user, &body.room_id)? { return Err(Error::BadRequest( ErrorKind::Forbidden, @@ -434,12 +433,12 @@ pub async fn joined_members_route( if !services() .rooms - .state_cache - .is_joined(sender_user, &body.room_id)? + .state_accessor + .user_can_see_state_events(&sender_user, &body.room_id)? { return Err(Error::BadRequest( ErrorKind::Forbidden, - "You aren't a member of the room.", + "You don't have permission to view this room.", )); } diff --git a/src/api/client_server/state.rs b/src/api/client_server/state.rs index e2abe48..8e4ceaf 100644 --- a/src/api/client_server/state.rs +++ b/src/api/client_server/state.rs @@ -81,7 +81,7 @@ pub async fn get_state_events_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - if services() + if !services() .rooms .state_accessor .user_can_see_state_events(&sender_user, &body.room_id)? @@ -114,7 +114,7 @@ pub async fn get_state_events_for_key_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - if services() + if !services() .rooms .state_accessor .user_can_see_state_events(&sender_user, &body.room_id)? @@ -150,7 +150,7 @@ pub async fn get_state_events_for_empty_key_route( ) -> Result> { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - if services() + if !services() .rooms .state_accessor .user_can_see_state_events(&sender_user, &body.room_id)? -- cgit v1.2.3 From 63f787f6357ef1344243d97ffa79cacba4694bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 13 Mar 2023 08:27:59 +0100 Subject: Reduce logs from info to debug --- src/api/server_server.rs | 44 +++++++++++++++++----------------- src/service/rooms/event_handler/mod.rs | 1 + src/service/sending/mod.rs | 6 ++--- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 3a6da4f..852e59a 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -125,7 +125,7 @@ where return Err(Error::bad_config("Federation is disabled.")); } - info!("Preparing to send request to {destination}"); + debug!("Preparing to send request to {destination}"); let mut write_destination_to_cache = false; @@ -233,13 +233,13 @@ where let url = reqwest_request.url().clone(); - info!("Sending request to {destination} at {url}"); + debug!("Sending request to {destination} at {url}"); let response = services() .globals .federation_client() .execute(reqwest_request) .await; - info!("Received response from {destination} at {url}"); + debug!("Received response from {destination} at {url}"); match response { Ok(mut response) => { @@ -255,12 +255,12 @@ where .expect("http::response::Builder is usable"), ); - info!("Getting response bytes from {destination}"); + debug!("Getting response bytes from {destination}"); let body = response.bytes().await.unwrap_or_else(|e| { warn!("server error {}", e); Vec::new().into() }); // TODO: handle timeout - info!("Got response bytes from {destination}"); + debug!("Got response bytes from {destination}"); if status != 200 { warn!( @@ -279,7 +279,7 @@ where .expect("reqwest body is valid http body"); if status == 200 { - info!("Parsing response bytes from {destination}"); + debug!("Parsing response bytes from {destination}"); let response = T::IncomingResponse::try_from_http_response(http_response); if response.is_ok() && write_destination_to_cache { services() @@ -301,7 +301,7 @@ where Error::BadServerResponse("Server returned bad 200 response.") }) } else { - info!("Returning error from {destination}"); + debug!("Returning error from {destination}"); Err(Error::FederationError( destination.to_owned(), RumaError::from_http_response(http_response), @@ -340,38 +340,38 @@ fn add_port_to_hostname(destination_str: &str) -> FedDest { /// Implemented according to the specification at https://matrix.org/docs/spec/server_server/r0.1.4#resolving-server-names /// Numbers in comments below refer to bullet points in linked section of specification async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDest) { - info!("Finding actual destination for {destination}"); + debug!("Finding actual destination for {destination}"); let destination_str = destination.as_str().to_owned(); let mut hostname = destination_str.clone(); let actual_destination = match get_ip_with_port(&destination_str) { Some(host_port) => { - info!("1: IP literal with provided or default port"); + debug!("1: IP literal with provided or default port"); host_port } None => { if let Some(pos) = destination_str.find(':') { - info!("2: Hostname with included port"); + debug!("2: Hostname with included port"); let (host, port) = destination_str.split_at(pos); FedDest::Named(host.to_owned(), port.to_owned()) } else { - info!("Requesting well known for {destination}"); + debug!("Requesting well known for {destination}"); match request_well_known(destination.as_str()).await { Some(delegated_hostname) => { - info!("3: A .well-known file is available"); + debug!("3: A .well-known file is available"); hostname = add_port_to_hostname(&delegated_hostname).into_uri_string(); match get_ip_with_port(&delegated_hostname) { Some(host_and_port) => host_and_port, // 3.1: IP literal in .well-known file None => { if let Some(pos) = delegated_hostname.find(':') { - info!("3.2: Hostname with port in .well-known file"); + debug!("3.2: Hostname with port in .well-known file"); let (host, port) = delegated_hostname.split_at(pos); FedDest::Named(host.to_owned(), port.to_owned()) } else { - info!("Delegated hostname has no port in this branch"); + debug!("Delegated hostname has no port in this branch"); if let Some(hostname_override) = query_srv_record(&delegated_hostname).await { - info!("3.3: SRV lookup successful"); + debug!("3.3: SRV lookup successful"); let force_port = hostname_override.port(); if let Ok(override_ip) = services() @@ -402,7 +402,7 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe add_port_to_hostname(&delegated_hostname) } } else { - info!("3.4: No SRV records, just use the hostname from .well-known"); + debug!("3.4: No SRV records, just use the hostname from .well-known"); add_port_to_hostname(&delegated_hostname) } } @@ -410,10 +410,10 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe } } None => { - info!("4: No .well-known or an error occured"); + debug!("4: No .well-known or an error occured"); match query_srv_record(&destination_str).await { Some(hostname_override) => { - info!("4: SRV record found"); + debug!("4: SRV record found"); let force_port = hostname_override.port(); if let Ok(override_ip) = services() @@ -445,7 +445,7 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe } } None => { - info!("5: No SRV record found"); + debug!("5: No SRV record found"); add_port_to_hostname(&destination_str) } } @@ -454,7 +454,7 @@ async fn find_actual_destination(destination: &'_ ServerName) -> (FedDest, FedDe } } }; - info!("Actual destination: {actual_destination:?}"); + debug!("Actual destination: {actual_destination:?}"); // Can't use get_ip_with_port here because we don't want to add a port // to an IP address if it wasn't specified @@ -500,9 +500,9 @@ async fn request_well_known(destination: &str) -> Option { .get(&format!("https://{destination}/.well-known/matrix/server")) .send() .await; - info!("Got well known response"); + debug!("Got well known response"); let text = response.ok()?.text().await; - info!("Got well known response text"); + debug!("Got well known response text"); let body: serde_json::Value = serde_json::from_str(&text.ok()?).ok()?; Some(body.get("m.server")?.as_str()?.to_owned()) } diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index da40e6f..b01a282 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -1530,6 +1530,7 @@ impl Service { while let Some(result) = futures.next().await { info!("Received new result"); if let (Ok(get_keys_response), origin) = result { + info!("Result is from {origin}"); if let Ok(key) = get_keys_response.server_key.deserialize() { let result: BTreeMap<_, _> = services() .globals diff --git a/src/service/sending/mod.rs b/src/service/sending/mod.rs index b0d9b4b..14d83be 100644 --- a/src/service/sending/mod.rs +++ b/src/service/sending/mod.rs @@ -40,7 +40,7 @@ use tokio::{ select, sync::{mpsc, Mutex, Semaphore}, }; -use tracing::{error, info, warn}; +use tracing::{debug, error, warn}; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum OutgoingKind { @@ -683,9 +683,9 @@ impl Service { where T: Debug, { - info!("Waiting for permit"); + debug!("Waiting for permit"); let permit = self.maximum_requests.acquire().await; - info!("Got permit"); + debug!("Got permit"); let response = tokio::time::timeout( Duration::from_secs(2 * 60), server_server::send_request(destination, request), -- cgit v1.2.3 From 42b12934e33c81b0684347d5c02e874bf3492674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 13 Mar 2023 10:39:02 +0100 Subject: Don't crash when a room errors --- src/api/client_server/sync.rs | 1473 +++++++++++++++++++++-------------------- 1 file changed, 751 insertions(+), 722 deletions(-) diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 834438c..5eb820c 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -2,7 +2,14 @@ use crate::{service::rooms::timeline::PduCount, services, Error, Result, Ruma, R use ruma::{ api::client::{ filter::{FilterDefinition, LazyLoadOptions}, - sync::sync_events::{self, DeviceLists, UnreadNotificationsCount}, + sync::sync_events::{ + self, + v3::{ + Ephemeral, Filter, GlobalAccountData, InviteState, InvitedRoom, JoinedRoom, + LeftRoom, Presence, RoomAccountData, RoomSummary, Rooms, State, Timeline, ToDevice, + }, + DeviceLists, UnreadNotificationsCount, + }, uiaa::UiaaResponse, }, events::{ @@ -10,7 +17,7 @@ use ruma::{ RoomEventType, StateEventType, }, serde::Raw, - OwnedDeviceId, OwnedUserId, RoomId, UserId, + DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UserId, }; use std::{ collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, @@ -160,11 +167,6 @@ async fn sync_helper( body: sync_events::v3::Request, // bool = caching allowed ) -> Result<(sync_events::v3::Response, bool), Error> { - use sync_events::v3::{ - Ephemeral, Filter, GlobalAccountData, InviteState, InvitedRoom, JoinedRoom, LeftRoom, - Presence, RoomAccountData, RoomSummary, Rooms, State, Timeline, ToDevice, - }; - // TODO: match body.set_presence { services().rooms.edus.presence.ping_presence(&sender_user)?; @@ -192,6 +194,8 @@ async fn sync_helper( _ => (false, false), }; + let full_state = body.full_state; + let mut joined_rooms = BTreeMap::new(); let since = body .since @@ -220,10 +224,76 @@ async fn sync_helper( .collect::>(); for room_id in all_joined_rooms { let room_id = room_id?; + if let Ok(joined_room) = load_joined_room( + &sender_user, + &sender_device, + &room_id, + since, + sincecount, + next_batch, + next_batchcount, + lazy_load_enabled, + lazy_load_send_redundant, + full_state, + &mut device_list_updates, + &mut left_encrypted_users, + ) + .await + { + if !joined_room.is_empty() { + joined_rooms.insert(room_id.clone(), joined_room); + } + + // Take presence updates from this room + for (user_id, presence) in services() + .rooms + .edus + .presence + .presence_since(&room_id, since)? + { + match presence_updates.entry(user_id) { + Entry::Vacant(v) => { + v.insert(presence); + } + Entry::Occupied(mut o) => { + let p = o.get_mut(); + + // Update existing presence event with more info + p.content.presence = presence.content.presence; + if let Some(status_msg) = presence.content.status_msg { + p.content.status_msg = Some(status_msg); + } + if let Some(last_active_ago) = presence.content.last_active_ago { + p.content.last_active_ago = Some(last_active_ago); + } + if let Some(displayname) = presence.content.displayname { + p.content.displayname = Some(displayname); + } + if let Some(avatar_url) = presence.content.avatar_url { + p.content.avatar_url = Some(avatar_url); + } + if let Some(currently_active) = presence.content.currently_active { + p.content.currently_active = Some(currently_active); + } + } + } + } + } + } + + let mut left_rooms = BTreeMap::new(); + let all_left_rooms: Vec<_> = services() + .rooms + .state_cache + .rooms_left(&sender_user) + .collect(); + for result in all_left_rooms { + let (room_id, _) = result?; + + let mut left_state_events = Vec::new(); { // Get and drop the lock to wait for remaining operations to finish - // This will make sure the we have all events until next_batch let mutex_insert = Arc::clone( services() .globals @@ -237,219 +307,77 @@ async fn sync_helper( drop(insert_lock); } - let timeline_pdus; - let limited; - if services() + let left_count = services() .rooms - .timeline - .last_timeline_count(&sender_user, &room_id)? - > sincecount - { - let mut non_timeline_pdus = services() - .rooms - .timeline - .pdus_until(&sender_user, &room_id, PduCount::max())? - .filter_map(|r| { - // Filter out buggy events - if r.is_err() { - error!("Bad pdu in pdus_since: {:?}", r); - } - r.ok() - }) - .take_while(|(pducount, _)| pducount > &sincecount); - - // Take the last 10 events for the timeline - timeline_pdus = non_timeline_pdus - .by_ref() - .take(10) - .collect::>() - .into_iter() - .rev() - .collect::>(); + .state_cache + .get_left_count(&room_id, &sender_user)?; - // They /sync response doesn't always return all messages, so we say the output is - // limited unless there are events in non_timeline_pdus - limited = non_timeline_pdus.next().is_some(); - } else { - timeline_pdus = Vec::new(); - limited = false; + // Left before last sync + if Some(since) >= left_count { + continue; } - let send_notification_counts = !timeline_pdus.is_empty() - || services() - .rooms - .user - .last_notification_read(&sender_user, &room_id)? - > since; - - let mut timeline_users = HashSet::new(); - for (_, event) in &timeline_pdus { - timeline_users.insert(event.sender.as_str().to_owned()); + if !services().rooms.metadata.exists(&room_id)? { + // This is just a rejected invite, not a room we know + continue; } - services().rooms.lazy_loading.lazy_load_confirm_delivery( - &sender_user, - &sender_device, - &room_id, - sincecount, - )?; - - // Database queries: - - let current_shortstatehash = - if let Some(s) = services().rooms.state.get_room_shortstatehash(&room_id)? { - s - } else { - error!("Room {} has no state", room_id); - continue; - }; - let since_shortstatehash = services() .rooms .user .get_token_shortstatehash(&room_id, since)?; - // Calculates joined_member_count, invited_member_count and heroes - let calculate_counts = || { - let joined_member_count = services() - .rooms - .state_cache - .room_joined_count(&room_id)? - .unwrap_or(0); - let invited_member_count = services() - .rooms - .state_cache - .room_invited_count(&room_id)? - .unwrap_or(0); - - // Recalculate heroes (first 5 members) - let mut heroes = Vec::new(); - - if joined_member_count + invited_member_count <= 5 { - // Go through all PDUs and for each member event, check if the user is still joined or - // invited until we have 5 or we reach the end - - for hero in services() - .rooms - .timeline - .all_pdus(&sender_user, &room_id)? - .filter_map(|pdu| pdu.ok()) // Ignore all broken pdus - .filter(|(_, pdu)| pdu.kind == RoomEventType::RoomMember) - .map(|(_, pdu)| { - let content: RoomMemberEventContent = - serde_json::from_str(pdu.content.get()).map_err(|_| { - Error::bad_database("Invalid member event in database.") - })?; - - if let Some(state_key) = &pdu.state_key { - let user_id = UserId::parse(state_key.clone()).map_err(|_| { - Error::bad_database("Invalid UserId in member PDU.") - })?; - - // The membership was and still is invite or join - if matches!( - content.membership, - MembershipState::Join | MembershipState::Invite - ) && (services().rooms.state_cache.is_joined(&user_id, &room_id)? - || services() - .rooms - .state_cache - .is_invited(&user_id, &room_id)?) - { - Ok::<_, Error>(Some(state_key.clone())) - } else { - Ok(None) - } - } else { - Ok(None) - } - }) - // Filter out buggy users - .filter_map(|u| u.ok()) - // Filter for possible heroes - .flatten() - { - if heroes.contains(&hero) || hero == sender_user.as_str() { - continue; - } + let since_state_ids = match since_shortstatehash { + Some(s) => services().rooms.state_accessor.state_full_ids(s).await?, + None => HashMap::new(), + }; - heroes.push(hero); - } + let left_event_id = match services().rooms.state_accessor.room_state_get_id( + &room_id, + &StateEventType::RoomMember, + sender_user.as_str(), + )? { + Some(e) => e, + None => { + error!("Left room but no left state event"); + continue; } - - Ok::<_, Error>(( - Some(joined_member_count), - Some(invited_member_count), - heroes, - )) }; - let since_sender_member: Option = since_shortstatehash - .and_then(|shortstatehash| { - services() - .rooms - .state_accessor - .state_get( - shortstatehash, - &StateEventType::RoomMember, - sender_user.as_str(), - ) - .transpose() - }) - .transpose()? - .and_then(|pdu| { - serde_json::from_str(pdu.content.get()) - .map_err(|_| Error::bad_database("Invalid PDU in database.")) - .ok() - }); - - let joined_since_last_sync = - since_sender_member.map_or(true, |member| member.membership != MembershipState::Join); - - let ( - heroes, - joined_member_count, - invited_member_count, - joined_since_last_sync, - state_events, - ) = if since_shortstatehash.is_none() || joined_since_last_sync { - // Probably since = 0, we will do an initial sync - - let (joined_member_count, invited_member_count, heroes) = calculate_counts()?; + let left_shortstatehash = match services() + .rooms + .state_accessor + .pdu_shortstatehash(&left_event_id)? + { + Some(s) => s, + None => { + error!("Leave event has no state"); + continue; + } + }; - let current_state_ids = services() - .rooms - .state_accessor - .state_full_ids(current_shortstatehash) - .await?; + let mut left_state_ids = services() + .rooms + .state_accessor + .state_full_ids(left_shortstatehash) + .await?; - let mut state_events = Vec::new(); - let mut lazy_loaded = HashSet::new(); + let leave_shortstatekey = services() + .rooms + .short + .get_or_create_shortstatekey(&StateEventType::RoomMember, sender_user.as_str())?; - let mut i = 0; - for (shortstatekey, id) in current_state_ids { - let (event_type, state_key) = services() - .rooms - .short - .get_statekey_from_short(shortstatekey)?; + left_state_ids.insert(leave_shortstatekey, left_event_id); - if event_type != StateEventType::RoomMember { - let pdu = match services().rooms.timeline.get_pdu(&id)? { - Some(pdu) => pdu, - None => { - error!("Pdu in state not found: {}", id); - continue; - } - }; - state_events.push(pdu); + let mut i = 0; + for (key, id) in left_state_ids { + if full_state || since_state_ids.get(&key) != Some(&id) { + let (event_type, state_key) = + services().rooms.short.get_statekey_from_short(key)?; - i += 1; - if i % 100 == 0 { - tokio::task::yield_now().await; - } - } else if !lazy_load_enabled - || body.full_state - || timeline_users.contains(&state_key) + if !lazy_load_enabled + || event_type != StateEventType::RoomMember + || full_state // TODO: Delete the following line when this is resolved: https://github.com/vector-im/element-web/issues/22565 || *sender_user == state_key { @@ -461,11 +389,7 @@ async fn sync_helper( } }; - // This check is in case a bad user ID made it into the database - if let Ok(uid) = UserId::parse(&state_key) { - lazy_loaded.insert(uid); - } - state_events.push(pdu); + left_state_events.push(pdu.to_sync_state_event()); i += 1; if i % 100 == 0 { @@ -473,55 +397,469 @@ async fn sync_helper( } } } + } - // Reset lazy loading because this is an initial sync - services().rooms.lazy_loading.lazy_load_reset( - &sender_user, - &sender_device, - &room_id, - )?; + left_rooms.insert( + room_id.clone(), + LeftRoom { + account_data: RoomAccountData { events: Vec::new() }, + timeline: Timeline { + limited: false, + prev_batch: Some(next_batch_string.clone()), + events: Vec::new(), + }, + state: State { + events: left_state_events, + }, + }, + ); + } - // The state_events above should contain all timeline_users, let's mark them as lazy - // loaded. - services().rooms.lazy_loading.lazy_load_mark_sent( - &sender_user, - &sender_device, - &room_id, - lazy_loaded, - next_batchcount, - ); + let mut invited_rooms = BTreeMap::new(); + let all_invited_rooms: Vec<_> = services() + .rooms + .state_cache + .rooms_invited(&sender_user) + .collect(); + for result in all_invited_rooms { + let (room_id, invite_state_events) = result?; - ( - heroes, - joined_member_count, - invited_member_count, - true, - state_events, - ) - } else if timeline_pdus.is_empty() && since_shortstatehash == Some(current_shortstatehash) { - // No state changes - (Vec::new(), None, None, false, Vec::new()) - } else { - // Incremental /sync - let since_shortstatehash = since_shortstatehash.unwrap(); + { + // Get and drop the lock to wait for remaining operations to finish + let mutex_insert = Arc::clone( + services() + .globals + .roomid_mutex_insert + .write() + .unwrap() + .entry(room_id.clone()) + .or_default(), + ); + let insert_lock = mutex_insert.lock().unwrap(); + drop(insert_lock); + } - let mut state_events = Vec::new(); - let mut lazy_loaded = HashSet::new(); + let invite_count = services() + .rooms + .state_cache + .get_invite_count(&room_id, &sender_user)?; - if since_shortstatehash != current_shortstatehash { - let current_state_ids = services() - .rooms - .state_accessor - .state_full_ids(current_shortstatehash) - .await?; - let since_state_ids = services() - .rooms - .state_accessor - .state_full_ids(since_shortstatehash) - .await?; + // Invited before last sync + if Some(since) >= invite_count { + continue; + } + + invited_rooms.insert( + room_id.clone(), + InvitedRoom { + invite_state: InviteState { + events: invite_state_events, + }, + }, + ); + } + + for user_id in left_encrypted_users { + let still_share_encrypted_room = services() + .rooms + .user + .get_shared_rooms(vec![sender_user.clone(), user_id.clone()])? + .filter_map(|r| r.ok()) + .filter_map(|other_room_id| { + Some( + services() + .rooms + .state_accessor + .room_state_get(&other_room_id, &StateEventType::RoomEncryption, "") + .ok()? + .is_some(), + ) + }) + .all(|encrypted| !encrypted); + // If the user doesn't share an encrypted room with the target anymore, we need to tell + // them + if still_share_encrypted_room { + device_list_left.insert(user_id); + } + } + + // Remove all to-device events the device received *last time* + services() + .users + .remove_to_device_events(&sender_user, &sender_device, since)?; + + let response = sync_events::v3::Response { + next_batch: next_batch_string, + rooms: Rooms { + leave: left_rooms, + join: joined_rooms, + invite: invited_rooms, + knock: BTreeMap::new(), // TODO + }, + presence: Presence { + events: presence_updates + .into_values() + .map(|v| Raw::new(&v).expect("PresenceEvent always serializes successfully")) + .collect(), + }, + account_data: GlobalAccountData { + events: services() + .account_data + .changes_since(None, &sender_user, since)? + .into_iter() + .filter_map(|(_, v)| { + serde_json::from_str(v.json().get()) + .map_err(|_| Error::bad_database("Invalid account event in database.")) + .ok() + }) + .collect(), + }, + device_lists: DeviceLists { + changed: device_list_updates.into_iter().collect(), + left: device_list_left.into_iter().collect(), + }, + device_one_time_keys_count: services() + .users + .count_one_time_keys(&sender_user, &sender_device)?, + to_device: ToDevice { + events: services() + .users + .get_to_device_events(&sender_user, &sender_device)?, + }, + // Fallback keys are not yet supported + device_unused_fallback_key_types: None, + }; + + // TODO: Retry the endpoint instead of returning (waiting for #118) + if !full_state + && response.rooms.is_empty() + && response.presence.is_empty() + && response.account_data.is_empty() + && response.device_lists.is_empty() + && response.to_device.is_empty() + { + // Hang a few seconds so requests are not spammed + // Stop hanging if new info arrives + let mut duration = body.timeout.unwrap_or_default(); + if duration.as_secs() > 30 { + duration = Duration::from_secs(30); + } + let _ = tokio::time::timeout(duration, watcher).await; + Ok((response, false)) + } else { + Ok((response, since != next_batch)) // Only cache if we made progress + } +} + +async fn load_joined_room( + sender_user: &UserId, + sender_device: &DeviceId, + room_id: &RoomId, + since: u64, + sincecount: PduCount, + next_batch: u64, + next_batchcount: PduCount, + lazy_load_enabled: bool, + lazy_load_send_redundant: bool, + full_state: bool, + device_list_updates: &mut HashSet, + left_encrypted_users: &mut HashSet, +) -> Result { + { + // Get and drop the lock to wait for remaining operations to finish + // This will make sure the we have all events until next_batch + let mutex_insert = Arc::clone( + services() + .globals + .roomid_mutex_insert + .write() + .unwrap() + .entry(room_id.to_owned()) + .or_default(), + ); + let insert_lock = mutex_insert.lock().unwrap(); + drop(insert_lock); + } + + let timeline_pdus; + let limited; + if services() + .rooms + .timeline + .last_timeline_count(&sender_user, &room_id)? + > sincecount + { + let mut non_timeline_pdus = services() + .rooms + .timeline + .pdus_until(&sender_user, &room_id, PduCount::max())? + .filter_map(|r| { + // Filter out buggy events + if r.is_err() { + error!("Bad pdu in pdus_since: {:?}", r); + } + r.ok() + }) + .take_while(|(pducount, _)| pducount > &sincecount); + + // Take the last 10 events for the timeline + timeline_pdus = non_timeline_pdus + .by_ref() + .take(10) + .collect::>() + .into_iter() + .rev() + .collect::>(); + + // They /sync response doesn't always return all messages, so we say the output is + // limited unless there are events in non_timeline_pdus + limited = non_timeline_pdus.next().is_some(); + } else { + timeline_pdus = Vec::new(); + limited = false; + } + + let send_notification_counts = !timeline_pdus.is_empty() + || services() + .rooms + .user + .last_notification_read(&sender_user, &room_id)? + > since; + + let mut timeline_users = HashSet::new(); + for (_, event) in &timeline_pdus { + timeline_users.insert(event.sender.as_str().to_owned()); + } + + services().rooms.lazy_loading.lazy_load_confirm_delivery( + &sender_user, + &sender_device, + &room_id, + sincecount, + )?; + + // Database queries: + + let current_shortstatehash = + if let Some(s) = services().rooms.state.get_room_shortstatehash(&room_id)? { + s + } else { + error!("Room {} has no state", room_id); + return Err(Error::BadDatabase("Room has no state")); + }; + + let since_shortstatehash = services() + .rooms + .user + .get_token_shortstatehash(&room_id, since)?; + + // Calculates joined_member_count, invited_member_count and heroes + let calculate_counts = || { + let joined_member_count = services() + .rooms + .state_cache + .room_joined_count(&room_id)? + .unwrap_or(0); + let invited_member_count = services() + .rooms + .state_cache + .room_invited_count(&room_id)? + .unwrap_or(0); + + // Recalculate heroes (first 5 members) + let mut heroes = Vec::new(); + + if joined_member_count + invited_member_count <= 5 { + // Go through all PDUs and for each member event, check if the user is still joined or + // invited until we have 5 or we reach the end + + for hero in services() + .rooms + .timeline + .all_pdus(&sender_user, &room_id)? + .filter_map(|pdu| pdu.ok()) // Ignore all broken pdus + .filter(|(_, pdu)| pdu.kind == RoomEventType::RoomMember) + .map(|(_, pdu)| { + let content: RoomMemberEventContent = serde_json::from_str(pdu.content.get()) + .map_err(|_| { + Error::bad_database("Invalid member event in database.") + })?; + + if let Some(state_key) = &pdu.state_key { + let user_id = UserId::parse(state_key.clone()) + .map_err(|_| Error::bad_database("Invalid UserId in member PDU."))?; + + // The membership was and still is invite or join + if matches!( + content.membership, + MembershipState::Join | MembershipState::Invite + ) && (services().rooms.state_cache.is_joined(&user_id, &room_id)? + || services() + .rooms + .state_cache + .is_invited(&user_id, &room_id)?) + { + Ok::<_, Error>(Some(state_key.clone())) + } else { + Ok(None) + } + } else { + Ok(None) + } + }) + // Filter out buggy users + .filter_map(|u| u.ok()) + // Filter for possible heroes + .flatten() + { + if heroes.contains(&hero) || hero == sender_user.as_str() { + continue; + } + + heroes.push(hero); + } + } + + Ok::<_, Error>(( + Some(joined_member_count), + Some(invited_member_count), + heroes, + )) + }; + + let since_sender_member: Option = since_shortstatehash + .and_then(|shortstatehash| { + services() + .rooms + .state_accessor + .state_get( + shortstatehash, + &StateEventType::RoomMember, + sender_user.as_str(), + ) + .transpose() + }) + .transpose()? + .and_then(|pdu| { + serde_json::from_str(pdu.content.get()) + .map_err(|_| Error::bad_database("Invalid PDU in database.")) + .ok() + }); + + let joined_since_last_sync = + since_sender_member.map_or(true, |member| member.membership != MembershipState::Join); + + let (heroes, joined_member_count, invited_member_count, joined_since_last_sync, state_events) = + if since_shortstatehash.is_none() || joined_since_last_sync { + // Probably since = 0, we will do an initial sync + + let (joined_member_count, invited_member_count, heroes) = calculate_counts()?; + + let current_state_ids = services() + .rooms + .state_accessor + .state_full_ids(current_shortstatehash) + .await?; + + let mut state_events = Vec::new(); + let mut lazy_loaded = HashSet::new(); + + let mut i = 0; + for (shortstatekey, id) in current_state_ids { + let (event_type, state_key) = services() + .rooms + .short + .get_statekey_from_short(shortstatekey)?; + + if event_type != StateEventType::RoomMember { + let pdu = match services().rooms.timeline.get_pdu(&id)? { + Some(pdu) => pdu, + None => { + error!("Pdu in state not found: {}", id); + continue; + } + }; + state_events.push(pdu); + + i += 1; + if i % 100 == 0 { + tokio::task::yield_now().await; + } + } else if !lazy_load_enabled + || full_state + || timeline_users.contains(&state_key) + // TODO: Delete the following line when this is resolved: https://github.com/vector-im/element-web/issues/22565 + || *sender_user == state_key + { + let pdu = match services().rooms.timeline.get_pdu(&id)? { + Some(pdu) => pdu, + None => { + error!("Pdu in state not found: {}", id); + continue; + } + }; + + // This check is in case a bad user ID made it into the database + if let Ok(uid) = UserId::parse(&state_key) { + lazy_loaded.insert(uid); + } + state_events.push(pdu); + + i += 1; + if i % 100 == 0 { + tokio::task::yield_now().await; + } + } + } + + // Reset lazy loading because this is an initial sync + services().rooms.lazy_loading.lazy_load_reset( + &sender_user, + &sender_device, + &room_id, + )?; + + // The state_events above should contain all timeline_users, let's mark them as lazy + // loaded. + services().rooms.lazy_loading.lazy_load_mark_sent( + &sender_user, + &sender_device, + &room_id, + lazy_loaded, + next_batchcount, + ); + + ( + heroes, + joined_member_count, + invited_member_count, + true, + state_events, + ) + } else if timeline_pdus.is_empty() && since_shortstatehash == Some(current_shortstatehash) { + // No state changes + (Vec::new(), None, None, false, Vec::new()) + } else { + // Incremental /sync + let since_shortstatehash = since_shortstatehash.unwrap(); + + let mut state_events = Vec::new(); + let mut lazy_loaded = HashSet::new(); + + if since_shortstatehash != current_shortstatehash { + let current_state_ids = services() + .rooms + .state_accessor + .state_full_ids(current_shortstatehash) + .await?; + let since_state_ids = services() + .rooms + .state_accessor + .state_full_ids(since_shortstatehash) + .await?; for (key, id) in current_state_ids { - if body.full_state || since_state_ids.get(&key) != Some(&id) { + if full_state || since_state_ids.get(&key) != Some(&id) { let pdu = match services().rooms.timeline.get_pdu(&id)? { Some(pdu) => pdu, None => { @@ -585,471 +923,174 @@ async fn sync_helper( .rooms .state_accessor .state_get(current_shortstatehash, &StateEventType::RoomEncryption, "")? - .is_some(); - - let since_encryption = services().rooms.state_accessor.state_get( - since_shortstatehash, - &StateEventType::RoomEncryption, - "", - )?; - - // Calculations: - let new_encrypted_room = encrypted_room && since_encryption.is_none(); - - let send_member_count = state_events - .iter() - .any(|event| event.kind == RoomEventType::RoomMember); - - if encrypted_room { - for state_event in &state_events { - if state_event.kind != RoomEventType::RoomMember { - continue; - } - - if let Some(state_key) = &state_event.state_key { - let user_id = UserId::parse(state_key.clone()) - .map_err(|_| Error::bad_database("Invalid UserId in member PDU."))?; - - if user_id == sender_user { - continue; - } - - let new_membership = serde_json::from_str::( - state_event.content.get(), - ) - .map_err(|_| Error::bad_database("Invalid PDU in database."))? - .membership; - - match new_membership { - MembershipState::Join => { - // A new user joined an encrypted room - if !share_encrypted_room(&sender_user, &user_id, &room_id)? { - device_list_updates.insert(user_id); - } - } - MembershipState::Leave => { - // Write down users that have left encrypted rooms we are in - left_encrypted_users.insert(user_id); - } - _ => {} - } - } - } - } - - if joined_since_last_sync && encrypted_room || new_encrypted_room { - // If the user is in a new encrypted room, give them all joined users - device_list_updates.extend( - services() - .rooms - .state_cache - .room_members(&room_id) - .flatten() - .filter(|user_id| { - // Don't send key updates from the sender to the sender - &sender_user != user_id - }) - .filter(|user_id| { - // Only send keys if the sender doesn't share an encrypted room with the target already - !share_encrypted_room(&sender_user, user_id, &room_id).unwrap_or(false) - }), - ); - } - - let (joined_member_count, invited_member_count, heroes) = if send_member_count { - calculate_counts()? - } else { - (None, None, Vec::new()) - }; - - ( - heroes, - joined_member_count, - invited_member_count, - joined_since_last_sync, - state_events, - ) - }; - - // Look for device list updates in this room - device_list_updates.extend( - services() - .users - .keys_changed(room_id.as_ref(), since, None) - .filter_map(|r| r.ok()), - ); - - let notification_count = if send_notification_counts { - Some( - services() - .rooms - .user - .notification_count(&sender_user, &room_id)? - .try_into() - .expect("notification count can't go that high"), - ) - } else { - None - }; - - let highlight_count = if send_notification_counts { - Some( - services() - .rooms - .user - .highlight_count(&sender_user, &room_id)? - .try_into() - .expect("highlight count can't go that high"), - ) - } else { - None - }; - - let prev_batch = timeline_pdus - .first() - .map_or(Ok::<_, Error>(None), |(pdu_count, _)| { - Ok(Some(match pdu_count { - PduCount::Backfilled(_) => { - error!("timeline in backfill state?!"); - "0".to_owned() - } - PduCount::Normal(c) => c.to_string(), - })) - })?; - - let room_events: Vec<_> = timeline_pdus - .iter() - .map(|(_, pdu)| pdu.to_sync_room_event()) - .collect(); - - let mut edus: Vec<_> = services() - .rooms - .edus - .read_receipt - .readreceipts_since(&room_id, since) - .filter_map(|r| r.ok()) // Filter out buggy events - .map(|(_, _, v)| v) - .collect(); - - if services().rooms.edus.typing.last_typing_update(&room_id)? > since { - edus.push( - serde_json::from_str( - &serde_json::to_string(&services().rooms.edus.typing.typings_all(&room_id)?) - .expect("event is valid, we just created it"), - ) - .expect("event is valid, we just created it"), - ); - } - - // Save the state after this sync so we can send the correct state diff next sync - services().rooms.user.associate_token_shortstatehash( - &room_id, - next_batch, - current_shortstatehash, - )?; - - let joined_room = JoinedRoom { - account_data: RoomAccountData { - events: services() - .account_data - .changes_since(Some(&room_id), &sender_user, since)? - .into_iter() - .filter_map(|(_, v)| { - serde_json::from_str(v.json().get()) - .map_err(|_| Error::bad_database("Invalid account event in database.")) - .ok() - }) - .collect(), - }, - summary: RoomSummary { - heroes, - joined_member_count: joined_member_count.map(|n| (n as u32).into()), - invited_member_count: invited_member_count.map(|n| (n as u32).into()), - }, - unread_notifications: UnreadNotificationsCount { - highlight_count, - notification_count, - }, - timeline: Timeline { - limited: limited || joined_since_last_sync, - prev_batch, - events: room_events, - }, - state: State { - events: state_events - .iter() - .map(|pdu| pdu.to_sync_state_event()) - .collect(), - }, - ephemeral: Ephemeral { events: edus }, - unread_thread_notifications: BTreeMap::new(), - }; - - if !joined_room.is_empty() { - joined_rooms.insert(room_id.clone(), joined_room); - } - - // Take presence updates from this room - for (user_id, presence) in services() - .rooms - .edus - .presence - .presence_since(&room_id, since)? - { - match presence_updates.entry(user_id) { - Entry::Vacant(v) => { - v.insert(presence); - } - Entry::Occupied(mut o) => { - let p = o.get_mut(); - - // Update existing presence event with more info - p.content.presence = presence.content.presence; - if let Some(status_msg) = presence.content.status_msg { - p.content.status_msg = Some(status_msg); - } - if let Some(last_active_ago) = presence.content.last_active_ago { - p.content.last_active_ago = Some(last_active_ago); - } - if let Some(displayname) = presence.content.displayname { - p.content.displayname = Some(displayname); - } - if let Some(avatar_url) = presence.content.avatar_url { - p.content.avatar_url = Some(avatar_url); - } - if let Some(currently_active) = presence.content.currently_active { - p.content.currently_active = Some(currently_active); - } - } - } - } - } - - let mut left_rooms = BTreeMap::new(); - let all_left_rooms: Vec<_> = services() - .rooms - .state_cache - .rooms_left(&sender_user) - .collect(); - for result in all_left_rooms { - let (room_id, _) = result?; - - let mut left_state_events = Vec::new(); - - { - // Get and drop the lock to wait for remaining operations to finish - let mutex_insert = Arc::clone( - services() - .globals - .roomid_mutex_insert - .write() - .unwrap() - .entry(room_id.clone()) - .or_default(), - ); - let insert_lock = mutex_insert.lock().unwrap(); - drop(insert_lock); - } - - let left_count = services() - .rooms - .state_cache - .get_left_count(&room_id, &sender_user)?; - - // Left before last sync - if Some(since) >= left_count { - continue; - } - - if !services().rooms.metadata.exists(&room_id)? { - // This is just a rejected invite, not a room we know - continue; - } - - let since_shortstatehash = services() - .rooms - .user - .get_token_shortstatehash(&room_id, since)?; - - let since_state_ids = match since_shortstatehash { - Some(s) => services().rooms.state_accessor.state_full_ids(s).await?, - None => HashMap::new(), - }; - - let left_event_id = match services().rooms.state_accessor.room_state_get_id( - &room_id, - &StateEventType::RoomMember, - sender_user.as_str(), - )? { - Some(e) => e, - None => { - error!("Left room but no left state event"); - continue; - } - }; - - let left_shortstatehash = match services() - .rooms - .state_accessor - .pdu_shortstatehash(&left_event_id)? - { - Some(s) => s, - None => { - error!("Leave event has no state"); - continue; - } - }; + .is_some(); - let mut left_state_ids = services() - .rooms - .state_accessor - .state_full_ids(left_shortstatehash) - .await?; + let since_encryption = services().rooms.state_accessor.state_get( + since_shortstatehash, + &StateEventType::RoomEncryption, + "", + )?; - let leave_shortstatekey = services() - .rooms - .short - .get_or_create_shortstatekey(&StateEventType::RoomMember, sender_user.as_str())?; + // Calculations: + let new_encrypted_room = encrypted_room && since_encryption.is_none(); - left_state_ids.insert(leave_shortstatekey, left_event_id); + let send_member_count = state_events + .iter() + .any(|event| event.kind == RoomEventType::RoomMember); - let mut i = 0; - for (key, id) in left_state_ids { - if body.full_state || since_state_ids.get(&key) != Some(&id) { - let (event_type, state_key) = - services().rooms.short.get_statekey_from_short(key)?; + if encrypted_room { + for state_event in &state_events { + if state_event.kind != RoomEventType::RoomMember { + continue; + } - if !lazy_load_enabled - || event_type != StateEventType::RoomMember - || body.full_state - // TODO: Delete the following line when this is resolved: https://github.com/vector-im/element-web/issues/22565 - || *sender_user == state_key - { - let pdu = match services().rooms.timeline.get_pdu(&id)? { - Some(pdu) => pdu, - None => { - error!("Pdu in state not found: {}", id); + if let Some(state_key) = &state_event.state_key { + let user_id = UserId::parse(state_key.clone()) + .map_err(|_| Error::bad_database("Invalid UserId in member PDU."))?; + + if user_id == sender_user { continue; } - }; - left_state_events.push(pdu.to_sync_state_event()); + let new_membership = serde_json::from_str::( + state_event.content.get(), + ) + .map_err(|_| Error::bad_database("Invalid PDU in database."))? + .membership; - i += 1; - if i % 100 == 0 { - tokio::task::yield_now().await; + match new_membership { + MembershipState::Join => { + // A new user joined an encrypted room + if !share_encrypted_room(&sender_user, &user_id, &room_id)? { + device_list_updates.insert(user_id); + } + } + MembershipState::Leave => { + // Write down users that have left encrypted rooms we are in + left_encrypted_users.insert(user_id); + } + _ => {} + } } } } - } - left_rooms.insert( - room_id.clone(), - LeftRoom { - account_data: RoomAccountData { events: Vec::new() }, - timeline: Timeline { - limited: false, - prev_batch: Some(next_batch_string.clone()), - events: Vec::new(), - }, - state: State { - events: left_state_events, - }, - }, - ); - } + if joined_since_last_sync && encrypted_room || new_encrypted_room { + // If the user is in a new encrypted room, give them all joined users + device_list_updates.extend( + services() + .rooms + .state_cache + .room_members(&room_id) + .flatten() + .filter(|user_id| { + // Don't send key updates from the sender to the sender + &sender_user != user_id + }) + .filter(|user_id| { + // Only send keys if the sender doesn't share an encrypted room with the target already + !share_encrypted_room(&sender_user, user_id, &room_id).unwrap_or(false) + }), + ); + } - let mut invited_rooms = BTreeMap::new(); - let all_invited_rooms: Vec<_> = services() - .rooms - .state_cache - .rooms_invited(&sender_user) - .collect(); - for result in all_invited_rooms { - let (room_id, invite_state_events) = result?; + let (joined_member_count, invited_member_count, heroes) = if send_member_count { + calculate_counts()? + } else { + (None, None, Vec::new()) + }; - { - // Get and drop the lock to wait for remaining operations to finish - let mutex_insert = Arc::clone( - services() - .globals - .roomid_mutex_insert - .write() - .unwrap() - .entry(room_id.clone()) - .or_default(), - ); - let insert_lock = mutex_insert.lock().unwrap(); - drop(insert_lock); - } + ( + heroes, + joined_member_count, + invited_member_count, + joined_since_last_sync, + state_events, + ) + }; - let invite_count = services() - .rooms - .state_cache - .get_invite_count(&room_id, &sender_user)?; + // Look for device list updates in this room + device_list_updates.extend( + services() + .users + .keys_changed(room_id.as_ref(), since, None) + .filter_map(|r| r.ok()), + ); - // Invited before last sync - if Some(since) >= invite_count { - continue; - } + let notification_count = if send_notification_counts { + Some( + services() + .rooms + .user + .notification_count(&sender_user, &room_id)? + .try_into() + .expect("notification count can't go that high"), + ) + } else { + None + }; - invited_rooms.insert( - room_id.clone(), - InvitedRoom { - invite_state: InviteState { - events: invite_state_events, - }, - }, - ); - } + let highlight_count = if send_notification_counts { + Some( + services() + .rooms + .user + .highlight_count(&sender_user, &room_id)? + .try_into() + .expect("highlight count can't go that high"), + ) + } else { + None + }; - for user_id in left_encrypted_users { - let still_share_encrypted_room = services() - .rooms - .user - .get_shared_rooms(vec![sender_user.clone(), user_id.clone()])? - .filter_map(|r| r.ok()) - .filter_map(|other_room_id| { - Some( - services() - .rooms - .state_accessor - .room_state_get(&other_room_id, &StateEventType::RoomEncryption, "") - .ok()? - .is_some(), - ) - }) - .all(|encrypted| !encrypted); - // If the user doesn't share an encrypted room with the target anymore, we need to tell - // them - if still_share_encrypted_room { - device_list_left.insert(user_id); - } + let prev_batch = timeline_pdus + .first() + .map_or(Ok::<_, Error>(None), |(pdu_count, _)| { + Ok(Some(match pdu_count { + PduCount::Backfilled(_) => { + error!("timeline in backfill state?!"); + "0".to_owned() + } + PduCount::Normal(c) => c.to_string(), + })) + })?; + + let room_events: Vec<_> = timeline_pdus + .iter() + .map(|(_, pdu)| pdu.to_sync_room_event()) + .collect(); + + let mut edus: Vec<_> = services() + .rooms + .edus + .read_receipt + .readreceipts_since(&room_id, since) + .filter_map(|r| r.ok()) // Filter out buggy events + .map(|(_, _, v)| v) + .collect(); + + if services().rooms.edus.typing.last_typing_update(&room_id)? > since { + edus.push( + serde_json::from_str( + &serde_json::to_string(&services().rooms.edus.typing.typings_all(&room_id)?) + .expect("event is valid, we just created it"), + ) + .expect("event is valid, we just created it"), + ); } - // Remove all to-device events the device received *last time* - services() - .users - .remove_to_device_events(&sender_user, &sender_device, since)?; + // Save the state after this sync so we can send the correct state diff next sync + services().rooms.user.associate_token_shortstatehash( + &room_id, + next_batch, + current_shortstatehash, + )?; - let response = sync_events::v3::Response { - next_batch: next_batch_string, - rooms: Rooms { - leave: left_rooms, - join: joined_rooms, - invite: invited_rooms, - knock: BTreeMap::new(), // TODO - }, - presence: Presence { - events: presence_updates - .into_values() - .map(|v| Raw::new(&v).expect("PresenceEvent always serializes successfully")) - .collect(), - }, - account_data: GlobalAccountData { + Ok(JoinedRoom { + account_data: RoomAccountData { events: services() .account_data - .changes_since(None, &sender_user, since)? + .changes_since(Some(&room_id), &sender_user, since)? .into_iter() .filter_map(|(_, v)| { serde_json::from_str(v.json().get()) @@ -1058,41 +1099,29 @@ async fn sync_helper( }) .collect(), }, - device_lists: DeviceLists { - changed: device_list_updates.into_iter().collect(), - left: device_list_left.into_iter().collect(), + summary: RoomSummary { + heroes, + joined_member_count: joined_member_count.map(|n| (n as u32).into()), + invited_member_count: invited_member_count.map(|n| (n as u32).into()), }, - device_one_time_keys_count: services() - .users - .count_one_time_keys(&sender_user, &sender_device)?, - to_device: ToDevice { - events: services() - .users - .get_to_device_events(&sender_user, &sender_device)?, + unread_notifications: UnreadNotificationsCount { + highlight_count, + notification_count, }, - // Fallback keys are not yet supported - device_unused_fallback_key_types: None, - }; - - // TODO: Retry the endpoint instead of returning (waiting for #118) - if !body.full_state - && response.rooms.is_empty() - && response.presence.is_empty() - && response.account_data.is_empty() - && response.device_lists.is_empty() - && response.to_device.is_empty() - { - // Hang a few seconds so requests are not spammed - // Stop hanging if new info arrives - let mut duration = body.timeout.unwrap_or_default(); - if duration.as_secs() > 30 { - duration = Duration::from_secs(30); - } - let _ = tokio::time::timeout(duration, watcher).await; - Ok((response, false)) - } else { - Ok((response, since != next_batch)) // Only cache if we made progress - } + timeline: Timeline { + limited: limited || joined_since_last_sync, + prev_batch, + events: room_events, + }, + state: State { + events: state_events + .iter() + .map(|pdu| pdu.to_sync_state_event()) + .collect(), + }, + ephemeral: Ephemeral { events: edus }, + unread_thread_notifications: BTreeMap::new(), + }) } fn share_encrypted_room( -- cgit v1.2.3 From da3871f39a3a0a7b5b34e2110e41717c33754a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Fri, 17 Mar 2023 22:44:50 +0100 Subject: fix: let requests continue event if client disconnects --- src/main.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main.rs b/src/main.rs index fe6cfc0..a51416d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -147,6 +147,7 @@ async fn run_server() -> io::Result<()> { let middlewares = ServiceBuilder::new() .sensitive_headers([header::AUTHORIZATION]) + .layer(axum::middleware::from_fn(spawn_task)) .layer( TraceLayer::new_for_http().make_span_with(|request: &http::Request<_>| { let path = if let Some(path) = request.extensions().get::() { @@ -221,6 +222,15 @@ async fn run_server() -> io::Result<()> { Ok(()) } +async fn spawn_task( + req: axum::http::Request, + next: axum::middleware::Next, +) -> std::result::Result { + tokio::spawn(next.run(req)) + .await + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) +} + async fn unrecognized_method( req: axum::http::Request, next: axum::middleware::Next, -- cgit v1.2.3 From 2a7c4693b8680ab8f00e990e1c779a8d36967520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sat, 18 Mar 2023 08:58:20 +0100 Subject: fix: don't accept new requests when shutting down --- src/main.rs | 17 +++++++++-------- src/service/globals/mod.rs | 15 +++++++++++++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index a51416d..59e82a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ #![allow(clippy::suspicious_else_formatting)] #![deny(clippy::dbg_macro)] -use std::{future::Future, io, net::SocketAddr, time::Duration}; +use std::{future::Future, io, net::SocketAddr, sync::atomic, time::Duration}; use axum::{ extract::{DefaultBodyLimit, FromRequest, MatchedPath}, @@ -212,13 +212,6 @@ async fn run_server() -> io::Result<()> { } } - // On shutdown - info!(target: "shutdown-sync", "Received shutdown notification, notifying sync helpers..."); - services().globals.rotate.fire(); - - #[cfg(feature = "systemd")] - let _ = sd_notify::notify(true, &[sd_notify::NotifyState::Stopping]); - Ok(()) } @@ -226,6 +219,9 @@ async fn spawn_task( req: axum::http::Request, next: axum::middleware::Next, ) -> std::result::Result { + if services().globals.shutdown.load(atomic::Ordering::Relaxed) { + return Err(StatusCode::SERVICE_UNAVAILABLE); + } tokio::spawn(next.run(req)) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) @@ -452,6 +448,11 @@ async fn shutdown_signal(handle: ServerHandle) { warn!("Received {}, shutting down...", sig); handle.graceful_shutdown(Some(Duration::from_secs(30))); + + services().globals.shutdown(); + + #[cfg(feature = "systemd")] + let _ = sd_notify::notify(true, &[sd_notify::NotifyState::Stopping]); } async fn not_found(uri: Uri) -> impl IntoResponse { diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index cd3be08..9206d43 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -6,7 +6,7 @@ use ruma::{ use crate::api::server_server::FedDest; -use crate::{Config, Error, Result}; +use crate::{services, Config, Error, Result}; use ruma::{ api::{ client::sync::sync_events, @@ -14,6 +14,7 @@ use ruma::{ }, DeviceId, RoomVersionId, ServerName, UserId, }; +use std::sync::atomic::{self, AtomicBool}; use std::{ collections::{BTreeMap, HashMap}, fs, @@ -24,7 +25,7 @@ use std::{ time::{Duration, Instant}, }; use tokio::sync::{broadcast, watch::Receiver, Mutex as TokioMutex, Semaphore}; -use tracing::error; +use tracing::{error, info}; use trust_dns_resolver::TokioAsyncResolver; type WellKnownMap = HashMap; @@ -58,6 +59,8 @@ pub struct Service { pub roomid_federationhandletime: RwLock>, pub stateres_mutex: Arc>, pub rotate: RotationHandler, + + pub shutdown: AtomicBool, } /// Handles "rotation" of long-polling requests. "Rotation" in this context is similar to "rotation" of log files and the like. @@ -160,6 +163,7 @@ impl Service { stateres_mutex: Arc::new(Mutex::new(())), sync_receivers: RwLock::new(HashMap::new()), rotate: RotationHandler::new(), + shutdown: AtomicBool::new(false), }; fs::create_dir_all(s.get_media_folder())?; @@ -341,6 +345,13 @@ impl Service { r.push(base64::encode_config(key, base64::URL_SAFE_NO_PAD)); r } + + pub fn shutdown(&self) { + self.shutdown.store(true, atomic::Ordering::Relaxed); + // On shutdown + info!(target: "shutdown-sync", "Received shutdown notification, notifying sync helpers..."); + services().globals.rotate.fire(); + } } fn reqwest_client_builder(config: &Config) -> Result { -- cgit v1.2.3 From f53ecaa97db45e8ab749bd65195a3eaf85a28a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 26 Feb 2023 16:29:06 +0100 Subject: Bump Ruma --- Cargo.lock | 143 +++++++++++++++++++++++++++--------- Cargo.toml | 4 +- src/api/client_server/config.rs | 8 +- src/api/client_server/membership.rs | 18 +++-- src/api/client_server/message.rs | 12 +-- src/api/client_server/profile.rs | 6 +- src/api/client_server/redact.rs | 4 +- src/api/client_server/room.rs | 30 ++++---- src/api/client_server/sync.rs | 10 +-- src/api/client_server/to_device.rs | 7 +- src/api/ruma_wrapper/axum.rs | 2 +- src/api/server_server.rs | 27 ++++--- src/service/admin/mod.rs | 30 ++++---- src/service/pdu.rs | 18 ++--- src/service/pusher/mod.rs | 7 +- src/service/rooms/state/mod.rs | 4 +- src/service/rooms/timeline/mod.rs | 44 ++++++----- 17 files changed, 228 insertions(+), 146 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 505c71c..385d8f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,9 +183,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64ct" @@ -412,6 +412,7 @@ dependencies = [ "rust-argon2", "sd-notify", "serde", + "serde_html_form", "serde_json", "serde_yaml", "sha-1", @@ -669,7 +670,7 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2", + "sha2 0.9.9", "zeroize", ] @@ -721,7 +722,7 @@ dependencies = [ "atomic", "pear", "serde", - "toml", + "toml 0.5.9", "uncased", "version_check", ] @@ -1819,7 +1820,7 @@ checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ "once_cell", "thiserror", - "toml", + "toml 0.5.9", ] [[package]] @@ -2075,8 +2076,8 @@ dependencies = [ [[package]] name = "ruma" -version = "0.7.4" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.8.2" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "assign", "js_int", @@ -2093,8 +2094,8 @@ dependencies = [ [[package]] name = "ruma-appservice-api" -version = "0.7.0" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.8.1" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "js_int", "ruma-common", @@ -2104,8 +2105,8 @@ dependencies = [ [[package]] name = "ruma-client-api" -version = "0.15.3" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.16.2" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "assign", "bytes", @@ -2113,23 +2114,22 @@ dependencies = [ "js_int", "js_option", "maplit", - "percent-encoding", "ruma-common", "serde", + "serde_html_form", "serde_json", ] [[package]] name = "ruma-common" -version = "0.10.5" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.11.3" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ - "base64 0.20.0", + "base64 0.21.0", "bytes", "form_urlencoded", "http", "indexmap", - "itoa", "js_int", "js_option", "konst", @@ -2139,6 +2139,7 @@ dependencies = [ "ruma-identifiers-validation", "ruma-macros", "serde", + "serde_html_form", "serde_json", "thiserror", "tracing", @@ -2149,8 +2150,8 @@ dependencies = [ [[package]] name = "ruma-federation-api" -version = "0.6.0" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.7.1" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "js_int", "ruma-common", @@ -2160,8 +2161,8 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" -version = "0.9.0" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.9.1" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "js_int", "thiserror", @@ -2169,8 +2170,8 @@ dependencies = [ [[package]] name = "ruma-identity-service-api" -version = "0.6.0" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.7.1" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "js_int", "ruma-common", @@ -2179,8 +2180,8 @@ dependencies = [ [[package]] name = "ruma-macros" -version = "0.10.5" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.11.3" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "once_cell", "proc-macro-crate", @@ -2189,13 +2190,13 @@ dependencies = [ "ruma-identifiers-validation", "serde", "syn", - "toml", + "toml 0.7.2", ] [[package]] name = "ruma-push-gateway-api" -version = "0.6.0" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.7.1" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "js_int", "ruma-common", @@ -2205,24 +2206,24 @@ dependencies = [ [[package]] name = "ruma-signatures" -version = "0.12.0" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.13.1" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ - "base64 0.20.0", + "base64 0.21.0", "ed25519-dalek", "pkcs8", "rand 0.7.3", "ruma-common", "serde_json", - "sha2", + "sha2 0.10.6", "subslice", "thiserror", ] [[package]] name = "ruma-state-res" -version = "0.8.0" -source = "git+https://github.com/ruma/ruma?rev=67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26#67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26" +version = "0.9.1" +source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" dependencies = [ "itertools", "js_int", @@ -2388,6 +2389,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_html_form" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53192e38d5c88564b924dbe9b60865ecbb71b81d38c4e61c817cffd3e36ef696" +dependencies = [ + "form_urlencoded", + "indexmap", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_json" version = "1.0.89" @@ -2399,6 +2413,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2459,6 +2482,17 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -2807,6 +2841,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -3343,6 +3411,15 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "winnow" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.7.0" diff --git a/Cargo.toml b/Cargo.toml index 36ffb13..7c7df7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ tower-http = { version = "0.3.4", features = ["add-extension", "cors", "compress # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -ruma = { git = "https://github.com/ruma/ruma", rev = "67d0f3cc04a8d1dc4a8a1ec947519967ce11ce26", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +ruma = { git = "https://github.com/ruma/ruma", rev = "8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } #ruma = { git = "https://github.com/timokoesters/ruma", rev = "50c1db7e0a3a21fc794b0cce3b64285a4c750c71", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } #ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } @@ -83,6 +83,8 @@ num_cpus = "1.13.0" threadpool = "1.8.1" heed = { git = "https://github.com/timokoesters/heed.git", rev = "f6f825da7fb2c758867e05ad973ef800a6fe1d5d", optional = true } rocksdb = { version = "0.17.0", default-features = true, features = ["multi-threaded-cf", "zstd"], optional = true } +# Used for ruma wrapper +serde_html_form = "0.2.0" thread_local = "1.1.3" # used for TURN server authentication diff --git a/src/api/client_server/config.rs b/src/api/client_server/config.rs index 12f9aea..37279e3 100644 --- a/src/api/client_server/config.rs +++ b/src/api/client_server/config.rs @@ -75,7 +75,7 @@ pub async fn get_global_account_data_route( let event: Box = services() .account_data - .get(None, sender_user, body.event_type.clone().into())? + .get(None, sender_user, body.event_type.to_string().into())? .ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?; let account_data = serde_json::from_str::(event.get()) @@ -95,11 +95,7 @@ pub async fn get_room_account_data_route( let event: Box = services() .account_data - .get( - Some(&body.room_id), - sender_user, - body.event_type.clone().into(), - )? + .get(Some(&body.room_id), sender_user, body.event_type.clone())? .ok_or(Error::BadRequest(ErrorKind::NotFound, "Data not found."))?; let account_data = serde_json::from_str::(event.get()) diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index b9b1756..cd26372 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -17,7 +17,7 @@ use ruma::{ member::{MembershipState, RoomMemberEventContent}, power_levels::RoomPowerLevelsEventContent, }, - RoomEventType, StateEventType, + StateEventType, TimelineEventType, }, serde::Base64, state_res, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, @@ -209,7 +209,7 @@ pub async fn kick_user_route( services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&event).expect("event is valid, we just created it"), unsigned: None, state_key: Some(body.user_id.to_string()), @@ -273,7 +273,7 @@ pub async fn ban_user_route(body: Ruma) -> Result( let (pdu, pdu_json) = services().rooms.timeline.create_hash_and_sign_event( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content, unsigned: None, state_key: Some(user_id.to_string()), @@ -1295,7 +1297,7 @@ pub(crate) async fn invite_helper<'a>( services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { membership: MembershipState::Invite, displayname: services().users.displayname(user_id)?, @@ -1420,7 +1422,7 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option PduCount::try_from_string(&from)?, None => match body.dir { - ruma::api::client::Direction::Forward => PduCount::min(), - ruma::api::client::Direction::Backward => PduCount::max(), + ruma::api::Direction::Forward => PduCount::min(), + ruma::api::Direction::Backward => PduCount::max(), }, }; @@ -143,7 +143,7 @@ pub async fn get_message_events_route( let mut lazy_loaded = HashSet::new(); match body.dir { - ruma::api::client::Direction::Forward => { + ruma::api::Direction::Forward => { let events_after: Vec<_> = services() .rooms .timeline @@ -187,7 +187,7 @@ pub async fn get_message_events_route( resp.end = next_token.map(|count| count.stringify()); resp.chunk = events_after; } - ruma::api::client::Direction::Backward => { + ruma::api::Direction::Backward => { services() .rooms .timeline diff --git a/src/api/client_server/profile.rs b/src/api/client_server/profile.rs index 6400e89..8fb38b5 100644 --- a/src/api/client_server/profile.rs +++ b/src/api/client_server/profile.rs @@ -9,7 +9,7 @@ use ruma::{ }, federation::{self, query::get_profile_information::v1::ProfileField}, }, - events::{room::member::RoomMemberEventContent, RoomEventType, StateEventType}, + events::{room::member::RoomMemberEventContent, StateEventType, TimelineEventType}, }; use serde_json::value::to_raw_value; use std::sync::Arc; @@ -37,7 +37,7 @@ pub async fn set_displayname_route( .map(|room_id| { Ok::<_, Error>(( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { displayname: body.displayname.clone(), ..serde_json::from_str( @@ -172,7 +172,7 @@ pub async fn set_avatar_url_route( .map(|room_id| { Ok::<_, Error>(( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { avatar_url: body.avatar_url.clone(), ..serde_json::from_str( diff --git a/src/api/client_server/redact.rs b/src/api/client_server/redact.rs index a29a561..20f7e91 100644 --- a/src/api/client_server/redact.rs +++ b/src/api/client_server/redact.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use crate::{service::pdu::PduBuilder, services, Result, Ruma}; use ruma::{ api::client::redact::redact_event, - events::{room::redaction::RoomRedactionEventContent, RoomEventType}, + events::{room::redaction::RoomRedactionEventContent, TimelineEventType}, }; use serde_json::value::to_raw_value; @@ -32,7 +32,7 @@ pub async fn redact_event_route( let event_id = services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomRedaction, + event_type: TimelineEventType::RoomRedaction, content: to_raw_value(&RoomRedactionEventContent { reason: body.reason.clone(), }) diff --git a/src/api/client_server/room.rs b/src/api/client_server/room.rs index aa6fa5f..8c39b78 100644 --- a/src/api/client_server/room.rs +++ b/src/api/client_server/room.rs @@ -19,7 +19,7 @@ use ruma::{ tombstone::RoomTombstoneEventContent, topic::RoomTopicEventContent, }, - RoomEventType, StateEventType, + StateEventType, TimelineEventType, }, int, serde::JsonObject, @@ -175,7 +175,7 @@ pub async fn create_room_route( // 1. The room create event services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomCreate, + event_type: TimelineEventType::RoomCreate, content: to_raw_value(&content).expect("event is valid, we just created it"), unsigned: None, state_key: Some("".to_owned()), @@ -189,7 +189,7 @@ pub async fn create_room_route( // 2. Let the room creator join services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { membership: MembershipState::Join, displayname: services().users.displayname(sender_user)?, @@ -247,7 +247,7 @@ pub async fn create_room_route( services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomPowerLevels, + event_type: TimelineEventType::RoomPowerLevels, content: to_raw_value(&power_levels_content) .expect("to_raw_value always works on serde_json::Value"), unsigned: None, @@ -263,7 +263,7 @@ pub async fn create_room_route( if let Some(room_alias_id) = &alias { services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomCanonicalAlias, + event_type: TimelineEventType::RoomCanonicalAlias, content: to_raw_value(&RoomCanonicalAliasEventContent { alias: Some(room_alias_id.to_owned()), alt_aliases: vec![], @@ -284,7 +284,7 @@ pub async fn create_room_route( // 5.1 Join Rules services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomJoinRules, + event_type: TimelineEventType::RoomJoinRules, content: to_raw_value(&RoomJoinRulesEventContent::new(match preset { RoomPreset::PublicChat => JoinRule::Public, // according to spec "invite" is the default @@ -303,7 +303,7 @@ pub async fn create_room_route( // 5.2 History Visibility services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomHistoryVisibility, + event_type: TimelineEventType::RoomHistoryVisibility, content: to_raw_value(&RoomHistoryVisibilityEventContent::new( HistoryVisibility::Shared, )) @@ -320,7 +320,7 @@ pub async fn create_room_route( // 5.3 Guest Access services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomGuestAccess, + event_type: TimelineEventType::RoomGuestAccess, content: to_raw_value(&RoomGuestAccessEventContent::new(match preset { RoomPreset::PublicChat => GuestAccess::Forbidden, _ => GuestAccess::CanJoin, @@ -346,7 +346,7 @@ pub async fn create_room_route( pdu_builder.state_key.get_or_insert_with(|| "".to_owned()); // Silently skip encryption events if they are not allowed - if pdu_builder.event_type == RoomEventType::RoomEncryption + if pdu_builder.event_type == TimelineEventType::RoomEncryption && !services().globals.allow_encryption() { continue; @@ -364,7 +364,7 @@ pub async fn create_room_route( if let Some(name) = &body.name { services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomName, + event_type: TimelineEventType::RoomName, content: to_raw_value(&RoomNameEventContent::new(Some(name.clone()))) .expect("event is valid, we just created it"), unsigned: None, @@ -380,7 +380,7 @@ pub async fn create_room_route( if let Some(topic) = &body.topic { services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomTopic, + event_type: TimelineEventType::RoomTopic, content: to_raw_value(&RoomTopicEventContent { topic: topic.clone(), }) @@ -526,7 +526,7 @@ pub async fn upgrade_room_route( // Fail if the sender does not have the required permissions let tombstone_event_id = services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomTombstone, + event_type: TimelineEventType::RoomTombstone, content: to_raw_value(&RoomTombstoneEventContent { body: "This room has been replaced".to_owned(), replacement_room: replacement_room.clone(), @@ -608,7 +608,7 @@ pub async fn upgrade_room_route( services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomCreate, + event_type: TimelineEventType::RoomCreate, content: to_raw_value(&create_event_content) .expect("event is valid, we just created it"), unsigned: None, @@ -623,7 +623,7 @@ pub async fn upgrade_room_route( // Join the new room services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { membership: MembershipState::Join, displayname: services().users.displayname(sender_user)?, @@ -716,7 +716,7 @@ pub async fn upgrade_room_route( // Modify the power levels in the old room to prevent sending of events and inviting new users let _ = services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomPowerLevels, + event_type: TimelineEventType::RoomPowerLevels, content: to_raw_value(&power_levels_event_content) .expect("event is valid, we just created it"), unsigned: None, diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 5eb820c..b4baec1 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -14,7 +14,7 @@ use ruma::{ }, events::{ room::member::{MembershipState, RoomMemberEventContent}, - RoomEventType, StateEventType, + StateEventType, TimelineEventType, }, serde::Raw, DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UserId, @@ -678,7 +678,7 @@ async fn load_joined_room( .timeline .all_pdus(&sender_user, &room_id)? .filter_map(|pdu| pdu.ok()) // Ignore all broken pdus - .filter(|(_, pdu)| pdu.kind == RoomEventType::RoomMember) + .filter(|(_, pdu)| pdu.kind == TimelineEventType::RoomMember) .map(|(_, pdu)| { let content: RoomMemberEventContent = serde_json::from_str(pdu.content.get()) .map_err(|_| { @@ -868,7 +868,7 @@ async fn load_joined_room( } }; - if pdu.kind == RoomEventType::RoomMember { + if pdu.kind == TimelineEventType::RoomMember { match UserId::parse( pdu.state_key .as_ref() @@ -936,11 +936,11 @@ async fn load_joined_room( let send_member_count = state_events .iter() - .any(|event| event.kind == RoomEventType::RoomMember); + .any(|event| event.kind == TimelineEventType::RoomMember); if encrypted_room { for state_event in &state_events { - if state_event.kind != RoomEventType::RoomMember { + if state_event.kind != TimelineEventType::RoomMember { continue; } diff --git a/src/api/client_server/to_device.rs b/src/api/client_server/to_device.rs index 26db4e4..31590fc 100644 --- a/src/api/client_server/to_device.rs +++ b/src/api/client_server/to_device.rs @@ -1,4 +1,3 @@ -use ruma::events::ToDeviceEventType; use std::collections::BTreeMap; use crate::{services, Error, Result, Ruma}; @@ -42,7 +41,7 @@ pub async fn send_event_to_device_route( serde_json::to_vec(&federation::transactions::edu::Edu::DirectToDevice( DirectDeviceContent { sender: sender_user.clone(), - ev_type: ToDeviceEventType::from(&*body.event_type), + ev_type: body.event_type.clone(), message_id: count.to_string().into(), messages, }, @@ -60,7 +59,7 @@ pub async fn send_event_to_device_route( sender_user, target_user_id, target_device_id, - &body.event_type, + &body.event_type.to_string(), event.deserialize_as().map_err(|_| { Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid") })?, @@ -73,7 +72,7 @@ pub async fn send_event_to_device_route( sender_user, target_user_id, &target_device_id?, - &body.event_type, + &body.event_type.to_string(), event.deserialize_as().map_err(|_| { Error::BadRequest(ErrorKind::InvalidParam, "Event is invalid") })?, diff --git a/src/api/ruma_wrapper/axum.rs b/src/api/ruma_wrapper/axum.rs index 74f506f..2d2af70 100644 --- a/src/api/ruma_wrapper/axum.rs +++ b/src/api/ruma_wrapper/axum.rs @@ -47,7 +47,7 @@ where let path_params = Path::>::from_request(req).await?; let query = req.uri().query().unwrap_or_default(); - let query_params: QueryParams = match ruma::serde::urlencoded::from_str(query) { + let query_params: QueryParams = match serde_html_form::from_str(query) { Ok(params) => params, Err(e) => { error!(%query, "Failed to deserialize query parameters: {}", e); diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 852e59a..961b658 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -18,11 +18,7 @@ use ruma::{ discovery::{get_server_keys, get_server_version, ServerSigningKeys, VerifyKey}, event::{get_event, get_missing_events, get_room_state, get_room_state_ids}, keys::{claim_keys, get_keys}, - membership::{ - create_invite, - create_join_event::{self, RoomState}, - prepare_join_event, - }, + membership::{create_invite, create_join_event, prepare_join_event}, query::{get_profile_information, get_room_information}, transactions::{ edu::{DeviceListUpdateContent, DirectDeviceContent, Edu, SigningKeyUpdateContent}, @@ -39,7 +35,7 @@ use ruma::{ join_rules::{JoinRule, RoomJoinRulesEventContent}, member::{MembershipState, RoomMemberEventContent}, }, - RoomEventType, StateEventType, + StateEventType, TimelineEventType, }, serde::{Base64, JsonObject, Raw}, to_device::DeviceIdOrAllDevices, @@ -1440,7 +1436,7 @@ pub async fn create_join_event_template_route( let (_pdu, mut pdu_json) = services().rooms.timeline.create_hash_and_sign_event( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content, unsigned: None, state_key: Some(body.user_id.to_string()), @@ -1465,7 +1461,7 @@ async fn create_join_event( sender_servername: &ServerName, room_id: &RoomId, pdu: &RawJsonValue, -) -> Result { +) -> Result { if !services().globals.allow_federation() { return Err(Error::bad_config("Federation is disabled.")); } @@ -1587,7 +1583,7 @@ async fn create_join_event( services().sending.send_pdu(servers, &pdu_id)?; - Ok(RoomState { + Ok(create_join_event::v1::RoomState { auth_chain: auth_chain_ids .filter_map(|id| services().rooms.timeline.get_pdu_json(&id).ok().flatten()) .map(PduEvent::convert_to_outgoing_federation_event) @@ -1628,7 +1624,18 @@ pub async fn create_join_event_v2_route( .as_ref() .expect("server is authenticated"); - let room_state = create_join_event(sender_servername, &body.room_id, &body.pdu).await?; + let create_join_event::v1::RoomState { + auth_chain, + state, + event, + } = create_join_event(sender_servername, &body.room_id, &body.pdu).await?; + let room_state = create_join_event::v2::RoomState { + members_omitted: false, + auth_chain, + state, + event, + servers_in_room: None, + }; Ok(create_join_event::v2::Response { room_state }) } diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index b6609e1..d37ec69 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -21,7 +21,7 @@ use ruma::{ power_levels::RoomPowerLevelsEventContent, topic::RoomTopicEventContent, }, - RoomEventType, + TimelineEventType, }, EventId, OwnedRoomAliasId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId, }; @@ -212,7 +212,7 @@ impl Service { .timeline .build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMessage, + event_type: TimelineEventType::RoomMessage, content: to_raw_value(&message) .expect("event is valid, we just created it"), unsigned: None, @@ -854,7 +854,7 @@ impl Service { // 1. The room create event services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomCreate, + event_type: TimelineEventType::RoomCreate, content: to_raw_value(&content).expect("event is valid, we just created it"), unsigned: None, state_key: Some("".to_owned()), @@ -868,7 +868,7 @@ impl Service { // 2. Make conduit bot join services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { membership: MembershipState::Join, displayname: None, @@ -895,7 +895,7 @@ impl Service { services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomPowerLevels, + event_type: TimelineEventType::RoomPowerLevels, content: to_raw_value(&RoomPowerLevelsEventContent { users, ..Default::default() @@ -913,7 +913,7 @@ impl Service { // 4.1 Join Rules services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomJoinRules, + event_type: TimelineEventType::RoomJoinRules, content: to_raw_value(&RoomJoinRulesEventContent::new(JoinRule::Invite)) .expect("event is valid, we just created it"), unsigned: None, @@ -928,7 +928,7 @@ impl Service { // 4.2 History Visibility services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomHistoryVisibility, + event_type: TimelineEventType::RoomHistoryVisibility, content: to_raw_value(&RoomHistoryVisibilityEventContent::new( HistoryVisibility::Shared, )) @@ -945,7 +945,7 @@ impl Service { // 4.3 Guest Access services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomGuestAccess, + event_type: TimelineEventType::RoomGuestAccess, content: to_raw_value(&RoomGuestAccessEventContent::new(GuestAccess::Forbidden)) .expect("event is valid, we just created it"), unsigned: None, @@ -961,7 +961,7 @@ impl Service { let room_name = format!("{} Admin Room", services().globals.server_name()); services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomName, + event_type: TimelineEventType::RoomName, content: to_raw_value(&RoomNameEventContent::new(Some(room_name))) .expect("event is valid, we just created it"), unsigned: None, @@ -975,7 +975,7 @@ impl Service { services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomTopic, + event_type: TimelineEventType::RoomTopic, content: to_raw_value(&RoomTopicEventContent { topic: format!("Manage {}", services().globals.server_name()), }) @@ -996,7 +996,7 @@ impl Service { services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomCanonicalAlias, + event_type: TimelineEventType::RoomCanonicalAlias, content: to_raw_value(&RoomCanonicalAliasEventContent { alias: Some(alias.clone()), alt_aliases: Vec::new(), @@ -1053,7 +1053,7 @@ impl Service { // Invite and join the real user services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { membership: MembershipState::Invite, displayname: None, @@ -1075,7 +1075,7 @@ impl Service { )?; services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMember, + event_type: TimelineEventType::RoomMember, content: to_raw_value(&RoomMemberEventContent { membership: MembershipState::Join, displayname: Some(displayname), @@ -1103,7 +1103,7 @@ impl Service { services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomPowerLevels, + event_type: TimelineEventType::RoomPowerLevels, content: to_raw_value(&RoomPowerLevelsEventContent { users, ..Default::default() @@ -1121,7 +1121,7 @@ impl Service { // Send welcome message services().rooms.timeline.build_and_append_pdu( PduBuilder { - event_type: RoomEventType::RoomMessage, + event_type: TimelineEventType::RoomMessage, content: to_raw_value(&RoomMessageEventContent::text_html( format!("## Thank you for trying out Conduit!\n\nConduit is currently in Beta. This means you can join and participate in most Matrix rooms, but not all features are supported and you might run into bugs from time to time.\n\nHelpful links:\n> Website: https://conduit.rs\n> Git and Documentation: https://gitlab.com/famedly/conduit\n> Report issues: https://gitlab.com/famedly/conduit/-/issues\n\nFor a list of available commands, send the following message in this room: `@conduit:{}: --help`\n\nHere are some rooms you can join (by typing the command):\n\nConduit room (Ask questions and get notified on updates):\n`/join #conduit:fachschaften.org`\n\nConduit lounge (Off-topic, only Conduit users are allowed to join)\n`/join #conduit-lounge:conduit.rs`", services().globals.server_name()), format!("

Thank you for trying out Conduit!

\n

Conduit is currently in Beta. This means you can join and participate in most Matrix rooms, but not all features are supported and you might run into bugs from time to time.

\n

Helpful links:

\n
\n

Website: https://conduit.rs
Git and Documentation: https://gitlab.com/famedly/conduit
Report issues: https://gitlab.com/famedly/conduit/-/issues

\n
\n

For a list of available commands, send the following message in this room: @conduit:{}: --help

\n

Here are some rooms you can join (by typing the command):

\n

Conduit room (Ask questions and get notified on updates):
/join #conduit:fachschaften.org

\n

Conduit lounge (Off-topic, only Conduit users are allowed to join)
/join #conduit-lounge:conduit.rs

\n", services().globals.server_name()), diff --git a/src/service/pdu.rs b/src/service/pdu.rs index 5b5cbd0..a497b11 100644 --- a/src/service/pdu.rs +++ b/src/service/pdu.rs @@ -3,7 +3,7 @@ use ruma::{ events::{ room::member::RoomMemberEventContent, AnyEphemeralRoomEvent, AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, - RoomEventType, StateEvent, + StateEvent, TimelineEventType, }, serde::Raw, state_res, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, @@ -31,7 +31,7 @@ pub struct PduEvent { pub sender: OwnedUserId, pub origin_server_ts: UInt, #[serde(rename = "type")] - pub kind: RoomEventType, + pub kind: TimelineEventType, pub content: Box, #[serde(skip_serializing_if = "Option::is_none")] pub state_key: Option, @@ -53,10 +53,10 @@ impl PduEvent { self.unsigned = None; let allowed: &[&str] = match self.kind { - RoomEventType::RoomMember => &["join_authorised_via_users_server", "membership"], - RoomEventType::RoomCreate => &["creator"], - RoomEventType::RoomJoinRules => &["join_rule"], - RoomEventType::RoomPowerLevels => &[ + TimelineEventType::RoomMember => &["join_authorised_via_users_server", "membership"], + TimelineEventType::RoomCreate => &["creator"], + TimelineEventType::RoomJoinRules => &["join_rule"], + TimelineEventType::RoomPowerLevels => &[ "ban", "events", "events_default", @@ -66,7 +66,7 @@ impl PduEvent { "users", "users_default", ], - RoomEventType::RoomHistoryVisibility => &["history_visibility"], + TimelineEventType::RoomHistoryVisibility => &["history_visibility"], _ => &[], }; @@ -296,7 +296,7 @@ impl state_res::Event for PduEvent { &self.sender } - fn event_type(&self) -> &RoomEventType { + fn event_type(&self) -> &TimelineEventType { &self.kind } @@ -372,7 +372,7 @@ pub(crate) fn gen_event_id_canonical_json( #[derive(Debug, Deserialize)] pub struct PduBuilder { #[serde(rename = "type")] - pub event_type: RoomEventType, + pub event_type: TimelineEventType, pub content: Box, pub unsigned: Option>, pub state_key: Option, diff --git a/src/service/pusher/mod.rs b/src/service/pusher/mod.rs index ba096a2..5933c03 100644 --- a/src/service/pusher/mod.rs +++ b/src/service/pusher/mod.rs @@ -15,7 +15,7 @@ use ruma::{ }, events::{ room::{name::RoomNameEventContent, power_levels::RoomPowerLevelsEventContent}, - RoomEventType, StateEventType, + StateEventType, TimelineEventType, }, push::{Action, PushConditionRoomCtx, PushFormat, Ruleset, Tweak}, serde::Raw, @@ -169,6 +169,7 @@ impl Service { tweaks.push(tweak.clone()); continue; } + _ => false, }; if notify.is_some() { @@ -248,7 +249,7 @@ impl Service { // TODO: missed calls notifi.counts = NotificationCounts::new(unread, uint!(0)); - if event.kind == RoomEventType::RoomEncrypted + if event.kind == TimelineEventType::RoomEncrypted || tweaks .iter() .any(|t| matches!(t, Tweak::Highlight(true) | Tweak::Sound(_))) @@ -264,7 +265,7 @@ impl Service { notifi.event_type = Some(event.kind.clone()); notifi.content = serde_json::value::to_raw_value(&event.content).ok(); - if event.kind == RoomEventType::RoomMember { + if event.kind == TimelineEventType::RoomMember { notifi.user_is_target = event.state_key.as_deref() == Some(event.sender.as_str()); } diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index 3072b80..21ad2f9 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -8,7 +8,7 @@ pub use data::Data; use ruma::{ events::{ room::{create::RoomCreateEventContent, member::MembershipState}, - AnyStrippedStateEvent, RoomEventType, StateEventType, + AnyStrippedStateEvent, StateEventType, TimelineEventType, }, serde::Raw, state_res::{self, StateMap}, @@ -358,7 +358,7 @@ impl Service { pub fn get_auth_events( &self, room_id: &RoomId, - kind: &RoomEventType, + kind: &TimelineEventType, sender: &UserId, state_key: Option<&str>, content: &serde_json::value::RawValue, diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 47f4c65..99c5876 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -1,20 +1,19 @@ mod data; -use std::cmp::Ordering; -use std::collections::{BTreeMap, HashMap}; +use std::{ + cmp::Ordering, + collections::{BTreeMap, HashMap}, +}; -use std::sync::RwLock; use std::{ collections::HashSet, - sync::{Arc, Mutex}, + sync::{Arc, Mutex, RwLock}, }; pub use data::Data; use regex::Regex; -use ruma::api::federation; -use ruma::serde::Base64; use ruma::{ - api::client::error::ErrorKind, + api::{client::error::ErrorKind, federation}, canonical_json::to_canonical_value, events::{ push_rules::PushRulesEvent, @@ -22,23 +21,22 @@ use ruma::{ create::RoomCreateEventContent, member::MembershipState, power_levels::RoomPowerLevelsEventContent, }, - GlobalAccountDataEventType, RoomEventType, StateEventType, + GlobalAccountDataEventType, StateEventType, TimelineEventType, }, push::{Action, Ruleset, Tweak}, + serde::Base64, state_res, - state_res::Event, - state_res::RoomVersion, - uint, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, - OwnedServerName, RoomAliasId, RoomId, UserId, + state_res::{Event, RoomVersion}, + uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, + OwnedServerName, RoomAliasId, RoomId, ServerName, UserId, }; -use ruma::{user_id, ServerName}; use serde::Deserialize; use serde_json::value::{to_raw_value, RawValue as RawJsonValue}; use tokio::sync::MutexGuard; use tracing::{error, info, warn}; -use crate::api::server_server; use crate::{ + api::server_server, service::pdu::{EventHash, PduBuilder}, services, utils, Error, PduEvent, Result, }; @@ -381,12 +379,12 @@ impl Service { .increment_notification_counts(&pdu.room_id, notifies, highlights)?; match pdu.kind { - RoomEventType::RoomRedaction => { + TimelineEventType::RoomRedaction => { if let Some(redact_id) = &pdu.redacts { self.redact_pdu(redact_id, pdu)?; } } - RoomEventType::RoomMember => { + TimelineEventType::RoomMember => { if let Some(state_key) = &pdu.state_key { #[derive(Deserialize)] struct ExtractMembership { @@ -420,7 +418,7 @@ impl Service { )?; } } - RoomEventType::RoomMessage => { + TimelineEventType::RoomMessage => { #[derive(Deserialize)] struct ExtractBody { body: Option, @@ -472,7 +470,7 @@ impl Service { // If the RoomMember event has a non-empty state_key, it is targeted at someone. // If it is our appservice user, we send this PDU to it. - if pdu.kind == RoomEventType::RoomMember { + if pdu.kind == TimelineEventType::RoomMember { if let Some(state_key_uid) = &pdu .state_key .as_ref() @@ -522,7 +520,7 @@ impl Service { let matching_users = |users: &Regex| { users.is_match(pdu.sender.as_str()) - || pdu.kind == RoomEventType::RoomMember + || pdu.kind == TimelineEventType::RoomMember && pdu .state_key .as_ref() @@ -756,14 +754,14 @@ impl Service { )?; if admin_room.filter(|v| v == room_id).is_some() { match pdu.event_type() { - RoomEventType::RoomEncryption => { + TimelineEventType::RoomEncryption => { warn!("Encryption is not allowed in the admins room"); return Err(Error::BadRequest( ErrorKind::Forbidden, "Encryption is not allowed in the admins room.", )); } - RoomEventType::RoomMember => { + TimelineEventType::RoomMember => { #[derive(Deserialize)] struct ExtractMembership { membership: MembershipState, @@ -862,7 +860,7 @@ impl Service { .collect(); // In case we are kicking or banning a user, we need to inform their server of the change - if pdu.kind == RoomEventType::RoomMember { + if pdu.kind == TimelineEventType::RoomMember { if let Some(state_key_uid) = &pdu .state_key .as_ref() @@ -1100,7 +1098,7 @@ impl Service { drop(insert_lock); match pdu.kind { - RoomEventType::RoomMessage => { + TimelineEventType::RoomMessage => { #[derive(Deserialize)] struct ExtractBody { body: Option, -- cgit v1.2.3 From 4635644e21cfdefd076d011d4f747b37d10da5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 26 Feb 2023 16:55:42 +0100 Subject: Use the ruma methods for managing rulesets --- src/api/client_server/push.rs | 316 +++++++++++------------------------------- 1 file changed, 80 insertions(+), 236 deletions(-) diff --git a/src/api/client_server/push.rs b/src/api/client_server/push.rs index b044138..ab7c686 100644 --- a/src/api/client_server/push.rs +++ b/src/api/client_server/push.rs @@ -5,11 +5,11 @@ use ruma::{ push::{ delete_pushrule, get_pushers, get_pushrule, get_pushrule_actions, get_pushrule_enabled, get_pushrules_all, set_pusher, set_pushrule, set_pushrule_actions, - set_pushrule_enabled, RuleKind, RuleScope, + set_pushrule_enabled, RuleScope, }, }, events::{push_rules::PushRulesEvent, GlobalAccountDataEventType}, - push::{ConditionalPushRuleInit, NewPushRule, PatternedPushRuleInit, SimplePushRuleInit}, + push::{InsertPushRuleError, RemovePushRuleError}, }; /// # `GET /_matrix/client/r0/pushrules` @@ -65,30 +65,10 @@ pub async fn get_pushrule_route( .map_err(|_| Error::bad_database("Invalid account data event in db."))? .content; - let global = account_data.global; - let rule = match body.kind { - RuleKind::Override => global - .override_ - .get(body.rule_id.as_str()) - .map(|rule| rule.clone().into()), - RuleKind::Underride => global - .underride - .get(body.rule_id.as_str()) - .map(|rule| rule.clone().into()), - RuleKind::Sender => global - .sender - .get(body.rule_id.as_str()) - .map(|rule| rule.clone().into()), - RuleKind::Room => global - .room - .get(body.rule_id.as_str()) - .map(|rule| rule.clone().into()), - RuleKind::Content => global - .content - .get(body.rule_id.as_str()) - .map(|rule| rule.clone().into()), - _ => None, - }; + let rule = account_data + .global + .get(body.kind.clone(), &body.rule_id) + .map(Into::into); if let Some(rule) = rule { Ok(get_pushrule::v3::Response { rule }) @@ -131,66 +111,36 @@ pub async fn set_pushrule_route( let mut account_data = serde_json::from_str::(event.get()) .map_err(|_| Error::bad_database("Invalid account data event in db."))?; - let global = &mut account_data.content.global; - match body.rule { - NewPushRule::Override(rule) => { - global.override_.replace( - ConditionalPushRuleInit { - actions: rule.actions, - default: false, - enabled: true, - rule_id: rule.rule_id, - conditions: rule.conditions, - } - .into(), - ); - } - NewPushRule::Underride(rule) => { - global.underride.replace( - ConditionalPushRuleInit { - actions: rule.actions, - default: false, - enabled: true, - rule_id: rule.rule_id, - conditions: rule.conditions, - } - .into(), - ); - } - NewPushRule::Sender(rule) => { - global.sender.replace( - SimplePushRuleInit { - actions: rule.actions, - default: false, - enabled: true, - rule_id: rule.rule_id, - } - .into(), - ); - } - NewPushRule::Room(rule) => { - global.room.replace( - SimplePushRuleInit { - actions: rule.actions, - default: false, - enabled: true, - rule_id: rule.rule_id, - } - .into(), - ); - } - NewPushRule::Content(rule) => { - global.content.replace( - PatternedPushRuleInit { - actions: rule.actions, - default: false, - enabled: true, - rule_id: rule.rule_id, - pattern: rule.pattern, - } - .into(), - ); - } + if let Err(error) = account_data.content.global.insert( + body.rule.clone(), + body.after.as_deref(), + body.before.as_deref(), + ) { + let err = match error { + InsertPushRuleError::ServerDefaultRuleId => Error::BadRequest( + ErrorKind::InvalidParam, + "Rule IDs starting with a dot are reserved for server-default rules.", + ), + InsertPushRuleError::InvalidRuleId => Error::BadRequest( + ErrorKind::InvalidParam, + "Rule ID containing invalid characters.", + ), + InsertPushRuleError::RelativeToServerDefaultRule => Error::BadRequest( + ErrorKind::InvalidParam, + "Can't place a push rule relatively to a server-default rule.", + ), + InsertPushRuleError::UnknownRuleId => Error::BadRequest( + ErrorKind::NotFound, + "The before or after rule could not be found.", + ), + InsertPushRuleError::BeforeHigherThanAfter => Error::BadRequest( + ErrorKind::InvalidParam, + "The before rule has a higher priority than the after rule.", + ), + _ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."), + }; + + return Err(err); } services().account_data.update( @@ -235,29 +185,9 @@ pub async fn get_pushrule_actions_route( .content; let global = account_data.global; - let actions = match body.kind { - RuleKind::Override => global - .override_ - .get(body.rule_id.as_str()) - .map(|rule| rule.actions.clone()), - RuleKind::Underride => global - .underride - .get(body.rule_id.as_str()) - .map(|rule| rule.actions.clone()), - RuleKind::Sender => global - .sender - .get(body.rule_id.as_str()) - .map(|rule| rule.actions.clone()), - RuleKind::Room => global - .room - .get(body.rule_id.as_str()) - .map(|rule| rule.actions.clone()), - RuleKind::Content => global - .content - .get(body.rule_id.as_str()) - .map(|rule| rule.actions.clone()), - _ => None, - }; + let actions = global + .get(body.kind.clone(), &body.rule_id) + .map(|rule| rule.actions().to_owned()); Ok(get_pushrule_actions::v3::Response { actions: actions.unwrap_or_default(), @@ -294,40 +224,17 @@ pub async fn set_pushrule_actions_route( let mut account_data = serde_json::from_str::(event.get()) .map_err(|_| Error::bad_database("Invalid account data event in db."))?; - let global = &mut account_data.content.global; - match body.kind { - RuleKind::Override => { - if let Some(mut rule) = global.override_.get(body.rule_id.as_str()).cloned() { - rule.actions = body.actions.clone(); - global.override_.replace(rule); - } - } - RuleKind::Underride => { - if let Some(mut rule) = global.underride.get(body.rule_id.as_str()).cloned() { - rule.actions = body.actions.clone(); - global.underride.replace(rule); - } - } - RuleKind::Sender => { - if let Some(mut rule) = global.sender.get(body.rule_id.as_str()).cloned() { - rule.actions = body.actions.clone(); - global.sender.replace(rule); - } - } - RuleKind::Room => { - if let Some(mut rule) = global.room.get(body.rule_id.as_str()).cloned() { - rule.actions = body.actions.clone(); - global.room.replace(rule); - } - } - RuleKind::Content => { - if let Some(mut rule) = global.content.get(body.rule_id.as_str()).cloned() { - rule.actions = body.actions.clone(); - global.content.replace(rule); - } - } - _ => {} - }; + if account_data + .content + .global + .set_actions(body.kind.clone(), &body.rule_id, body.actions.clone()) + .is_err() + { + return Err(Error::BadRequest( + ErrorKind::NotFound, + "Push rule not found.", + )); + } services().account_data.update( None, @@ -370,34 +277,10 @@ pub async fn get_pushrule_enabled_route( .map_err(|_| Error::bad_database("Invalid account data event in db."))?; let global = account_data.content.global; - let enabled = match body.kind { - RuleKind::Override => global - .override_ - .iter() - .find(|rule| rule.rule_id == body.rule_id) - .map_or(false, |rule| rule.enabled), - RuleKind::Underride => global - .underride - .iter() - .find(|rule| rule.rule_id == body.rule_id) - .map_or(false, |rule| rule.enabled), - RuleKind::Sender => global - .sender - .iter() - .find(|rule| rule.rule_id == body.rule_id) - .map_or(false, |rule| rule.enabled), - RuleKind::Room => global - .room - .iter() - .find(|rule| rule.rule_id == body.rule_id) - .map_or(false, |rule| rule.enabled), - RuleKind::Content => global - .content - .iter() - .find(|rule| rule.rule_id == body.rule_id) - .map_or(false, |rule| rule.enabled), - _ => false, - }; + let enabled = global + .get(body.kind.clone(), &body.rule_id) + .map(|r| r.enabled()) + .unwrap_or_default(); Ok(get_pushrule_enabled::v3::Response { enabled }) } @@ -432,44 +315,16 @@ pub async fn set_pushrule_enabled_route( let mut account_data = serde_json::from_str::(event.get()) .map_err(|_| Error::bad_database("Invalid account data event in db."))?; - let global = &mut account_data.content.global; - match body.kind { - RuleKind::Override => { - if let Some(mut rule) = global.override_.get(body.rule_id.as_str()).cloned() { - global.override_.remove(&rule); - rule.enabled = body.enabled; - global.override_.insert(rule); - } - } - RuleKind::Underride => { - if let Some(mut rule) = global.underride.get(body.rule_id.as_str()).cloned() { - global.underride.remove(&rule); - rule.enabled = body.enabled; - global.underride.insert(rule); - } - } - RuleKind::Sender => { - if let Some(mut rule) = global.sender.get(body.rule_id.as_str()).cloned() { - global.sender.remove(&rule); - rule.enabled = body.enabled; - global.sender.insert(rule); - } - } - RuleKind::Room => { - if let Some(mut rule) = global.room.get(body.rule_id.as_str()).cloned() { - global.room.remove(&rule); - rule.enabled = body.enabled; - global.room.insert(rule); - } - } - RuleKind::Content => { - if let Some(mut rule) = global.content.get(body.rule_id.as_str()).cloned() { - global.content.remove(&rule); - rule.enabled = body.enabled; - global.content.insert(rule); - } - } - _ => {} + if account_data + .content + .global + .set_enabled(body.kind.clone(), &body.rule_id, body.enabled) + .is_err() + { + return Err(Error::BadRequest( + ErrorKind::NotFound, + "Push rule not found.", + )); } services().account_data.update( @@ -512,34 +367,23 @@ pub async fn delete_pushrule_route( let mut account_data = serde_json::from_str::(event.get()) .map_err(|_| Error::bad_database("Invalid account data event in db."))?; - let global = &mut account_data.content.global; - match body.kind { - RuleKind::Override => { - if let Some(rule) = global.override_.get(body.rule_id.as_str()).cloned() { - global.override_.remove(&rule); - } - } - RuleKind::Underride => { - if let Some(rule) = global.underride.get(body.rule_id.as_str()).cloned() { - global.underride.remove(&rule); - } - } - RuleKind::Sender => { - if let Some(rule) = global.sender.get(body.rule_id.as_str()).cloned() { - global.sender.remove(&rule); + if let Err(error) = account_data + .content + .global + .remove(body.kind.clone(), &body.rule_id) + { + let err = match error { + RemovePushRuleError::ServerDefault => Error::BadRequest( + ErrorKind::InvalidParam, + "Cannot delete a server-default pushrule.", + ), + RemovePushRuleError::NotFound => { + Error::BadRequest(ErrorKind::NotFound, "Push rule not found.") } - } - RuleKind::Room => { - if let Some(rule) = global.room.get(body.rule_id.as_str()).cloned() { - global.room.remove(&rule); - } - } - RuleKind::Content => { - if let Some(rule) = global.content.get(body.rule_id.as_str()).cloned() { - global.content.remove(&rule); - } - } - _ => {} + _ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."), + }; + + return Err(err); } services().account_data.update( -- cgit v1.2.3 From 88c6bf75954ead182fffc900585b418b018e98e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 26 Feb 2023 17:49:42 +0100 Subject: Always return an error if a push rule is not found --- src/api/client_server/push.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/api/client_server/push.rs b/src/api/client_server/push.rs index ab7c686..7276866 100644 --- a/src/api/client_server/push.rs +++ b/src/api/client_server/push.rs @@ -187,11 +187,13 @@ pub async fn get_pushrule_actions_route( let global = account_data.global; let actions = global .get(body.kind.clone(), &body.rule_id) - .map(|rule| rule.actions().to_owned()); + .map(|rule| rule.actions().to_owned()) + .ok_or(Error::BadRequest( + ErrorKind::NotFound, + "Push rule not found.", + ))?; - Ok(get_pushrule_actions::v3::Response { - actions: actions.unwrap_or_default(), - }) + Ok(get_pushrule_actions::v3::Response { actions }) } /// # `PUT /_matrix/client/r0/pushrules/{scope}/{kind}/{ruleId}/actions` @@ -280,7 +282,10 @@ pub async fn get_pushrule_enabled_route( let enabled = global .get(body.kind.clone(), &body.rule_id) .map(|r| r.enabled()) - .unwrap_or_default(); + .ok_or(Error::BadRequest( + ErrorKind::NotFound, + "Push rule not found.", + ))?; Ok(get_pushrule_enabled::v3::Response { enabled }) } -- cgit v1.2.3 From 1929ca5d9d8d8b43a2f3fcce7af19e197f93f562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Sun, 26 Feb 2023 17:57:44 +0100 Subject: Add a database migration to fix and update the default pushrules --- src/database/mod.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index e05991d..1415f68 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -411,7 +411,7 @@ impl KeyValueDatabase { } // If the database has any data, perform data migrations before starting - let latest_database_version = 12; + let latest_database_version = 13; if services().users.count()? > 0 { // MIGRATIONS @@ -880,6 +880,52 @@ impl KeyValueDatabase { warn!("Migration: 11 -> 12 finished"); } + // This migration can be reused as-is anytime the server-default rules are updated. + if services().globals.database_version()? < 13 { + for username in services().users.list_local_users()? { + let user = match UserId::parse_with_server_name( + username.clone(), + services().globals.server_name(), + ) { + Ok(u) => u, + Err(e) => { + warn!("Invalid username {username}: {e}"); + continue; + } + }; + + let raw_rules_list = services() + .account_data + .get( + None, + &user, + GlobalAccountDataEventType::PushRules.to_string().into(), + ) + .unwrap() + .expect("Username is invalid"); + + let mut account_data = + serde_json::from_str::(raw_rules_list.get()).unwrap(); + + let user_default_rules = ruma::push::Ruleset::server_default(&user); + account_data + .content + .global + .update_with_server_default(user_default_rules); + + services().account_data.update( + None, + &user, + GlobalAccountDataEventType::PushRules.to_string().into(), + &serde_json::to_value(account_data).expect("to json value always works"), + )?; + } + + services().globals.bump_database_version(13)?; + + warn!("Migration: 12 -> 13 finished"); + } + assert_eq!( services().globals.database_version().unwrap(), latest_database_version -- cgit v1.2.3 From c997311beae4becb5f8c11c46bb1c821b0935dbd Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Tue, 4 Apr 2023 16:56:51 -0700 Subject: Revert "build(nix): fix flake builds" This reverts commit 5d913f701083e1519a3595190e63193c519fbc6b. Sorry, I don't understand how any of this works, and it seems pretty opaque/difficult to fine-tune. --- flake.lock | 372 +++++-------------------------------------------------------- flake.nix | 124 ++++++++++++--------- 2 files changed, 99 insertions(+), 397 deletions(-) diff --git a/flake.lock b/flake.lock index 1bb1123..bfe0a9b 100644 --- a/flake.lock +++ b/flake.lock @@ -1,124 +1,18 @@ { "nodes": { - "alejandra": { - "inputs": { - "fenix": "fenix", - "flakeCompat": "flakeCompat", - "nixpkgs": [ - "d2n", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1658427149, - "narHash": "sha256-ToD/1z/q5VHsLMrS2h96vjJoLho59eNRtknOUd19ey8=", - "owner": "kamadorueda", - "repo": "alejandra", - "rev": "f5a22afd2adfb249b4e68e0b33aa1f0fb73fb1be", - "type": "github" - }, - "original": { - "owner": "kamadorueda", - "repo": "alejandra", - "type": "github" - } - }, - "all-cabal-json": { - "flake": false, - "locked": { - "lastModified": 1665552503, - "narHash": "sha256-r14RmRSwzv5c+bWKUDaze6pXM7nOsiz1H8nvFHJvufc=", - "owner": "nix-community", - "repo": "all-cabal-json", - "rev": "d7c0434eebffb305071404edcf9d5cd99703878e", - "type": "github" - }, - "original": { - "owner": "nix-community", - "ref": "hackage", - "repo": "all-cabal-json", - "type": "github" - } - }, - "crane": { - "flake": false, - "locked": { - "lastModified": 1670900067, - "narHash": "sha256-VXVa+KBfukhmWizaiGiHRVX/fuk66P8dgSFfkVN4/MY=", - "owner": "ipetkov", - "repo": "crane", - "rev": "59b31b41a589c0a65e4a1f86b0e5eac68081468b", - "type": "github" - }, - "original": { - "owner": "ipetkov", - "repo": "crane", - "type": "github" - } - }, - "d2n": { - "inputs": { - "alejandra": "alejandra", - "all-cabal-json": "all-cabal-json", - "crane": "crane", - "devshell": "devshell", - "flake-parts": "flake-parts", - "flake-utils-pre-commit": "flake-utils-pre-commit", - "ghc-utils": "ghc-utils", - "gomod2nix": "gomod2nix", - "mach-nix": "mach-nix", - "nix-pypi-fetcher": "nix-pypi-fetcher", - "nixpkgs": [ - "nixpkgs" - ], - "poetry2nix": "poetry2nix", - "pre-commit-hooks": "pre-commit-hooks" - }, - "locked": { - "lastModified": 1674848374, - "narHash": "sha256-1+xlsmUWzpptK8mLjznwqOLogeicLkxB8tV6XUZbobc=", - "owner": "nix-community", - "repo": "dream2nix", - "rev": "d91e7381fa303be02f70e472207e05b26ce35b41", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "dream2nix", - "type": "github" - } - }, - "devshell": { - "flake": false, - "locked": { - "lastModified": 1663445644, - "narHash": "sha256-+xVlcK60x7VY1vRJbNUEAHi17ZuoQxAIH4S4iUFUGBA=", - "owner": "numtide", - "repo": "devshell", - "rev": "e3dc3e21594fe07bdb24bdf1c8657acaa4cb8f66", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "devshell", - "type": "github" - } - }, "fenix": { "inputs": { "nixpkgs": [ - "d2n", - "alejandra", "nixpkgs" ], "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1657607339, - "narHash": "sha256-HaqoAwlbVVZH2n4P3jN2FFPMpVuhxDy1poNOR7kzODc=", + "lastModified": 1671776618, + "narHash": "sha256-myjhExbKIzZy+kqqFyqvX59KErqYZVNTPsCfgByTOKo=", "owner": "nix-community", "repo": "fenix", - "rev": "b814c83d9e6aa5a28d0cf356ecfdafb2505ad37d", + "rev": "64d1607710b99e72d9afb2cde11bd1c2cea7cb91", "type": "github" }, "original": { @@ -127,46 +21,13 @@ "type": "github" } }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1668450977, - "narHash": "sha256-cfLhMhnvXn6x1vPm+Jow3RiFAUSCw/l1utktCw5rVA4=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "d591857e9d7dd9ddbfba0ea02b43b927c3c0f1fa", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, "flake-utils": { "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils-pre-commit": { - "locked": { - "lastModified": 1644229661, - "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", "owner": "numtide", "repo": "flake-utils", - "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", "type": "github" }, "original": { @@ -175,213 +36,57 @@ "type": "github" } }, - "flakeCompat": { - "flake": false, - "locked": { - "lastModified": 1650374568, - "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "b4a34015c698c7793d592d66adbab377907a2be8", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "ghc-utils": { - "flake": false, - "locked": { - "lastModified": 1662774800, - "narHash": "sha256-1Rd2eohGUw/s1tfvkepeYpg8kCEXiIot0RijapUjAkE=", - "ref": "refs/heads/master", - "rev": "bb3a2d3dc52ff0253fb9c2812bd7aa2da03e0fea", - "revCount": 1072, - "type": "git", - "url": "https://gitlab.haskell.org/bgamari/ghc-utils" - }, - "original": { - "type": "git", - "url": "https://gitlab.haskell.org/bgamari/ghc-utils" - } - }, - "gomod2nix": { - "flake": false, - "locked": { - "lastModified": 1627572165, - "narHash": "sha256-MFpwnkvQpauj799b4QTBJQFEddbD02+Ln5k92QyHOSk=", - "owner": "tweag", - "repo": "gomod2nix", - "rev": "67f22dd738d092c6ba88e420350ada0ed4992ae8", - "type": "github" - }, - "original": { - "owner": "tweag", - "repo": "gomod2nix", - "type": "github" - } - }, - "mach-nix": { - "flake": false, - "locked": { - "lastModified": 1634711045, - "narHash": "sha256-m5A2Ty88NChLyFhXucECj6+AuiMZPHXNbw+9Kcs7F6Y=", - "owner": "DavHau", - "repo": "mach-nix", - "rev": "4433f74a97b94b596fa6cd9b9c0402104aceef5d", - "type": "github" + "naersk": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] }, - "original": { - "id": "mach-nix", - "type": "indirect" - } - }, - "nix-pypi-fetcher": { - "flake": false, "locked": { - "lastModified": 1669065297, - "narHash": "sha256-UStjXjNIuIm7SzMOWvuYWIHBkPUKQ8Id63BMJjnIDoA=", - "owner": "DavHau", - "repo": "nix-pypi-fetcher", - "rev": "a9885ac6a091576b5195d547ac743d45a2a615ac", + "lastModified": 1671096816, + "narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=", + "owner": "nix-community", + "repo": "naersk", + "rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114", "type": "github" }, "original": { - "owner": "DavHau", - "repo": "nix-pypi-fetcher", + "owner": "nix-community", + "repo": "naersk", "type": "github" } }, "nixpkgs": { "locked": { - "lastModified": 1674641431, - "narHash": "sha256-qfo19qVZBP4qn5M5gXc/h1MDgAtPA5VxJm9s8RUAkVk=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "9b97ad7b4330aacda9b2343396eb3df8a853b4fc", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "dir": "lib", - "lastModified": 1665349835, - "narHash": "sha256-UK4urM3iN80UXQ7EaOappDzcisYIuEURFRoGQ/yPkug=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "34c5293a71ffdb2fe054eb5288adc1882c1eb0b1", - "type": "github" - }, - "original": { - "dir": "lib", - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib_2": { - "locked": { - "dir": "lib", - "lastModified": 1672350804, - "narHash": "sha256-jo6zkiCabUBn3ObuKXHGqqORUMH27gYDIFFfLq5P4wg=", + "lastModified": 1671780662, + "narHash": "sha256-Tsc64sN8LLHa7eqDZVVeubI8CyqIjs9l5tQ5EeRlgvM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "677ed08a50931e38382dbef01cba08a8f7eac8f6", + "rev": "339063a22409514cb2baea677b329e618faa6a08", "type": "github" }, "original": { - "dir": "lib", "owner": "NixOS", - "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, - "parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib_2" - }, - "locked": { - "lastModified": 1674771137, - "narHash": "sha256-Zpk1GbEsYrqKmuIZkx+f+8pU0qcCYJoSUwNz1Zk+R00=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "7c7a8bce3dffe71203dcd4276504d1cb49dfe05f", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, - "poetry2nix": { - "flake": false, - "locked": { - "lastModified": 1666918719, - "narHash": "sha256-BkK42fjAku+2WgCOv2/1NrPa754eQPV7gPBmoKQBWlc=", - "owner": "nix-community", - "repo": "poetry2nix", - "rev": "289efb187123656a116b915206e66852f038720e", - "type": "github" - }, - "original": { - "owner": "nix-community", - "ref": "1.36.0", - "repo": "poetry2nix", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-utils": [ - "d2n", - "flake-utils-pre-commit" - ], - "nixpkgs": [ - "d2n", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1646153636, - "narHash": "sha256-AlWHMzK+xJ1mG267FdT8dCq/HvLCA6jwmx2ZUy5O8tY=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "b6bc0b21e1617e2b07d8205e7fae7224036dfa4b", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, "root": { "inputs": { - "d2n": "d2n", - "nixpkgs": "nixpkgs", - "parts": "parts", - "rust-overlay": "rust-overlay" + "fenix": "fenix", + "flake-utils": "flake-utils", + "naersk": "naersk", + "nixpkgs": "nixpkgs" } }, "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1657557289, - "narHash": "sha256-PRW+nUwuqNTRAEa83SfX+7g+g8nQ+2MMbasQ9nt6+UM=", + "lastModified": 1671750139, + "narHash": "sha256-xbL8BZU87rHfQkF3tuFXduNGPW8fDwFI+0fFmRJx66E=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "caf23f29144b371035b864a1017dbc32573ad56d", + "rev": "a06525517b0b69cd97f2c39a4012d96f44bf0776", "type": "github" }, "original": { @@ -390,27 +95,6 @@ "repo": "rust-analyzer", "type": "github" } - }, - "rust-overlay": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1674786480, - "narHash": "sha256-n25V3Ug/dJewbJaxj1gL0cUMBdOonrVkIQCHd9yHHvw=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "296dd673b46aaebe1c8355f1848ceb7c905dda35", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index f4db253..e10e8bb 100644 --- a/flake.nix +++ b/flake.nix @@ -1,56 +1,74 @@ { - inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - inputs.d2n.url = "github:nix-community/dream2nix"; - inputs.d2n.inputs.nixpkgs.follows = "nixpkgs"; - inputs.parts.url = "github:hercules-ci/flake-parts"; - inputs.rust-overlay.url = "github:oxalica/rust-overlay"; - inputs.rust-overlay.inputs.nixpkgs.follows = "nixpkgs"; - - outputs = inp: - inp.parts.lib.mkFlake {inputs = inp;} { - systems = ["x86_64-linux"]; - imports = [inp.d2n.flakeModuleBeta]; - perSystem = { - config, - system, - pkgs, - ... - }: let - cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); - pkgsWithToolchain = pkgs.appendOverlays [inp.rust-overlay.overlays.default]; - - toolchains = pkgsWithToolchain.rust-bin.stable."${cargoToml.package.rust-version}"; - # toolchain to use when building conduit, includes only cargo and rustc to reduce closure size - buildToolchain = toolchains.minimal; - # toolchain to use in development shell - # the "default" component set of toolchain adds rustfmt, clippy etc. - devToolchain = toolchains.default.override { - extensions = ["rust-src"]; - }; - - # flake outputs for conduit project - conduitOutputs = config.dream2nix.outputs.conduit; - in { - dream2nix.inputs.conduit = { - source = inp.self; - projects.conduit = { - name = "conduit"; - subsystem = "rust"; - translator = "cargo-lock"; - }; - packageOverrides = { - "^.*".set-toolchain.overrideRustToolchain = _: { - cargo = buildToolchain; - rustc = buildToolchain; - }; - }; - }; - devShells.conduit = conduitOutputs.devShells.conduit.overrideAttrs (old: { - # export default crate sources for rust-analyzer to read - RUST_SRC_PATH = "${devToolchain}/lib/rustlib/src/rust/library"; - nativeBuildInputs = (old.nativeBuildInputs or []) ++ [devToolchain]; - }); - devShells.default = config.devShells.conduit; - }; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + naersk = { + url = "github:nix-community/naersk"; + inputs.nixpkgs.follows = "nixpkgs"; }; + }; + + outputs = + { self + , nixpkgs + , flake-utils + + , fenix + , naersk + }: flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + + # Nix-accessible `Cargo.toml` + cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); + + # The Rust toolchain to use + toolchain = fenix.packages.${system}.toolchainOf { + # Use the Rust version defined in `Cargo.toml` + channel = cargoToml.package.rust-version; + + # THE rust-version HASH + sha256 = "sha256-8len3i8oTwJSOJZMosGGXHBL5BVuGQnWOT2St5YAUFU="; + }; + + builder = (pkgs.callPackage naersk { + inherit (toolchain) rustc cargo; + }).buildPackage; + in + { + packages.default = builder { + src = ./.; + + nativeBuildInputs = (with pkgs.rustPlatform; [ + bindgenHook + ]); + }; + + devShells.default = pkgs.mkShell { + # Rust Analyzer needs to be able to find the path to default crate + # sources, and it can read this environment variable to do so + RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library"; + + # Development tools + nativeBuildInputs = (with pkgs.rustPlatform; [ + bindgenHook + ]) ++ (with toolchain; [ + cargo + clippy + rust-src + rustc + rustfmt + ]); + }; + + checks = { + packagesDefault = self.packages.${system}.default; + devShellsDefault = self.devShells.${system}.default; + }; + }); } -- cgit v1.2.3 From a0c449e570886b67d1558016689dfdf7fef990ff Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Tue, 4 Apr 2023 16:58:19 -0700 Subject: update flake.lock --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index bfe0a9b..280e1b5 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1671776618, - "narHash": "sha256-myjhExbKIzZy+kqqFyqvX59KErqYZVNTPsCfgByTOKo=", + "lastModified": 1680607374, + "narHash": "sha256-U5iiPqbAanr+sQCCZ7zxYhwCXdcDpish8Uy4ELZeXM0=", "owner": "nix-community", "repo": "fenix", - "rev": "64d1607710b99e72d9afb2cde11bd1c2cea7cb91", + "rev": "e70d498e97017daa59363eafa054619d4fa160c3", "type": "github" }, "original": { @@ -23,11 +23,11 @@ }, "flake-utils": { "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1678901627, + "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", "type": "github" }, "original": { @@ -43,11 +43,11 @@ ] }, "locked": { - "lastModified": 1671096816, - "narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=", + "lastModified": 1679567394, + "narHash": "sha256-ZvLuzPeARDLiQUt6zSZFGOs+HZmE+3g4QURc8mkBsfM=", "owner": "nix-community", "repo": "naersk", - "rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114", + "rev": "88cd22380154a2c36799fe8098888f0f59861a15", "type": "github" }, "original": { @@ -58,11 +58,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1671780662, - "narHash": "sha256-Tsc64sN8LLHa7eqDZVVeubI8CyqIjs9l5tQ5EeRlgvM=", + "lastModified": 1680652733, + "narHash": "sha256-FFG6Nai9M71C0Uc+D8TxyHoAjTplM0/9uWKsl7ALfUs=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "339063a22409514cb2baea677b329e618faa6a08", + "rev": "cc5bde408572508efd1273852862d418bb313443", "type": "github" }, "original": { @@ -82,11 +82,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1671750139, - "narHash": "sha256-xbL8BZU87rHfQkF3tuFXduNGPW8fDwFI+0fFmRJx66E=", + "lastModified": 1680435407, + "narHash": "sha256-IPBtZCOh3BdrR+V77cL7r6WQnclWcZ/85BDYnmq/GnQ=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "a06525517b0b69cd97f2c39a4012d96f44bf0776", + "rev": "236576227a299fd19ba836b1834ab50c948af994", "type": "github" }, "original": { -- cgit v1.2.3 From 2b63e46fc5c4234823a1d71b2a7eac4ee15cd9be Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Tue, 4 Apr 2023 16:47:08 -0700 Subject: use system rocksdb This mostly just improves build times. --- flake.nix | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/flake.nix b/flake.nix index e10e8bb..baa3261 100644 --- a/flake.nix +++ b/flake.nix @@ -36,6 +36,10 @@ sha256 = "sha256-8len3i8oTwJSOJZMosGGXHBL5BVuGQnWOT2St5YAUFU="; }; + # Point to system RocksDB + ROCKSDB_INCLUDE_DIR = "${pkgs.rocksdb_6_23}/include"; + ROCKSDB_LIB_DIR = "${pkgs.rocksdb_6_23}/lib"; + builder = (pkgs.callPackage naersk { inherit (toolchain) rustc cargo; }).buildPackage; @@ -44,6 +48,9 @@ packages.default = builder { src = ./.; + # Use system RocksDB + inherit ROCKSDB_INCLUDE_DIR ROCKSDB_LIB_DIR; + nativeBuildInputs = (with pkgs.rustPlatform; [ bindgenHook ]); @@ -54,6 +61,9 @@ # sources, and it can read this environment variable to do so RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library"; + # Use system RocksDB + inherit ROCKSDB_INCLUDE_DIR ROCKSDB_LIB_DIR; + # Development tools nativeBuildInputs = (with pkgs.rustPlatform; [ bindgenHook -- cgit v1.2.3 From 55149e33361b07c87be66a8b6632d9fcb2711548 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Tue, 4 Apr 2023 17:30:30 -0700 Subject: use crane instead of naersk I guess naersk still doesn't support git dependencies using workspace inheritance, but crane does. --- flake.lock | 88 +++++++++++++++++++++++++++++++++++++++++++++++--------------- flake.nix | 12 ++++----- 2 files changed, 73 insertions(+), 27 deletions(-) diff --git a/flake.lock b/flake.lock index 280e1b5..d76ff59 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,30 @@ { "nodes": { + "crane": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1680584903, + "narHash": "sha256-uraq+D3jcLzw/UVk0xMHcnfILfIMa0DLrtAEq2nNlxU=", + "owner": "ipetkov", + "repo": "crane", + "rev": "65d3f6a3970cd46bef5eedfd458300f72c56b3c5", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, "fenix": { "inputs": { "nixpkgs": [ @@ -21,6 +46,22 @@ "type": "github" } }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1678901627, @@ -36,26 +77,6 @@ "type": "github" } }, - "naersk": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1679567394, - "narHash": "sha256-ZvLuzPeARDLiQUt6zSZFGOs+HZmE+3g4QURc8mkBsfM=", - "owner": "nix-community", - "repo": "naersk", - "rev": "88cd22380154a2c36799fe8098888f0f59861a15", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "naersk", - "type": "github" - } - }, "nixpkgs": { "locked": { "lastModified": 1680652733, @@ -73,9 +94,9 @@ }, "root": { "inputs": { + "crane": "crane", "fenix": "fenix", "flake-utils": "flake-utils", - "naersk": "naersk", "nixpkgs": "nixpkgs" } }, @@ -95,6 +116,31 @@ "repo": "rust-analyzer", "type": "github" } + }, + "rust-overlay": { + "inputs": { + "flake-utils": [ + "crane", + "flake-utils" + ], + "nixpkgs": [ + "crane", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1680488274, + "narHash": "sha256-0vYMrZDdokVmPQQXtFpnqA2wEgCCUXf5a3dDuDVshn0=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "7ec2ff598a172c6e8584457167575b3a1a5d80d8", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index baa3261..6ed12de 100644 --- a/flake.nix +++ b/flake.nix @@ -7,9 +7,10 @@ url = "github:nix-community/fenix"; inputs.nixpkgs.follows = "nixpkgs"; }; - naersk = { - url = "github:nix-community/naersk"; + crane = { + url = "github:ipetkov/crane"; inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; }; }; @@ -19,7 +20,7 @@ , flake-utils , fenix - , naersk + , crane }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; @@ -40,9 +41,8 @@ ROCKSDB_INCLUDE_DIR = "${pkgs.rocksdb_6_23}/include"; ROCKSDB_LIB_DIR = "${pkgs.rocksdb_6_23}/lib"; - builder = (pkgs.callPackage naersk { - inherit (toolchain) rustc cargo; - }).buildPackage; + builder = + ((crane.mkLib pkgs).overrideToolchain toolchain.toolchain).buildPackage; in { packages.default = builder { -- cgit v1.2.3 From 3be32c4dac30fe428eefc007d565fd23fddaae40 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Tue, 4 Apr 2023 17:52:15 -0700 Subject: factor out shared things --- flake.nix | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/flake.nix b/flake.nix index 6ed12de..5e7d206 100644 --- a/flake.nix +++ b/flake.nix @@ -41,6 +41,11 @@ ROCKSDB_INCLUDE_DIR = "${pkgs.rocksdb_6_23}/include"; ROCKSDB_LIB_DIR = "${pkgs.rocksdb_6_23}/lib"; + # Shared between the package and the devShell + nativeBuildInputs = (with pkgs.rustPlatform; [ + bindgenHook + ]); + builder = ((crane.mkLib pkgs).overrideToolchain toolchain.toolchain).buildPackage; in @@ -51,9 +56,7 @@ # Use system RocksDB inherit ROCKSDB_INCLUDE_DIR ROCKSDB_LIB_DIR; - nativeBuildInputs = (with pkgs.rustPlatform; [ - bindgenHook - ]); + inherit nativeBuildInputs; }; devShells.default = pkgs.mkShell { @@ -65,9 +68,7 @@ inherit ROCKSDB_INCLUDE_DIR ROCKSDB_LIB_DIR; # Development tools - nativeBuildInputs = (with pkgs.rustPlatform; [ - bindgenHook - ]) ++ (with toolchain; [ + nativeBuildInputs = nativeBuildInputs ++ (with toolchain; [ cargo clippy rust-src -- cgit v1.2.3 From a6712627e4758a973af4f6f157778e55308b076d Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Tue, 4 Apr 2023 19:15:09 -0700 Subject: tiny refactor --- flake.nix | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/flake.nix b/flake.nix index 5e7d206..7162c93 100644 --- a/flake.nix +++ b/flake.nix @@ -37,7 +37,7 @@ sha256 = "sha256-8len3i8oTwJSOJZMosGGXHBL5BVuGQnWOT2St5YAUFU="; }; - # Point to system RocksDB + # The system's RocksDB ROCKSDB_INCLUDE_DIR = "${pkgs.rocksdb_6_23}/include"; ROCKSDB_LIB_DIR = "${pkgs.rocksdb_6_23}/lib"; @@ -53,10 +53,10 @@ packages.default = builder { src = ./.; - # Use system RocksDB - inherit ROCKSDB_INCLUDE_DIR ROCKSDB_LIB_DIR; - - inherit nativeBuildInputs; + inherit + nativeBuildInputs + ROCKSDB_INCLUDE_DIR + ROCKSDB_LIB_DIR; }; devShells.default = pkgs.mkShell { @@ -64,8 +64,9 @@ # sources, and it can read this environment variable to do so RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library"; - # Use system RocksDB - inherit ROCKSDB_INCLUDE_DIR ROCKSDB_LIB_DIR; + inherit + ROCKSDB_INCLUDE_DIR + ROCKSDB_LIB_DIR; # Development tools nativeBuildInputs = nativeBuildInputs ++ (with toolchain; [ -- cgit v1.2.3 From eb4323cc0fab563655ddf9ce1471302e657724e4 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Tue, 4 Apr 2023 19:11:34 -0700 Subject: use mold on linux --- flake.nix | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 7162c93..970e847 100644 --- a/flake.nix +++ b/flake.nix @@ -25,6 +25,12 @@ let pkgs = nixpkgs.legacyPackages.${system}; + # Use mold on Linux + stdenv = if pkgs.stdenv.isLinux then + pkgs.stdenvAdapters.useMoldLinker pkgs.stdenv + else + pkgs.stdenv; + # Nix-accessible `Cargo.toml` cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml); @@ -54,12 +60,13 @@ src = ./.; inherit + stdenv nativeBuildInputs ROCKSDB_INCLUDE_DIR ROCKSDB_LIB_DIR; }; - devShells.default = pkgs.mkShell { + devShells.default = (pkgs.mkShell.override { inherit stdenv; }) { # Rust Analyzer needs to be able to find the path to default crate # sources, and it can read this environment variable to do so RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library"; -- cgit v1.2.3 From f5e3b0e2dd1c47d6d7dc3a9c21da892472ab57de Mon Sep 17 00:00:00 2001 From: Jonathan Flueren <9669250-JonOfUs@users.noreply.gitlab.com> Date: Mon, 15 May 2023 19:25:57 +0000 Subject: Recognize admin commands without : after tag Very useful since many Matrix clients don't insert : after user tags --- src/service/rooms/timeline/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 47f4c65..249b2a2 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -443,7 +443,8 @@ impl Service { )?; let server_user = format!("@conduit:{}", services().globals.server_name()); - let to_conduit = body.starts_with(&format!("{server_user}: ")); + let to_conduit = body.starts_with(&format!("{server_user}: ")) + || body.starts_with(&format!("{server_user} ")); // This will evaluate to false if the emergency password is set up so that // the administrator can execute commands as conduit -- cgit v1.2.3 From 921b266d86dd933250879870d9e91bb3c0189484 Mon Sep 17 00:00:00 2001 From: x4u Date: Sun, 21 May 2023 07:04:58 +0000 Subject: X4u/add apache cloudflare deploy info --- DEPLOY.md | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index 1d1fc13..c8f4a25 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -19,7 +19,7 @@ You may simply download the binary that fits your machine. Run `uname -m` to see | armv8 / aarch64 | [Binary][armv8-glibc-master] / [.deb][armv8-glibc-master-deb] | [Binary][armv8-glibc-next] / [.deb][armv8-glibc-next-deb] | These builds were created on and linked against the glibc version shipped with Debian bullseye. -If you use a system with an older glibc version, you might need to compile Conduit yourself. +If you use a system with an older glibc version (e.g. RHEL8), you might need to compile Conduit yourself. [x84_64-glibc-master]: https://gitlab.com/famedly/conduit/-/jobs/artifacts/master/raw/build-output/linux_amd64/conduit?job=docker:master [armv7-glibc-master]: https://gitlab.com/famedly/conduit/-/jobs/artifacts/master/raw/build-output/linux_arm_v7/conduit?job=docker:master @@ -39,12 +39,16 @@ $ sudo wget -O /usr/local/bin/matrix-conduit $ sudo chmod +x /usr/local/bin/matrix-conduit ``` -Alternatively, you may compile the binary yourself +Alternatively, you may compile the binary yourself. First, install any dependencies: ```bash +# Debian $ sudo apt install libclang-dev build-essential -``` +# RHEL +$ sudo dnf install clang +``` +Then, `cd` into the source tree of conduit-next and run: ```bash $ cargo build --release ``` @@ -74,7 +78,7 @@ cross build --release --no-default-features --features conduit_bin,backend_rocks While Conduit can run as any user it is usually better to use dedicated users for different services. This also allows you to make sure that the file permissions are correctly set up. -In Debian you can use this command to create a Conduit user: +In Debian or RHEL, you can use this command to create a Conduit user: ```bash sudo adduser --system conduit --no-create-home @@ -86,6 +90,19 @@ Conduit uses the ports 443 and 8448 both of which need to be open in the firewal If Conduit runs behind a router or in a container and has a different public IP address than the host system these public ports need to be forwarded directly or indirectly to the port mentioned in the config. +## Delegation of federation traffic + +If Conduit runs behind Cloudflare reverse proxy, which doesn't support port 8448 on free plans, [delegation](https://matrix-org.github.io/synapse/latest/delegate.html) can be set up to have federation traffic routed to port 443: +```apache +# .well-known delegation on Apache + + ErrorDocument 200 '{"m.server": "your.server.name:443"}' + Header always set Content-Type application/json + Header always set Access-Control-Allow-Origin * + +``` +[SRV DNS record](https://spec.matrix.org/latest/server-server-api/#resolving-server-names) delegation is also [possible](https://www.cloudflare.com/en-gb/learning/dns/dns-records/dns-srv-record/). + ## Setting up a systemd service Now we'll set up a systemd service for Conduit, so it's easy to start/stop Conduit and set it to autostart when your @@ -101,6 +118,7 @@ After=network.target Environment="CONDUIT_CONFIG=/etc/matrix-conduit/conduit.toml" User=conduit Group=nogroup +# On RHEL: Group=nobody Restart=always ExecStart=/usr/local/bin/matrix-conduit @@ -168,7 +186,7 @@ address = "127.0.0.1" # This makes sure Conduit can only be reached using the re ## Setting the correct file permissions As we are using a Conduit specific user we need to allow it to read the config. To do that you can run this command on -Debian: +Debian or RHEL: ```bash sudo chown -R root:root /etc/matrix-conduit @@ -180,6 +198,7 @@ If you use the default database path you also need to run this: ```bash sudo mkdir -p /var/lib/matrix-conduit/ sudo chown -R conduit:nogroup /var/lib/matrix-conduit/ +# On RHEL: sudo chown -R conduit:nobody /var/lib/matrix-conduit/ sudo chmod 700 /var/lib/matrix-conduit/ ``` @@ -192,6 +211,11 @@ This depends on whether you use Apache, Caddy, Nginx or another web server. Create `/etc/apache2/sites-enabled/050-conduit.conf` and copy-and-paste this: ```apache +# Requires mod_proxy and mod_proxy_http +# +# On Apache instance compiled from source, +# paste into httpd-ssl.conf or httpd.conf + Listen 8448 @@ -208,7 +232,11 @@ ProxyPassReverse /_matrix/ http://127.0.0.1:6167/_matrix/ **You need to make some edits again.** When you are done, run ```bash +# Debian $ sudo systemctl reload apache2 + +# Installed from source +$ sudo apachectl -k graceful ``` ### Caddy @@ -266,11 +294,19 @@ $ sudo systemctl reload nginx If you chose Caddy as your web proxy SSL certificates are handled automatically and you can skip this step. -The easiest way to get an SSL certificate, if you don't have one already, is to install `certbot` and run this: +The easiest way to get an SSL certificate, if you don't have one already, is to [install](https://certbot.eff.org/instructions) `certbot` and run this: ```bash +# To use ECC for the private key, +# paste into /etc/letsencrypt/cli.ini: +# key-type = ecdsa +# elliptic-curve = secp384r1 + $ sudo certbot -d your.server.name ``` +[Automated renewal](https://eff-certbot.readthedocs.io/en/stable/using.html#automated-renewals) is usually preconfigured. + +If using Cloudflare, configure instead the edge and origin certificates in dashboard. In case you’re already running a website on the same Apache server, you can just copy-and-paste the SSL configuration from your main virtual host on port 443 into the above-mentioned vhost. ## You're done! @@ -294,6 +330,8 @@ You can also use these commands as a quick health check. ```bash $ curl https://your.server.name/_matrix/client/versions + +# If using port 8448 $ curl https://your.server.name:8448/_matrix/client/versions ``` -- cgit v1.2.3 From 49b5af6d454f27f543ca080a605ab56bbeeeac37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 21 May 2023 11:51:36 +0200 Subject: chore: bump rocksdb --- Cargo.lock | 975 ++++++++++++++++++++---------------- Cargo.toml | 3 +- src/database/abstraction/rocksdb.rs | 8 +- 3 files changed, 545 insertions(+), 441 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 385d8f6..9c86f7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,20 +10,20 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ - "getrandom 0.2.8", + "cfg-if", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" dependencies = [ "memchr", ] @@ -43,17 +43,23 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + [[package]] name = "arc-swap" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -83,23 +89,20 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] name = "atomic" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" -dependencies = [ - "autocfg", -] +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" [[package]] name = "autocfg" @@ -157,9 +160,9 @@ dependencies = [ [[package]] name = "axum-server" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8456dab8f11484979a86651da8e619b355ede5d61a160755155f6c344bd18c47" +checksum = "bace45b270e36e3c27a190c65883de6dfc9f1d18c829907c127464815dc67b24" dependencies = [ "arc-swap", "bytes", @@ -169,7 +172,7 @@ dependencies = [ "hyper", "pin-project-lite", "rustls", - "rustls-pemfile 1.0.1", + "rustls-pemfile 1.0.2", "tokio", "tokio-rustls", "tower-service", @@ -189,9 +192,9 @@ checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" [[package]] name = "base64ct" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bincode" @@ -204,9 +207,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.59.2" +version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ "bitflags", "cexpr", @@ -214,11 +217,13 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", + "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", + "syn 2.0.16", ] [[package]] @@ -229,13 +234,13 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2b_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec", - "constant_time_eq", + "constant_time_eq 0.2.5", ] [[package]] @@ -249,9 +254,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -269,9 +274,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.2" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -279,15 +284,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" [[package]] name = "bytemuck" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -297,15 +302,26 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] [[package]] name = "cc" -version = "1.0.77" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -327,9 +343,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", @@ -338,37 +354,43 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.27" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0acbd8d28a0a60d7108d7ae850af6ba34cf2d1257fc646980e5f97ce14275966" +checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", "once_cell", ] +[[package]] +name = "clap_builder" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +dependencies = [ + "anstyle", + "bitflags", + "clap_lex", +] + [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "color_quant" @@ -433,9 +455,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "constant_time_eq" @@ -443,6 +465,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "constant_time_eq" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" + [[package]] name = "core-foundation" version = "0.9.3" @@ -455,33 +483,33 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" dependencies = [ "libc", ] [[package]] name = "crc" -version = "2.1.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "1.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" [[package]] name = "crc32fast" @@ -508,9 +536,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -518,9 +546,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -529,9 +557,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", @@ -552,9 +580,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -589,7 +617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.12.3", "lock_api", "once_cell", "parking_lot_core", @@ -597,15 +625,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.3.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" +checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "der" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", "zeroize", @@ -622,11 +650,11 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", "subtle", ] @@ -653,9 +681,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature", ] @@ -676,15 +704,15 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] @@ -698,7 +726,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -713,6 +741,15 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + [[package]] name = "figment" version = "0.10.8" @@ -722,16 +759,16 @@ dependencies = [ "atomic", "pear", "serde", - "toml 0.5.9", + "toml 0.5.11", "uncased", "version_check", ] [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", "miniz_oxide", @@ -762,17 +799,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - [[package]] name = "futures" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -785,9 +816,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -795,15 +826,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -812,38 +843,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -859,9 +890,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -880,9 +911,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" dependencies = [ "cfg-if", "libc", @@ -891,9 +922,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.11.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" dependencies = [ "color_quant", "weezl", @@ -901,15 +932,15 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.15" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -929,17 +960,23 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ "ahash", ] [[package]] name = "hashlink" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" +checksum = "0761a1b9491c4f2e3d66aa0f62d0fba0af9a0e2852e4d48ea506632a4b56e6aa" dependencies = [ - "hashbrown", + "hashbrown 0.13.2", ] [[package]] @@ -969,9 +1006,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "heed" @@ -1011,9 +1048,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] @@ -1024,7 +1061,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -1040,9 +1077,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -1080,9 +1117,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -1104,9 +1141,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", @@ -1138,9 +1175,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.5" +version = "0.24.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" dependencies = [ "bytemuck", "byteorder", @@ -1154,12 +1191,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] @@ -1189,9 +1226,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.5.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "itertools" @@ -1204,15 +1241,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] @@ -1225,9 +1262,9 @@ checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -1252,11 +1289,11 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "8.1.1" +version = "8.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa4b4af834c6cfd35d8763d359661b90f2e45d8f750a0849156c7f4671af09c" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", "pem", "ring", "serde", @@ -1300,9 +1337,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libloading" @@ -1316,14 +1353,18 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "6.20.3" +version = "0.11.0+8.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c309a9d2470844aceb9a4a098cf5286154d20596868b75a6b36357d2bb9ca25d" +checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" dependencies = [ "bindgen", + "bzip2-sys", "cc", "glob", "libc", + "libz-sys", + "lz4-sys", + "zstd-sys", ] [[package]] @@ -1337,6 +1378,17 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1382,6 +1434,16 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "maplit" version = "1.0.2" @@ -1405,9 +1467,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matchit" @@ -1423,18 +1485,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" @@ -1444,30 +1506,31 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", + "simd-adler32", ] [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -1526,9 +1589,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ "hermit-abi", "libc", @@ -1536,9 +1599,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opaque-debug" @@ -1635,12 +1698,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "overload" version = "0.1.1" @@ -1669,28 +1726,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "paste" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pear" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" +checksum = "0ec95680a7087503575284e5063e14b694b7a9c0b065e5dceec661e0497127e8" dependencies = [ "inlinable_string", "pear_codegen", @@ -1699,14 +1756,14 @@ dependencies = [ [[package]] name = "pear_codegen" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" +checksum = "9661a3a53f93f09f2ea882018e4d7c88f6ff2956d809a276060476fd8c879d3c" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn", + "syn 2.0.16", ] [[package]] @@ -1717,9 +1774,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ "base64 0.13.1", ] @@ -1732,9 +1789,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "persy" -version = "1.3.4" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5511189f4dbd737283b0dd2ff6715f2e35fd0d3e1ddf953ed6a772e439e1f73f" +checksum = "3712821f12453814409ec149071bd4832a8ec458e648579c104aee30ed70b300" dependencies = [ "crc", "data-encoding", @@ -1748,22 +1805,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] @@ -1790,18 +1847,19 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "png" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" dependencies = [ "bitflags", "crc32fast", + "fdeflate", "flate2", "miniz_oxide", ] @@ -1813,58 +1871,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] -name = "proc-macro-crate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" -dependencies = [ - "once_cell", - "thiserror", - "toml 0.5.9", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "prettyplease" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "617feabb81566b593beb4886fb8c1f38064169dae4dccad0e3220160c3b37203" dependencies = [ - "proc-macro-error-attr", "proc-macro2", - "quote", - "syn", - "version_check", + "syn 2.0.16", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-crate" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "once_cell", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" dependencies = [ "unicode-ident", ] [[package]] name = "proc-macro2-diagnostics" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", "version_check", "yansi", ] @@ -1877,9 +1920,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.21" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] @@ -1943,7 +1986,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.9", ] [[package]] @@ -1970,20 +2013,20 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.9", "redox_syscall", "thiserror", ] [[package]] name = "regex" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.1", ] [[package]] @@ -1992,14 +2035,20 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "reqwest" @@ -2066,9 +2115,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.17.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a62eca5cacf2c8261128631bed9f045598d40bfbe4b29f5163f0f802f8f44a7" +checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" dependencies = [ "libc", "librocksdb-sys", @@ -2189,8 +2238,8 @@ dependencies = [ "quote", "ruma-identifiers-validation", "serde", - "syn", - "toml 0.7.2", + "syn 1.0.109", + "toml 0.7.4", ] [[package]] @@ -2256,7 +2305,7 @@ checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9" dependencies = [ "base64 0.13.1", "blake2b_simd", - "constant_time_eq", + "constant_time_eq 0.1.5", "crossbeam-utils", ] @@ -2268,9 +2317,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -2285,7 +2334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.1", + "rustls-pemfile 1.0.2", "schannel", "security-framework", ] @@ -2301,27 +2350,26 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", ] [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -2348,9 +2396,9 @@ checksum = "621e3680f3e07db4c9c2c3fb07c6223ab2fab2e54bd3c04c3ae037990f428c32" [[package]] name = "security-framework" -version = "2.7.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ "bitflags", "core-foundation", @@ -2361,9 +2409,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" dependencies = [ "core-foundation-sys", "libc", @@ -2371,22 +2419,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] @@ -2404,9 +2452,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -2415,9 +2463,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" dependencies = [ "serde", ] @@ -2436,9 +2484,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.14" +version = "0.9.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d232d893b10de3eb7258ff01974d6ee20663d8e833263c99409d4b13a0209da" +checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" dependencies = [ "indexmap", "itoa", @@ -2449,13 +2497,13 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2466,7 +2514,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2490,7 +2538,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2510,9 +2558,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -2523,6 +2571,12 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + [[package]] name = "simple_asn1" version = "0.6.2" @@ -2537,9 +2591,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -2552,9 +2606,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -2587,15 +2641,26 @@ dependencies = [ [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ "proc-macro2", "quote", @@ -2604,9 +2669,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synchronoise" @@ -2617,44 +2682,33 @@ dependencies = [ "crossbeam-queue", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -2693,12 +2747,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -2714,9 +2767,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" dependencies = [ "itoa", "serde", @@ -2726,15 +2779,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" dependencies = [ "time-core", ] @@ -2750,38 +2803,37 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.22.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] @@ -2809,9 +2861,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -2820,9 +2872,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -2834,18 +2886,18 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "toml" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" dependencies = [ "serde", "serde_spanned", @@ -2855,18 +2907,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.4" +version = "0.19.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" +checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" dependencies = [ "indexmap", "serde", @@ -2893,9 +2945,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" dependencies = [ "async-compression", "bitflags", @@ -2941,20 +2993,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -2998,9 +3050,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -3061,36 +3113,36 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "uncased" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -3101,17 +3153,11 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "unsafe-libyaml" -version = "0.2.4" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68" +checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" [[package]] name = "unsigned-varint" @@ -3138,11 +3184,11 @@ dependencies = [ [[package]] name = "uuid" -version = "1.2.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" dependencies = [ - "getrandom 0.2.8", + "getrandom 0.2.9", ] [[package]] @@ -3187,9 +3233,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3197,24 +3243,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.16", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" dependencies = [ "cfg-if", "js-sys", @@ -3224,9 +3270,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3234,28 +3280,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.16", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", @@ -3313,109 +3359,156 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.3.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf09497b8f8b5ac5d3bb4d05c0a99be20f26fd3d5f2db7b0716e946d5103658" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" dependencies = [ "memchr", ] @@ -3446,23 +3539,22 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", - "synstructure", + "syn 2.0.16", ] [[package]] @@ -3473,3 +3565,14 @@ checksum = "70b40401a28d86ce16a330b863b86fd7dbee4d7c940587ab09ab8c019f9e3fdf" dependencies = [ "num-traits", ] + +[[package]] +name = "zstd-sys" +version = "2.0.8+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 7c7df7f..5dfb38a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,10 +82,11 @@ crossbeam = { version = "0.8.1", optional = true } num_cpus = "1.13.0" threadpool = "1.8.1" heed = { git = "https://github.com/timokoesters/heed.git", rev = "f6f825da7fb2c758867e05ad973ef800a6fe1d5d", optional = true } -rocksdb = { version = "0.17.0", default-features = true, features = ["multi-threaded-cf", "zstd"], optional = true } # Used for ruma wrapper serde_html_form = "0.2.0" +rocksdb = { version = "0.21.0", default-features = true, features = ["multi-threaded-cf", "zstd"], optional = true } + thread_local = "1.1.3" # used for TURN server authentication hmac = "0.12.1" diff --git a/src/database/abstraction/rocksdb.rs b/src/database/abstraction/rocksdb.rs index 34d91d2..3e64e8b 100644 --- a/src/database/abstraction/rocksdb.rs +++ b/src/database/abstraction/rocksdb.rs @@ -54,7 +54,7 @@ fn db_options(max_open_files: i32, rocksdb_cache: &rocksdb::Cache) -> rocksdb::O impl KeyValueDatabaseEngine for Arc { fn open(config: &Config) -> Result { let cache_capacity_bytes = (config.db_cache_capacity_mb * 1024.0 * 1024.0) as usize; - let rocksdb_cache = rocksdb::Cache::new_lru_cache(cache_capacity_bytes).unwrap(); + let rocksdb_cache = rocksdb::Cache::new_lru_cache(cache_capacity_bytes); let db_opts = db_options(config.rocksdb_max_open_files, &rocksdb_cache); @@ -161,7 +161,7 @@ impl KvTree for RocksDbEngineTree<'_> { self.db .rocks .iterator_cf(&self.cf(), rocksdb::IteratorMode::Start) - //.map(|r| r.unwrap()) + .map(|r| r.unwrap()) .map(|(k, v)| (Vec::from(k), Vec::from(v))), ) } @@ -185,7 +185,7 @@ impl KvTree for RocksDbEngineTree<'_> { }, ), ) - //.map(|r| r.unwrap()) + .map(|r| r.unwrap()) .map(|(k, v)| (Vec::from(k), Vec::from(v))), ) } @@ -226,7 +226,7 @@ impl KvTree for RocksDbEngineTree<'_> { &self.cf(), rocksdb::IteratorMode::From(&prefix, rocksdb::Direction::Forward), ) - //.map(|r| r.unwrap()) + .map(|r| r.unwrap()) .map(|(k, v)| (Vec::from(k), Vec::from(v))) .take_while(move |(k, _)| k.starts_with(&prefix)), ) -- cgit v1.2.3 From d62cd2ae51449d018c4d0d223b0b5d0d53260af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 21 May 2023 13:42:59 +0200 Subject: chore: bump dependencies --- Cargo.toml | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5dfb38a..c925bf2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,9 +20,9 @@ rust-version = "1.64.0" [dependencies] # Web framework axum = { version = "0.5.17", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path"], optional = true } -axum-server = { version = "0.4.0", features = ["tls-rustls"] } -tower = { version = "0.4.8", features = ["util"] } -tower-http = { version = "0.3.4", features = ["add-extension", "cors", "compression-full", "sensitive-headers", "trace", "util"] } +axum-server = { version = "0.4.7", features = ["tls-rustls"] } +tower = { version = "0.4.13", features = ["util"] } +tower-http = { version = "0.3.5", features = ["add-extension", "cors", "compression-full", "sensitive-headers", "trace", "util"] } # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } @@ -31,46 +31,46 @@ ruma = { git = "https://github.com/ruma/ruma", rev = "8eea3e05490fa9a318f9ed66c3 #ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } # Async runtime and utilities -tokio = { version = "1.11.0", features = ["fs", "macros", "signal", "sync"] } +tokio = { version = "1.28.1", features = ["fs", "macros", "signal", "sync"] } # Used for storing data permanently #sled = { version = "0.34.7", features = ["compression", "no_metrics"], optional = true } #sled = { git = "https://github.com/spacejam/sled.git", rev = "e4640e0773595229f398438886f19bca6f7326a2", features = ["compression"] } -persy = { version = "1.0.0", optional = true, features = ["background_ops"] } +persy = { version = "1.4.4", optional = true, features = ["background_ops"] } # Used for the http request / response body type for Ruma endpoints used with reqwest -bytes = "1.1.0" -http = "0.2.4" +bytes = "1.4.0" +http = "0.2.9" # Used to find data directory for default db path -directories = "4.0.0" +directories = "4.0.1" # Used for ruma wrapper -serde_json = { version = "1.0.68", features = ["raw_value"] } +serde_json = { version = "1.0.96", features = ["raw_value"] } # Used for appservice registration files -serde_yaml = "0.9.13" +serde_yaml = "0.9.21" # Used for pdu definition -serde = { version = "1.0.130", features = ["rc"] } +serde = { version = "1.0.163", features = ["rc"] } # Used for secure identifiers -rand = "0.8.4" +rand = "0.8.5" # Used to hash passwords rust-argon2 = "1.0.0" # Used to send requests reqwest = { default-features = false, features = ["rustls-tls-native-roots", "socks"], git = "https://github.com/timokoesters/reqwest", rev = "57b7cf4feb921573dfafad7d34b9ac6e44ead0bd" } # Used for conduit::Error type -thiserror = "1.0.29" +thiserror = "1.0.40" # Used to generate thumbnails for images -image = { version = "0.24.4", default-features = false, features = ["jpeg", "png", "gif"] } +image = { version = "0.24.6", default-features = false, features = ["jpeg", "png", "gif"] } # Used to encode server public key -base64 = "0.13.0" +base64 = "0.13.1" # Used when hashing the state ring = "0.16.20" # Used when querying the SRV record of other servers trust-dns-resolver = "0.22.0" # Used to find matching events for appservices -regex = "1.5.4" +regex = "1.8.1" # jwt jsonwebtokens -jsonwebtoken = "8.1.1" +jsonwebtoken = "8.3.0" # Performance measurements -tracing = { version = "0.1.27", features = [] } -tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +tracing = { version = "0.1.37", features = [] } +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing-flame = "0.2.0" opentelemetry = { version = "0.18.0", features = ["rt-tokio"] } opentelemetry-jaeger = { version = "0.17.0", features = ["rt-tokio"] } @@ -78,8 +78,8 @@ tracing-opentelemetry = "0.18.0" lru-cache = "0.1.2" rusqlite = { version = "0.28.0", optional = true, features = ["bundled"] } parking_lot = { version = "0.12.1", optional = true } -crossbeam = { version = "0.8.1", optional = true } -num_cpus = "1.13.0" +crossbeam = { version = "0.8.2", optional = true } +num_cpus = "1.15.0" threadpool = "1.8.1" heed = { git = "https://github.com/timokoesters/heed.git", rev = "f6f825da7fb2c758867e05ad973ef800a6fe1d5d", optional = true } # Used for ruma wrapper @@ -87,20 +87,20 @@ serde_html_form = "0.2.0" rocksdb = { version = "0.21.0", default-features = true, features = ["multi-threaded-cf", "zstd"], optional = true } -thread_local = "1.1.3" +thread_local = "1.1.7" # used for TURN server authentication hmac = "0.12.1" -sha-1 = "0.10.0" +sha-1 = "0.10.1" # used for conduit's CLI and admin room command parsing -clap = { version = "4.0.11", default-features = false, features = ["std", "derive", "help", "usage", "error-context"] } -futures-util = { version = "0.3.17", default-features = false } +clap = { version = "4.3.0", default-features = false, features = ["std", "derive", "help", "usage", "error-context"] } +futures-util = { version = "0.3.28", default-features = false } # Used for reading the configuration from conduit.toml & environment variables -figment = { version = "0.10.6", features = ["env", "toml"] } +figment = { version = "0.10.8", features = ["env", "toml"] } tikv-jemalloc-ctl = { version = "0.5.0", features = ["use_std"], optional = true } tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_supported_platforms"], optional = true } lazy_static = "1.4.0" -async-trait = "0.1.57" +async-trait = "0.1.68" sd-notify = { version = "0.4.1", optional = true } -- cgit v1.2.3 From 4e2bbf9d6aec7773d66cfba56c49e0f87003d47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 21 May 2023 15:16:23 +0200 Subject: Minor DEPLOY.md changes --- DEPLOY.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index c8f4a25..75db366 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -7,7 +7,7 @@ ## Installing Conduit -Although you might be able to compile Conduit for Windows, we do recommend running it on a linux server. We therefore +Although you might be able to compile Conduit for Windows, we do recommend running it on a Linux server. We therefore only offer Linux binaries. You may simply download the binary that fits your machine. Run `uname -m` to see what you need. Now copy the right url: @@ -90,7 +90,7 @@ Conduit uses the ports 443 and 8448 both of which need to be open in the firewal If Conduit runs behind a router or in a container and has a different public IP address than the host system these public ports need to be forwarded directly or indirectly to the port mentioned in the config. -## Delegation of federation traffic +## Optional: Avoid port 8448 If Conduit runs behind Cloudflare reverse proxy, which doesn't support port 8448 on free plans, [delegation](https://matrix-org.github.io/synapse/latest/delegate.html) can be set up to have federation traffic routed to port 443: ```apache @@ -174,6 +174,7 @@ allow_registration = true allow_federation = true +# Server to get public keys from. You probably shouldn't change this trusted_servers = ["matrix.org"] #max_concurrent_requests = 100 # How many requests Conduit sends to other servers at the same time -- cgit v1.2.3 From a4261aac767758c756512f6cf5c4173b8af80354 Mon Sep 17 00:00:00 2001 From: Jonas Zohren Date: Sun, 21 May 2023 20:41:08 +0000 Subject: * Fix Debian builds by actually including the whole `debian` directory into deb creation * Fix CI by explicitly setting hostname of docker in docker service * Fix Docker build by bumping the Rust version to 1.69 * Fix cargo check in CI by bumping the Rust version to 1.69 --- .gitlab-ci.yml | 5 +++-- Dockerfile | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d05bb89..24db9f4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -28,7 +28,8 @@ variables: # Famedly runners use BTRFS, overlayfs and overlay2 often break jobs DOCKER_DRIVER: btrfs services: - - docker:dind + - name: docker:dind + alias: docker script: - apk add openssh-client - eval $(ssh-agent -s) @@ -109,7 +110,7 @@ docker:tags: cargo check: stage: test - image: docker.io/rust:1.64.0-bullseye + image: docker.io/rust:1.69.0-bullseye needs: [] interruptible: true before_script: diff --git a/Dockerfile b/Dockerfile index 2763b12..32ba81f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM docker.io/rust:1.64-bullseye AS builder +FROM docker.io/rust:1.69-bullseye AS builder WORKDIR /usr/src/conduit # Install required packages to build Conduit and it's dependencies @@ -37,7 +37,7 @@ COPY --from=builder /usr/src/conduit/target/release/conduit /conduit # --------------------------------------------------------------------------------------------------------------- # Build cargo-deb, a tool to package up rust binaries into .deb packages for Debian/Ubuntu based systems: # --------------------------------------------------------------------------------------------------------------- -FROM docker.io/rust:1.64-bullseye AS build-cargo-deb +FROM docker.io/rust:1.69-bullseye AS build-cargo-deb RUN apt-get update && \ apt-get install -y --no-install-recommends \ @@ -57,7 +57,7 @@ WORKDIR /usr/src/conduit COPY ./LICENSE ./LICENSE COPY ./README.md ./README.md -COPY debian/README.Debian ./debian/ +COPY debian ./debian COPY --from=build-cargo-deb /usr/local/cargo/bin/cargo-deb /usr/local/cargo/bin/cargo-deb # --no-build makes cargo-deb reuse already compiled project -- cgit v1.2.3 From be9196430d422c37c25a7f32a09a9c1fa9c52c43 Mon Sep 17 00:00:00 2001 From: Jade Date: Thu, 25 May 2023 18:21:01 +0000 Subject: fix nix readme to work with ipv6 --- nix/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/nix/README.md b/nix/README.md index 77bad0f..f8537d5 100644 --- a/nix/README.md +++ b/nix/README.md @@ -118,10 +118,19 @@ in ssl = true; } { + addr = "[::]"; + port = 443; + ssl = true; + } { addr = "0.0.0.0"; port = 8448; ssl = true; } + { + addr = "[::]"; + port = 8448; + ssl = true; + } ]; locations."/_matrix/" = { -- cgit v1.2.3 From 664d6baace232e929dd248636625f9ae835938c5 Mon Sep 17 00:00:00 2001 From: digital Date: Fri, 26 May 2023 13:06:28 +0200 Subject: fix: make requested changes --- src/api/client_server/session.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/client_server/session.rs b/src/api/client_server/session.rs index f8fc7f1..b3328e4 100644 --- a/src/api/client_server/session.rs +++ b/src/api/client_server/session.rs @@ -105,12 +105,10 @@ pub async fn login_route(body: Ruma) -> Result { - info!("hi"); if !body.from_appservice { return Err(Error::BadRequest( ErrorKind::Forbidden, - // TODO: is this the correct response - "Wrong username or password.", + "Forbidden login type." )); }; let username = if let UserIdentifier::UserIdOrLocalpart(user_id) = identifier { -- cgit v1.2.3 From 1ea27c4f97bfc717f9753d8bbd91eafa395cdd2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 8 Jun 2023 20:48:35 +0200 Subject: fix: restricted room error is now FORBIDDEN --- src/api/client_server/membership.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index cd26372..11e37e6 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -106,6 +106,7 @@ pub async fn join_room_by_id_or_alias_route( ); servers.push(room_id.server_name().to_owned()); + (servers, room_id) } Err(room_alias) => { @@ -598,7 +599,7 @@ async fn join_room_by_id_helper( info!("send_join finished"); if let Some(signed_raw) = &send_join_response.room_state.event { - info!("There is a signed event. This room is probably using restricted joins"); + info!("There is a signed event. This room is probably using restricted joins. Adding signature to our event"); let (signed_event_id, signed_value) = match gen_event_id_canonical_json(signed_raw, &room_version_id) { Ok(t) => t, @@ -901,7 +902,13 @@ async fn join_room_by_id_helper( Err(e) => e, }; - if !restriction_rooms.is_empty() { + if !restriction_rooms.is_empty() + && servers + .iter() + .filter(|s| *s != services().globals.server_name()) + .count() + > 0 + { info!( "We couldn't do the join locally, maybe federation can help to satisfy the restricted join requirements" ); -- cgit v1.2.3 From faa9208a3e484756f7e535ca0d51488fbf1e4dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 8 Jun 2023 20:51:34 +0200 Subject: cargo fmt --- src/api/client_server/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/client_server/session.rs b/src/api/client_server/session.rs index b3328e4..8908fef 100644 --- a/src/api/client_server/session.rs +++ b/src/api/client_server/session.rs @@ -108,7 +108,7 @@ pub async fn login_route(body: Ruma) -> Result Date: Sat, 10 Jun 2023 15:35:22 +0000 Subject: chore(ci): Adjust to rust version bumps --- .gitlab-ci.yml | 8 ++------ Dockerfile | 6 ++++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24db9f4..b7df56f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -110,7 +110,7 @@ docker:tags: cargo check: stage: test - image: docker.io/rust:1.69.0-bullseye + image: docker.io/rust:1.70.0-bullseye needs: [] interruptible: true before_script: @@ -135,11 +135,7 @@ test:cargo: - apt-get update && apt-get -y --no-install-recommends install libclang-dev # dependency for rocksdb script: - rustc --version && cargo --version # Print version info for debugging - - "cargo test --color always --workspace --verbose --locked --no-fail-fast -- -Z unstable-options --format json | gitlab-report -p test > $CI_PROJECT_DIR/report.xml" - artifacts: - when: always - reports: - junit: report.xml + - "cargo test --color always --workspace --verbose --locked --no-fail-fast" test:clippy: extends: .test-shared-settings diff --git a/Dockerfile b/Dockerfile index 32ba81f..943f686 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,7 @@ # syntax=docker/dockerfile:1 -FROM docker.io/rust:1.69-bullseye AS builder +FROM docker.io/rust:1.70-bullseye AS base + +FROM base AS builder WORKDIR /usr/src/conduit # Install required packages to build Conduit and it's dependencies @@ -37,7 +39,7 @@ COPY --from=builder /usr/src/conduit/target/release/conduit /conduit # --------------------------------------------------------------------------------------------------------------- # Build cargo-deb, a tool to package up rust binaries into .deb packages for Debian/Ubuntu based systems: # --------------------------------------------------------------------------------------------------------------- -FROM docker.io/rust:1.69-bullseye AS build-cargo-deb +FROM base AS build-cargo-deb RUN apt-get update && \ apt-get install -y --no-install-recommends \ -- cgit v1.2.3 From 15e60818c908e58d53580e3fd049e452b2133610 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Sat, 17 Jun 2023 17:02:10 -0700 Subject: pin nixos-unstable, update flake.lock `nixos-unstable` is the rolling release channel of NixOS. The default is the master branch, which doesn't always have a populated binary cache and so may result in compiling a bunch of stuff unnecessarily. --- flake.lock | 55 +++++++++++++++++++++++++++++++++++++------------------ flake.nix | 2 +- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/flake.lock b/flake.lock index d76ff59..b69bb8c 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1680584903, - "narHash": "sha256-uraq+D3jcLzw/UVk0xMHcnfILfIMa0DLrtAEq2nNlxU=", + "lastModified": 1686621798, + "narHash": "sha256-FUwWszmSiDzUdTk8f69xwMoYlhdPaLvDaIYOE/y6VXc=", "owner": "ipetkov", "repo": "crane", - "rev": "65d3f6a3970cd46bef5eedfd458300f72c56b3c5", + "rev": "75f7d715f8088f741be9981405f6444e2d49efdd", "type": "github" }, "original": { @@ -33,11 +33,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1680607374, - "narHash": "sha256-U5iiPqbAanr+sQCCZ7zxYhwCXdcDpish8Uy4ELZeXM0=", + "lastModified": 1687004852, + "narHash": "sha256-wRSUs+v8xtIJaFlWO5NLFQjkq5+eYhxHHXnZKsZ9DpQ=", "owner": "nix-community", "repo": "fenix", - "rev": "e70d498e97017daa59363eafa054619d4fa160c3", + "rev": "df0a6e4ec44b4a276acfa5a96d2a83cb2dfdc791", "type": "github" }, "original": { @@ -63,12 +63,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1678901627, - "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", "owner": "numtide", "repo": "flake-utils", - "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", "type": "github" }, "original": { @@ -79,15 +82,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1680652733, - "narHash": "sha256-FFG6Nai9M71C0Uc+D8TxyHoAjTplM0/9uWKsl7ALfUs=", + "lastModified": 1686960236, + "narHash": "sha256-AYCC9rXNLpUWzD9hm+askOfpliLEC9kwAo7ITJc4HIw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "cc5bde408572508efd1273852862d418bb313443", + "rev": "04af42f3b31dba0ef742d254456dc4c14eedac86", "type": "github" }, "original": { "owner": "NixOS", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } @@ -103,11 +107,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1680435407, - "narHash": "sha256-IPBtZCOh3BdrR+V77cL7r6WQnclWcZ/85BDYnmq/GnQ=", + "lastModified": 1686936697, + "narHash": "sha256-mCoPr1nNWKpsoGMBFaK/sswkLloRCZuoWi2a+OKs3vk=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "236576227a299fd19ba836b1834ab50c948af994", + "rev": "a5a71c75e62a0eaa1b42a376f7cf3d348cb5dec6", "type": "github" }, "original": { @@ -129,11 +133,11 @@ ] }, "locked": { - "lastModified": 1680488274, - "narHash": "sha256-0vYMrZDdokVmPQQXtFpnqA2wEgCCUXf5a3dDuDVshn0=", + "lastModified": 1685759304, + "narHash": "sha256-I3YBH6MS3G5kGzNuc1G0f9uYfTcNY9NYoRc3QsykLk4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "7ec2ff598a172c6e8584457167575b3a1a5d80d8", + "rev": "c535b4f3327910c96dcf21851bbdd074d0760290", "type": "github" }, "original": { @@ -141,6 +145,21 @@ "repo": "rust-overlay", "type": "github" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 970e847..669d90a 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,6 @@ { inputs = { - nixpkgs.url = "github:NixOS/nixpkgs"; + nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; fenix = { -- cgit v1.2.3 From 4a7d3c7301bc86655299345f264cf151c17faceb Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Sat, 17 Jun 2023 17:04:11 -0700 Subject: upgrade rust in Cargo.toml/flake.nix Looks like this should've happened as part of !479. --- Cargo.toml | 2 +- flake.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c925bf2..c50f3d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" # `nix flake update`. If you don't have Nix installed or otherwise don't know # how to do this, ping `@charles:computer.surgery` or `@dusk:gaze.systems` in # the matrix room. -rust-version = "1.64.0" +rust-version = "1.70.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/flake.nix b/flake.nix index 669d90a..ba8e829 100644 --- a/flake.nix +++ b/flake.nix @@ -40,7 +40,7 @@ channel = cargoToml.package.rust-version; # THE rust-version HASH - sha256 = "sha256-8len3i8oTwJSOJZMosGGXHBL5BVuGQnWOT2St5YAUFU="; + sha256 = "sha256-gdYqng0y9iHYzYPAdkC/ka3DRny3La/S5G8ASj0Ayyc="; }; # The system's RocksDB -- cgit v1.2.3 From abd0a014e852d41d25320f6ccd19ac1de4156f96 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Sat, 17 Jun 2023 17:04:57 -0700 Subject: nixpkgs' rocksdb is too old :( --- flake.nix | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/flake.nix b/flake.nix index ba8e829..5de5621 100644 --- a/flake.nix +++ b/flake.nix @@ -43,10 +43,6 @@ sha256 = "sha256-gdYqng0y9iHYzYPAdkC/ka3DRny3La/S5G8ASj0Ayyc="; }; - # The system's RocksDB - ROCKSDB_INCLUDE_DIR = "${pkgs.rocksdb_6_23}/include"; - ROCKSDB_LIB_DIR = "${pkgs.rocksdb_6_23}/lib"; - # Shared between the package and the devShell nativeBuildInputs = (with pkgs.rustPlatform; [ bindgenHook @@ -61,9 +57,7 @@ inherit stdenv - nativeBuildInputs - ROCKSDB_INCLUDE_DIR - ROCKSDB_LIB_DIR; + nativeBuildInputs; }; devShells.default = (pkgs.mkShell.override { inherit stdenv; }) { @@ -71,10 +65,6 @@ # sources, and it can read this environment variable to do so RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library"; - inherit - ROCKSDB_INCLUDE_DIR - ROCKSDB_LIB_DIR; - # Development tools nativeBuildInputs = nativeBuildInputs ++ (with toolchain; [ cargo -- cgit v1.2.3 From c7e0ea525a3c6f66072c3518bb8c533c87f1e3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 25 Jun 2023 19:31:40 +0200 Subject: feat: WIP relationships and threads --- Cargo.lock | 595 ++++++++++++++------------- Cargo.toml | 8 +- Cross.toml | 23 -- src/api/client_server/context.rs | 19 +- src/api/client_server/media.rs | 6 + src/api/client_server/message.rs | 8 +- src/api/client_server/mod.rs | 2 + src/api/client_server/relations.rs | 10 + src/api/client_server/threads.rs | 49 +++ src/api/client_server/unversioned.rs | 2 + src/api/server_server.rs | 4 + src/database/key_value/rooms/mod.rs | 1 + src/database/key_value/rooms/pdu_metadata.rs | 7 + src/database/key_value/rooms/threads.rs | 78 ++++ src/database/key_value/rooms/timeline.rs | 21 +- src/database/mod.rs | 7 + src/main.rs | 1 + src/service/media/mod.rs | 6 +- src/service/mod.rs | 1 + src/service/pdu.rs | 30 +- src/service/pusher/mod.rs | 4 +- src/service/rooms/mod.rs | 3 + src/service/rooms/pdu_metadata/data.rs | 1 + src/service/rooms/pdu_metadata/mod.rs | 9 +- src/service/rooms/threads/data.rs | 15 + src/service/rooms/threads/mod.rs | 119 ++++++ src/service/rooms/timeline/data.rs | 7 +- src/service/rooms/timeline/mod.rs | 68 ++- 28 files changed, 765 insertions(+), 339 deletions(-) delete mode 100644 Cross.toml create mode 100644 src/api/client_server/relations.rs create mode 100644 src/api/client_server/threads.rs create mode 100644 src/database/key_value/rooms/threads.rs create mode 100644 src/service/rooms/threads/data.rs create mode 100644 src/service/rooms/threads/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 9c86f7d..ebb47d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,33 +21,24 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] [[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" +name = "allocator-api2" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] +checksum = "56fc6cf8dc8c4158eed8649f9b8b0ea1518eb62b544fe9490d66fa0b349eafe9" [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "arc-swap" @@ -63,9 +54,9 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "assign" @@ -79,12 +70,12 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" dependencies = [ - "brotli", - "flate2", "futures-core", "memchr", "pin-project-lite", "tokio", + "zstd", + "zstd-safe", ] [[package]] @@ -95,7 +86,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -118,7 +109,7 @@ checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "headers", @@ -137,7 +128,7 @@ dependencies = [ "sync_wrapper", "tokio", "tower", - "tower-http", + "tower-http 0.3.5", "tower-layer", "tower-service", ] @@ -160,9 +151,9 @@ dependencies = [ [[package]] name = "axum-server" -version = "0.4.7" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bace45b270e36e3c27a190c65883de6dfc9f1d18c829907c127464815dc67b24" +checksum = "447f28c85900215cc1bea282f32d4a2f22d55c5a300afdfbc661c8d6a632e063" dependencies = [ "arc-swap", "bytes", @@ -171,10 +162,10 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "rustls", + "rustls 0.21.2", "rustls-pemfile 1.0.2", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", ] @@ -186,9 +177,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64ct" @@ -211,7 +202,7 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -223,7 +214,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -232,6 +223,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" + [[package]] name = "blake2b_simd" version = "1.0.1" @@ -240,7 +237,7 @@ checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec", - "constant_time_eq 0.2.5", + "constant_time_eq 0.2.6", ] [[package]] @@ -261,32 +258,11 @@ dependencies = [ "generic-array", ] -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bumpalo" -version = "3.12.2" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytemuck" @@ -354,9 +330,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.0" +version = "4.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +checksum = "d9394150f5b4273a1763355bd1c2ec54cc5a2593f790587bcd6b2c947cfa9211" dependencies = [ "clap_builder", "clap_derive", @@ -365,25 +341,25 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.0" +version = "4.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +checksum = "9a78fbdd3cc2914ddf37ba444114bc7765bbdcb55ec9cbe6fa054f0137400717" dependencies = [ "anstyle", - "bitflags", + "bitflags 1.3.2", "clap_lex", ] [[package]] name = "clap_derive" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -445,7 +421,7 @@ dependencies = [ "tikv-jemallocator", "tokio", "tower", - "tower-http", + "tower-http 0.4.1", "tracing", "tracing-flame", "tracing-opentelemetry", @@ -467,9 +443,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "constant_time_eq" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" [[package]] name = "core-foundation" @@ -489,9 +465,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -557,9 +533,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", @@ -580,9 +556,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -729,6 +705,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "fallible-iterator" version = "0.2.0" @@ -752,14 +734,14 @@ dependencies = [ [[package]] name = "figment" -version = "0.10.8" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e56602b469b2201400dec66a66aec5a9b8761ee97cd1b8c96ab2483fcc16cc9" +checksum = "4547e226f4c9ab860571e070a9034192b3175580ecea38da34fcdb53a018c9a5" dependencies = [ "atomic", "pear", "serde", - "toml 0.5.11", + "toml", "uncased", "version_check", ] @@ -782,9 +764,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -855,7 +837,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -911,9 +893,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -948,7 +930,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -963,20 +945,21 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" dependencies = [ "ahash", + "allocator-api2", ] [[package]] name = "hashlink" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0761a1b9491c4f2e3d66aa0f62d0fba0af9a0e2852e4d48ea506632a4b56e6aa" +checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" dependencies = [ - "hashbrown 0.13.2", + "hashbrown 0.14.0", ] [[package]] @@ -986,7 +969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.1", - "bitflags", + "bitflags 1.3.2", "bytes", "headers-core", "http", @@ -1132,7 +1115,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -1147,9 +1130,9 @@ checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", - "rustls", + "rustls 0.20.8", "tokio", - "tokio-rustls", + "tokio-rustls 0.23.4", ] [[package]] @@ -1165,9 +1148,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1200,6 +1183,16 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "inlinable_string" version = "0.1.15" @@ -1214,14 +1207,14 @@ checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" [[package]] name = "ipconfig" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2", + "socket2 0.5.3", "widestring", - "winapi", - "winreg 0.10.1", + "windows-sys 0.48.0", + "winreg 0.50.0", ] [[package]] @@ -1262,9 +1255,9 @@ checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1293,7 +1286,7 @@ version = "8.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "pem", "ring", "serde", @@ -1337,9 +1330,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libloading" @@ -1408,9 +1401,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1418,12 +1411,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "lru-cache" @@ -1485,9 +1475,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -1516,14 +1506,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1599,9 +1588,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -1660,7 +1649,7 @@ dependencies = [ "fnv", "futures-channel", "futures-util", - "indexmap", + "indexmap 1.9.3", "js-sys", "once_cell", "pin-project-lite", @@ -1726,15 +1715,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] @@ -1763,7 +1752,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -1783,9 +1772,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "persy" @@ -1820,7 +1809,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -1853,11 +1842,11 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "png" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" +checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", @@ -1872,12 +1861,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.2.5" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617feabb81566b593beb4886fb8c1f38064169dae4dccad0e3220160c3b37203" +checksum = "9825a04601d60621feed79c4e6b56d65db77cdca55cef43b46b0de1096d1c282" dependencies = [ "proc-macro2", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -1892,9 +1881,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "363a6f739a0c0addeaf6ed75150b95743aa18643a3c6f40409ed7b6db3a6911f" dependencies = [ "unicode-ident", ] @@ -1907,7 +1896,7 @@ checksum = "606c4ba35817e2922a308af55ad51bab3645b59eae5c570d4a6cf07e36bd493b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", "version_check", "yansi", ] @@ -1920,9 +1909,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -1986,7 +1975,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] @@ -2004,7 +1993,16 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", ] [[package]] @@ -2013,20 +2011,20 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.9", - "redox_syscall", + "getrandom 0.2.10", + "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.8.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.1", + "regex-syntax 0.7.2", ] [[package]] @@ -2046,9 +2044,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" @@ -2072,14 +2070,14 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.20.8", "rustls-native-certs", "rustls-pemfile 0.2.1", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls", + "tokio-rustls 0.23.4", "tokio-socks", "url", "wasm-bindgen", @@ -2126,7 +2124,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "assign", "js_int", @@ -2144,7 +2142,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.8.1" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "js_int", "ruma-common", @@ -2155,7 +2153,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "assign", "bytes", @@ -2172,13 +2170,13 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "bytes", "form_urlencoded", "http", - "indexmap", + "indexmap 1.9.3", "js_int", "js_option", "konst", @@ -2200,7 +2198,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "js_int", "ruma-common", @@ -2211,7 +2209,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "js_int", "thiserror", @@ -2220,7 +2218,7 @@ dependencies = [ [[package]] name = "ruma-identity-service-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "js_int", "ruma-common", @@ -2230,7 +2228,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "once_cell", "proc-macro-crate", @@ -2238,14 +2236,14 @@ dependencies = [ "quote", "ruma-identifiers-validation", "serde", - "syn 1.0.109", - "toml 0.7.4", + "syn 2.0.21", + "toml", ] [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "js_int", "ruma-common", @@ -2256,15 +2254,15 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.13.1" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "ed25519-dalek", "pkcs8", "rand 0.7.3", "ruma-common", "serde_json", - "sha2 0.10.6", + "sha2 0.10.7", "subslice", "thiserror", ] @@ -2272,7 +2270,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5#8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5" +source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" dependencies = [ "itertools", "js_int", @@ -2289,7 +2287,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -2327,11 +2325,23 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + [[package]] name = "rustls-native-certs" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", "rustls-pemfile 1.0.2", @@ -2354,7 +2364,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +dependencies = [ + "ring", + "untrusted", ] [[package]] @@ -2400,7 +2420,7 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -2419,22 +2439,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -2444,7 +2464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53192e38d5c88564b924dbe9b60865ecbb71b81d38c4e61c817cffd3e36ef696" dependencies = [ "form_urlencoded", - "indexmap", + "indexmap 1.9.3", "itoa", "ryu", "serde", @@ -2452,9 +2472,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", @@ -2463,9 +2483,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -2484,11 +2504,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.21" +version = "0.9.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "452e67b9c20c37fa79df53201dc03839651086ed9bbe92b3ca585ca9fdaa7d85" dependencies = [ - "indexmap", + "indexmap 2.0.0", "itoa", "ryu", "serde", @@ -2532,9 +2552,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -2614,6 +2634,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -2658,9 +2688,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.16" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +checksum = "1182caafaab7018eaea9b404afa8184c0baf42a04d5e10ae4f4843c2029c8aab" dependencies = [ "proc-macro2", "quote", @@ -2699,7 +2729,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -2767,9 +2797,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "itoa", "serde", @@ -2809,9 +2839,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -2820,7 +2850,7 @@ dependencies = [ "num_cpus", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "tokio-macros", "windows-sys 0.48.0", ] @@ -2833,7 +2863,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -2842,11 +2872,21 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls", + "rustls 0.20.8", "tokio", "webpki", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.2", + "tokio", +] + [[package]] name = "tokio-socks" version = "0.5.1" @@ -2886,18 +2926,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.11" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", @@ -2907,20 +2938,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.9" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -2948,9 +2979,28 @@ name = "tower-http" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8bd22a874a2d0b70452d5597b12c537331d49060824a95f49f108994f94aa4c" dependencies = [ "async-compression", - "bitflags", + "bitflags 2.3.2", "bytes", "futures-core", "futures-util", @@ -2993,13 +3043,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -3140,9 +3190,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -3173,22 +3223,22 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna 0.4.0", "percent-encoding", ] [[package]] name = "uuid" -version = "1.3.3" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" +checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] @@ -3211,11 +3261,10 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -3233,9 +3282,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3243,24 +3292,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -3270,9 +3319,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3280,28 +3329,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -3325,9 +3374,9 @@ checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" [[package]] name = "widestring" -version = "0.5.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" [[package]] name = "wildmatch" @@ -3372,37 +3421,13 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -3506,9 +3531,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] @@ -3524,11 +3549,12 @@ dependencies = [ [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -3554,7 +3580,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.21", ] [[package]] @@ -3566,6 +3592,25 @@ dependencies = [ "num-traits", ] +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index c925bf2..12e9109 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,14 +19,14 @@ rust-version = "1.64.0" [dependencies] # Web framework -axum = { version = "0.5.17", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path"], optional = true } -axum-server = { version = "0.4.7", features = ["tls-rustls"] } +axum = { version = "0.5.16", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path"], optional = true } +axum-server = { version = "0.5.1", features = ["tls-rustls"] } tower = { version = "0.4.13", features = ["util"] } -tower-http = { version = "0.3.5", features = ["add-extension", "cors", "compression-full", "sensitive-headers", "trace", "util"] } +tower-http = { version = "0.4.1", features = ["add-extension", "cors", "compression-zstd", "sensitive-headers", "trace", "util"] } # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -ruma = { git = "https://github.com/ruma/ruma", rev = "8eea3e05490fa9a318f9ed66c3a75272e6ef0ee5", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +ruma = { git = "https://github.com/ruma/ruma", rev = "761771a317460f30590da170115d007892381e85", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } #ruma = { git = "https://github.com/timokoesters/ruma", rev = "50c1db7e0a3a21fc794b0cce3b64285a4c750c71", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } #ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } diff --git a/Cross.toml b/Cross.toml deleted file mode 100644 index 5d99a35..0000000 --- a/Cross.toml +++ /dev/null @@ -1,23 +0,0 @@ -[build.env] -# CI uses an S3 endpoint to store sccache artifacts, so their config needs to -# be available in the cross container as well -passthrough = [ - "RUSTC_WRAPPER", - "AWS_ACCESS_KEY_ID", - "AWS_SECRET_ACCESS_KEY", - "SCCACHE_BUCKET", - "SCCACHE_ENDPOINT", - "SCCACHE_S3_USE_SSL", -] - -[target.aarch64-unknown-linux-musl] -image = "registry.gitlab.com/jfowl/conduit-containers/rust-cross-aarch64-unknown-linux-musl:latest" - -[target.arm-unknown-linux-musleabihf] -image = "registry.gitlab.com/jfowl/conduit-containers/rust-cross-arm-unknown-linux-musleabihf:latest" - -[target.armv7-unknown-linux-musleabihf] -image = "registry.gitlab.com/jfowl/conduit-containers/rust-cross-armv7-unknown-linux-musleabihf:latest" - -[target.x86_64-unknown-linux-musl] -image = "registry.gitlab.com/jfowl/conduit-containers/rust-cross-x86_64-unknown-linux-musl@sha256:b6d689e42f0236c8a38b961bca2a12086018b85ed20e0826310421daf182e2bb" diff --git a/src/api/client_server/context.rs b/src/api/client_server/context.rs index 5a3013b..a824ea0 100644 --- a/src/api/client_server/context.rs +++ b/src/api/client_server/context.rs @@ -69,18 +69,18 @@ pub async fn get_context_route( lazy_loaded.insert(base_event.sender.as_str().to_owned()); } + // Use limit with maximum 100 + let limit = usize::try_from(body.limit) + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid."))? + .min(100); + let base_event = base_event.to_room_event(); let events_before: Vec<_> = services() .rooms .timeline .pdus_until(sender_user, &room_id, base_token)? - .take( - u32::try_from(body.limit).map_err(|_| { - Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.") - })? as usize - / 2, - ) + .take(limit / 2) .filter_map(|r| r.ok()) // Remove buggy events .filter(|(_, pdu)| { services() @@ -114,12 +114,7 @@ pub async fn get_context_route( .rooms .timeline .pdus_after(sender_user, &room_id, base_token)? - .take( - u32::try_from(body.limit).map_err(|_| { - Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid.") - })? as usize - / 2, - ) + .take(limit / 2) .filter_map(|r| r.ok()) // Remove buggy events .filter(|(_, pdu)| { services() diff --git a/src/api/client_server/media.rs b/src/api/client_server/media.rs index 3410cc0..75f8e15 100644 --- a/src/api/client_server/media.rs +++ b/src/api/client_server/media.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + use crate::{service::media::FileMeta, services, utils, Error, Result, Ruma}; use ruma::api::client::{ error::ErrorKind, @@ -67,6 +69,8 @@ pub async fn get_remote_content( allow_remote: false, server_name: server_name.to_owned(), media_id, + timeout_ms: Duration::from_secs(20), + allow_redirect: false, }, ) .await?; @@ -194,6 +198,8 @@ pub async fn get_content_thumbnail_route( method: body.method.clone(), server_name: body.server_name.clone(), media_id: body.media_id.clone(), + timeout_ms: Duration::from_secs(20), + allow_redirect: false, }, ) .await?; diff --git a/src/api/client_server/message.rs b/src/api/client_server/message.rs index faf178d..dc2d994 100644 --- a/src/api/client_server/message.rs +++ b/src/api/client_server/message.rs @@ -133,8 +133,12 @@ pub async fn get_message_events_route( from, )?; - // Use limit or else 10 - let limit = body.limit.try_into().map_or(10_usize, |l: u32| l as usize); + // Use limit or else 10, with maximum 100 + let limit = body + .limit + .try_into() + .map_or(10_usize, |l: u32| l as usize) + .min(100); let next_token; diff --git a/src/api/client_server/mod.rs b/src/api/client_server/mod.rs index 6ed17e7..4a77f23 100644 --- a/src/api/client_server/mod.rs +++ b/src/api/client_server/mod.rs @@ -24,6 +24,7 @@ mod state; mod sync; mod tag; mod thirdparty; +mod threads; mod to_device; mod typing; mod unversioned; @@ -56,6 +57,7 @@ pub use state::*; pub use sync::*; pub use tag::*; pub use thirdparty::*; +pub use threads::*; pub use to_device::*; pub use typing::*; pub use unversioned::*; diff --git a/src/api/client_server/relations.rs b/src/api/client_server/relations.rs new file mode 100644 index 0000000..4d2af47 --- /dev/null +++ b/src/api/client_server/relations.rs @@ -0,0 +1,10 @@ +use crate::{services, Result, Ruma}; +use std::time::{Duration, SystemTime}; + +/// # `GET /_matrix/client/r0/todo` +pub async fn get_relating_events_route( + body: Ruma, +) -> Result { + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + todo!(); +} diff --git a/src/api/client_server/threads.rs b/src/api/client_server/threads.rs new file mode 100644 index 0000000..a095b42 --- /dev/null +++ b/src/api/client_server/threads.rs @@ -0,0 +1,49 @@ +use ruma::api::client::{error::ErrorKind, threads::get_threads}; + +use crate::{services, Error, Result, Ruma}; + +/// # `GET /_matrix/client/r0/rooms/{roomId}/threads` +pub async fn get_threads_route( + body: Ruma, +) -> Result { + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + + // Use limit or else 10, with maximum 100 + let limit = body + .limit + .and_then(|l| l.try_into().ok()) + .unwrap_or(10) + .min(100); + + let from = if let Some(from) = &body.from { + from.parse() + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, ""))? + } else { + u64::MAX + }; + + let threads = services() + .rooms + .threads + .threads_until(sender_user, &body.room_id, from, &body.include)? + .take(limit) + .filter_map(|r| r.ok()) + .filter(|(_, pdu)| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &body.room_id, &pdu.event_id) + .unwrap_or(false) + }) + .collect::>(); + + let next_batch = threads.last().map(|(count, _)| count.to_string()); + + Ok(get_threads::v1::Response { + chunk: threads + .into_iter() + .map(|(_, pdu)| pdu.to_room_event()) + .collect(), + next_batch, + }) +} diff --git a/src/api/client_server/unversioned.rs b/src/api/client_server/unversioned.rs index 526598b..b4f03f4 100644 --- a/src/api/client_server/unversioned.rs +++ b/src/api/client_server/unversioned.rs @@ -23,6 +23,8 @@ pub async fn get_supported_versions_route( "r0.6.0".to_owned(), "v1.1".to_owned(), "v1.2".to_owned(), + "v1.3".to_owned(), + "v1.4".to_owned(), ], unstable_features: BTreeMap::from_iter([("org.matrix.e2e_cross_signing".to_owned(), true)]), }; diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 961b658..c1c23a5 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -1,3 +1,4 @@ +#[allow(deprecated)] use crate::{ api::client_server::{self, claim_keys_helper, get_keys_helper}, service::pdu::{gen_event_id_canonical_json, PduBuilder}, @@ -497,6 +498,9 @@ async fn request_well_known(destination: &str) -> Option { .send() .await; debug!("Got well known response"); + if let Err(e) = &response { + error!("Well known error: {e:?}"); + } let text = response.ok()?.text().await; debug!("Got well known response text"); let body: serde_json::Value = serde_json::from_str(&text.ok()?).ok()?; diff --git a/src/database/key_value/rooms/mod.rs b/src/database/key_value/rooms/mod.rs index 406943e..e7b53d3 100644 --- a/src/database/key_value/rooms/mod.rs +++ b/src/database/key_value/rooms/mod.rs @@ -12,6 +12,7 @@ mod state; mod state_accessor; mod state_cache; mod state_compressor; +mod threads; mod timeline; mod user; diff --git a/src/database/key_value/rooms/pdu_metadata.rs b/src/database/key_value/rooms/pdu_metadata.rs index 76ec734..4b3f810 100644 --- a/src/database/key_value/rooms/pdu_metadata.rs +++ b/src/database/key_value/rooms/pdu_metadata.rs @@ -5,6 +5,13 @@ use ruma::{EventId, RoomId}; use crate::{database::KeyValueDatabase, service, Result}; impl service::rooms::pdu_metadata::Data for KeyValueDatabase { + fn add_relation(&self, from: u64, to: u64) -> Result<()> { + let mut key = from.to_be_bytes().to_vec(); + key.extend_from_slice(&to.to_be_bytes()); + self.fromto_relation.insert(&key, &[])?; + Ok(()) + } + fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc]) -> Result<()> { for prev in event_ids { let mut key = room_id.as_bytes().to_vec(); diff --git a/src/database/key_value/rooms/threads.rs b/src/database/key_value/rooms/threads.rs new file mode 100644 index 0000000..4be289b --- /dev/null +++ b/src/database/key_value/rooms/threads.rs @@ -0,0 +1,78 @@ +use std::mem; + +use ruma::{api::client::threads::get_threads::v1::IncludeThreads, OwnedUserId, RoomId, UserId}; + +use crate::{database::KeyValueDatabase, service, services, utils, Error, PduEvent, Result}; + +impl service::rooms::threads::Data for KeyValueDatabase { + fn threads_until<'a>( + &'a self, + user_id: &'a UserId, + room_id: &'a RoomId, + until: u64, + include: &'a IncludeThreads, + ) -> Result> + 'a>> { + let prefix = services() + .rooms + .short + .get_shortroomid(room_id)? + .expect("room exists") + .to_be_bytes() + .to_vec(); + + let mut current = prefix.clone(); + current.extend_from_slice(&(until - 1).to_be_bytes()); + + Ok(Box::new( + self.threadid_userids + .iter_from(¤t, true) + .take_while(move |(k, _)| k.starts_with(&prefix)) + .map(move |(pduid, users)| { + let count = utils::u64_from_bytes(&pduid[(mem::size_of::())..]) + .map_err(|_| Error::bad_database("Invalid pduid in threadid_userids."))?; + let mut pdu = services() + .rooms + .timeline + .get_pdu_from_id(&pduid)? + .ok_or_else(|| { + Error::bad_database("Invalid pduid reference in threadid_userids") + })?; + if pdu.sender != user_id { + pdu.remove_transaction_id()?; + } + Ok((count, pdu)) + }), + )) + } + + fn update_participants(&self, root_id: &[u8], participants: &[OwnedUserId]) -> Result<()> { + let users = participants + .iter() + .map(|user| user.as_bytes()) + .collect::>() + .join(&[0xff][..]); + + self.threadid_userids.insert(&root_id, &users)?; + + Ok(()) + } + + fn get_participants(&self, root_id: &[u8]) -> Result>> { + if let Some(users) = self.threadid_userids.get(&root_id)? { + Ok(Some( + users + .split(|b| *b == 0xff) + .map(|bytes| { + UserId::parse(utils::string_from_bytes(bytes).map_err(|_| { + Error::bad_database("Invalid UserId bytes in threadid_userids.") + })?) + .map_err(|_| Error::bad_database("Invalid UserId in threadid_userids.")) + }) + .filter_map(|r| r.ok()) + .collect(), + )) + } else { + Ok(None) + } + } +} diff --git a/src/database/key_value/rooms/timeline.rs b/src/database/key_value/rooms/timeline.rs index d9c4423..74e3e5c 100644 --- a/src/database/key_value/rooms/timeline.rs +++ b/src/database/key_value/rooms/timeline.rs @@ -198,19 +198,30 @@ impl service::rooms::timeline::Data for KeyValueDatabase { } /// Removes a pdu and creates a new one with the same id. - fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()> { + fn replace_pdu( + &self, + pdu_id: &[u8], + pdu_json: &CanonicalJsonObject, + pdu: &PduEvent, + ) -> Result<()> { if self.pduid_pdu.get(pdu_id)?.is_some() { self.pduid_pdu.insert( pdu_id, - &serde_json::to_vec(pdu).expect("CanonicalJsonObject is always a valid"), + &serde_json::to_vec(pdu_json).expect("CanonicalJsonObject is always a valid"), )?; - Ok(()) } else { - Err(Error::BadRequest( + return Err(Error::BadRequest( ErrorKind::NotFound, "PDU does not exist.", - )) + )); } + + self.pdu_cache + .lock() + .unwrap() + .remove(&(*pdu.event_id).to_owned()); + + Ok(()) } /// Returns an iterator over all events and their tokens in a room that happened before the diff --git a/src/database/mod.rs b/src/database/mod.rs index 1415f68..b864ceb 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -80,6 +80,8 @@ pub struct KeyValueDatabase { pub(super) aliasid_alias: Arc, // AliasId = RoomId + Count pub(super) publicroomids: Arc, + pub(super) threadid_userids: Arc, // ThreadId = RoomId + Count + pub(super) tokenids: Arc, // TokenId = ShortRoomId + Token + PduIdCount /// Participating servers in a room. @@ -128,6 +130,8 @@ pub struct KeyValueDatabase { pub(super) eventid_outlierpdu: Arc, pub(super) softfailedeventids: Arc, + /// ShortEventId + ShortEventId -> (). + pub(super) fromto_relation: Arc, /// RoomId + EventId -> Parent PDU EventId. pub(super) referencedevents: Arc, @@ -302,6 +306,8 @@ impl KeyValueDatabase { aliasid_alias: builder.open_tree("aliasid_alias")?, publicroomids: builder.open_tree("publicroomids")?, + threadid_userids: builder.open_tree("threadid_userids")?, + tokenids: builder.open_tree("tokenids")?, roomserverids: builder.open_tree("roomserverids")?, @@ -342,6 +348,7 @@ impl KeyValueDatabase { eventid_outlierpdu: builder.open_tree("eventid_outlierpdu")?, softfailedeventids: builder.open_tree("softfailedeventids")?, + fromto_relation: builder.open_tree("fromto_relation")?, referencedevents: builder.open_tree("referencedevents")?, roomuserdataid_accountdata: builder.open_tree("roomuserdataid_accountdata")?, roomusertype_roomuserdataid: builder.open_tree("roomusertype_roomuserdataid")?, diff --git a/src/main.rs b/src/main.rs index 59e82a7..edb7640 100644 --- a/src/main.rs +++ b/src/main.rs @@ -383,6 +383,7 @@ fn routes() -> Router { .ruma_route(client_server::set_pushers_route) // .ruma_route(client_server::third_party_route) .ruma_route(client_server::upgrade_room_route) + .ruma_route(client_server::get_threads_route) .ruma_route(server_server::get_server_version_route) .route( "/_matrix/key/v2/server", diff --git a/src/service/media/mod.rs b/src/service/media/mod.rs index 9393753..fc8fa56 100644 --- a/src/service/media/mod.rs +++ b/src/service/media/mod.rs @@ -8,7 +8,7 @@ use image::imageops::FilterType; use tokio::{ fs::File, - io::{AsyncReadExt, AsyncWriteExt}, + io::{AsyncReadExt, AsyncWriteExt, BufReader}, }; pub struct FileMeta { @@ -70,7 +70,9 @@ impl Service { { let path = services().globals.get_media_file(&key); let mut file = Vec::new(); - File::open(path).await?.read_to_end(&mut file).await?; + BufReader::new(File::open(path).await?) + .read_to_end(&mut file) + .await?; Ok(Some(FileMeta { content_disposition, diff --git a/src/service/mod.rs b/src/service/mod.rs index eea397f..3b48810 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -97,6 +97,7 @@ impl Services { db, lasttimelinecount_cache: Mutex::new(HashMap::new()), }, + threads: rooms::threads::Service { db }, user: rooms::user::Service { db }, }, transaction_ids: transaction_ids::Service { db }, diff --git a/src/service/pdu.rs b/src/service/pdu.rs index a497b11..9d284c0 100644 --- a/src/service/pdu.rs +++ b/src/service/pdu.rs @@ -1,9 +1,9 @@ use crate::Error; use ruma::{ events::{ - room::member::RoomMemberEventContent, AnyEphemeralRoomEvent, AnyStateEvent, - AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, - StateEvent, TimelineEventType, + room::member::RoomMemberEventContent, AnyEphemeralRoomEvent, AnyMessageLikeEvent, + AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, + AnyTimelineEvent, StateEvent, TimelineEventType, }, serde::Raw, state_res, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, @@ -175,6 +175,30 @@ impl PduEvent { serde_json::from_value(json).expect("Raw::from_value always works") } + #[tracing::instrument(skip(self))] + pub fn to_message_like_event(&self) -> Raw { + let mut json = json!({ + "content": self.content, + "type": self.kind, + "event_id": self.event_id, + "sender": self.sender, + "origin_server_ts": self.origin_server_ts, + "room_id": self.room_id, + }); + + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + if let Some(state_key) = &self.state_key { + json["state_key"] = json!(state_key); + } + if let Some(redacts) = &self.redacts { + json["redacts"] = json!(redacts); + } + + serde_json::from_value(json).expect("Raw::from_value always works") + } + #[tracing::instrument(skip(self))] pub fn to_state_event(&self) -> Raw { let mut json = json!({ diff --git a/src/service/pusher/mod.rs b/src/service/pusher/mod.rs index 5933c03..d4acaa5 100644 --- a/src/service/pusher/mod.rs +++ b/src/service/pusher/mod.rs @@ -162,9 +162,7 @@ impl Service { &pdu.room_id, )? { let n = match action { - Action::DontNotify => false, - // TODO: Implement proper support for coalesce - Action::Notify | Action::Coalesce => true, + Action::Notify => true, Action::SetTweak(tweak) => { tweaks.push(tweak.clone()); continue; diff --git a/src/service/rooms/mod.rs b/src/service/rooms/mod.rs index 8956e4d..61304d1 100644 --- a/src/service/rooms/mod.rs +++ b/src/service/rooms/mod.rs @@ -13,6 +13,7 @@ pub mod state; pub mod state_accessor; pub mod state_cache; pub mod state_compressor; +pub mod threads; pub mod timeline; pub mod user; @@ -32,6 +33,7 @@ pub trait Data: + state_cache::Data + state_compressor::Data + timeline::Data + + threads::Data + user::Data { } @@ -53,5 +55,6 @@ pub struct Service { pub state_cache: state_cache::Service, pub state_compressor: state_compressor::Service, pub timeline: timeline::Service, + pub threads: threads::Service, pub user: user::Service, } diff --git a/src/service/rooms/pdu_metadata/data.rs b/src/service/rooms/pdu_metadata/data.rs index b157938..5577b3e 100644 --- a/src/service/rooms/pdu_metadata/data.rs +++ b/src/service/rooms/pdu_metadata/data.rs @@ -4,6 +4,7 @@ use crate::Result; use ruma::{EventId, RoomId}; pub trait Data: Send + Sync { + fn add_relation(&self, from: u64, to: u64) -> Result<()>; fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc]) -> Result<()>; fn is_event_referenced(&self, room_id: &RoomId, event_id: &EventId) -> Result; fn mark_event_soft_failed(&self, event_id: &EventId) -> Result<()>; diff --git a/src/service/rooms/pdu_metadata/mod.rs b/src/service/rooms/pdu_metadata/mod.rs index b816678..a82b9a6 100644 --- a/src/service/rooms/pdu_metadata/mod.rs +++ b/src/service/rooms/pdu_metadata/mod.rs @@ -4,13 +4,20 @@ use std::sync::Arc; pub use data::Data; use ruma::{EventId, RoomId}; -use crate::Result; +use crate::{services, Result}; pub struct Service { pub db: &'static dyn Data, } impl Service { + #[tracing::instrument(skip(self, from, to))] + pub fn add_relation(&self, from: &EventId, to: &EventId) -> Result<()> { + let from = services().rooms.short.get_or_create_shorteventid(from)?; + let to = services().rooms.short.get_or_create_shorteventid(to)?; + self.db.add_relation(from, to) + } + #[tracing::instrument(skip(self, room_id, event_ids))] pub fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc]) -> Result<()> { self.db.mark_as_referenced(room_id, event_ids) diff --git a/src/service/rooms/threads/data.rs b/src/service/rooms/threads/data.rs new file mode 100644 index 0000000..9221e8e --- /dev/null +++ b/src/service/rooms/threads/data.rs @@ -0,0 +1,15 @@ +use crate::{PduEvent, Result}; +use ruma::{api::client::threads::get_threads::v1::IncludeThreads, OwnedUserId, RoomId, UserId}; + +pub trait Data: Send + Sync { + fn threads_until<'a>( + &'a self, + user_id: &'a UserId, + room_id: &'a RoomId, + until: u64, + include: &'a IncludeThreads, + ) -> Result> + 'a>>; + + fn update_participants(&self, root_id: &[u8], participants: &[OwnedUserId]) -> Result<()>; + fn get_participants(&self, root_id: &[u8]) -> Result>>; +} diff --git a/src/service/rooms/threads/mod.rs b/src/service/rooms/threads/mod.rs new file mode 100644 index 0000000..241927a --- /dev/null +++ b/src/service/rooms/threads/mod.rs @@ -0,0 +1,119 @@ +mod data; +use std::sync::Arc; + +pub use data::Data; +use ruma::{ + api::client::{error::ErrorKind, threads::get_threads::v1::IncludeThreads}, + events::{relation::BundledThread, StateEventType}, + uint, CanonicalJsonValue, EventId, OwnedUserId, RoomId, UserId, +}; +use serde::Deserialize; +use serde_json::json; + +use crate::{services, utils, Error, PduEvent, Result}; + +use super::timeline::PduCount; + +pub struct Service { + pub db: &'static dyn Data, +} + +impl Service { + pub fn threads_until<'a>( + &'a self, + user_id: &'a UserId, + room_id: &'a RoomId, + until: u64, + include: &'a IncludeThreads, + ) -> Result> + 'a> { + self.db.threads_until(user_id, room_id, until, include) + } + + pub fn add_to_thread<'a>(&'a self, root_event_id: &EventId, pdu: &PduEvent) -> Result<()> { + let root_id = &services() + .rooms + .timeline + .get_pdu_id(root_event_id)? + .ok_or_else(|| { + Error::BadRequest( + ErrorKind::InvalidParam, + "Invalid event id in thread message", + ) + })?; + + let root_pdu = services() + .rooms + .timeline + .get_pdu_from_id(root_id)? + .ok_or_else(|| { + Error::BadRequest(ErrorKind::InvalidParam, "Thread root pdu not found") + })?; + + let mut root_pdu_json = services() + .rooms + .timeline + .get_pdu_json_from_id(root_id)? + .ok_or_else(|| { + Error::BadRequest(ErrorKind::InvalidParam, "Thread root pdu not found") + })?; + + if let CanonicalJsonValue::Object(unsigned) = root_pdu_json + .entry("unsigned".to_owned()) + .or_insert_with(|| CanonicalJsonValue::Object(Default::default())) + { + if let Some(mut relations) = unsigned + .get("m.relations") + .and_then(|r| r.as_object()) + .and_then(|r| r.get("m.thread")) + .and_then(|relations| { + serde_json::from_value::(relations.clone().into()).ok() + }) + { + // Thread already existed + relations.count += uint!(1); + relations.latest_event = pdu.to_message_like_event(); + + let content = serde_json::to_value(relations).expect("to_value always works"); + + unsigned.insert( + "m.relations".to_owned(), + json!({ "m.thread": content }) + .try_into() + .expect("thread is valid json"), + ); + } else { + // New thread + let relations = BundledThread { + latest_event: pdu.to_message_like_event(), + count: uint!(1), + current_user_participated: true, + }; + + let content = serde_json::to_value(relations).expect("to_value always works"); + + unsigned.insert( + "m.relations".to_owned(), + json!({ "m.thread": content }) + .try_into() + .expect("thread is valid json"), + ); + } + + services() + .rooms + .timeline + .replace_pdu(root_id, &root_pdu_json, &root_pdu)?; + } + + let mut users = Vec::new(); + if let Some(userids) = self.db.get_participants(&root_id)? { + users.extend_from_slice(&userids); + users.push(pdu.sender.clone()); + } else { + users.push(root_pdu.sender); + users.push(pdu.sender.clone()); + } + + self.db.update_participants(root_id, &users) + } +} diff --git a/src/service/rooms/timeline/data.rs b/src/service/rooms/timeline/data.rs index 193f384..afa2cfb 100644 --- a/src/service/rooms/timeline/data.rs +++ b/src/service/rooms/timeline/data.rs @@ -57,7 +57,12 @@ pub trait Data: Send + Sync { ) -> Result<()>; /// Removes a pdu and creates a new one with the same id. - fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()>; + fn replace_pdu( + &self, + pdu_id: &[u8], + pdu_json: &CanonicalJsonObject, + pdu: &PduEvent, + ) -> Result<()>; /// Returns an iterator over all events and their tokens in a room that happened before the /// event with id `until` in reverse-chronological order. diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 2ffd3a6..0547fcf 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -18,13 +18,13 @@ use ruma::{ events::{ push_rules::PushRulesEvent, room::{ - create::RoomCreateEventContent, member::MembershipState, + create::RoomCreateEventContent, encrypted::Relation, member::MembershipState, power_levels::RoomPowerLevelsEventContent, }, GlobalAccountDataEventType, StateEventType, TimelineEventType, }, push::{Action, Ruleset, Tweak}, - serde::Base64, + serde::{Base64, JsonObject}, state_res, state_res::{Event, RoomVersion}, uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, @@ -197,8 +197,13 @@ impl Service { /// Removes a pdu and creates a new one with the same id. #[tracing::instrument(skip(self))] - fn replace_pdu(&self, pdu_id: &[u8], pdu: &PduEvent) -> Result<()> { - self.db.replace_pdu(pdu_id, pdu) + pub fn replace_pdu( + &self, + pdu_id: &[u8], + pdu_json: &CanonicalJsonObject, + pdu: &PduEvent, + ) -> Result<()> { + self.db.replace_pdu(pdu_id, pdu_json, pdu) } /// Creates a new persisted data unit and adds it to a room. @@ -352,9 +357,7 @@ impl Service { &pdu.room_id, )? { match action { - Action::DontNotify => notify = false, - // TODO: Implement proper support for coalesce - Action::Notify | Action::Coalesce => notify = true, + Action::Notify => notify = true, Action::SetTweak(Tweak::Highlight(true)) => { highlight = true; } @@ -457,6 +460,50 @@ impl Service { _ => {} } + // Update Relationships + #[derive(Deserialize)] + struct ExtractRelatesTo { + #[serde(rename = "m.relates_to")] + relates_to: Relation, + } + + #[derive(Clone, Debug, Deserialize)] + struct ExtractEventId { + event_id: OwnedEventId, + } + #[derive(Clone, Debug, Deserialize)] + struct ExtractRelatesToEventId { + #[serde(rename = "m.relates_to")] + relates_to: ExtractEventId, + } + + if let Ok(content) = serde_json::from_str::(pdu.content.get()) { + services() + .rooms + .pdu_metadata + .add_relation(&pdu.event_id, &content.relates_to.event_id)?; + } + + if let Ok(content) = serde_json::from_str::(pdu.content.get()) { + match content.relates_to { + Relation::Reply { in_reply_to } => { + // We need to do it again here, because replies don't have + // event_id as a top level field + services() + .rooms + .pdu_metadata + .add_relation(&pdu.event_id, &in_reply_to.event_id)?; + } + Relation::Thread(thread) => { + services() + .rooms + .threads + .add_to_thread(&thread.event_id, pdu)?; + } + _ => {} // TODO: Aggregate other types + } + } + for appservice in services().appservice.all()? { if services() .rooms @@ -957,12 +1004,17 @@ impl Service { /// Replace a PDU with the redacted form. #[tracing::instrument(skip(self, reason))] pub fn redact_pdu(&self, event_id: &EventId, reason: &PduEvent) -> Result<()> { + // TODO: Don't reserialize, keep original json if let Some(pdu_id) = self.get_pdu_id(event_id)? { let mut pdu = self .get_pdu_from_id(&pdu_id)? .ok_or_else(|| Error::bad_database("PDU ID points to invalid PDU."))?; pdu.redact(reason)?; - self.replace_pdu(&pdu_id, &pdu)?; + self.replace_pdu( + &pdu_id, + &utils::to_canonical_object(&pdu).expect("PDU is an object"), + &pdu, + )?; } // If event does not exist, just noop Ok(()) -- cgit v1.2.3 From 15cc801840465ec5bfd309deecd09b484dd27734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 25 Jun 2023 23:43:19 +0200 Subject: Disable compression, see https://en.wikipedia.org/wiki/BREACH --- Cargo.lock | 36 ------------------------------------ Cargo.toml | 2 +- src/main.rs | 1 - 3 files changed, 1 insertion(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebb47d9..b33a7d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,20 +64,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f093eed78becd229346bf859eec0aa4dd7ddde0757287b2b4107a1f09c80002" -[[package]] -name = "async-compression" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" -dependencies = [ - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "zstd", - "zstd-safe", -] - [[package]] name = "async-trait" version = "0.1.68" @@ -2999,7 +2985,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8bd22a874a2d0b70452d5597b12c537331d49060824a95f49f108994f94aa4c" dependencies = [ - "async-compression", "bitflags 2.3.2", "bytes", "futures-core", @@ -3008,8 +2993,6 @@ dependencies = [ "http-body", "http-range-header", "pin-project-lite", - "tokio", - "tokio-util", "tower", "tower-layer", "tower-service", @@ -3592,25 +3575,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", -] - [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index 12e9109..6055563 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ rust-version = "1.64.0" axum = { version = "0.5.16", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path"], optional = true } axum-server = { version = "0.5.1", features = ["tls-rustls"] } tower = { version = "0.4.13", features = ["util"] } -tower-http = { version = "0.4.1", features = ["add-extension", "cors", "compression-zstd", "sensitive-headers", "trace", "util"] } +tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitive-headers", "trace", "util"] } # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } diff --git a/src/main.rs b/src/main.rs index edb7640..20fab91 100644 --- a/src/main.rs +++ b/src/main.rs @@ -159,7 +159,6 @@ async fn run_server() -> io::Result<()> { tracing::info_span!("http_request", %path) }), ) - .compression() .layer(axum::middleware::from_fn(unrecognized_method)) .layer( CorsLayer::new() -- cgit v1.2.3 From 49a0f3a60ddb1b707c97218e5ccc7d747b4f34a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 26 Jun 2023 08:33:31 +0200 Subject: fix: /context for element android. start and end must be set even with limit=0 --- src/api/client_server/context.rs | 14 ++++++++++---- src/api/server_server.rs | 3 ++- src/service/rooms/threads/mod.rs | 11 ++++------- src/service/rooms/timeline/mod.rs | 2 +- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/api/client_server/context.rs b/src/api/client_server/context.rs index a824ea0..e70f9f1 100644 --- a/src/api/client_server/context.rs +++ b/src/api/client_server/context.rs @@ -103,7 +103,10 @@ pub async fn get_context_route( } } - let start_token = events_before.last().map(|(count, _)| count.stringify()); + let start_token = events_before + .last() + .map(|(count, _)| count.stringify()) + .unwrap_or_else(|| base_token.stringify()); let events_before: Vec<_> = events_before .into_iter() @@ -156,7 +159,10 @@ pub async fn get_context_route( .state_full_ids(shortstatehash) .await?; - let end_token = events_after.last().map(|(count, _)| count.stringify()); + let end_token = events_after + .last() + .map(|(count, _)| count.stringify()) + .unwrap_or_else(|| base_token.stringify()); let events_after: Vec<_> = events_after .into_iter() @@ -193,8 +199,8 @@ pub async fn get_context_route( } let resp = get_context::v3::Response { - start: start_token, - end: end_token, + start: Some(start_token), + end: Some(end_token), events_before, event: Some(base_event), events_after, diff --git a/src/api/server_server.rs b/src/api/server_server.rs index c1c23a5..5e218be 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -1,4 +1,5 @@ -#[allow(deprecated)] +#![allow(deprecated)] + use crate::{ api::client_server::{self, claim_keys_helper, get_keys_helper}, service::pdu::{gen_event_id_canonical_json, PduBuilder}, diff --git a/src/service/rooms/threads/mod.rs b/src/service/rooms/threads/mod.rs index 241927a..fb70383 100644 --- a/src/service/rooms/threads/mod.rs +++ b/src/service/rooms/threads/mod.rs @@ -1,18 +1,15 @@ mod data; -use std::sync::Arc; pub use data::Data; use ruma::{ api::client::{error::ErrorKind, threads::get_threads::v1::IncludeThreads}, - events::{relation::BundledThread, StateEventType}, - uint, CanonicalJsonValue, EventId, OwnedUserId, RoomId, UserId, + events::relation::BundledThread, + uint, CanonicalJsonValue, EventId, RoomId, UserId, }; -use serde::Deserialize; -use serde_json::json; -use crate::{services, utils, Error, PduEvent, Result}; +use serde_json::json; -use super::timeline::PduCount; +use crate::{services, Error, PduEvent, Result}; pub struct Service { pub db: &'static dyn Data, diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 0547fcf..625d346 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -24,7 +24,7 @@ use ruma::{ GlobalAccountDataEventType, StateEventType, TimelineEventType, }, push::{Action, Ruleset, Tweak}, - serde::{Base64, JsonObject}, + serde::Base64, state_res, state_res::{Event, RoomVersion}, uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, -- cgit v1.2.3 From db6def8800e12a778dd0c1117c7a0623deb76984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 26 Jun 2023 09:15:14 +0200 Subject: fix: send correct bearer token to appservices --- src/api/appservice_server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/appservice_server.rs b/src/api/appservice_server.rs index dc319e2..082a1bc 100644 --- a/src/api/appservice_server.rs +++ b/src/api/appservice_server.rs @@ -18,7 +18,7 @@ where let mut http_request = request .try_into_http_request::( destination, - SendAccessToken::IfRequired(""), + SendAccessToken::IfRequired(hs_token), &[MatrixVersion::V1_0], ) .unwrap() -- cgit v1.2.3 From 72eb1972c18307d77c9dbfaddc2cb92bd9f38efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 26 Jun 2023 12:38:51 +0200 Subject: Add relations endpoints, edits and threads work now --- src/api/client_server/mod.rs | 2 + src/api/client_server/relations.rs | 148 +++++++++++++++++++++++- src/database/key_value/rooms/pdu_metadata.rs | 59 +++++++++- src/database/mod.rs | 4 +- src/main.rs | 3 + src/service/rooms/pdu_metadata/data.rs | 11 +- src/service/rooms/pdu_metadata/mod.rs | 161 ++++++++++++++++++++++++++- src/service/rooms/timeline/mod.rs | 24 +++- 8 files changed, 384 insertions(+), 28 deletions(-) diff --git a/src/api/client_server/mod.rs b/src/api/client_server/mod.rs index 4a77f23..2ab3a98 100644 --- a/src/api/client_server/mod.rs +++ b/src/api/client_server/mod.rs @@ -16,6 +16,7 @@ mod profile; mod push; mod read_marker; mod redact; +mod relations; mod report; mod room; mod search; @@ -49,6 +50,7 @@ pub use profile::*; pub use push::*; pub use read_marker::*; pub use redact::*; +pub use relations::*; pub use report::*; pub use room::*; pub use search::*; diff --git a/src/api/client_server/relations.rs b/src/api/client_server/relations.rs index 4d2af47..a7cea78 100644 --- a/src/api/client_server/relations.rs +++ b/src/api/client_server/relations.rs @@ -1,10 +1,146 @@ -use crate::{services, Result, Ruma}; -use std::time::{Duration, SystemTime}; +use ruma::api::client::relations::{ + get_relating_events, get_relating_events_with_rel_type, + get_relating_events_with_rel_type_and_event_type, +}; -/// # `GET /_matrix/client/r0/todo` +use crate::{service::rooms::timeline::PduCount, services, Result, Ruma}; + +/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}` +pub async fn get_relating_events_with_rel_type_and_event_type_route( + body: Ruma, +) -> Result { + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + + let from = match body.from.clone() { + Some(from) => PduCount::try_from_string(&from)?, + None => match ruma::api::Direction::Backward { + // TODO: fix ruma so `body.dir` exists + ruma::api::Direction::Forward => PduCount::min(), + ruma::api::Direction::Backward => PduCount::max(), + }, + }; + + let to = body + .to + .as_ref() + .and_then(|t| PduCount::try_from_string(&t).ok()); + + // Use limit or else 10, with maximum 100 + let limit = body + .limit + .and_then(|u| u32::try_from(u).ok()) + .map_or(10_usize, |u| u as usize) + .min(100); + + let res = services() + .rooms + .pdu_metadata + .paginate_relations_with_filter( + sender_user, + &body.room_id, + &body.event_id, + Some(body.event_type.clone()), + Some(body.rel_type.clone()), + from, + to, + limit, + )?; + + Ok( + get_relating_events_with_rel_type_and_event_type::v1::Response { + chunk: res.chunk, + next_batch: res.next_batch, + prev_batch: res.prev_batch, + }, + ) +} + +/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}/{relType}` +pub async fn get_relating_events_with_rel_type_route( + body: Ruma, +) -> Result { + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + + let from = match body.from.clone() { + Some(from) => PduCount::try_from_string(&from)?, + None => match ruma::api::Direction::Backward { + // TODO: fix ruma so `body.dir` exists + ruma::api::Direction::Forward => PduCount::min(), + ruma::api::Direction::Backward => PduCount::max(), + }, + }; + + let to = body + .to + .as_ref() + .and_then(|t| PduCount::try_from_string(&t).ok()); + + // Use limit or else 10, with maximum 100 + let limit = body + .limit + .and_then(|u| u32::try_from(u).ok()) + .map_or(10_usize, |u| u as usize) + .min(100); + + let res = services() + .rooms + .pdu_metadata + .paginate_relations_with_filter( + sender_user, + &body.room_id, + &body.event_id, + None, + Some(body.rel_type.clone()), + from, + to, + limit, + )?; + + Ok(get_relating_events_with_rel_type::v1::Response { + chunk: res.chunk, + next_batch: res.next_batch, + prev_batch: res.prev_batch, + }) +} + +/// # `GET /_matrix/client/r0/rooms/{roomId}/relations/{eventId}` pub async fn get_relating_events_route( - body: Ruma, -) -> Result { + body: Ruma, +) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - todo!(); + + let from = match body.from.clone() { + Some(from) => PduCount::try_from_string(&from)?, + None => match ruma::api::Direction::Backward { + // TODO: fix ruma so `body.dir` exists + ruma::api::Direction::Forward => PduCount::min(), + ruma::api::Direction::Backward => PduCount::max(), + }, + }; + + let to = body + .to + .as_ref() + .and_then(|t| PduCount::try_from_string(&t).ok()); + + // Use limit or else 10, with maximum 100 + let limit = body + .limit + .and_then(|u| u32::try_from(u).ok()) + .map_or(10_usize, |u| u as usize) + .min(100); + + services() + .rooms + .pdu_metadata + .paginate_relations_with_filter( + sender_user, + &body.room_id, + &body.event_id, + None, + None, + from, + to, + limit, + ) } diff --git a/src/database/key_value/rooms/pdu_metadata.rs b/src/database/key_value/rooms/pdu_metadata.rs index 4b3f810..0641f9d 100644 --- a/src/database/key_value/rooms/pdu_metadata.rs +++ b/src/database/key_value/rooms/pdu_metadata.rs @@ -1,17 +1,64 @@ -use std::sync::Arc; +use std::{mem, sync::Arc}; -use ruma::{EventId, RoomId}; +use ruma::{EventId, RoomId, UserId}; -use crate::{database::KeyValueDatabase, service, Result}; +use crate::{ + database::KeyValueDatabase, + service::{self, rooms::timeline::PduCount}, + services, utils, Error, PduEvent, Result, +}; impl service::rooms::pdu_metadata::Data for KeyValueDatabase { fn add_relation(&self, from: u64, to: u64) -> Result<()> { - let mut key = from.to_be_bytes().to_vec(); - key.extend_from_slice(&to.to_be_bytes()); - self.fromto_relation.insert(&key, &[])?; + let mut key = to.to_be_bytes().to_vec(); + key.extend_from_slice(&from.to_be_bytes()); + self.tofrom_relation.insert(&key, &[])?; Ok(()) } + fn relations_until<'a>( + &'a self, + user_id: &'a UserId, + shortroomid: u64, + target: u64, + until: PduCount, + ) -> Result> + 'a>> { + let prefix = target.to_be_bytes().to_vec(); + let mut current = prefix.clone(); + + let count_raw = match until { + PduCount::Normal(x) => x - 1, + PduCount::Backfilled(x) => { + current.extend_from_slice(&0_u64.to_be_bytes()); + u64::MAX - x - 1 + } + }; + current.extend_from_slice(&count_raw.to_be_bytes()); + + Ok(Box::new( + self.tofrom_relation + .iter_from(¤t, true) + .take_while(move |(k, _)| k.starts_with(&prefix)) + .map(move |(tofrom, _data)| { + let from = utils::u64_from_bytes(&tofrom[(mem::size_of::())..]) + .map_err(|_| Error::bad_database("Invalid count in tofrom_relation."))?; + + let mut pduid = shortroomid.to_be_bytes().to_vec(); + pduid.extend_from_slice(&from.to_be_bytes()); + + let mut pdu = services() + .rooms + .timeline + .get_pdu_from_id(&pduid)? + .ok_or_else(|| Error::bad_database("Pdu in tofrom_relation is invalid."))?; + if pdu.sender != user_id { + pdu.remove_transaction_id()?; + } + Ok((PduCount::Normal(from), pdu)) + }), + )) + } + fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc]) -> Result<()> { for prev in event_ids { let mut key = room_id.as_bytes().to_vec(); diff --git a/src/database/mod.rs b/src/database/mod.rs index b864ceb..5d89d4a 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -131,7 +131,7 @@ pub struct KeyValueDatabase { pub(super) softfailedeventids: Arc, /// ShortEventId + ShortEventId -> (). - pub(super) fromto_relation: Arc, + pub(super) tofrom_relation: Arc, /// RoomId + EventId -> Parent PDU EventId. pub(super) referencedevents: Arc, @@ -348,7 +348,7 @@ impl KeyValueDatabase { eventid_outlierpdu: builder.open_tree("eventid_outlierpdu")?, softfailedeventids: builder.open_tree("softfailedeventids")?, - fromto_relation: builder.open_tree("fromto_relation")?, + tofrom_relation: builder.open_tree("tofrom_relation")?, referencedevents: builder.open_tree("referencedevents")?, roomuserdataid_accountdata: builder.open_tree("roomuserdataid_accountdata")?, roomusertype_roomuserdataid: builder.open_tree("roomusertype_roomuserdataid")?, diff --git a/src/main.rs b/src/main.rs index 20fab91..f9f88f4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -383,6 +383,9 @@ fn routes() -> Router { // .ruma_route(client_server::third_party_route) .ruma_route(client_server::upgrade_room_route) .ruma_route(client_server::get_threads_route) + .ruma_route(client_server::get_relating_events_with_rel_type_and_event_type_route) + .ruma_route(client_server::get_relating_events_with_rel_type_route) + .ruma_route(client_server::get_relating_events_route) .ruma_route(server_server::get_server_version_route) .route( "/_matrix/key/v2/server", diff --git a/src/service/rooms/pdu_metadata/data.rs b/src/service/rooms/pdu_metadata/data.rs index 5577b3e..6c4cb3c 100644 --- a/src/service/rooms/pdu_metadata/data.rs +++ b/src/service/rooms/pdu_metadata/data.rs @@ -1,10 +1,17 @@ use std::sync::Arc; -use crate::Result; -use ruma::{EventId, RoomId}; +use crate::{service::rooms::timeline::PduCount, PduEvent, Result}; +use ruma::{EventId, RoomId, UserId}; pub trait Data: Send + Sync { fn add_relation(&self, from: u64, to: u64) -> Result<()>; + fn relations_until<'a>( + &'a self, + user_id: &'a UserId, + room_id: u64, + target: u64, + until: PduCount, + ) -> Result> + 'a>>; fn mark_as_referenced(&self, room_id: &RoomId, event_ids: &[Arc]) -> Result<()>; fn is_event_referenced(&self, room_id: &RoomId, event_id: &EventId) -> Result; fn mark_event_soft_failed(&self, event_id: &EventId) -> Result<()>; diff --git a/src/service/rooms/pdu_metadata/mod.rs b/src/service/rooms/pdu_metadata/mod.rs index a82b9a6..9ce74f4 100644 --- a/src/service/rooms/pdu_metadata/mod.rs +++ b/src/service/rooms/pdu_metadata/mod.rs @@ -2,20 +2,169 @@ mod data; use std::sync::Arc; pub use data::Data; -use ruma::{EventId, RoomId}; +use ruma::{ + api::client::relations::get_relating_events, + events::{relation::RelationType, TimelineEventType}, + EventId, RoomId, UserId, +}; +use serde::Deserialize; -use crate::{services, Result}; +use crate::{services, PduEvent, Result}; + +use super::timeline::PduCount; pub struct Service { pub db: &'static dyn Data, } +#[derive(Clone, Debug, Deserialize)] +struct ExtractRelType { + rel_type: RelationType, +} +#[derive(Clone, Debug, Deserialize)] +struct ExtractRelatesToEventId { + #[serde(rename = "m.relates_to")] + relates_to: ExtractRelType, +} + impl Service { #[tracing::instrument(skip(self, from, to))] - pub fn add_relation(&self, from: &EventId, to: &EventId) -> Result<()> { - let from = services().rooms.short.get_or_create_shorteventid(from)?; - let to = services().rooms.short.get_or_create_shorteventid(to)?; - self.db.add_relation(from, to) + pub fn add_relation(&self, from: PduCount, to: PduCount) -> Result<()> { + match (from, to) { + (PduCount::Normal(f), PduCount::Normal(t)) => self.db.add_relation(f, t), + _ => { + // TODO: Relations with backfilled pdus + + Ok(()) + } + } + } + + pub fn paginate_relations_with_filter( + &self, + sender_user: &UserId, + room_id: &RoomId, + target: &EventId, + filter_event_type: Option, + filter_rel_type: Option, + from: PduCount, + to: Option, + limit: usize, + ) -> Result { + let next_token; + + //TODO: Fix ruma: match body.dir { + match ruma::api::Direction::Backward { + ruma::api::Direction::Forward => { + let events_after: Vec<_> = services() + .rooms + .pdu_metadata + .relations_until(sender_user, room_id, target, from)? // TODO: should be relations_after + .filter(|r| { + r.as_ref().map_or(true, |(_, pdu)| { + filter_event_type.as_ref().map_or(true, |t| &pdu.kind == t) + && if let Ok(content) = + serde_json::from_str::( + pdu.content.get(), + ) + { + filter_rel_type + .as_ref() + .map_or(true, |r| &content.relates_to.rel_type == r) + } else { + false + } + }) + }) + .take(limit) + .filter_map(|r| r.ok()) // Filter out buggy events + .filter(|(_, pdu)| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &room_id, &pdu.event_id) + .unwrap_or(false) + }) + .take_while(|&(k, _)| Some(k) != to) // Stop at `to` + .collect(); + + next_token = events_after.last().map(|(count, _)| count).copied(); + + let events_after: Vec<_> = events_after + .into_iter() + .rev() // relations are always most recent first + .map(|(_, pdu)| pdu.to_message_like_event()) + .collect(); + + Ok(get_relating_events::v1::Response { + chunk: events_after, + next_batch: next_token.map(|t| t.stringify()), + prev_batch: Some(from.stringify()), + }) + } + ruma::api::Direction::Backward => { + let events_before: Vec<_> = services() + .rooms + .pdu_metadata + .relations_until(sender_user, &room_id, target, from)? + .filter(|r| { + r.as_ref().map_or(true, |(_, pdu)| { + filter_event_type.as_ref().map_or(true, |t| &pdu.kind == t) + && if let Ok(content) = + serde_json::from_str::( + pdu.content.get(), + ) + { + filter_rel_type + .as_ref() + .map_or(true, |r| &content.relates_to.rel_type == r) + } else { + false + } + }) + }) + .take(limit) + .filter_map(|r| r.ok()) // Filter out buggy events + .filter(|(_, pdu)| { + services() + .rooms + .state_accessor + .user_can_see_event(sender_user, &room_id, &pdu.event_id) + .unwrap_or(false) + }) + .take_while(|&(k, _)| Some(k) != to) // Stop at `to` + .collect(); + + next_token = events_before.last().map(|(count, _)| count).copied(); + + let events_before: Vec<_> = events_before + .into_iter() + .map(|(_, pdu)| pdu.to_message_like_event()) + .collect(); + + Ok(get_relating_events::v1::Response { + chunk: events_before, + next_batch: next_token.map(|t| t.stringify()), + prev_batch: Some(from.stringify()), + }) + } + } + } + + pub fn relations_until<'a>( + &'a self, + user_id: &'a UserId, + room_id: &'a RoomId, + target: &'a EventId, + until: PduCount, + ) -> Result> + 'a> { + let room_id = services().rooms.short.get_or_create_shortroomid(room_id)?; + let target = match services().rooms.timeline.get_pdu_count(target)? { + Some(PduCount::Normal(c)) => c, + // TODO: Support backfilled relations + _ => 0, // This will result in an empty iterator + }; + self.db.relations_until(user_id, room_id, target, until) } #[tracing::instrument(skip(self, room_id, event_ids))] diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 625d346..2356a00 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -478,10 +478,16 @@ impl Service { } if let Ok(content) = serde_json::from_str::(pdu.content.get()) { - services() + if let Some(related_pducount) = services() .rooms - .pdu_metadata - .add_relation(&pdu.event_id, &content.relates_to.event_id)?; + .timeline + .get_pdu_count(&content.relates_to.event_id)? + { + services() + .rooms + .pdu_metadata + .add_relation(PduCount::Normal(count2), related_pducount)?; + } } if let Ok(content) = serde_json::from_str::(pdu.content.get()) { @@ -489,10 +495,16 @@ impl Service { Relation::Reply { in_reply_to } => { // We need to do it again here, because replies don't have // event_id as a top level field - services() + if let Some(related_pducount) = services() .rooms - .pdu_metadata - .add_relation(&pdu.event_id, &in_reply_to.event_id)?; + .timeline + .get_pdu_count(&in_reply_to.event_id)? + { + services() + .rooms + .pdu_metadata + .add_relation(PduCount::Normal(count2), related_pducount)?; + } } Relation::Thread(thread) => { services() -- cgit v1.2.3 From 26b8605fa0483775acaa1a41dfada24d01cabb6f Mon Sep 17 00:00:00 2001 From: Jonas Zohren Date: Mon, 26 Jun 2023 22:06:17 +0200 Subject: ci: Adjust to current docker --- .gitlab-ci.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b7df56f..d2da91b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,19 +16,15 @@ variables: .docker-shared-settings: stage: "build docker image" - image: - name: jdrouet/docker-with-buildx:20.10.21-0.9.1 - pull_policy: if-not-present needs: [] tags: [ "docker" ] variables: # Docker in Docker: - DOCKER_HOST: tcp://docker:2375/ - DOCKER_TLS_CERTDIR: "" - # Famedly runners use BTRFS, overlayfs and overlay2 often break jobs - DOCKER_DRIVER: btrfs + DOCKER_BUILDKIT: 1 + image: + name: docker.io/docker services: - - name: docker:dind + - name: docker.io/docker:dind alias: docker script: - apk add openssh-client @@ -104,6 +100,13 @@ docker:tags: TAG: "matrix-conduit:$CI_COMMIT_TAG" +docker build debugging: + extends: .docker-shared-settings + rules: + - if: "$CI_MERGE_REQUEST_TITLE =~ /.*[Dd]ocker.*/" + variables: + TAG: "matrix-conduit-docker-tests:latest" + # --------------------------------------------------------------------- # # Run tests # # --------------------------------------------------------------------- # -- cgit v1.2.3 From 91180e011db93230aabec51e2504765303e9379a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 26 Jun 2023 23:10:26 +0200 Subject: bump ruma --- Cargo.lock | 22 +++++++++++----------- Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b33a7d9..19f63b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2110,7 +2110,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "assign", "js_int", @@ -2128,7 +2128,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.8.1" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "js_int", "ruma-common", @@ -2139,7 +2139,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "assign", "bytes", @@ -2156,7 +2156,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "base64 0.21.2", "bytes", @@ -2184,7 +2184,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "js_int", "ruma-common", @@ -2195,7 +2195,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "js_int", "thiserror", @@ -2204,7 +2204,7 @@ dependencies = [ [[package]] name = "ruma-identity-service-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "js_int", "ruma-common", @@ -2214,7 +2214,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "once_cell", "proc-macro-crate", @@ -2229,7 +2229,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "js_int", "ruma-common", @@ -2240,7 +2240,7 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.13.1" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "base64 0.21.2", "ed25519-dalek", @@ -2256,7 +2256,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=761771a317460f30590da170115d007892381e85#761771a317460f30590da170115d007892381e85" +source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" dependencies = [ "itertools", "js_int", diff --git a/Cargo.toml b/Cargo.toml index f024b06..3164842 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitiv # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -ruma = { git = "https://github.com/ruma/ruma", rev = "761771a317460f30590da170115d007892381e85", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +ruma = { git = "https://github.com/ruma/ruma", rev = "de9a5a6ecca197e59623c210bd21f53055f83568", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } #ruma = { git = "https://github.com/timokoesters/ruma", rev = "50c1db7e0a3a21fc794b0cce3b64285a4c750c71", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } #ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -- cgit v1.2.3 From 7c6d25dcd165ffa3535ba103ab5ffb4acbe8c558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 26 Jun 2023 21:57:59 +0200 Subject: Do state res even if the event soft fails --- src/service/rooms/event_handler/mod.rs | 310 ++++++++++++++------------------- 1 file changed, 129 insertions(+), 181 deletions(-) diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index b01a282..800d849 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -38,6 +38,8 @@ use tracing::{debug, error, info, trace, warn}; use crate::{service::*, services, Error, PduEvent, Result}; +use super::state_compressor::CompressedStateEvent; + pub struct Service; impl Service { @@ -62,9 +64,8 @@ impl Service { /// 12. Ensure that the state is derived from the previous current state (i.e. we calculated by /// doing state res where one of the inputs was a previously trusted set of state, don't just /// trust a set of state we got from a remote) - /// 13. Check if the event passes auth based on the "current state" of the room, if not "soft fail" - /// it - /// 14. Use state resolution to find new room state + /// 13. Use state resolution to find new room state + /// 14. Check if the event passes auth based on the "current state" of the room, if not soft fail it // We use some AsyncRecursiveType hacks here so we can call this async funtion recursively #[tracing::instrument(skip(self, value, is_timeline_event, pub_key_map))] pub(crate) async fn handle_incoming_pdu<'a>( @@ -304,7 +305,7 @@ impl Service { ) { Err(e) => { // Drop - warn!("Dropping bad event {}: {}", event_id, e); + warn!("Dropping bad event {}: {}", event_id, e,); return Err(Error::BadRequest( ErrorKind::InvalidParam, "Signature verification failed", @@ -735,8 +736,9 @@ impl Service { } info!("Auth check succeeded"); - // We start looking at current room state now, so lets lock the room + // 13. Use state resolution to find new room state + // We start looking at current room state now, so lets lock the room let mutex_state = Arc::clone( services() .globals @@ -782,7 +784,40 @@ impl Service { }) .collect::>()?; - // 13. Check if the event passes auth based on the "current state" of the room, if not "soft fail" it + if incoming_pdu.state_key.is_some() { + info!("Preparing for stateres to derive new room state"); + + // We also add state after incoming event to the fork states + let mut state_after = state_at_incoming_event.clone(); + if let Some(state_key) = &incoming_pdu.state_key { + let shortstatekey = services().rooms.short.get_or_create_shortstatekey( + &incoming_pdu.kind.to_string().into(), + state_key, + )?; + + state_after.insert(shortstatekey, Arc::from(&*incoming_pdu.event_id)); + } + + let new_room_state = self + .resolve_state(room_id, room_version_id, state_after) + .await?; + + // Set the new room state to the resolved state + info!("Forcing new room state"); + + let (sstatehash, new, removed) = services() + .rooms + .state_compressor + .save_state(room_id, new_room_state)?; + + services() + .rooms + .state + .force_state(room_id, sstatehash, new, removed, &state_lock) + .await?; + } + + // 14. Check if the event passes auth based on the "current state" of the room, if not soft fail it info!("Starting soft fail auth check"); let auth_events = services().rooms.state.get_auth_events( @@ -823,181 +858,6 @@ impl Service { )); } - if incoming_pdu.state_key.is_some() { - info!("Loading current room state ids"); - let current_sstatehash = services() - .rooms - .state - .get_room_shortstatehash(room_id)? - .expect("every room has state"); - - let current_state_ids = services() - .rooms - .state_accessor - .state_full_ids(current_sstatehash) - .await?; - - info!("Preparing for stateres to derive new room state"); - let mut extremity_sstatehashes = HashMap::new(); - - info!(?extremities, "Loading extremities"); - for id in &extremities { - match services().rooms.timeline.get_pdu(id)? { - Some(leaf_pdu) => { - extremity_sstatehashes.insert( - services() - .rooms - .state_accessor - .pdu_shortstatehash(&leaf_pdu.event_id)? - .ok_or_else(|| { - error!( - "Found extremity pdu with no statehash in db: {:?}", - leaf_pdu - ); - Error::bad_database("Found pdu with no statehash in db.") - })?, - leaf_pdu, - ); - } - _ => { - error!("Missing state snapshot for {:?}", id); - return Err(Error::BadDatabase("Missing state snapshot.")); - } - } - } - - let mut fork_states = Vec::new(); - - // 12. Ensure that the state is derived from the previous current state (i.e. we calculated - // by doing state res where one of the inputs was a previously trusted set of state, - // don't just trust a set of state we got from a remote). - - // We do this by adding the current state to the list of fork states - extremity_sstatehashes.remove(¤t_sstatehash); - fork_states.push(current_state_ids); - - // We also add state after incoming event to the fork states - let mut state_after = state_at_incoming_event.clone(); - if let Some(state_key) = &incoming_pdu.state_key { - let shortstatekey = services().rooms.short.get_or_create_shortstatekey( - &incoming_pdu.kind.to_string().into(), - state_key, - )?; - - state_after.insert(shortstatekey, Arc::from(&*incoming_pdu.event_id)); - } - fork_states.push(state_after); - - let mut update_state = false; - // 14. Use state resolution to find new room state - let new_room_state = if fork_states.is_empty() { - panic!("State is empty"); - } else if fork_states.iter().skip(1).all(|f| &fork_states[0] == f) { - info!("State resolution trivial"); - // There was only one state, so it has to be the room's current state (because that is - // always included) - fork_states[0] - .iter() - .map(|(k, id)| { - services() - .rooms - .state_compressor - .compress_state_event(*k, id) - }) - .collect::>()? - } else { - info!("Loading auth chains"); - // We do need to force an update to this room's state - update_state = true; - - let mut auth_chain_sets = Vec::new(); - for state in &fork_states { - auth_chain_sets.push( - services() - .rooms - .auth_chain - .get_auth_chain( - room_id, - state.iter().map(|(_, id)| id.clone()).collect(), - ) - .await? - .collect(), - ); - } - - info!("Loading fork states"); - - let fork_states: Vec<_> = fork_states - .into_iter() - .map(|map| { - map.into_iter() - .filter_map(|(k, id)| { - services() - .rooms - .short - .get_statekey_from_short(k) - .map(|(ty, st_key)| ((ty.to_string().into(), st_key), id)) - .ok() - }) - .collect::>() - }) - .collect(); - - info!("Resolving state"); - - let lock = services().globals.stateres_mutex.lock(); - let state = match state_res::resolve( - room_version_id, - &fork_states, - auth_chain_sets, - |id| { - let res = services().rooms.timeline.get_pdu(id); - if let Err(e) = &res { - error!("LOOK AT ME Failed to fetch event: {}", e); - } - res.ok().flatten() - }, - ) { - Ok(new_state) => new_state, - Err(_) => { - return Err(Error::bad_database("State resolution failed, either an event could not be found or deserialization")); - } - }; - - drop(lock); - - info!("State resolution done. Compressing state"); - - state - .into_iter() - .map(|((event_type, state_key), event_id)| { - let shortstatekey = services().rooms.short.get_or_create_shortstatekey( - &event_type.to_string().into(), - &state_key, - )?; - services() - .rooms - .state_compressor - .compress_state_event(shortstatekey, &event_id) - }) - .collect::>()? - }; - - // Set the new room state to the resolved state - if update_state { - info!("Forcing new room state"); - let (sstatehash, new, removed) = services() - .rooms - .state_compressor - .save_state(room_id, new_room_state)?; - services() - .rooms - .state - .force_state(room_id, sstatehash, new, removed, &state_lock) - .await?; - } - } - info!("Appending pdu to timeline"); extremities.insert(incoming_pdu.event_id.clone()); @@ -1021,6 +881,94 @@ impl Service { Ok(pdu_id) } + async fn resolve_state( + &self, + room_id: &RoomId, + room_version_id: &RoomVersionId, + incoming_state: HashMap>, + ) -> Result> { + info!("Loading current room state ids"); + let current_sstatehash = services() + .rooms + .state + .get_room_shortstatehash(room_id)? + .expect("every room has state"); + + let current_state_ids = services() + .rooms + .state_accessor + .state_full_ids(current_sstatehash) + .await?; + + let fork_states = [current_state_ids, incoming_state]; + + let mut auth_chain_sets = Vec::new(); + for state in &fork_states { + auth_chain_sets.push( + services() + .rooms + .auth_chain + .get_auth_chain(room_id, state.iter().map(|(_, id)| id.clone()).collect()) + .await? + .collect(), + ); + } + + info!("Loading fork states"); + + let fork_states: Vec<_> = fork_states + .into_iter() + .map(|map| { + map.into_iter() + .filter_map(|(k, id)| { + services() + .rooms + .short + .get_statekey_from_short(k) + .map(|(ty, st_key)| ((ty.to_string().into(), st_key), id)) + .ok() + }) + .collect::>() + }) + .collect(); + + info!("Resolving state"); + + let lock = services().globals.stateres_mutex.lock(); + let state = match state_res::resolve(room_version_id, &fork_states, auth_chain_sets, |id| { + let res = services().rooms.timeline.get_pdu(id); + if let Err(e) = &res { + error!("LOOK AT ME Failed to fetch event: {}", e); + } + res.ok().flatten() + }) { + Ok(new_state) => new_state, + Err(_) => { + return Err(Error::bad_database("State resolution failed, either an event could not be found or deserialization")); + } + }; + + drop(lock); + + info!("State resolution done. Compressing state"); + + let new_room_state = state + .into_iter() + .map(|((event_type, state_key), event_id)| { + let shortstatekey = services() + .rooms + .short + .get_or_create_shortstatekey(&event_type.to_string().into(), &state_key)?; + services() + .rooms + .state_compressor + .compress_state_event(shortstatekey, &event_id) + }) + .collect::>()?; + + Ok(new_room_state) + } + /// Find the event and auth it. Once the event is validated (steps 1 - 8) /// it is appended to the outliers Tree. /// -- cgit v1.2.3 From be877ef7191a2d6cbe9a3c9b40125f1bc42e6961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 27 Jun 2023 13:06:55 +0200 Subject: Improve sync performance with more caching and wrapping things in Arcs to avoid copies --- Cargo.lock | 22 +++--- Cargo.toml | 2 +- src/api/client_server/membership.rs | 20 ++--- src/database/key_value/rooms/state_accessor.rs | 6 +- src/database/key_value/rooms/state_compressor.rs | 10 +-- src/database/mod.rs | 4 +- src/service/mod.rs | 2 +- src/service/rooms/event_handler/mod.rs | 24 +++--- src/service/rooms/state/mod.rs | 18 ++--- src/service/rooms/state_compressor/data.rs | 6 +- src/service/rooms/state_compressor/mod.rs | 94 +++++++++++++----------- src/service/rooms/timeline/mod.rs | 2 +- 12 files changed, 112 insertions(+), 98 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19f63b1..9f62c18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2110,7 +2110,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "assign", "js_int", @@ -2128,7 +2128,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.8.1" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "js_int", "ruma-common", @@ -2139,7 +2139,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "assign", "bytes", @@ -2156,7 +2156,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "base64 0.21.2", "bytes", @@ -2184,7 +2184,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "js_int", "ruma-common", @@ -2195,7 +2195,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "js_int", "thiserror", @@ -2204,7 +2204,7 @@ dependencies = [ [[package]] name = "ruma-identity-service-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "js_int", "ruma-common", @@ -2214,7 +2214,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "once_cell", "proc-macro-crate", @@ -2229,7 +2229,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "js_int", "ruma-common", @@ -2240,7 +2240,7 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.13.1" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "base64 0.21.2", "ed25519-dalek", @@ -2256,7 +2256,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=de9a5a6ecca197e59623c210bd21f53055f83568#de9a5a6ecca197e59623c210bd21f53055f83568" +source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" dependencies = [ "itertools", "js_int", diff --git a/Cargo.toml b/Cargo.toml index 3164842..9698caf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitiv # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -ruma = { git = "https://github.com/ruma/ruma", rev = "de9a5a6ecca197e59623c210bd21f53055f83568", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +ruma = { git = "https://github.com/ruma/ruma", rev = "38294bd5206498c02b1001227d65654eb548308b", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } #ruma = { git = "https://github.com/timokoesters/ruma", rev = "50c1db7e0a3a21fc794b0cce3b64285a4c750c71", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } #ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index 11e37e6..ccd8d7a 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -743,15 +743,17 @@ async fn join_room_by_id_helper( info!("Saving state from send_join"); let (statehash_before_join, new, removed) = services().rooms.state_compressor.save_state( room_id, - state - .into_iter() - .map(|(k, id)| { - services() - .rooms - .state_compressor - .compress_state_event(k, &id) - }) - .collect::>()?, + Arc::new( + state + .into_iter() + .map(|(k, id)| { + services() + .rooms + .state_compressor + .compress_state_event(k, &id) + }) + .collect::>()?, + ), )?; services() diff --git a/src/database/key_value/rooms/state_accessor.rs b/src/database/key_value/rooms/state_accessor.rs index 0f0c0dc..ad08f46 100644 --- a/src/database/key_value/rooms/state_accessor.rs +++ b/src/database/key_value/rooms/state_accessor.rs @@ -16,7 +16,7 @@ impl service::rooms::state_accessor::Data for KeyValueDatabase { .1; let mut result = HashMap::new(); let mut i = 0; - for compressed in full_state.into_iter() { + for compressed in full_state.iter() { let parsed = services() .rooms .state_compressor @@ -45,7 +45,7 @@ impl service::rooms::state_accessor::Data for KeyValueDatabase { let mut result = HashMap::new(); let mut i = 0; - for compressed in full_state { + for compressed in full_state.iter() { let (_, eventid) = services() .rooms .state_compressor @@ -95,7 +95,7 @@ impl service::rooms::state_accessor::Data for KeyValueDatabase { .expect("there is always one layer") .1; Ok(full_state - .into_iter() + .iter() .find(|bytes| bytes.starts_with(&shortstatekey.to_be_bytes())) .and_then(|compressed| { services() diff --git a/src/database/key_value/rooms/state_compressor.rs b/src/database/key_value/rooms/state_compressor.rs index d0a9be4..65ea603 100644 --- a/src/database/key_value/rooms/state_compressor.rs +++ b/src/database/key_value/rooms/state_compressor.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, mem::size_of}; +use std::{collections::HashSet, mem::size_of, sync::Arc}; use crate::{ database::KeyValueDatabase, @@ -37,20 +37,20 @@ impl service::rooms::state_compressor::Data for KeyValueDatabase { Ok(StateDiff { parent, - added, - removed, + added: Arc::new(added), + removed: Arc::new(removed), }) } fn save_statediff(&self, shortstatehash: u64, diff: StateDiff) -> Result<()> { let mut value = diff.parent.unwrap_or(0).to_be_bytes().to_vec(); - for new in &diff.added { + for new in diff.added.iter() { value.extend_from_slice(&new[..]); } if !diff.removed.is_empty() { value.extend_from_slice(&0_u64.to_be_bytes()); - for removed in &diff.removed { + for removed in diff.removed.iter() { value.extend_from_slice(&removed[..]); } } diff --git a/src/database/mod.rs b/src/database/mod.rs index 5d89d4a..4e7bda6 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -587,8 +587,8 @@ impl KeyValueDatabase { services().rooms.state_compressor.save_state_from_diff( current_sstatehash, - statediffnew, - statediffremoved, + Arc::new(statediffnew), + Arc::new(statediffremoved), 2, // every state change is 2 event changes on average states_parents, )?; diff --git a/src/service/mod.rs b/src/service/mod.rs index 3b48810..7a2bb64 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -90,7 +90,7 @@ impl Services { state_compressor: rooms::state_compressor::Service { db, stateinfo_cache: Mutex::new(LruCache::new( - (100.0 * config.conduit_cache_capacity_modifier) as usize, + (1000.0 * config.conduit_cache_capacity_modifier) as usize, )), }, timeline: rooms::timeline::Service { diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index 800d849..066cef4 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -774,15 +774,17 @@ impl Service { }); info!("Compressing state at event"); - let state_ids_compressed = state_at_incoming_event - .iter() - .map(|(shortstatekey, id)| { - services() - .rooms - .state_compressor - .compress_state_event(*shortstatekey, id) - }) - .collect::>()?; + let state_ids_compressed = Arc::new( + state_at_incoming_event + .iter() + .map(|(shortstatekey, id)| { + services() + .rooms + .state_compressor + .compress_state_event(*shortstatekey, id) + }) + .collect::>()?, + ); if incoming_pdu.state_key.is_some() { info!("Preparing for stateres to derive new room state"); @@ -886,7 +888,7 @@ impl Service { room_id: &RoomId, room_version_id: &RoomVersionId, incoming_state: HashMap>, - ) -> Result> { + ) -> Result>> { info!("Loading current room state ids"); let current_sstatehash = services() .rooms @@ -966,7 +968,7 @@ impl Service { }) .collect::>()?; - Ok(new_room_state) + Ok(Arc::new(new_room_state)) } /// Find the event and auth it. Once the event is validated (steps 1 - 8) diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index 21ad2f9..ca9430f 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -32,11 +32,11 @@ impl Service { &self, room_id: &RoomId, shortstatehash: u64, - statediffnew: HashSet, - _statediffremoved: HashSet, + statediffnew: Arc>, + _statediffremoved: Arc>, state_lock: &MutexGuard<'_, ()>, // Take mutex guard to make sure users get the room state mutex ) -> Result<()> { - for event_id in statediffnew.into_iter().filter_map(|new| { + for event_id in statediffnew.iter().filter_map(|new| { services() .rooms .state_compressor @@ -107,7 +107,7 @@ impl Service { &self, event_id: &EventId, room_id: &RoomId, - state_ids_compressed: HashSet, + state_ids_compressed: Arc>, ) -> Result { let shorteventid = services() .rooms @@ -152,9 +152,9 @@ impl Service { .copied() .collect(); - (statediffnew, statediffremoved) + (Arc::new(statediffnew), Arc::new(statediffremoved)) } else { - (state_ids_compressed, HashSet::new()) + (state_ids_compressed, Arc::new(HashSet::new())) }; services().rooms.state_compressor.save_state_from_diff( shortstatehash, @@ -234,8 +234,8 @@ impl Service { services().rooms.state_compressor.save_state_from_diff( shortstatehash, - statediffnew, - statediffremoved, + Arc::new(statediffnew), + Arc::new(statediffremoved), 2, states_parents, )?; @@ -396,7 +396,7 @@ impl Service { .1; Ok(full_state - .into_iter() + .iter() .filter_map(|compressed| { services() .rooms diff --git a/src/service/rooms/state_compressor/data.rs b/src/service/rooms/state_compressor/data.rs index ce164c6..d221d57 100644 --- a/src/service/rooms/state_compressor/data.rs +++ b/src/service/rooms/state_compressor/data.rs @@ -1,12 +1,12 @@ -use std::collections::HashSet; +use std::{collections::HashSet, sync::Arc}; use super::CompressedStateEvent; use crate::Result; pub struct StateDiff { pub parent: Option, - pub added: HashSet, - pub removed: HashSet, + pub added: Arc>, + pub removed: Arc>, } pub trait Data: Send + Sync { diff --git a/src/service/rooms/state_compressor/mod.rs b/src/service/rooms/state_compressor/mod.rs index 356f32c..d29b020 100644 --- a/src/service/rooms/state_compressor/mod.rs +++ b/src/service/rooms/state_compressor/mod.rs @@ -20,10 +20,10 @@ pub struct Service { LruCache< u64, Vec<( - u64, // sstatehash - HashSet, // full state - HashSet, // added - HashSet, // removed + u64, // sstatehash + Arc>, // full state + Arc>, // added + Arc>, // removed )>, >, >, @@ -39,10 +39,10 @@ impl Service { shortstatehash: u64, ) -> Result< Vec<( - u64, // sstatehash - HashSet, // full state - HashSet, // added - HashSet, // removed + u64, // sstatehash + Arc>, // full state + Arc>, // added + Arc>, // removed )>, > { if let Some(r) = self @@ -62,13 +62,19 @@ impl Service { if let Some(parent) = parent { let mut response = self.load_shortstatehash_info(parent)?; - let mut state = response.last().unwrap().1.clone(); + let mut state = (*response.last().unwrap().1).clone(); state.extend(added.iter().copied()); + let removed = (*removed).clone(); for r in &removed { state.remove(r); } - response.push((shortstatehash, state, added, removed)); + response.push((shortstatehash, Arc::new(state), added, Arc::new(removed))); + + self.stateinfo_cache + .lock() + .unwrap() + .insert(shortstatehash, response.clone()); Ok(response) } else { @@ -135,14 +141,14 @@ impl Service { pub fn save_state_from_diff( &self, shortstatehash: u64, - statediffnew: HashSet, - statediffremoved: HashSet, + statediffnew: Arc>, + statediffremoved: Arc>, diff_to_sibling: usize, mut parent_states: Vec<( - u64, // sstatehash - HashSet, // full state - HashSet, // added - HashSet, // removed + u64, // sstatehash + Arc>, // full state + Arc>, // added + Arc>, // removed )>, ) -> Result<()> { let diffsum = statediffnew.len() + statediffremoved.len(); @@ -152,29 +158,29 @@ impl Service { // To many layers, we have to go deeper let parent = parent_states.pop().unwrap(); - let mut parent_new = parent.2; - let mut parent_removed = parent.3; + let mut parent_new = (*parent.2).clone(); + let mut parent_removed = (*parent.3).clone(); - for removed in statediffremoved { - if !parent_new.remove(&removed) { + for removed in statediffremoved.iter() { + if !parent_new.remove(removed) { // It was not added in the parent and we removed it - parent_removed.insert(removed); + parent_removed.insert(removed.clone()); } // Else it was added in the parent and we removed it again. We can forget this change } - for new in statediffnew { - if !parent_removed.remove(&new) { + for new in statediffnew.iter() { + if !parent_removed.remove(new) { // It was not touched in the parent and we added it - parent_new.insert(new); + parent_new.insert(new.clone()); } // Else it was removed in the parent and we added it again. We can forget this change } self.save_state_from_diff( shortstatehash, - parent_new, - parent_removed, + Arc::new(parent_new), + Arc::new(parent_removed), diffsum, parent_states, )?; @@ -205,29 +211,29 @@ impl Service { if diffsum * diffsum >= 2 * diff_to_sibling * parent_diff { // Diff too big, we replace above layer(s) - let mut parent_new = parent.2; - let mut parent_removed = parent.3; + let mut parent_new = (*parent.2).clone(); + let mut parent_removed = (*parent.3).clone(); - for removed in statediffremoved { - if !parent_new.remove(&removed) { + for removed in statediffremoved.iter() { + if !parent_new.remove(removed) { // It was not added in the parent and we removed it - parent_removed.insert(removed); + parent_removed.insert(removed.clone()); } // Else it was added in the parent and we removed it again. We can forget this change } - for new in statediffnew { - if !parent_removed.remove(&new) { + for new in statediffnew.iter() { + if !parent_removed.remove(new) { // It was not touched in the parent and we added it - parent_new.insert(new); + parent_new.insert(new.clone()); } // Else it was removed in the parent and we added it again. We can forget this change } self.save_state_from_diff( shortstatehash, - parent_new, - parent_removed, + Arc::new(parent_new), + Arc::new(parent_removed), diffsum, parent_states, )?; @@ -250,11 +256,11 @@ impl Service { pub fn save_state( &self, room_id: &RoomId, - new_state_ids_compressed: HashSet, + new_state_ids_compressed: Arc>, ) -> Result<( u64, - HashSet, - HashSet, + Arc>, + Arc>, )> { let previous_shortstatehash = services().rooms.state.get_room_shortstatehash(room_id)?; @@ -271,7 +277,11 @@ impl Service { .get_or_create_shortstatehash(&state_hash)?; if Some(new_shortstatehash) == previous_shortstatehash { - return Ok((new_shortstatehash, HashSet::new(), HashSet::new())); + return Ok(( + new_shortstatehash, + Arc::new(HashSet::new()), + Arc::new(HashSet::new()), + )); } let states_parents = previous_shortstatehash @@ -290,9 +300,9 @@ impl Service { .copied() .collect(); - (statediffnew, statediffremoved) + (Arc::new(statediffnew), Arc::new(statediffremoved)) } else { - (new_state_ids_compressed, HashSet::new()) + (new_state_ids_compressed, Arc::new(HashSet::new())) }; if !already_existed { diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 2356a00..56769d5 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -946,7 +946,7 @@ impl Service { pdu: &PduEvent, pdu_json: CanonicalJsonObject, new_room_leaves: Vec, - state_ids_compressed: HashSet, + state_ids_compressed: Arc>, soft_fail: bool, state_lock: &MutexGuard<'_, ()>, // Take mutex guard to make sure users get the room state mutex ) -> Result>> { -- cgit v1.2.3 From d64a56d88b72266abcb746d6c9e9691dbfe48301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Tue, 27 Jun 2023 18:48:34 +0200 Subject: Do soft fail check before doing state res to allow leave events --- src/service/rooms/event_handler/mod.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index 066cef4..ef5616e 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -736,6 +736,23 @@ impl Service { } info!("Auth check succeeded"); + // Soft fail check before doing state res + let auth_events = services().rooms.state.get_auth_events( + room_id, + &incoming_pdu.kind, + &incoming_pdu.sender, + incoming_pdu.state_key.as_deref(), + &incoming_pdu.content, + )?; + + let soft_fail = !state_res::event_auth::auth_check( + &room_version, + &incoming_pdu, + None::, + |k, s| auth_events.get(&(k.clone(), s.to_owned())), + ) + .map_err(|_e| Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed."))?; + // 13. Use state resolution to find new room state // We start looking at current room state now, so lets lock the room @@ -822,22 +839,6 @@ impl Service { // 14. Check if the event passes auth based on the "current state" of the room, if not soft fail it info!("Starting soft fail auth check"); - let auth_events = services().rooms.state.get_auth_events( - room_id, - &incoming_pdu.kind, - &incoming_pdu.sender, - incoming_pdu.state_key.as_deref(), - &incoming_pdu.content, - )?; - - let soft_fail = !state_res::event_auth::auth_check( - &room_version, - &incoming_pdu, - None::, - |k, s| auth_events.get(&(k.clone(), s.to_owned())), - ) - .map_err(|_e| Error::BadRequest(ErrorKind::InvalidParam, "Auth check failed."))?; - if soft_fail { services().rooms.timeline.append_incoming_pdu( &incoming_pdu, -- cgit v1.2.3 From fd1ccbd3ad474e2eac801a01ca71748827dce92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 28 Jun 2023 17:41:55 +0200 Subject: improvement: randomize server order for alias joins --- src/api/client_server/alias.rs | 9 +++++---- src/api/client_server/membership.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/api/client_server/alias.rs b/src/api/client_server/alias.rs index ab51b50..7660ca2 100644 --- a/src/api/client_server/alias.rs +++ b/src/api/client_server/alias.rs @@ -1,4 +1,5 @@ use crate::{services, Error, Result, Ruma}; +use rand::seq::SliceRandom; use regex::Regex; use ruma::{ api::{ @@ -90,10 +91,10 @@ pub(crate) async fn get_alias_helper( ) .await?; - return Ok(get_alias::v3::Response::new( - response.room_id, - response.servers, - )); + let mut servers = response.servers; + servers.shuffle(&mut rand::thread_rng()); + + return Ok(get_alias::v3::Response::new(response.room_id, servers)); } let mut room_id = None; diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index ccd8d7a..c9357b2 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -112,7 +112,7 @@ pub async fn join_room_by_id_or_alias_route( Err(room_alias) => { let response = get_alias_helper(room_alias).await?; - (response.servers.into_iter().collect(), response.room_id) + (response.servers, response.room_id) } }; -- cgit v1.2.3 From 06a1321e5692b240e0ce1e117cce0bd7008908eb Mon Sep 17 00:00:00 2001 From: purplemeteorite Date: Wed, 28 Jun 2023 18:51:44 +0200 Subject: easier-to-read docker setup instructions --- docker/README.md | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/docker/README.md b/docker/README.md index c702832..ef93af2 100644 --- a/docker/README.md +++ b/docker/README.md @@ -4,7 +4,31 @@ ## Docker -### Build & Dockerfile +To run conduit with docker you can either build the image yourself or pull it from a registry. + + +### Use a registry + +The image is available in the following registries: + +| Registry | Image | Size | +| --------------- | --------------------------------------------------------------- | --------------------- | +| Docker Hub | [matrixconduit/matrix-conduit:latest][dh] | ![Image Size][shield] | +| GitLab Registry | [registry.gitlab.com/famedly/conduit/matrix-conduit:latest][gl] | ![Image Size][shield] | + +[dh]: https://hub.docker.com/r/matrixconduit/matrix-conduit +[gl]: https://gitlab.com/famedly/conduit/container_registry/2497937 +[shield]: https://img.shields.io/docker/image-size/matrixconduit/matrix-conduit/latest + +Use +```bash +docker image pull +``` +to pull it to your machine. + + + +### Build using a dockerfile The Dockerfile provided by Conduit has two stages, each of which creates an image. @@ -19,9 +43,11 @@ docker build --tag matrixconduit/matrix-conduit:latest . which also will tag the resulting image as `matrixconduit/matrix-conduit:latest`. + + ### Run -After building the image you can simply run it with +When you have the image you can simply run it with ```bash docker run -d -p 8448:6167 \ @@ -37,16 +63,7 @@ docker run -d -p 8448:6167 \ --name conduit matrixconduit/matrix-conduit:latest ``` -or you can skip the build step and pull the image from one of the following registries: - -| Registry | Image | Size | -| --------------- | --------------------------------------------------------------- | --------------------- | -| Docker Hub | [matrixconduit/matrix-conduit:latest][dh] | ![Image Size][shield] | -| GitLab Registry | [registry.gitlab.com/famedly/conduit/matrix-conduit:latest][gl] | ![Image Size][shield] | - -[dh]: https://hub.docker.com/r/matrixconduit/matrix-conduit -[gl]: https://gitlab.com/famedly/conduit/container_registry/2497937 -[shield]: https://img.shields.io/docker/image-size/matrixconduit/matrix-conduit/latest +or you can use [docker-compose](#docker-compose). The `-d` flag lets the container run in detached mode. You now need to supply a `conduit.toml` config file, an example can be found [here](../conduit-example.toml). You can pass in different env vars to change config values on the fly. You can even configure Conduit completely by using env vars, but for that you need -- cgit v1.2.3 From dc50197a13e2d66608f1ee121b7db34a964031dd Mon Sep 17 00:00:00 2001 From: Jacob Taylor Date: Thu, 29 Jun 2023 02:42:32 +0000 Subject: update example configurations in DEPLOY.md for Apache and Nginx which include upstream proxy timeouts of 5 minutes to allow for room joins which take a while --- DEPLOY.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/DEPLOY.md b/DEPLOY.md index 75db366..8a6e48a 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -224,7 +224,8 @@ Listen 8448 ServerName your.server.name # EDIT THIS AllowEncodedSlashes NoDecode -ProxyPass /_matrix/ http://127.0.0.1:6167/_matrix/ nocanon +# joining large rooms can be slow. increase timeout to 600 if you still have issues. +ProxyPass /_matrix/ http://127.0.0.1:6167/_matrix/ timeout=300 nocanon ProxyPassReverse /_matrix/ http://127.0.0.1:6167/_matrix/ @@ -270,12 +271,15 @@ server { merge_slashes off; # Nginx defaults to only allow 1MB uploads + # Increase this to allow posting large files such as videos client_max_body_size 20M; location /_matrix/ { proxy_pass http://127.0.0.1:6167$request_uri; proxy_set_header Host $http_host; proxy_buffering off; + # joining large rooms can be slow. increase to 10m if you still have issues. + proxy_read_timeout 5m; } ssl_certificate /etc/letsencrypt/live/your.server.name/fullchain.pem; # EDIT THIS -- cgit v1.2.3 From 0ded637b4a6b885fc8d8015baeaaf1534b6b1d29 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 29 Jun 2023 11:20:52 +0200 Subject: Upgrade axum to 0.6 --- Cargo.lock | 54 ++++++++--------- Cargo.toml | 2 +- src/api/ruma_wrapper/axum.rs | 141 +++++++++++++++++++++++++++++++------------ src/main.rs | 7 +-- 4 files changed, 131 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f62c18..4148394 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,9 +89,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" -version = "0.5.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", @@ -108,22 +108,22 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", + "rustversion", "serde", "serde_json", + "serde_path_to_error", "serde_urlencoded", "sync_wrapper", - "tokio", "tower", - "tower-http 0.3.5", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.2.9" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ "async-trait", "bytes", @@ -131,6 +131,7 @@ dependencies = [ "http", "http-body", "mime", + "rustversion", "tower-layer", "tower-service", ] @@ -407,7 +408,7 @@ dependencies = [ "tikv-jemallocator", "tokio", "tower", - "tower-http 0.4.1", + "tower-http", "tracing", "tracing-flame", "tracing-opentelemetry", @@ -1449,9 +1450,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matchit" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" [[package]] name = "memchr" @@ -2363,6 +2364,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + [[package]] name = "ryu" version = "1.0.13" @@ -2467,6 +2474,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" +dependencies = [ + "serde", +] + [[package]] name = "serde_spanned" version = "0.6.3" @@ -2954,31 +2970,11 @@ dependencies = [ "futures-util", "pin-project", "pin-project-lite", - "tokio", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "tower-http" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" -dependencies = [ - "bitflags 1.3.2", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "tower-http" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index 9698caf..424007c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ rust-version = "1.70.0" [dependencies] # Web framework -axum = { version = "0.5.16", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path"], optional = true } +axum = { version = "0.6.18", default-features = false, features = ["form", "headers", "http1", "http2", "json", "matched-path"], optional = true } axum-server = { version = "0.5.1", features = ["tls-rustls"] } tower = { version = "0.4.13", features = ["util"] } tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitive-headers", "trace", "util"] } diff --git a/src/api/ruma_wrapper/axum.rs b/src/api/ruma_wrapper/axum.rs index 2d2af70..069e12b 100644 --- a/src/api/ruma_wrapper/axum.rs +++ b/src/api/ruma_wrapper/axum.rs @@ -3,18 +3,16 @@ use std::{collections::BTreeMap, iter::FromIterator, str}; use axum::{ async_trait, body::{Full, HttpBody}, - extract::{ - rejection::TypedHeaderRejectionReason, FromRequest, Path, RequestParts, TypedHeader, - }, + extract::{rejection::TypedHeaderRejectionReason, FromRequest, Path, TypedHeader}, headers::{ authorization::{Bearer, Credentials}, Authorization, }, response::{IntoResponse, Response}, - BoxError, + BoxError, RequestExt, RequestPartsExt, }; -use bytes::{BufMut, Bytes, BytesMut}; -use http::StatusCode; +use bytes::{Buf, BufMut, Bytes, BytesMut}; +use http::{Request, StatusCode}; use ruma::{ api::{client::error::ErrorKind, AuthScheme, IncomingRequest, OutgoingResponse}, CanonicalJsonValue, OwnedDeviceId, OwnedServerName, UserId, @@ -26,27 +24,44 @@ use super::{Ruma, RumaResponse}; use crate::{services, Error, Result}; #[async_trait] -impl FromRequest for Ruma +impl FromRequest for Ruma where T: IncomingRequest, - B: HttpBody + Send, + B: HttpBody + Send + 'static, B::Data: Send, B::Error: Into, { type Rejection = Error; - async fn from_request(req: &mut RequestParts) -> Result { + async fn from_request(req: Request, _state: &S) -> Result { #[derive(Deserialize)] struct QueryParams { access_token: Option, user_id: Option, } + let (mut parts, mut body) = match req.with_limited_body() { + Ok(limited_req) => { + let (parts, body) = limited_req.into_parts(); + let body = to_bytes(body) + .await + .map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?; + (parts, body) + } + Err(original_req) => { + let (parts, body) = original_req.into_parts(); + let body = to_bytes(body) + .await + .map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?; + (parts, body) + } + }; + let metadata = T::METADATA; - let auth_header = Option::>>::from_request(req).await?; - let path_params = Path::>::from_request(req).await?; + let auth_header: Option>> = parts.extract().await?; + let path_params: Path> = parts.extract().await?; - let query = req.uri().query().unwrap_or_default(); + let query = parts.uri.query().unwrap_or_default(); let query_params: QueryParams = match serde_html_form::from_str(query) { Ok(params) => params, Err(e) => { @@ -63,10 +78,6 @@ where None => query_params.access_token.as_deref(), }; - let mut body = Bytes::from_request(req) - .await - .map_err(|_| Error::BadRequest(ErrorKind::MissingToken, "Missing token."))?; - let mut json_body = serde_json::from_slice::(&body).ok(); let appservices = services().appservice.all().unwrap(); @@ -138,24 +149,24 @@ where } } AuthScheme::ServerSignatures => { - let TypedHeader(Authorization(x_matrix)) = - TypedHeader::>::from_request(req) - .await - .map_err(|e| { - warn!("Missing or invalid Authorization header: {}", e); - - let msg = match e.reason() { - TypedHeaderRejectionReason::Missing => { - "Missing Authorization header." - } - TypedHeaderRejectionReason::Error(_) => { - "Invalid X-Matrix signatures." - } - _ => "Unknown header-related error", - }; - - Error::BadRequest(ErrorKind::Forbidden, msg) - })?; + let TypedHeader(Authorization(x_matrix)) = parts + .extract::>>() + .await + .map_err(|e| { + warn!("Missing or invalid Authorization header: {}", e); + + let msg = match e.reason() { + TypedHeaderRejectionReason::Missing => { + "Missing Authorization header." + } + TypedHeaderRejectionReason::Error(_) => { + "Invalid X-Matrix signatures." + } + _ => "Unknown header-related error", + }; + + Error::BadRequest(ErrorKind::Forbidden, msg) + })?; let origin_signatures = BTreeMap::from_iter([( x_matrix.key.clone(), @@ -170,11 +181,11 @@ where let mut request_map = BTreeMap::from_iter([ ( "method".to_owned(), - CanonicalJsonValue::String(req.method().to_string()), + CanonicalJsonValue::String(parts.method.to_string()), ), ( "uri".to_owned(), - CanonicalJsonValue::String(req.uri().to_string()), + CanonicalJsonValue::String(parts.uri.to_string()), ), ( "origin".to_owned(), @@ -224,7 +235,7 @@ where x_matrix.origin, e, request_map ); - if req.uri().to_string().contains('@') { + if parts.uri.to_string().contains('@') { warn!( "Request uri contained '@' character. Make sure your \ reverse proxy gives Conduit the raw uri (apache: use \ @@ -243,8 +254,8 @@ where } }; - let mut http_request = http::Request::builder().uri(req.uri()).method(req.method()); - *http_request.headers_mut().unwrap() = req.headers().clone(); + let mut http_request = http::Request::builder().uri(parts.uri).method(parts.method); + *http_request.headers_mut().unwrap() = parts.headers; if let Some(CanonicalJsonValue::Object(json_body)) = &mut json_body { let user_id = sender_user.clone().unwrap_or_else(|| { @@ -364,3 +375,55 @@ impl IntoResponse for RumaResponse { } } } + +// copied from hyper under the following license: +// Copyright (c) 2014-2021 Sean McArthur + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +pub(crate) async fn to_bytes(body: T) -> Result +where + T: HttpBody, +{ + futures_util::pin_mut!(body); + + // If there's only 1 chunk, we can just return Buf::to_bytes() + let mut first = if let Some(buf) = body.data().await { + buf? + } else { + return Ok(Bytes::new()); + }; + + let second = if let Some(buf) = body.data().await { + buf? + } else { + return Ok(first.copy_to_bytes(first.remaining())); + }; + + // With more than 1 buf, we gotta flatten into a Vec first. + let cap = first.remaining() + second.remaining() + body.size_hint().lower() as usize; + let mut vec = Vec::with_capacity(cap); + vec.put(first); + vec.put(second); + + while let Some(buf) = body.data().await { + vec.put(buf?); + } + + Ok(vec.into()) +} diff --git a/src/main.rs b/src/main.rs index f9f88f4..e0f84d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,8 +10,7 @@ use std::{future::Future, io, net::SocketAddr, sync::atomic, time::Duration}; use axum::{ - extract::{DefaultBodyLimit, FromRequest, MatchedPath}, - handler::Handler, + extract::{DefaultBodyLimit, FromRequestParts, MatchedPath}, response::IntoResponse, routing::{get, on, MethodFilter}, Router, @@ -421,7 +420,7 @@ fn routes() -> Router { "/_matrix/client/v3/rooms/:room_id/initialSync", get(initial_sync), ) - .fallback(not_found.into_service()) + .fallback(not_found) } async fn shutdown_signal(handle: ServerHandle) { @@ -505,7 +504,7 @@ macro_rules! impl_ruma_handler { Fut: Future> + Send, E: IntoResponse, - $( $ty: FromRequest + Send + 'static, )* + $( $ty: FromRequestParts<()> + Send + 'static, )* { fn add_to_router(self, mut router: Router) -> Router { let meta = Req::METADATA; -- cgit v1.2.3 From 2640f67e4b6373c6db0032cdc3786d07d14e4309 Mon Sep 17 00:00:00 2001 From: Jacob Taylor Date: Sun, 2 Jul 2023 18:00:30 +0000 Subject: remove comments --- DEPLOY.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index 8a6e48a..e5e1530 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -224,7 +224,6 @@ Listen 8448 ServerName your.server.name # EDIT THIS AllowEncodedSlashes NoDecode -# joining large rooms can be slow. increase timeout to 600 if you still have issues. ProxyPass /_matrix/ http://127.0.0.1:6167/_matrix/ timeout=300 nocanon ProxyPassReverse /_matrix/ http://127.0.0.1:6167/_matrix/ @@ -278,7 +277,6 @@ server { proxy_pass http://127.0.0.1:6167$request_uri; proxy_set_header Host $http_host; proxy_buffering off; - # joining large rooms can be slow. increase to 10m if you still have issues. proxy_read_timeout 5m; } -- cgit v1.2.3 From 9d49d599f3a1d5da535b71f2f8e4986c25b997e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 2 Jul 2023 16:06:54 +0200 Subject: feat: space hierarchies --- src/api/client_server/context.rs | 6 +- src/api/client_server/message.rs | 7 +- src/api/client_server/mod.rs | 2 + src/api/client_server/search.rs | 3 +- src/api/client_server/space.rs | 34 +++ src/api/server_server.rs | 2 +- src/main.rs | 4 +- src/service/mod.rs | 5 +- src/service/pdu.rs | 19 +- src/service/rooms/mod.rs | 2 + src/service/rooms/spaces/mod.rs | 436 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 503 insertions(+), 17 deletions(-) create mode 100644 src/api/client_server/space.rs create mode 100644 src/service/rooms/spaces/mod.rs diff --git a/src/api/client_server/context.rs b/src/api/client_server/context.rs index e70f9f1..8e193e6 100644 --- a/src/api/client_server/context.rs +++ b/src/api/client_server/context.rs @@ -3,7 +3,7 @@ use ruma::{ api::client::{context::get_context, error::ErrorKind, filter::LazyLoadOptions}, events::StateEventType, }; -use std::{collections::HashSet, convert::TryFrom}; +use std::collections::HashSet; use tracing::error; /// # `GET /_matrix/client/r0/rooms/{roomId}/context` @@ -70,9 +70,7 @@ pub async fn get_context_route( } // Use limit with maximum 100 - let limit = usize::try_from(body.limit) - .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Limit value is invalid."))? - .min(100); + let limit = u64::from(body.limit).min(100) as usize; let base_event = base_event.to_room_event(); diff --git a/src/api/client_server/message.rs b/src/api/client_server/message.rs index dc2d994..750e030 100644 --- a/src/api/client_server/message.rs +++ b/src/api/client_server/message.rs @@ -133,12 +133,7 @@ pub async fn get_message_events_route( from, )?; - // Use limit or else 10, with maximum 100 - let limit = body - .limit - .try_into() - .map_or(10_usize, |l: u32| l as usize) - .min(100); + let limit = u64::from(body.limit).min(100) as usize; let next_token; diff --git a/src/api/client_server/mod.rs b/src/api/client_server/mod.rs index 2ab3a98..54c99aa 100644 --- a/src/api/client_server/mod.rs +++ b/src/api/client_server/mod.rs @@ -21,6 +21,7 @@ mod report; mod room; mod search; mod session; +mod space; mod state; mod sync; mod tag; @@ -55,6 +56,7 @@ pub use report::*; pub use room::*; pub use search::*; pub use session::*; +pub use space::*; pub use state::*; pub use sync::*; pub use tag::*; diff --git a/src/api/client_server/search.rs b/src/api/client_server/search.rs index fe69e7c..e9fac36 100644 --- a/src/api/client_server/search.rs +++ b/src/api/client_server/search.rs @@ -31,7 +31,8 @@ pub async fn search_events_route( .collect() }); - let limit = filter.limit.map_or(10, |l| u64::from(l) as usize); + // Use limit or else 10, with maximum 100 + let limit = filter.limit.map_or(10, u64::from).min(100) as usize; let mut searches = Vec::new(); diff --git a/src/api/client_server/space.rs b/src/api/client_server/space.rs new file mode 100644 index 0000000..e2ea8c3 --- /dev/null +++ b/src/api/client_server/space.rs @@ -0,0 +1,34 @@ +use crate::{services, Result, Ruma}; +use ruma::api::client::space::get_hierarchy; + +/// # `GET /_matrix/client/v1/rooms/{room_id}/hierarchy`` +/// +/// Paginates over the space tree in a depth-first manner to locate child rooms of a given space. +pub async fn get_hierarchy_route( + body: Ruma, +) -> Result { + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + + let skip = body + .from + .as_ref() + .and_then(|s| s.parse::().ok()) + .unwrap_or(0); + + let limit = body.limit.map_or(10, u64::from).min(100) as usize; + + let max_depth = body.max_depth.map_or(3, u64::from).min(10) as usize + 1; // +1 to skip the space room itself + + services() + .rooms + .spaces + .get_hierarchy( + sender_user, + &body.room_id, + limit, + skip, + max_depth, + body.suggested_only, + ) + .await +} diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 5e218be..adb5f1f 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -151,7 +151,7 @@ where .try_into_http_request::>( &actual_destination_str, SendAccessToken::IfRequired(""), - &[MatrixVersion::V1_0], + &[MatrixVersion::V1_4], ) .map_err(|e| { warn!( diff --git a/src/main.rs b/src/main.rs index f9f88f4..3f14ca8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,8 @@ rust_2018_idioms, unused_qualifications, clippy::cloned_instead_of_copied, - clippy::str_to_string + clippy::str_to_string, + clippy::future_not_send )] #![allow(clippy::suspicious_else_formatting)] #![deny(clippy::dbg_macro)] @@ -386,6 +387,7 @@ fn routes() -> Router { .ruma_route(client_server::get_relating_events_with_rel_type_and_event_type_route) .ruma_route(client_server::get_relating_events_with_rel_type_route) .ruma_route(client_server::get_relating_events_route) + .ruma_route(client_server::get_hierarchy_route) .ruma_route(server_server::get_server_version_route) .route( "/_matrix/key/v2/server", diff --git a/src/service/mod.rs b/src/service/mod.rs index 7a2bb64..dfdc5a6 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -90,7 +90,7 @@ impl Services { state_compressor: rooms::state_compressor::Service { db, stateinfo_cache: Mutex::new(LruCache::new( - (1000.0 * config.conduit_cache_capacity_modifier) as usize, + (300.0 * config.conduit_cache_capacity_modifier) as usize, )), }, timeline: rooms::timeline::Service { @@ -98,6 +98,9 @@ impl Services { lasttimelinecount_cache: Mutex::new(HashMap::new()), }, threads: rooms::threads::Service { db }, + spaces: rooms::spaces::Service { + roomid_spacechunk_cache: Mutex::new(LruCache::new(200)), + }, user: rooms::user::Service { db }, }, transaction_ids: transaction_ids::Service { db }, diff --git a/src/service/pdu.rs b/src/service/pdu.rs index 9d284c0..d24e174 100644 --- a/src/service/pdu.rs +++ b/src/service/pdu.rs @@ -1,9 +1,9 @@ use crate::Error; use ruma::{ events::{ - room::member::RoomMemberEventContent, AnyEphemeralRoomEvent, AnyMessageLikeEvent, - AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent, AnySyncTimelineEvent, - AnyTimelineEvent, StateEvent, TimelineEventType, + room::member::RoomMemberEventContent, space::child::HierarchySpaceChildEvent, + AnyEphemeralRoomEvent, AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent, + AnySyncStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, StateEvent, TimelineEventType, }, serde::Raw, state_res, CanonicalJsonObject, CanonicalJsonValue, EventId, MilliSecondsSinceUnixEpoch, @@ -248,6 +248,19 @@ impl PduEvent { serde_json::from_value(json).expect("Raw::from_value always works") } + #[tracing::instrument(skip(self))] + pub fn to_stripped_spacechild_state_event(&self) -> Raw { + let json = json!({ + "content": self.content, + "type": self.kind, + "sender": self.sender, + "state_key": self.state_key, + "origin_server_ts": self.origin_server_ts, + }); + + serde_json::from_value(json).expect("Raw::from_value always works") + } + #[tracing::instrument(skip(self))] pub fn to_member_event(&self) -> Raw> { let mut json = json!({ diff --git a/src/service/rooms/mod.rs b/src/service/rooms/mod.rs index 61304d1..f073984 100644 --- a/src/service/rooms/mod.rs +++ b/src/service/rooms/mod.rs @@ -9,6 +9,7 @@ pub mod outlier; pub mod pdu_metadata; pub mod search; pub mod short; +pub mod spaces; pub mod state; pub mod state_accessor; pub mod state_cache; @@ -56,5 +57,6 @@ pub struct Service { pub state_compressor: state_compressor::Service, pub timeline: timeline::Service, pub threads: threads::Service, + pub spaces: spaces::Service, pub user: user::Service, } diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs new file mode 100644 index 0000000..76ba6c5 --- /dev/null +++ b/src/service/rooms/spaces/mod.rs @@ -0,0 +1,436 @@ +use std::sync::{Arc, Mutex}; + +use lru_cache::LruCache; +use ruma::{ + api::{ + client::{ + error::ErrorKind, + space::{get_hierarchy, SpaceHierarchyRoomsChunk, SpaceRoomJoinRule}, + }, + federation, + }, + directory::PublicRoomJoinRule, + events::{ + room::{ + avatar::RoomAvatarEventContent, + canonical_alias::RoomCanonicalAliasEventContent, + create::RoomCreateEventContent, + guest_access::{GuestAccess, RoomGuestAccessEventContent}, + history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, + join_rules::{JoinRule, RoomJoinRulesEventContent}, + name::RoomNameEventContent, + topic::RoomTopicEventContent, + }, + StateEventType, + }, + OwnedRoomId, RoomId, UserId, +}; + +use tracing::{debug, error, warn}; + +use crate::{services, Error, PduEvent, Result}; + +pub struct CachedSpaceChunk { + chunk: SpaceHierarchyRoomsChunk, + children: Vec, + join_rule: JoinRule, +} + +pub struct Service { + pub roomid_spacechunk_cache: Mutex>>, +} + +impl Service { + pub async fn get_hierarchy( + &self, + sender_user: &UserId, + room_id: &RoomId, + limit: usize, + skip: usize, + max_depth: usize, + suggested_only: bool, + ) -> Result { + let mut left_to_skip = skip; + + let mut rooms_in_path = Vec::new(); + let mut stack = vec![vec![room_id.to_owned()]]; + let mut results = Vec::new(); + + while let Some(current_room) = { + while stack.last().map_or(false, |s| s.is_empty()) { + stack.pop(); + } + if !stack.is_empty() { + stack.last_mut().and_then(|s| s.pop()) + } else { + None + } + } { + rooms_in_path.push(current_room.clone()); + if results.len() >= limit { + break; + } + + if let Some(cached) = self + .roomid_spacechunk_cache + .lock() + .unwrap() + .get_mut(¤t_room.to_owned()) + .as_ref() + { + if let Some(cached) = cached { + if let Some(_join_rule) = + self.handle_join_rule(&cached.join_rule, sender_user, ¤t_room)? + { + if left_to_skip > 0 { + left_to_skip -= 1; + } else { + results.push(cached.chunk.clone()); + } + if rooms_in_path.len() < max_depth { + stack.push(cached.children.clone()); + } + } + } + continue; + } + + if let Some(current_shortstatehash) = services() + .rooms + .state + .get_room_shortstatehash(¤t_room)? + { + let state = services() + .rooms + .state_accessor + .state_full_ids(current_shortstatehash) + .await?; + + let mut children_ids = Vec::new(); + let mut children_pdus = Vec::new(); + for (key, id) in state { + let (event_type, state_key) = + services().rooms.short.get_statekey_from_short(key)?; + if event_type != StateEventType::SpaceChild { + continue; + } + if let Ok(room_id) = OwnedRoomId::try_from(state_key) { + children_ids.push(room_id); + children_pdus.push(services().rooms.timeline.get_pdu(&id)?.ok_or_else( + || Error::bad_database("Event in space state not found"), + )?); + } + } + + // TODO: Sort children + children_ids.reverse(); + + let chunk = self.get_room_chunk(sender_user, ¤t_room, children_pdus); + if let Ok(chunk) = chunk { + if left_to_skip > 0 { + left_to_skip -= 1; + } else { + results.push(chunk.clone()); + } + let join_rule = services() + .rooms + .state_accessor + .room_state_get(¤t_room, &StateEventType::RoomJoinRules, "")? + .map(|s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomJoinRulesEventContent| c.join_rule) + .map_err(|e| { + error!("Invalid room join rule event in database: {}", e); + Error::BadDatabase("Invalid room join rule event in database.") + }) + }) + .transpose()? + .unwrap_or(JoinRule::Invite); + + self.roomid_spacechunk_cache.lock().unwrap().insert( + current_room.clone(), + Some(CachedSpaceChunk { + chunk, + children: children_ids.clone(), + join_rule, + }), + ); + } + + if rooms_in_path.len() < max_depth { + stack.push(children_ids); + } + } else { + let server = current_room.server_name(); + if server == services().globals.server_name() { + continue; + } + if !results.is_empty() { + // Early return so the client can see some data already + break; + } + warn!("Asking {server} for /hierarchy"); + if let Ok(response) = services() + .sending + .send_federation_request( + &server, + federation::space::get_hierarchy::v1::Request { + room_id: current_room.to_owned(), + suggested_only, + }, + ) + .await + { + warn!("Got response from {server} for /hierarchy\n{response:?}"); + let join_rule = self.translate_pjoinrule(&response.room.join_rule)?; + let chunk = SpaceHierarchyRoomsChunk { + canonical_alias: response.room.canonical_alias, + name: response.room.name, + num_joined_members: response.room.num_joined_members, + room_id: response.room.room_id, + topic: response.room.topic, + world_readable: response.room.world_readable, + guest_can_join: response.room.guest_can_join, + avatar_url: response.room.avatar_url, + join_rule: self.translate_sjoinrule(&response.room.join_rule)?, + room_type: response.room.room_type, + children_state: response.room.children_state, + }; + let children = response + .children + .iter() + .map(|c| c.room_id.clone()) + .collect::>(); + + if let Some(_join_rule) = + self.handle_join_rule(&join_rule, sender_user, ¤t_room)? + { + if left_to_skip > 0 { + left_to_skip -= 1; + } else { + results.push(chunk.clone()); + } + if rooms_in_path.len() < max_depth { + stack.push(children.clone()); + } + } + + self.roomid_spacechunk_cache.lock().unwrap().insert( + current_room.clone(), + Some(CachedSpaceChunk { + chunk, + children, + join_rule, + }), + ); + + /* TODO: + for child in response.children { + roomid_spacechunk_cache.insert( + current_room.clone(), + CachedSpaceChunk { + chunk: child.chunk, + children, + join_rule, + }, + ); + } + */ + } else { + self.roomid_spacechunk_cache + .lock() + .unwrap() + .insert(current_room.clone(), None); + } + } + } + + Ok(get_hierarchy::v1::Response { + next_batch: if results.is_empty() { + None + } else { + Some((skip + results.len()).to_string()) + }, + rooms: results, + }) + } + + fn get_room_chunk( + &self, + sender_user: &UserId, + room_id: &RoomId, + children: Vec>, + ) -> Result { + Ok(SpaceHierarchyRoomsChunk { + canonical_alias: services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomCanonicalAlias, "")? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomCanonicalAliasEventContent| c.alias) + .map_err(|_| { + Error::bad_database("Invalid canonical alias event in database.") + }) + })?, + name: services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomName, "")? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomNameEventContent| c.name) + .map_err(|_| Error::bad_database("Invalid room name event in database.")) + })?, + num_joined_members: services() + .rooms + .state_cache + .room_joined_count(&room_id)? + .unwrap_or_else(|| { + warn!("Room {} has no member count", room_id); + 0 + }) + .try_into() + .expect("user count should not be that big"), + room_id: room_id.to_owned(), + topic: services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomTopic, "")? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomTopicEventContent| Some(c.topic)) + .map_err(|_| Error::bad_database("Invalid room topic event in database.")) + })?, + world_readable: services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomHistoryVisibility, "")? + .map_or(Ok(false), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomHistoryVisibilityEventContent| { + c.history_visibility == HistoryVisibility::WorldReadable + }) + .map_err(|_| { + Error::bad_database( + "Invalid room history visibility event in database.", + ) + }) + })?, + guest_can_join: services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomGuestAccess, "")? + .map_or(Ok(false), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomGuestAccessEventContent| { + c.guest_access == GuestAccess::CanJoin + }) + .map_err(|_| { + Error::bad_database("Invalid room guest access event in database.") + }) + })?, + avatar_url: services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomAvatar, "")? + .map(|s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomAvatarEventContent| c.url) + .map_err(|_| Error::bad_database("Invalid room avatar event in database.")) + }) + .transpose()? + // url is now an Option so we must flatten + .flatten(), + join_rule: { + let join_rule = services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomJoinRules, "")? + .map(|s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomJoinRulesEventContent| c.join_rule) + .map_err(|e| { + error!("Invalid room join rule event in database: {}", e); + Error::BadDatabase("Invalid room join rule event in database.") + }) + }) + .transpose()? + .unwrap_or(JoinRule::Invite); + self.handle_join_rule(&join_rule, sender_user, room_id)? + .ok_or_else(|| { + debug!("User is not allowed to see room {room_id}"); + // This error will be caught later + Error::BadRequest( + ErrorKind::Forbidden, + "User is not allowed to see the room", + ) + })? + }, + room_type: services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomCreate, "")? + .map(|s| { + serde_json::from_str::(s.content.get()).map_err(|e| { + error!("Invalid room create event in database: {}", e); + Error::BadDatabase("Invalid room create event in database.") + }) + }) + .transpose()? + .and_then(|e| e.room_type), + children_state: children + .into_iter() + .map(|pdu| pdu.to_stripped_spacechild_state_event()) + .collect(), + }) + } + + fn translate_pjoinrule(&self, join_rule: &PublicRoomJoinRule) -> Result { + match join_rule { + PublicRoomJoinRule::Knock => Ok(JoinRule::Knock), + PublicRoomJoinRule::Public => Ok(JoinRule::Public), + _ => Err(Error::BadServerResponse("Unknown join rule")), + } + } + + fn translate_sjoinrule(&self, join_rule: &PublicRoomJoinRule) -> Result { + match join_rule { + PublicRoomJoinRule::Knock => Ok(SpaceRoomJoinRule::Knock), + PublicRoomJoinRule::Public => Ok(SpaceRoomJoinRule::Public), + _ => Err(Error::BadServerResponse("Unknown join rule")), + } + } + + fn handle_join_rule( + &self, + join_rule: &JoinRule, + sender_user: &UserId, + room_id: &RoomId, + ) -> Result> { + match join_rule { + JoinRule::Public => Ok::<_, Error>(Some(SpaceRoomJoinRule::Public)), + JoinRule::Knock => Ok(Some(SpaceRoomJoinRule::Knock)), + JoinRule::Invite => { + if services() + .rooms + .state_cache + .is_joined(sender_user, &room_id)? + { + Ok(Some(SpaceRoomJoinRule::Invite)) + } else { + Ok(None) + } + } + JoinRule::Restricted(_r) => { + // TODO: Check rules + Ok(None) + } + JoinRule::KnockRestricted(_r) => { + // TODO: Check rules + Ok(None) + } + _ => Ok(None), + } + } +} -- cgit v1.2.3 From bac13d08ae8cb8205725d31b72b09baec2ee9265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 2 Jul 2023 22:50:50 +0200 Subject: fix: cache invalidation --- src/service/rooms/state/mod.rs | 73 ++++++++++++++++++++++----------------- src/service/rooms/timeline/mod.rs | 11 ++++++ 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index ca9430f..d782386 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -49,10 +49,6 @@ impl Service { None => continue, }; - if pdu.get("type").and_then(|val| val.as_str()) != Some("m.room.member") { - continue; - } - let pdu: PduEvent = match serde_json::from_str( &serde_json::to_string(&pdu).expect("CanonicalJsonObj can be serialized to JSON"), ) { @@ -60,34 +56,49 @@ impl Service { Err(_) => continue, }; - #[derive(Deserialize)] - struct ExtractMembership { - membership: MembershipState, + match pdu.kind { + TimelineEventType::RoomMember => { + #[derive(Deserialize)] + struct ExtractMembership { + membership: MembershipState, + } + + let membership = + match serde_json::from_str::(pdu.content.get()) { + Ok(e) => e.membership, + Err(_) => continue, + }; + + let state_key = match pdu.state_key { + Some(k) => k, + None => continue, + }; + + let user_id = match UserId::parse(state_key) { + Ok(id) => id, + Err(_) => continue, + }; + + services().rooms.state_cache.update_membership( + room_id, + &user_id, + membership, + &pdu.sender, + None, + false, + )?; + } + TimelineEventType::SpaceChild => { + services() + .rooms + .spaces + .roomid_spacechunk_cache + .lock() + .unwrap() + .remove(&pdu.room_id); + } + _ => continue, } - - let membership = match serde_json::from_str::(pdu.content.get()) { - Ok(e) => e.membership, - Err(_) => continue, - }; - - let state_key = match pdu.state_key { - Some(k) => k, - None => continue, - }; - - let user_id = match UserId::parse(state_key) { - Ok(id) => id, - Err(_) => continue, - }; - - services().rooms.state_cache.update_membership( - room_id, - &user_id, - membership, - &pdu.sender, - None, - false, - )?; } services().rooms.state_cache.update_joined_count(room_id)?; diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 56769d5..83c3010 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -387,6 +387,17 @@ impl Service { self.redact_pdu(redact_id, pdu)?; } } + TimelineEventType::SpaceChild => { + if let Some(_state_key) = &pdu.state_key { + services() + .rooms + .spaces + .roomid_spacechunk_cache + .lock() + .unwrap() + .remove(&pdu.room_id); + } + } TimelineEventType::RoomMember => { if let Some(state_key) = &pdu.state_key { #[derive(Deserialize)] -- cgit v1.2.3 From a2c3256cedeeb696b303b6ca9533acd73d110e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 3 Jul 2023 19:37:54 +0200 Subject: improvement: better memory usage and admin commands to analyze it --- Cargo.toml | 2 +- src/api/client_server/sync.rs | 600 ++++++++++++++++++------------------ src/config/mod.rs | 2 +- src/database/abstraction.rs | 1 + src/database/abstraction/rocksdb.rs | 6 + src/database/key_value/globals.rs | 55 +++- src/service/admin/mod.rs | 32 +- src/service/globals/data.rs | 3 +- src/service/globals/mod.rs | 4 - src/service/mod.rs | 107 ++++++- 10 files changed, 499 insertions(+), 313 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9698caf..687f4b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,7 +105,7 @@ async-trait = "0.1.68" sd-notify = { version = "0.4.1", optional = true } [features] -default = ["conduit_bin", "backend_sqlite", "backend_rocksdb", "jemalloc", "systemd"] +default = ["conduit_bin", "backend_sqlite", "backend_rocksdb", "systemd"] #backend_sled = ["sled"] backend_persy = ["persy", "parking_lot"] backend_sqlite = ["sqlite"] diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index b4baec1..dd75347 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -653,213 +653,133 @@ async fn load_joined_room( .user .get_token_shortstatehash(&room_id, since)?; - // Calculates joined_member_count, invited_member_count and heroes - let calculate_counts = || { - let joined_member_count = services() - .rooms - .state_cache - .room_joined_count(&room_id)? - .unwrap_or(0); - let invited_member_count = services() - .rooms - .state_cache - .room_invited_count(&room_id)? - .unwrap_or(0); - - // Recalculate heroes (first 5 members) - let mut heroes = Vec::new(); - - if joined_member_count + invited_member_count <= 5 { - // Go through all PDUs and for each member event, check if the user is still joined or - // invited until we have 5 or we reach the end - - for hero in services() - .rooms - .timeline - .all_pdus(&sender_user, &room_id)? - .filter_map(|pdu| pdu.ok()) // Ignore all broken pdus - .filter(|(_, pdu)| pdu.kind == TimelineEventType::RoomMember) - .map(|(_, pdu)| { - let content: RoomMemberEventContent = serde_json::from_str(pdu.content.get()) - .map_err(|_| { - Error::bad_database("Invalid member event in database.") - })?; - - if let Some(state_key) = &pdu.state_key { - let user_id = UserId::parse(state_key.clone()) - .map_err(|_| Error::bad_database("Invalid UserId in member PDU."))?; - - // The membership was and still is invite or join - if matches!( - content.membership, - MembershipState::Join | MembershipState::Invite - ) && (services().rooms.state_cache.is_joined(&user_id, &room_id)? - || services() - .rooms - .state_cache - .is_invited(&user_id, &room_id)?) - { - Ok::<_, Error>(Some(state_key.clone())) - } else { - Ok(None) - } - } else { - Ok(None) - } - }) - // Filter out buggy users - .filter_map(|u| u.ok()) - // Filter for possible heroes - .flatten() - { - if heroes.contains(&hero) || hero == sender_user.as_str() { - continue; - } - - heroes.push(hero); - } - } - - Ok::<_, Error>(( - Some(joined_member_count), - Some(invited_member_count), - heroes, - )) - }; - - let since_sender_member: Option = since_shortstatehash - .and_then(|shortstatehash| { - services() - .rooms - .state_accessor - .state_get( - shortstatehash, - &StateEventType::RoomMember, - sender_user.as_str(), - ) - .transpose() - }) - .transpose()? - .and_then(|pdu| { - serde_json::from_str(pdu.content.get()) - .map_err(|_| Error::bad_database("Invalid PDU in database.")) - .ok() - }); - - let joined_since_last_sync = - since_sender_member.map_or(true, |member| member.membership != MembershipState::Join); - let (heroes, joined_member_count, invited_member_count, joined_since_last_sync, state_events) = - if since_shortstatehash.is_none() || joined_since_last_sync { - // Probably since = 0, we will do an initial sync - - let (joined_member_count, invited_member_count, heroes) = calculate_counts()?; - - let current_state_ids = services() - .rooms - .state_accessor - .state_full_ids(current_shortstatehash) - .await?; + if timeline_pdus.is_empty() && since_shortstatehash == Some(current_shortstatehash) { + // No state changes + (Vec::new(), None, None, false, Vec::new()) + } else { + // Calculates joined_member_count, invited_member_count and heroes + let calculate_counts = || { + let joined_member_count = services() + .rooms + .state_cache + .room_joined_count(&room_id)? + .unwrap_or(0); + let invited_member_count = services() + .rooms + .state_cache + .room_invited_count(&room_id)? + .unwrap_or(0); - let mut state_events = Vec::new(); - let mut lazy_loaded = HashSet::new(); + // Recalculate heroes (first 5 members) + let mut heroes = Vec::new(); - let mut i = 0; - for (shortstatekey, id) in current_state_ids { - let (event_type, state_key) = services() - .rooms - .short - .get_statekey_from_short(shortstatekey)?; + if joined_member_count + invited_member_count <= 5 { + // Go through all PDUs and for each member event, check if the user is still joined or + // invited until we have 5 or we reach the end - if event_type != StateEventType::RoomMember { - let pdu = match services().rooms.timeline.get_pdu(&id)? { - Some(pdu) => pdu, - None => { - error!("Pdu in state not found: {}", id); + for hero in services() + .rooms + .timeline + .all_pdus(&sender_user, &room_id)? + .filter_map(|pdu| pdu.ok()) // Ignore all broken pdus + .filter(|(_, pdu)| pdu.kind == TimelineEventType::RoomMember) + .map(|(_, pdu)| { + let content: RoomMemberEventContent = + serde_json::from_str(pdu.content.get()).map_err(|_| { + Error::bad_database("Invalid member event in database.") + })?; + + if let Some(state_key) = &pdu.state_key { + let user_id = UserId::parse(state_key.clone()).map_err(|_| { + Error::bad_database("Invalid UserId in member PDU.") + })?; + + // The membership was and still is invite or join + if matches!( + content.membership, + MembershipState::Join | MembershipState::Invite + ) && (services() + .rooms + .state_cache + .is_joined(&user_id, &room_id)? + || services() + .rooms + .state_cache + .is_invited(&user_id, &room_id)?) + { + Ok::<_, Error>(Some(state_key.clone())) + } else { + Ok(None) + } + } else { + Ok(None) + } + }) + // Filter out buggy users + .filter_map(|u| u.ok()) + // Filter for possible heroes + .flatten() + { + if heroes.contains(&hero) || hero == sender_user.as_str() { continue; } - }; - state_events.push(pdu); - i += 1; - if i % 100 == 0 { - tokio::task::yield_now().await; + heroes.push(hero); } - } else if !lazy_load_enabled - || full_state - || timeline_users.contains(&state_key) - // TODO: Delete the following line when this is resolved: https://github.com/vector-im/element-web/issues/22565 - || *sender_user == state_key - { - let pdu = match services().rooms.timeline.get_pdu(&id)? { - Some(pdu) => pdu, - None => { - error!("Pdu in state not found: {}", id); - continue; - } - }; + } - // This check is in case a bad user ID made it into the database - if let Ok(uid) = UserId::parse(&state_key) { - lazy_loaded.insert(uid); - } - state_events.push(pdu); + Ok::<_, Error>(( + Some(joined_member_count), + Some(invited_member_count), + heroes, + )) + }; - i += 1; - if i % 100 == 0 { - tokio::task::yield_now().await; - } - } - } + let since_sender_member: Option = since_shortstatehash + .and_then(|shortstatehash| { + services() + .rooms + .state_accessor + .state_get( + shortstatehash, + &StateEventType::RoomMember, + sender_user.as_str(), + ) + .transpose() + }) + .transpose()? + .and_then(|pdu| { + serde_json::from_str(pdu.content.get()) + .map_err(|_| Error::bad_database("Invalid PDU in database.")) + .ok() + }); - // Reset lazy loading because this is an initial sync - services().rooms.lazy_loading.lazy_load_reset( - &sender_user, - &sender_device, - &room_id, - )?; - - // The state_events above should contain all timeline_users, let's mark them as lazy - // loaded. - services().rooms.lazy_loading.lazy_load_mark_sent( - &sender_user, - &sender_device, - &room_id, - lazy_loaded, - next_batchcount, - ); + let joined_since_last_sync = since_sender_member + .map_or(true, |member| member.membership != MembershipState::Join); - ( - heroes, - joined_member_count, - invited_member_count, - true, - state_events, - ) - } else if timeline_pdus.is_empty() && since_shortstatehash == Some(current_shortstatehash) { - // No state changes - (Vec::new(), None, None, false, Vec::new()) - } else { - // Incremental /sync - let since_shortstatehash = since_shortstatehash.unwrap(); + if since_shortstatehash.is_none() || joined_since_last_sync { + // Probably since = 0, we will do an initial sync - let mut state_events = Vec::new(); - let mut lazy_loaded = HashSet::new(); + let (joined_member_count, invited_member_count, heroes) = calculate_counts()?; - if since_shortstatehash != current_shortstatehash { let current_state_ids = services() .rooms .state_accessor .state_full_ids(current_shortstatehash) .await?; - let since_state_ids = services() - .rooms - .state_accessor - .state_full_ids(since_shortstatehash) - .await?; - for (key, id) in current_state_ids { - if full_state || since_state_ids.get(&key) != Some(&id) { + let mut state_events = Vec::new(); + let mut lazy_loaded = HashSet::new(); + + let mut i = 0; + for (shortstatekey, id) in current_state_ids { + let (event_type, state_key) = services() + .rooms + .short + .get_statekey_from_short(shortstatekey)?; + + if event_type != StateEventType::RoomMember { let pdu = match services().rooms.timeline.get_pdu(&id)? { Some(pdu) => pdu, None => { @@ -867,146 +787,234 @@ async fn load_joined_room( continue; } }; + state_events.push(pdu); - if pdu.kind == TimelineEventType::RoomMember { - match UserId::parse( - pdu.state_key - .as_ref() - .expect("State event has state key") - .clone(), - ) { - Ok(state_key_userid) => { - lazy_loaded.insert(state_key_userid); - } - Err(e) => error!("Invalid state key for member event: {}", e), - } + i += 1; + if i % 100 == 0 { + tokio::task::yield_now().await; } + } else if !lazy_load_enabled + || full_state + || timeline_users.contains(&state_key) + // TODO: Delete the following line when this is resolved: https://github.com/vector-im/element-web/issues/22565 + || *sender_user == state_key + { + let pdu = match services().rooms.timeline.get_pdu(&id)? { + Some(pdu) => pdu, + None => { + error!("Pdu in state not found: {}", id); + continue; + } + }; + // This check is in case a bad user ID made it into the database + if let Ok(uid) = UserId::parse(&state_key) { + lazy_loaded.insert(uid); + } state_events.push(pdu); - tokio::task::yield_now().await; + + i += 1; + if i % 100 == 0 { + tokio::task::yield_now().await; + } } } - } - for (_, event) in &timeline_pdus { - if lazy_loaded.contains(&event.sender) { - continue; - } + // Reset lazy loading because this is an initial sync + services().rooms.lazy_loading.lazy_load_reset( + &sender_user, + &sender_device, + &room_id, + )?; - if !services().rooms.lazy_loading.lazy_load_was_sent_before( + // The state_events above should contain all timeline_users, let's mark them as lazy + // loaded. + services().rooms.lazy_loading.lazy_load_mark_sent( &sender_user, &sender_device, &room_id, - &event.sender, - )? || lazy_load_send_redundant - { - if let Some(member_event) = services().rooms.state_accessor.room_state_get( - &room_id, - &StateEventType::RoomMember, - event.sender.as_str(), - )? { - lazy_loaded.insert(event.sender.clone()); - state_events.push(member_event); + lazy_loaded, + next_batchcount, + ); + + ( + heroes, + joined_member_count, + invited_member_count, + true, + state_events, + ) + } else { + // Incremental /sync + let since_shortstatehash = since_shortstatehash.unwrap(); + + let mut state_events = Vec::new(); + let mut lazy_loaded = HashSet::new(); + + if since_shortstatehash != current_shortstatehash { + let current_state_ids = services() + .rooms + .state_accessor + .state_full_ids(current_shortstatehash) + .await?; + let since_state_ids = services() + .rooms + .state_accessor + .state_full_ids(since_shortstatehash) + .await?; + + for (key, id) in current_state_ids { + if full_state || since_state_ids.get(&key) != Some(&id) { + let pdu = match services().rooms.timeline.get_pdu(&id)? { + Some(pdu) => pdu, + None => { + error!("Pdu in state not found: {}", id); + continue; + } + }; + + if pdu.kind == TimelineEventType::RoomMember { + match UserId::parse( + pdu.state_key + .as_ref() + .expect("State event has state key") + .clone(), + ) { + Ok(state_key_userid) => { + lazy_loaded.insert(state_key_userid); + } + Err(e) => error!("Invalid state key for member event: {}", e), + } + } + + state_events.push(pdu); + tokio::task::yield_now().await; + } } } - } - services().rooms.lazy_loading.lazy_load_mark_sent( - &sender_user, - &sender_device, - &room_id, - lazy_loaded, - next_batchcount, - ); + for (_, event) in &timeline_pdus { + if lazy_loaded.contains(&event.sender) { + continue; + } - let encrypted_room = services() - .rooms - .state_accessor - .state_get(current_shortstatehash, &StateEventType::RoomEncryption, "")? - .is_some(); + if !services().rooms.lazy_loading.lazy_load_was_sent_before( + &sender_user, + &sender_device, + &room_id, + &event.sender, + )? || lazy_load_send_redundant + { + if let Some(member_event) = services().rooms.state_accessor.room_state_get( + &room_id, + &StateEventType::RoomMember, + event.sender.as_str(), + )? { + lazy_loaded.insert(event.sender.clone()); + state_events.push(member_event); + } + } + } - let since_encryption = services().rooms.state_accessor.state_get( - since_shortstatehash, - &StateEventType::RoomEncryption, - "", - )?; + services().rooms.lazy_loading.lazy_load_mark_sent( + &sender_user, + &sender_device, + &room_id, + lazy_loaded, + next_batchcount, + ); - // Calculations: - let new_encrypted_room = encrypted_room && since_encryption.is_none(); + let encrypted_room = services() + .rooms + .state_accessor + .state_get(current_shortstatehash, &StateEventType::RoomEncryption, "")? + .is_some(); - let send_member_count = state_events - .iter() - .any(|event| event.kind == TimelineEventType::RoomMember); + let since_encryption = services().rooms.state_accessor.state_get( + since_shortstatehash, + &StateEventType::RoomEncryption, + "", + )?; - if encrypted_room { - for state_event in &state_events { - if state_event.kind != TimelineEventType::RoomMember { - continue; - } + // Calculations: + let new_encrypted_room = encrypted_room && since_encryption.is_none(); - if let Some(state_key) = &state_event.state_key { - let user_id = UserId::parse(state_key.clone()) - .map_err(|_| Error::bad_database("Invalid UserId in member PDU."))?; + let send_member_count = state_events + .iter() + .any(|event| event.kind == TimelineEventType::RoomMember); - if user_id == sender_user { + if encrypted_room { + for state_event in &state_events { + if state_event.kind != TimelineEventType::RoomMember { continue; } - let new_membership = serde_json::from_str::( - state_event.content.get(), - ) - .map_err(|_| Error::bad_database("Invalid PDU in database."))? - .membership; - - match new_membership { - MembershipState::Join => { - // A new user joined an encrypted room - if !share_encrypted_room(&sender_user, &user_id, &room_id)? { - device_list_updates.insert(user_id); - } + if let Some(state_key) = &state_event.state_key { + let user_id = UserId::parse(state_key.clone()).map_err(|_| { + Error::bad_database("Invalid UserId in member PDU.") + })?; + + if user_id == sender_user { + continue; } - MembershipState::Leave => { - // Write down users that have left encrypted rooms we are in - left_encrypted_users.insert(user_id); + + let new_membership = serde_json::from_str::( + state_event.content.get(), + ) + .map_err(|_| Error::bad_database("Invalid PDU in database."))? + .membership; + + match new_membership { + MembershipState::Join => { + // A new user joined an encrypted room + if !share_encrypted_room(&sender_user, &user_id, &room_id)? { + device_list_updates.insert(user_id); + } + } + MembershipState::Leave => { + // Write down users that have left encrypted rooms we are in + left_encrypted_users.insert(user_id); + } + _ => {} } - _ => {} } } } - } - - if joined_since_last_sync && encrypted_room || new_encrypted_room { - // If the user is in a new encrypted room, give them all joined users - device_list_updates.extend( - services() - .rooms - .state_cache - .room_members(&room_id) - .flatten() - .filter(|user_id| { - // Don't send key updates from the sender to the sender - &sender_user != user_id - }) - .filter(|user_id| { - // Only send keys if the sender doesn't share an encrypted room with the target already - !share_encrypted_room(&sender_user, user_id, &room_id).unwrap_or(false) - }), - ); - } - let (joined_member_count, invited_member_count, heroes) = if send_member_count { - calculate_counts()? - } else { - (None, None, Vec::new()) - }; + if joined_since_last_sync && encrypted_room || new_encrypted_room { + // If the user is in a new encrypted room, give them all joined users + device_list_updates.extend( + services() + .rooms + .state_cache + .room_members(&room_id) + .flatten() + .filter(|user_id| { + // Don't send key updates from the sender to the sender + &sender_user != user_id + }) + .filter(|user_id| { + // Only send keys if the sender doesn't share an encrypted room with the target already + !share_encrypted_room(&sender_user, user_id, &room_id) + .unwrap_or(false) + }), + ); + } - ( - heroes, - joined_member_count, - invited_member_count, - joined_since_last_sync, - state_events, - ) + let (joined_member_count, invited_member_count, heroes) = if send_member_count { + calculate_counts()? + } else { + (None, None, Vec::new()) + }; + + ( + heroes, + joined_member_count, + invited_member_count, + joined_since_last_sync, + state_events, + ) + } }; // Look for device list updates in this room diff --git a/src/config/mod.rs b/src/config/mod.rs index 31a586f..f922282 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -224,7 +224,7 @@ fn default_database_backend() -> String { } fn default_db_cache_capacity_mb() -> f64 { - 1000.0 + 300.0 } fn default_conduit_cache_capacity_modifier() -> f64 { diff --git a/src/database/abstraction.rs b/src/database/abstraction.rs index 93660f9..0a32105 100644 --- a/src/database/abstraction.rs +++ b/src/database/abstraction.rs @@ -38,6 +38,7 @@ pub trait KeyValueDatabaseEngine: Send + Sync { fn memory_usage(&self) -> Result { Ok("Current database engine does not support memory usage reporting.".to_owned()) } + fn clear_caches(&self) {} } pub trait KvTree: Send + Sync { diff --git a/src/database/abstraction/rocksdb.rs b/src/database/abstraction/rocksdb.rs index 3e64e8b..f0b5f2a 100644 --- a/src/database/abstraction/rocksdb.rs +++ b/src/database/abstraction/rocksdb.rs @@ -45,6 +45,10 @@ fn db_options(max_open_files: i32, rocksdb_cache: &rocksdb::Cache) -> rocksdb::O db_opts.set_compaction_style(rocksdb::DBCompactionStyle::Level); db_opts.optimize_level_style_compaction(10 * 1024 * 1024); + // https://github.com/facebook/rocksdb/wiki/Setup-Options-and-Basic-Tuning + db_opts.set_max_background_jobs(6); + db_opts.set_bytes_per_sync(1048576); + let prefix_extractor = rocksdb::SliceTransform::create_fixed_prefix(1); db_opts.set_prefix_extractor(prefix_extractor); @@ -121,6 +125,8 @@ impl KeyValueDatabaseEngine for Arc { self.cache.get_pinned_usage() as f64 / 1024.0 / 1024.0, )) } + + fn clear_caches(&self) {} } impl RocksDbEngineTree<'_> { diff --git a/src/database/key_value/globals.rs b/src/database/key_value/globals.rs index 7b7675c..ab3dfe0 100644 --- a/src/database/key_value/globals.rs +++ b/src/database/key_value/globals.rs @@ -118,8 +118,59 @@ impl service::globals::Data for KeyValueDatabase { self._db.cleanup() } - fn memory_usage(&self) -> Result { - self._db.memory_usage() + fn memory_usage(&self) -> String { + let pdu_cache = self.pdu_cache.lock().unwrap().len(); + let shorteventid_cache = self.shorteventid_cache.lock().unwrap().len(); + let auth_chain_cache = self.auth_chain_cache.lock().unwrap().len(); + let eventidshort_cache = self.eventidshort_cache.lock().unwrap().len(); + let statekeyshort_cache = self.statekeyshort_cache.lock().unwrap().len(); + let our_real_users_cache = self.our_real_users_cache.read().unwrap().len(); + let appservice_in_room_cache = self.appservice_in_room_cache.read().unwrap().len(); + let lasttimelinecount_cache = self.lasttimelinecount_cache.lock().unwrap().len(); + + let mut response = format!( + "\ +pdu_cache: {pdu_cache} +shorteventid_cache: {shorteventid_cache} +auth_chain_cache: {auth_chain_cache} +eventidshort_cache: {eventidshort_cache} +statekeyshort_cache: {statekeyshort_cache} +our_real_users_cache: {our_real_users_cache} +appservice_in_room_cache: {appservice_in_room_cache} +lasttimelinecount_cache: {lasttimelinecount_cache}\n" + ); + if let Ok(db_stats) = self._db.memory_usage() { + response += &db_stats; + } + + response + } + + fn clear_caches(&self, amount: u32) { + if amount > 0 { + self.pdu_cache.lock().unwrap().clear(); + } + if amount > 1 { + self.shorteventid_cache.lock().unwrap().clear(); + } + if amount > 2 { + self.auth_chain_cache.lock().unwrap().clear(); + } + if amount > 3 { + self.eventidshort_cache.lock().unwrap().clear(); + } + if amount > 4 { + self.statekeyshort_cache.lock().unwrap().clear(); + } + if amount > 5 { + self.our_real_users_cache.write().unwrap().clear(); + } + if amount > 6 { + self.appservice_in_room_cache.write().unwrap().clear(); + } + if amount > 7 { + self.lasttimelinecount_cache.lock().unwrap().clear(); + } } fn load_keypair(&self) -> Result { diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index d37ec69..9250a3e 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -134,7 +134,13 @@ enum AdminCommand { }, /// Print database memory usage statistics - DatabaseMemoryUsage, + MemoryUsage, + + /// Clears all of Conduit's database caches with index smaller than the amount + ClearDatabaseCaches { amount: u32 }, + + /// Clears all of Conduit's service caches with index smaller than the amount + ClearServiceCaches { amount: u32 }, /// Show configuration values ShowConfig, @@ -531,12 +537,24 @@ impl Service { None => RoomMessageEventContent::text_plain("PDU not found."), } } - AdminCommand::DatabaseMemoryUsage => match services().globals.db.memory_usage() { - Ok(response) => RoomMessageEventContent::text_plain(response), - Err(e) => RoomMessageEventContent::text_plain(format!( - "Failed to get database memory usage: {e}" - )), - }, + AdminCommand::MemoryUsage => { + let response1 = services().memory_usage(); + let response2 = services().globals.db.memory_usage(); + + RoomMessageEventContent::text_plain(format!( + "Services:\n{response1}\n\nDatabase:\n{response2}" + )) + } + AdminCommand::ClearDatabaseCaches { amount } => { + services().globals.db.clear_caches(amount); + + RoomMessageEventContent::text_plain("Done.") + } + AdminCommand::ClearServiceCaches { amount } => { + services().clear_caches(amount); + + RoomMessageEventContent::text_plain("Done.") + } AdminCommand::ShowConfig => { // Construct and send the response RoomMessageEventContent::text_plain(format!("{}", services().globals.config)) diff --git a/src/service/globals/data.rs b/src/service/globals/data.rs index 04371a0..171b3fe 100644 --- a/src/service/globals/data.rs +++ b/src/service/globals/data.rs @@ -15,7 +15,8 @@ pub trait Data: Send + Sync { fn current_count(&self) -> Result; async fn watch(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()>; fn cleanup(&self) -> Result<()>; - fn memory_usage(&self) -> Result; + fn memory_usage(&self) -> String; + fn clear_caches(&self, amount: u32); fn load_keypair(&self) -> Result; fn remove_keypair(&self) -> Result<()>; fn add_signing_key( diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index 9206d43..e4affde 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -214,10 +214,6 @@ impl Service { self.db.cleanup() } - pub fn memory_usage(&self) -> Result { - self.db.memory_usage() - } - pub fn server_name(&self) -> &ServerName { self.config.server_name.as_ref() } diff --git a/src/service/mod.rs b/src/service/mod.rs index dfdc5a6..56aed7f 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -90,7 +90,7 @@ impl Services { state_compressor: rooms::state_compressor::Service { db, stateinfo_cache: Mutex::new(LruCache::new( - (300.0 * config.conduit_cache_capacity_modifier) as usize, + (100.0 * config.conduit_cache_capacity_modifier) as usize, )), }, timeline: rooms::timeline::Service { @@ -115,4 +115,109 @@ impl Services { globals: globals::Service::load(db, config)?, }) } + fn memory_usage(&self) -> String { + let lazy_load_waiting = self + .rooms + .lazy_loading + .lazy_load_waiting + .lock() + .unwrap() + .len(); + let server_visibility_cache = self + .rooms + .state_accessor + .server_visibility_cache + .lock() + .unwrap() + .len(); + let user_visibility_cache = self + .rooms + .state_accessor + .user_visibility_cache + .lock() + .unwrap() + .len(); + let stateinfo_cache = self + .rooms + .state_compressor + .stateinfo_cache + .lock() + .unwrap() + .len(); + let lasttimelinecount_cache = self + .rooms + .timeline + .lasttimelinecount_cache + .lock() + .unwrap() + .len(); + let roomid_spacechunk_cache = self + .rooms + .spaces + .roomid_spacechunk_cache + .lock() + .unwrap() + .len(); + + format!( + "\ +lazy_load_waiting: {lazy_load_waiting} +server_visibility_cache: {server_visibility_cache} +user_visibility_cache: {user_visibility_cache} +stateinfo_cache: {stateinfo_cache} +lasttimelinecount_cache: {lasttimelinecount_cache} +roomid_spacechunk_cache: {roomid_spacechunk_cache}\ + " + ) + } + fn clear_caches(&self, amount: u32) { + if amount > 0 { + self.rooms + .lazy_loading + .lazy_load_waiting + .lock() + .unwrap() + .clear(); + } + if amount > 1 { + self.rooms + .state_accessor + .server_visibility_cache + .lock() + .unwrap() + .clear(); + } + if amount > 2 { + self.rooms + .state_accessor + .user_visibility_cache + .lock() + .unwrap() + .clear(); + } + if amount > 3 { + self.rooms + .state_compressor + .stateinfo_cache + .lock() + .unwrap() + .clear(); + } + if amount > 4 { + self.rooms + .timeline + .lasttimelinecount_cache + .lock() + .unwrap() + .clear(); + } + if amount > 5 { + self.rooms + .spaces + .roomid_spacechunk_cache + .lock() + .unwrap() + .clear(); + } + } } -- cgit v1.2.3 From c4824a6ebcb7bb72528d87b26b7e3fb19c01212d Mon Sep 17 00:00:00 2001 From: Jonas Zohren Date: Tue, 4 Jul 2023 21:13:11 +0000 Subject: ci: Fix "0 B" image size display works around gitlab issue https://gitlab.com/gitlab-org/gitlab/-/issues/388865#workaround --- .gitlab-ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d2da91b..f5ab424 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,6 +41,7 @@ variables: --pull --tag "$CI_REGISTRY_IMAGE/temporary-ci-images:$CI_JOB_ID" --push + --provenance=false --file "Dockerfile" . # Build multiplatform image to deb stage and extract their .deb files: - > @@ -48,6 +49,7 @@ variables: --platform "linux/arm/v7,linux/arm64,linux/amd64" --target "packager-result" --output="type=local,dest=/tmp/build-output" + --provenance=false --file "Dockerfile" . # Build multiplatform image to binary stage and extract their binaries: - > @@ -55,6 +57,7 @@ variables: --platform "linux/arm/v7,linux/arm64,linux/amd64" --target "builder-result" --output="type=local,dest=/tmp/build-output" + --provenance=false --file "Dockerfile" . # Copy to GitLab container registry: - > -- cgit v1.2.3 From e4f769963fb880d6131ae940f89ab9b1193c5d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 6 Jul 2023 10:32:25 +0200 Subject: feat: very simple sliding sync implementation --- Cargo.lock | 22 +-- Cargo.toml | 6 +- README.md | 2 +- src/api/client_server/directory.rs | 12 +- src/api/client_server/sync.rs | 270 +++++++++++++++++++++++++++----- src/api/client_server/unversioned.rs | 20 ++- src/config/mod.rs | 1 + src/main.rs | 1 + src/service/globals/mod.rs | 4 + src/service/pusher/mod.rs | 16 +- src/service/rooms/spaces/mod.rs | 10 +- src/service/rooms/state_accessor/mod.rs | 13 ++ 12 files changed, 284 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4148394..487780d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2111,7 +2111,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "assign", "js_int", @@ -2129,7 +2129,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.8.1" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "js_int", "ruma-common", @@ -2140,7 +2140,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "assign", "bytes", @@ -2157,7 +2157,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "base64 0.21.2", "bytes", @@ -2185,7 +2185,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "js_int", "ruma-common", @@ -2196,7 +2196,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "js_int", "thiserror", @@ -2205,7 +2205,7 @@ dependencies = [ [[package]] name = "ruma-identity-service-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "js_int", "ruma-common", @@ -2215,7 +2215,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "once_cell", "proc-macro-crate", @@ -2230,7 +2230,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "js_int", "ruma-common", @@ -2241,7 +2241,7 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.13.1" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "base64 0.21.2", "ed25519-dalek", @@ -2257,7 +2257,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=38294bd5206498c02b1001227d65654eb548308b#38294bd5206498c02b1001227d65654eb548308b" +source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" dependencies = [ "itertools", "js_int", diff --git a/Cargo.toml b/Cargo.toml index bc29c5a..a01f410 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,9 +26,9 @@ tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitiv # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -ruma = { git = "https://github.com/ruma/ruma", rev = "38294bd5206498c02b1001227d65654eb548308b", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } -#ruma = { git = "https://github.com/timokoesters/ruma", rev = "50c1db7e0a3a21fc794b0cce3b64285a4c750c71", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -#ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } +#ruma = { git = "https://github.com/ruma/ruma", rev = "38294bd5206498c02b1001227d65654eb548308b", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +ruma = { git = "https://github.com/timokoesters/ruma", rev = "4ec9c69bb7e09391add2382b3ebac97b6e8f4c64", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +#ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } # Async runtime and utilities tokio = { version = "1.28.1", features = ["fs", "macros", "signal", "sync"] } diff --git a/README.md b/README.md index f73f6aa..8fabefd 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Thanks to the contributors to Conduit and all libraries we use, for example: If you run into any question, feel free to - Ask us in `#conduit:fachschaften.org` on Matrix - Write an E-Mail to `conduit@koesters.xyz` -- Send an direct message to `timo@fachschaften.org` on Matrix +- Send an direct message to `timokoesters@fachschaften.org` on Matrix - [Open an issue on GitLab](https://gitlab.com/famedly/conduit/-/issues/new) #### Donate diff --git a/src/api/client_server/directory.rs b/src/api/client_server/directory.rs index e132210..df1ac40 100644 --- a/src/api/client_server/directory.rs +++ b/src/api/client_server/directory.rs @@ -203,17 +203,7 @@ pub(crate) async fn get_public_rooms_filtered_helper( Error::bad_database("Invalid canonical alias event in database.") }) })?, - name: services() - .rooms - .state_accessor - .room_state_get(&room_id, &StateEventType::RoomName, "")? - .map_or(Ok(None), |s| { - serde_json::from_str(s.content.get()) - .map(|c: RoomNameEventContent| c.name) - .map_err(|_| { - Error::bad_database("Invalid room name event in database.") - }) - })?, + name: services().rooms.state_accessor.get_name(&room_id)?, num_joined_members: services() .rooms .state_cache diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index dd75347..bc89a4c 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -1,4 +1,6 @@ -use crate::{service::rooms::timeline::PduCount, services, Error, Result, Ruma, RumaResponse}; +use crate::{ + service::rooms::timeline::PduCount, services, Error, PduEvent, Result, Ruma, RumaResponse, +}; use ruma::{ api::client::{ filter::{FilterDefinition, LazyLoadOptions}, @@ -8,6 +10,7 @@ use ruma::{ Ephemeral, Filter, GlobalAccountData, InviteState, InvitedRoom, JoinedRoom, LeftRoom, Presence, RoomAccountData, RoomSummary, Rooms, State, Timeline, ToDevice, }, + v4::SlidingOp, DeviceLists, UnreadNotificationsCount, }, uiaa::UiaaResponse, @@ -17,10 +20,10 @@ use ruma::{ StateEventType, TimelineEventType, }, serde::Raw, - DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UserId, + uint, DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UInt, UserId, }; use std::{ - collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, + collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, sync::Arc, time::Duration, }; @@ -199,7 +202,7 @@ async fn sync_helper( let mut joined_rooms = BTreeMap::new(); let since = body .since - .clone() + .as_ref() .and_then(|string| string.parse().ok()) .unwrap_or(0); let sincecount = PduCount::Normal(since); @@ -581,43 +584,7 @@ async fn load_joined_room( drop(insert_lock); } - let timeline_pdus; - let limited; - if services() - .rooms - .timeline - .last_timeline_count(&sender_user, &room_id)? - > sincecount - { - let mut non_timeline_pdus = services() - .rooms - .timeline - .pdus_until(&sender_user, &room_id, PduCount::max())? - .filter_map(|r| { - // Filter out buggy events - if r.is_err() { - error!("Bad pdu in pdus_since: {:?}", r); - } - r.ok() - }) - .take_while(|(pducount, _)| pducount > &sincecount); - - // Take the last 10 events for the timeline - timeline_pdus = non_timeline_pdus - .by_ref() - .take(10) - .collect::>() - .into_iter() - .rev() - .collect::>(); - - // They /sync response doesn't always return all messages, so we say the output is - // limited unless there are events in non_timeline_pdus - limited = non_timeline_pdus.next().is_some(); - } else { - timeline_pdus = Vec::new(); - limited = false; - } + let (timeline_pdus, limited) = load_timeline(sender_user, room_id, sincecount, 10)?; let send_notification_counts = !timeline_pdus.is_empty() || services() @@ -1132,6 +1099,52 @@ async fn load_joined_room( }) } +fn load_timeline( + sender_user: &UserId, + room_id: &RoomId, + sincecount: PduCount, + limit: u64, +) -> Result<(Vec<(PduCount, PduEvent)>, bool), Error> { + let timeline_pdus; + let limited; + if services() + .rooms + .timeline + .last_timeline_count(&sender_user, &room_id)? + > sincecount + { + let mut non_timeline_pdus = services() + .rooms + .timeline + .pdus_until(&sender_user, &room_id, PduCount::max())? + .filter_map(|r| { + // Filter out buggy events + if r.is_err() { + error!("Bad pdu in pdus_since: {:?}", r); + } + r.ok() + }) + .take_while(|(pducount, _)| pducount > &sincecount); + + // Take the last events for the timeline + timeline_pdus = non_timeline_pdus + .by_ref() + .take(limit as usize) + .collect::>() + .into_iter() + .rev() + .collect::>(); + + // They /sync response doesn't always return all messages, so we say the output is + // limited unless there are events in non_timeline_pdus + limited = non_timeline_pdus.next().is_some(); + } else { + timeline_pdus = Vec::new(); + limited = false; + } + Ok((timeline_pdus, limited)) +} + fn share_encrypted_room( sender_user: &UserId, user_id: &UserId, @@ -1155,3 +1168,178 @@ fn share_encrypted_room( }) .any(|encrypted| encrypted)) } + +pub async fn sync_events_v4_route( + body: Ruma, +) -> Result> { + let sender_user = body.sender_user.expect("user is authenticated"); + let sender_device = body.sender_device.expect("user is authenticated"); + let body = dbg!(body.body); + + // Setup watchers, so if there's no response, we can wait for them + let watcher = services().globals.watch(&sender_user, &sender_device); + + let next_batch = services().globals.current_count()?; + + let since = body + .pos + .as_ref() + .and_then(|string| string.parse().ok()) + .unwrap_or(0); + let sincecount = PduCount::Normal(since); + + let initial = since == 0; + + let all_joined_rooms = services() + .rooms + .state_cache + .rooms_joined(&sender_user) + .filter_map(|r| r.ok()) + .collect::>(); + + let mut lists = BTreeMap::new(); + let mut todo_rooms = BTreeMap::new(); // and required state + + for (list_id, list) in body.lists { + if list.filters.and_then(|f| f.is_invite).unwrap_or(false) { + continue; + } + + lists.insert( + list_id, + sync_events::v4::SyncList { + ops: list + .ranges + .into_iter() + .map(|mut r| { + r.0 = + r.0.clamp(uint!(0), UInt::from(all_joined_rooms.len() as u32 - 1)); + r.1 = + r.1.clamp(r.0, UInt::from(all_joined_rooms.len() as u32 - 1)); + let room_ids = all_joined_rooms + [(u64::from(r.0) as usize)..=(u64::from(r.1) as usize)] + .to_vec(); + todo_rooms.extend(room_ids.iter().cloned().map(|r| { + let limit = list + .room_details + .timeline_limit + .map_or(10, u64::from) + .min(100); + (r, (list.room_details.required_state.clone(), limit)) + })); + sync_events::v4::SyncOp { + op: SlidingOp::Sync, + range: Some(r.clone()), + index: None, + room_ids, + room_id: None, + } + }) + .collect(), + count: UInt::from(all_joined_rooms.len() as u32), + }, + ); + } + + let mut rooms = BTreeMap::new(); + for (room_id, (required_state_request, timeline_limit)) in todo_rooms { + let (timeline_pdus, limited) = + load_timeline(&sender_user, &room_id, sincecount, timeline_limit)?; + + let room_events: Vec<_> = timeline_pdus + .iter() + .map(|(_, pdu)| pdu.to_sync_room_event()) + .collect(); + + let required_state = required_state_request + .iter() + .map(|state| { + services() + .rooms + .state_accessor + .room_state_get(&room_id, &state.0, &state.1) + }) + .filter_map(|r| r.ok()) + .filter_map(|o| o) + .map(|state| state.to_sync_state_event()) + .collect(); + + rooms.insert( + room_id.clone(), + sync_events::v4::SlidingSyncRoom { + name: services().rooms.state_accessor.get_name(&room_id)?, + initial: Some(initial), + is_dm: None, + invite_state: None, + unread_notifications: UnreadNotificationsCount { + highlight_count: None, + notification_count: None, + }, + timeline: room_events, + required_state, + prev_batch: None, + limited, + joined_count: Some( + (services() + .rooms + .state_cache + .room_joined_count(&room_id)? + .unwrap_or(0) as u32) + .into(), + ), + invited_count: Some( + (services() + .rooms + .state_cache + .room_invited_count(&room_id)? + .unwrap_or(0) as u32) + .into(), + ), + num_live: None, + }, + ); + } + + if rooms + .iter() + .all(|(_, r)| r.timeline.is_empty() && r.required_state.is_empty()) + { + // Hang a few seconds so requests are not spammed + // Stop hanging if new info arrives + let mut duration = body.timeout.unwrap_or(Duration::from_secs(30)); + if duration.as_secs() > 30 { + duration = Duration::from_secs(30); + } + let _ = tokio::time::timeout(duration, watcher).await; + } + + Ok(dbg!(sync_events::v4::Response { + initial: initial, + txn_id: body.txn_id.clone(), + pos: next_batch.to_string(), + lists, + rooms, + extensions: sync_events::v4::Extensions { + to_device: None, + e2ee: sync_events::v4::E2EE { + device_lists: DeviceLists { + changed: Vec::new(), + left: Vec::new(), + }, + device_one_time_keys_count: BTreeMap::new(), + device_unused_fallback_key_types: None, + }, + account_data: sync_events::v4::AccountData { + global: Vec::new(), + rooms: BTreeMap::new(), + }, + receipts: sync_events::v4::Receipts { + rooms: BTreeMap::new(), + }, + typing: sync_events::v4::Typing { + rooms: BTreeMap::new(), + }, + }, + delta_token: None, + })) +} diff --git a/src/api/client_server/unversioned.rs b/src/api/client_server/unversioned.rs index b4f03f4..797b952 100644 --- a/src/api/client_server/unversioned.rs +++ b/src/api/client_server/unversioned.rs @@ -1,8 +1,9 @@ use std::{collections::BTreeMap, iter::FromIterator}; -use ruma::api::client::discovery::get_supported_versions; +use axum::{response::IntoResponse, Json}; +use ruma::api::client::{discovery::get_supported_versions, error::ErrorKind}; -use crate::{Result, Ruma}; +use crate::{services, Error, Result, Ruma}; /// # `GET /_matrix/client/versions` /// @@ -31,3 +32,18 @@ pub async fn get_supported_versions_route( Ok(resp) } + +/// # `GET /.well-known/matrix/client` +pub async fn well_known_client_route( + _body: Ruma, +) -> Result { + let client_url = match services().globals.well_known_client() { + Some(url) => url.clone(), + None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")), + }; + + Ok(Json(serde_json::json!({ + "m.homeserver": {"base_url": client_url}, + "org.matrix.msc3575.proxy": {"url": client_url} + }))) +} diff --git a/src/config/mod.rs b/src/config/mod.rs index f922282..4dad9f7 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -54,6 +54,7 @@ pub struct Config { pub allow_unstable_room_versions: bool, #[serde(default = "default_default_room_version")] pub default_room_version: RoomVersionId, + pub well_known_client: Option, #[serde(default = "false_fn")] pub allow_jaeger: bool, #[serde(default = "false_fn")] diff --git a/src/main.rs b/src/main.rs index ea5572e..579eeb1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -357,6 +357,7 @@ fn routes() -> Router { .put(client_server::send_state_event_for_empty_key_route), ) .ruma_route(client_server::sync_events_route) + .ruma_route(client_server::sync_events_v4_route) .ruma_route(client_server::get_context_route) .ruma_route(client_server::get_message_events_route) .ruma_route(client_server::search_events_route) diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index e4affde..5326b7a 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -342,6 +342,10 @@ impl Service { r } + pub fn well_known_client(&self) -> &Option { + &self.config.well_known_client + } + pub fn shutdown(&self) { self.shutdown.store(true, atomic::Ordering::Relaxed); // On shutdown diff --git a/src/service/pusher/mod.rs b/src/service/pusher/mod.rs index d4acaa5..5e4281d 100644 --- a/src/service/pusher/mod.rs +++ b/src/service/pusher/mod.rs @@ -270,21 +270,7 @@ impl Service { notifi.sender_display_name = services().users.displayname(&event.sender)?; - let room_name = if let Some(room_name_pdu) = services() - .rooms - .state_accessor - .room_state_get(&event.room_id, &StateEventType::RoomName, "")? - { - serde_json::from_str::(room_name_pdu.content.get()) - .map_err(|_| { - Error::bad_database("Invalid room name event in database.") - })? - .name - } else { - None - }; - - notifi.room_name = room_name; + notifi.room_name = services().rooms.state_accessor.get_name(&event.room_id)?; self.send_request(&http.url, send_event_notification::v1::Request::new(notifi)) .await?; diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index 76ba6c5..380f86c 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -273,15 +273,7 @@ impl Service { Error::bad_database("Invalid canonical alias event in database.") }) })?, - name: services() - .rooms - .state_accessor - .room_state_get(&room_id, &StateEventType::RoomName, "")? - .map_or(Ok(None), |s| { - serde_json::from_str(s.content.get()) - .map(|c: RoomNameEventContent| c.name) - .map_err(|_| Error::bad_database("Invalid room name event in database.")) - })?, + name: services().rooms.state_accessor.get_name(&room_id)?, num_joined_members: services() .rooms .state_cache diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index a25a8b5..9d071a5 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -11,6 +11,7 @@ use ruma::{ room::{ history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, member::{MembershipState, RoomMemberEventContent}, + name::RoomNameEventContent, }, StateEventType, }, @@ -269,4 +270,16 @@ impl Service { ) -> Result>> { self.db.room_state_get(room_id, event_type, state_key) } + + pub fn get_name(&self, room_id: &RoomId) -> Result> { + services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomName, "")? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomNameEventContent| c.name) + .map_err(|_| Error::bad_database("Invalid room name event in database.")) + }) + } } -- cgit v1.2.3 From 4b7d3e24dd0f8d1d9db2f7ba3ea2103a880a215c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 10 Jul 2023 16:24:57 +0200 Subject: bump ruma --- Cargo.lock | 63 +++++++++++++++++++++++++++++++++++++++----------------------- Cargo.toml | 4 ++-- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 487780d..3480c01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -422,6 +422,12 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +[[package]] +name = "const_panic" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1167,7 +1173,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -1178,6 +1183,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", "hashbrown 0.14.0", + "serde", ] [[package]] @@ -1212,9 +1218,9 @@ checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] @@ -1283,25 +1289,30 @@ dependencies = [ [[package]] name = "konst" -version = "0.2.19" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f0e13e6483b8c34885f7e6c9f19b1a7bd449c673fbb948a51c99d66ef74f4" +checksum = "1d9a8bb6c7c71d151b25936b03e012a4c00daea99e3a3797c6ead66b0a0d55e2" dependencies = [ - "konst_macro_rules", + "const_panic", + "konst_kernel", "konst_proc_macros", + "typewit", ] [[package]] -name = "konst_macro_rules" -version = "0.2.19" +name = "konst_kernel" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" +checksum = "55d2ab266022e7309df89ed712bddc753e3a3c395c3ced1bb2e4470ec2a8146d" +dependencies = [ + "typewit", +] [[package]] name = "konst_proc_macros" -version = "0.2.11" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984e109462d46ad18314f10e392c286c3d47bce203088a09012de1015b45b737" +checksum = "4e28ab1dc35e09d60c2b8c90d12a9a8d9666c876c10a3739a3196db0103b6043" [[package]] name = "lazy_static" @@ -2111,7 +2122,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "assign", "js_int", @@ -2129,7 +2140,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.8.1" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "js_int", "ruma-common", @@ -2140,7 +2151,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "assign", "bytes", @@ -2157,13 +2168,13 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "base64 0.21.2", "bytes", "form_urlencoded", "http", - "indexmap 1.9.3", + "indexmap 2.0.0", "js_int", "js_option", "konst", @@ -2185,7 +2196,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "js_int", "ruma-common", @@ -2196,7 +2207,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "js_int", "thiserror", @@ -2205,7 +2216,7 @@ dependencies = [ [[package]] name = "ruma-identity-service-api" version = "0.7.1" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "js_int", "ruma-common", @@ -2215,7 +2226,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "once_cell", "proc-macro-crate", @@ -2230,7 +2241,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "js_int", "ruma-common", @@ -2241,7 +2252,7 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.13.1" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "base64 0.21.2", "ed25519-dalek", @@ -2257,7 +2268,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.9.1" -source = "git+https://github.com/timokoesters/ruma?rev=4ec9c69bb7e09391add2382b3ebac97b6e8f4c64#4ec9c69bb7e09391add2382b3ebac97b6e8f4c64" +source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" dependencies = [ "itertools", "js_int", @@ -3152,6 +3163,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "typewit" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4061a10d4d8f3081a8ccc025182afd8434302d8d4b4503ec6d8510d09df08c2d" + [[package]] name = "uncased" version = "0.9.9" diff --git a/Cargo.toml b/Cargo.toml index a01f410..ae7de59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,8 +26,8 @@ tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitiv # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -#ruma = { git = "https://github.com/ruma/ruma", rev = "38294bd5206498c02b1001227d65654eb548308b", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } -ruma = { git = "https://github.com/timokoesters/ruma", rev = "4ec9c69bb7e09391add2382b3ebac97b6e8f4c64", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +ruma = { git = "https://github.com/ruma/ruma", rev = "07bc06038fded40d4e9180637f056d256f9a1fbc", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +#ruma = { git = "https://github.com/timokoesters/ruma", rev = "4ec9c69bb7e09391add2382b3ebac97b6e8f4c64", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } #ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } # Async runtime and utilities -- cgit v1.2.3 From 78e7b711df213559150b5c6e7e7da1967d353e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 10 Jul 2023 16:25:33 +0200 Subject: fix: better sliding sync --- src/api/client_server/sync.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index bc89a4c..fed4fb7 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -23,7 +23,7 @@ use ruma::{ uint, DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UInt, UserId, }; use std::{ - collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, + collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, sync::Arc, time::Duration, }; @@ -1246,6 +1246,18 @@ pub async fn sync_events_v4_route( let (timeline_pdus, limited) = load_timeline(&sender_user, &room_id, sincecount, timeline_limit)?; + let prev_batch = timeline_pdus + .first() + .map_or(Ok::<_, Error>(None), |(pdu_count, _)| { + Ok(Some(match pdu_count { + PduCount::Backfilled(_) => { + error!("timeline in backfill state?!"); + "0".to_owned() + } + PduCount::Normal(c) => c.to_string(), + })) + })?; + let room_events: Vec<_> = timeline_pdus .iter() .map(|(_, pdu)| pdu.to_sync_room_event()) @@ -1277,7 +1289,7 @@ pub async fn sync_events_v4_route( }, timeline: room_events, required_state, - prev_batch: None, + prev_batch, limited, joined_count: Some( (services() -- cgit v1.2.3 From c17187777f5f3bb06183ce423d990bc1c1061929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 10 Jul 2023 16:26:36 +0200 Subject: fix: never try federation with self --- src/api/server_server.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index adb5f1f..0177f2a 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -123,6 +123,12 @@ where return Err(Error::bad_config("Federation is disabled.")); } + if destination == services().globals.server_name() { + return Err(Error::bad_config( + "Won't send federation request to ourselves", + )); + } + debug!("Preparing to send request to {destination}"); let mut write_destination_to_cache = false; -- cgit v1.2.3 From edd4a3733fb6cf842155441eef86435efdd1cc21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 10 Jul 2023 16:27:42 +0200 Subject: fix: actually clear memory in the admin commands --- src/database/key_value/globals.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/database/key_value/globals.rs b/src/database/key_value/globals.rs index ab3dfe0..1e02459 100644 --- a/src/database/key_value/globals.rs +++ b/src/database/key_value/globals.rs @@ -1,7 +1,8 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use async_trait::async_trait; use futures_util::{stream::FuturesUnordered, StreamExt}; +use lru_cache::LruCache; use ruma::{ api::federation::discovery::{ServerSigningKeys, VerifyKey}, signatures::Ed25519KeyPair, @@ -148,28 +149,36 @@ lasttimelinecount_cache: {lasttimelinecount_cache}\n" fn clear_caches(&self, amount: u32) { if amount > 0 { - self.pdu_cache.lock().unwrap().clear(); + let c = &mut *self.pdu_cache.lock().unwrap(); + *c = LruCache::new(c.capacity()); } if amount > 1 { - self.shorteventid_cache.lock().unwrap().clear(); + let c = &mut *self.shorteventid_cache.lock().unwrap(); + *c = LruCache::new(c.capacity()); } if amount > 2 { - self.auth_chain_cache.lock().unwrap().clear(); + let c = &mut *self.auth_chain_cache.lock().unwrap(); + *c = LruCache::new(c.capacity()); } if amount > 3 { - self.eventidshort_cache.lock().unwrap().clear(); + let c = &mut *self.eventidshort_cache.lock().unwrap(); + *c = LruCache::new(c.capacity()); } if amount > 4 { - self.statekeyshort_cache.lock().unwrap().clear(); + let c = &mut *self.statekeyshort_cache.lock().unwrap(); + *c = LruCache::new(c.capacity()); } if amount > 5 { - self.our_real_users_cache.write().unwrap().clear(); + let c = &mut *self.our_real_users_cache.write().unwrap(); + *c = HashMap::new(); } if amount > 6 { - self.appservice_in_room_cache.write().unwrap().clear(); + let c = &mut *self.appservice_in_room_cache.write().unwrap(); + *c = HashMap::new(); } if amount > 7 { - self.lasttimelinecount_cache.lock().unwrap().clear(); + let c = &mut *self.lasttimelinecount_cache.lock().unwrap(); + *c = HashMap::new(); } } -- cgit v1.2.3 From 0b4e3de9c0135258eb68a0fa3cccdfff45de81d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 10 Jul 2023 16:28:08 +0200 Subject: fix: spaces with restricted rooms --- src/service/rooms/spaces/mod.rs | 125 ++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 51 deletions(-) diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index 380f86c..36fa1fc 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -5,11 +5,10 @@ use ruma::{ api::{ client::{ error::ErrorKind, - space::{get_hierarchy, SpaceHierarchyRoomsChunk, SpaceRoomJoinRule}, + space::{get_hierarchy, SpaceHierarchyRoomsChunk}, }, federation, }, - directory::PublicRoomJoinRule, events::{ room::{ avatar::RoomAvatarEventContent, @@ -18,11 +17,11 @@ use ruma::{ guest_access::{GuestAccess, RoomGuestAccessEventContent}, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, join_rules::{JoinRule, RoomJoinRulesEventContent}, - name::RoomNameEventContent, topic::RoomTopicEventContent, }, StateEventType, }, + space::SpaceRoomJoinRule, OwnedRoomId, RoomId, UserId, }; @@ -30,10 +29,15 @@ use tracing::{debug, error, warn}; use crate::{services, Error, PduEvent, Result}; +pub enum CachedJoinRule { + Simplified(SpaceRoomJoinRule), + Full(JoinRule), +} + pub struct CachedSpaceChunk { chunk: SpaceHierarchyRoomsChunk, children: Vec, - join_rule: JoinRule, + join_rule: CachedJoinRule, } pub struct Service { @@ -79,9 +83,15 @@ impl Service { .as_ref() { if let Some(cached) = cached { - if let Some(_join_rule) = - self.handle_join_rule(&cached.join_rule, sender_user, ¤t_room)? - { + let allowed = match &cached.join_rule { + CachedJoinRule::Simplified(s) => { + self.handle_simplified_join_rule(s, sender_user, ¤t_room)? + } + CachedJoinRule::Full(f) => { + self.handle_join_rule(f, sender_user, ¤t_room)? + } + }; + if allowed { if left_to_skip > 0 { left_to_skip -= 1; } else { @@ -152,7 +162,7 @@ impl Service { Some(CachedSpaceChunk { chunk, children: children_ids.clone(), - join_rule, + join_rule: CachedJoinRule::Full(join_rule), }), ); } @@ -182,7 +192,6 @@ impl Service { .await { warn!("Got response from {server} for /hierarchy\n{response:?}"); - let join_rule = self.translate_pjoinrule(&response.room.join_rule)?; let chunk = SpaceHierarchyRoomsChunk { canonical_alias: response.room.canonical_alias, name: response.room.name, @@ -192,7 +201,7 @@ impl Service { world_readable: response.room.world_readable, guest_can_join: response.room.guest_can_join, avatar_url: response.room.avatar_url, - join_rule: self.translate_sjoinrule(&response.room.join_rule)?, + join_rule: response.room.join_rule.clone(), room_type: response.room.room_type, children_state: response.room.children_state, }; @@ -202,9 +211,11 @@ impl Service { .map(|c| c.room_id.clone()) .collect::>(); - if let Some(_join_rule) = - self.handle_join_rule(&join_rule, sender_user, ¤t_room)? - { + if self.handle_simplified_join_rule( + &response.room.join_rule, + sender_user, + ¤t_room, + )? { if left_to_skip > 0 { left_to_skip -= 1; } else { @@ -220,7 +231,7 @@ impl Service { Some(CachedSpaceChunk { chunk, children, - join_rule, + join_rule: CachedJoinRule::Simplified(response.room.join_rule), }), ); @@ -349,15 +360,17 @@ impl Service { }) .transpose()? .unwrap_or(JoinRule::Invite); - self.handle_join_rule(&join_rule, sender_user, room_id)? - .ok_or_else(|| { - debug!("User is not allowed to see room {room_id}"); - // This error will be caught later - Error::BadRequest( - ErrorKind::Forbidden, - "User is not allowed to see the room", - ) - })? + + if !self.handle_join_rule(&join_rule, sender_user, room_id)? { + debug!("User is not allowed to see room {room_id}"); + // This error will be caught later + return Err(Error::BadRequest( + ErrorKind::Forbidden, + "User is not allowed to see the room", + )); + } + + self.translate_joinrule(&join_rule)? }, room_type: services() .rooms @@ -378,20 +391,35 @@ impl Service { }) } - fn translate_pjoinrule(&self, join_rule: &PublicRoomJoinRule) -> Result { + fn translate_joinrule(&self, join_rule: &JoinRule) -> Result { match join_rule { - PublicRoomJoinRule::Knock => Ok(JoinRule::Knock), - PublicRoomJoinRule::Public => Ok(JoinRule::Public), + JoinRule::Invite => Ok(SpaceRoomJoinRule::Invite), + JoinRule::Knock => Ok(SpaceRoomJoinRule::Knock), + JoinRule::Private => Ok(SpaceRoomJoinRule::Private), + JoinRule::Restricted(_) => Ok(SpaceRoomJoinRule::Restricted), + JoinRule::KnockRestricted(_) => Ok(SpaceRoomJoinRule::KnockRestricted), + JoinRule::Public => Ok(SpaceRoomJoinRule::Public), _ => Err(Error::BadServerResponse("Unknown join rule")), } } - fn translate_sjoinrule(&self, join_rule: &PublicRoomJoinRule) -> Result { - match join_rule { - PublicRoomJoinRule::Knock => Ok(SpaceRoomJoinRule::Knock), - PublicRoomJoinRule::Public => Ok(SpaceRoomJoinRule::Public), - _ => Err(Error::BadServerResponse("Unknown join rule")), - } + fn handle_simplified_join_rule( + &self, + join_rule: &SpaceRoomJoinRule, + sender_user: &UserId, + room_id: &RoomId, + ) -> Result { + let allowed = match join_rule { + SpaceRoomJoinRule::Public => true, + SpaceRoomJoinRule::Knock => true, + SpaceRoomJoinRule::Invite => services() + .rooms + .state_cache + .is_joined(sender_user, &room_id)?, + _ => false, + }; + + Ok(allowed) } fn handle_join_rule( @@ -399,30 +427,25 @@ impl Service { join_rule: &JoinRule, sender_user: &UserId, room_id: &RoomId, - ) -> Result> { + ) -> Result { + if self.handle_simplified_join_rule( + &self.translate_joinrule(join_rule)?, + sender_user, + room_id, + )? { + return Ok(true); + } + match join_rule { - JoinRule::Public => Ok::<_, Error>(Some(SpaceRoomJoinRule::Public)), - JoinRule::Knock => Ok(Some(SpaceRoomJoinRule::Knock)), - JoinRule::Invite => { - if services() - .rooms - .state_cache - .is_joined(sender_user, &room_id)? - { - Ok(Some(SpaceRoomJoinRule::Invite)) - } else { - Ok(None) - } - } - JoinRule::Restricted(_r) => { + JoinRule::Restricted(_) => { // TODO: Check rules - Ok(None) + Ok(false) } - JoinRule::KnockRestricted(_r) => { + JoinRule::KnockRestricted(_) => { // TODO: Check rules - Ok(None) + Ok(false) } - _ => Ok(None), + _ => Ok(false), } } } -- cgit v1.2.3 From 56f0f3dfa44834478a4157cb91f0c860f844953f Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Mon, 10 Jul 2023 11:03:20 -0700 Subject: only use musl on x86_64 Since that's all I've tested it on. Apparently this caused issues on aarch64 even though it allegedly shouldn't. --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 5de5621..ef1a04b 100644 --- a/flake.nix +++ b/flake.nix @@ -25,8 +25,8 @@ let pkgs = nixpkgs.legacyPackages.${system}; - # Use mold on Linux - stdenv = if pkgs.stdenv.isLinux then + # Use mold where possible + stdenv = if pkgs.stdenv.isLinux && pkgs.stdenv.isx86_64 then pkgs.stdenvAdapters.useMoldLinker pkgs.stdenv else pkgs.stdenv; -- cgit v1.2.3 From c3966f501c5dbb495ca4ef8c044fac7049645594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 10 Jul 2023 23:10:27 +0200 Subject: fix: nheko e2ee verification bug --- src/api/client_server/keys.rs | 12 ------------ src/database/key_value/users.rs | 1 - 2 files changed, 13 deletions(-) diff --git a/src/api/client_server/keys.rs b/src/api/client_server/keys.rs index ba89ece..21f71b6 100644 --- a/src/api/client_server/keys.rs +++ b/src/api/client_server/keys.rs @@ -151,18 +151,6 @@ pub async fn upload_signatures_route( let key = serde_json::to_value(key) .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid key JSON"))?; - let is_signed_key = match key.get("usage") { - Some(usage) => usage - .as_array() - .map(|usage| !usage.contains(&json!("master"))) - .unwrap_or(false), - None => true, - }; - - if !is_signed_key { - continue; - } - for signature in key .get("signatures") .ok_or(Error::BadRequest( diff --git a/src/database/key_value/users.rs b/src/database/key_value/users.rs index 1cabab0..359a072 100644 --- a/src/database/key_value/users.rs +++ b/src/database/key_value/users.rs @@ -592,7 +592,6 @@ impl service::users::Data for KeyValueDatabase { &serde_json::to_vec(&cross_signing_key).expect("CrossSigningKey::to_vec always works"), )?; - // TODO: Should we notify about this change? self.mark_device_key_update(target_id)?; Ok(()) -- cgit v1.2.3 From 17180a3e0892f164b0f255c563e8d4fb13e2b2aa Mon Sep 17 00:00:00 2001 From: Jonas Zohren Date: Thu, 13 Jul 2023 16:54:56 +0000 Subject: capitalize names --- docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/README.md b/docker/README.md index ef93af2..1b9e046 100644 --- a/docker/README.md +++ b/docker/README.md @@ -4,7 +4,7 @@ ## Docker -To run conduit with docker you can either build the image yourself or pull it from a registry. +To run Conduit with Docker you can either build the image yourself or pull it from a registry. ### Use a registry -- cgit v1.2.3 From 24402312c58855679ccfe58b0d3d27ae041b4336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sat, 15 Jul 2023 23:43:25 +0200 Subject: fix: could not verify own events --- src/service/globals/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index 5326b7a..7d61829 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -1,5 +1,6 @@ mod data; pub use data::Data; +use ruma::serde::Base64; use ruma::{ OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, }; @@ -316,7 +317,19 @@ impl Service { &self, origin: &ServerName, ) -> Result> { - self.db.signing_keys_for(origin) + let mut keys = self.db.signing_keys_for(origin)?; + if origin == self.server_name() { + keys.insert( + format!("ed25519:{}", services().globals.keypair().version()) + .try_into() + .expect("found invalid server signing keys in DB"), + VerifyKey { + key: Base64::new(self.keypair.public_key().to_vec()), + }, + ); + } + + Ok(keys) } pub fn database_version(&self) -> Result { -- cgit v1.2.3 From a9ba067e7758207d1411b24c537cf755608632e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 16 Jul 2023 16:50:03 +0200 Subject: fix: e2ee over federation --- src/api/client_server/directory.rs | 1 - src/api/client_server/keys.rs | 34 ++++++++++--- src/api/server_server.rs | 10 ++-- src/database/key_value/users.rs | 100 +++++++++++++++++++++---------------- src/service/pusher/mod.rs | 5 +- src/service/users/data.rs | 16 ++++++ src/service/users/mod.rs | 32 ++++++++++-- 7 files changed, 136 insertions(+), 62 deletions(-) diff --git a/src/api/client_server/directory.rs b/src/api/client_server/directory.rs index df1ac40..a812dbc 100644 --- a/src/api/client_server/directory.rs +++ b/src/api/client_server/directory.rs @@ -20,7 +20,6 @@ use ruma::{ guest_access::{GuestAccess, RoomGuestAccessEventContent}, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, join_rules::{JoinRule, RoomJoinRulesEventContent}, - name::RoomNameEventContent, topic::RoomTopicEventContent, }, StateEventType, diff --git a/src/api/client_server/keys.rs b/src/api/client_server/keys.rs index 21f71b6..3e03221 100644 --- a/src/api/client_server/keys.rs +++ b/src/api/client_server/keys.rs @@ -311,15 +311,17 @@ pub(crate) async fn get_keys_helper bool>( } } - if let Some(master_key) = services() - .users - .get_master_key(user_id, &allowed_signatures)? + if let Some(master_key) = + services() + .users + .get_master_key(sender_user, user_id, &allowed_signatures)? { master_keys.insert(user_id.to_owned(), master_key); } - if let Some(self_signing_key) = services() - .users - .get_self_signing_key(user_id, &allowed_signatures)? + if let Some(self_signing_key) = + services() + .users + .get_self_signing_key(sender_user, user_id, &allowed_signatures)? { self_signing_keys.insert(user_id.to_owned(), self_signing_key); } @@ -357,7 +359,25 @@ pub(crate) async fn get_keys_helper bool>( while let Some((server, response)) = futures.next().await { match response { Ok(response) => { - master_keys.extend(response.master_keys); + for (user, masterkey) in response.master_keys { + let (master_key_id, mut master_key) = + services().users.parse_master_key(&user, &masterkey)?; + + if let Some(our_master_key) = services().users.get_key( + &master_key_id, + sender_user, + &user, + &allowed_signatures, + )? { + let (_, our_master_key) = + services().users.parse_master_key(&user, &our_master_key)?; + master_key.signatures.extend(our_master_key.signatures); + } + let json = serde_json::to_value(master_key).expect("to_value always works"); + let raw = serde_json::from_value(json).expect("Raw::from_value always works"); + master_keys.insert(user, raw); + } + self_signing_keys.extend(response.self_signing_keys); device_keys.extend(response.device_keys); } diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 0177f2a..2179b16 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -1806,12 +1806,14 @@ pub async fn get_devices_route( }) }) .collect(), - master_key: services() - .users - .get_master_key(&body.user_id, &|u| u.server_name() == sender_servername)?, + master_key: services().users.get_master_key(None, &body.user_id, &|u| { + u.server_name() == sender_servername + })?, self_signing_key: services() .users - .get_self_signing_key(&body.user_id, &|u| u.server_name() == sender_servername)?, + .get_self_signing_key(None, &body.user_id, &|u| { + u.server_name() == sender_servername + })?, }) } diff --git a/src/database/key_value/users.rs b/src/database/key_value/users.rs index 359a072..0301cda 100644 --- a/src/database/key_value/users.rs +++ b/src/database/key_value/users.rs @@ -451,31 +451,10 @@ impl service::users::Data for KeyValueDatabase { user_signing_key: &Option>, ) -> Result<()> { // TODO: Check signatures - let mut prefix = user_id.as_bytes().to_vec(); prefix.push(0xff); - // Master key - let mut master_key_ids = master_key - .deserialize() - .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid master key"))? - .keys - .into_values(); - - let master_key_id = master_key_ids.next().ok_or(Error::BadRequest( - ErrorKind::InvalidParam, - "Master key contained no key.", - ))?; - - if master_key_ids.next().is_some() { - return Err(Error::BadRequest( - ErrorKind::InvalidParam, - "Master key contained more than one key.", - )); - } - - let mut master_key_key = prefix.clone(); - master_key_key.extend_from_slice(master_key_id.as_bytes()); + let (master_key_key, _) = self.parse_master_key(user_id, master_key)?; self.keyid_key .insert(&master_key_key, master_key.json().get().as_bytes())?; @@ -690,45 +669,80 @@ impl service::users::Data for KeyValueDatabase { }) } + fn parse_master_key( + &self, + user_id: &UserId, + master_key: &Raw, + ) -> Result<(Vec, CrossSigningKey)> { + let mut prefix = user_id.as_bytes().to_vec(); + prefix.push(0xff); + + let master_key = master_key + .deserialize() + .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid master key"))?; + let mut master_key_ids = master_key.keys.values(); + let master_key_id = master_key_ids.next().ok_or(Error::BadRequest( + ErrorKind::InvalidParam, + "Master key contained no key.", + ))?; + if master_key_ids.next().is_some() { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Master key contained more than one key.", + )); + } + let mut master_key_key = prefix.clone(); + master_key_key.extend_from_slice(master_key_id.as_bytes()); + Ok((master_key_key, master_key)) + } + + fn get_key( + &self, + key: &[u8], + sender_user: Option<&UserId>, + user_id: &UserId, + allowed_signatures: &dyn Fn(&UserId) -> bool, + ) -> Result>> { + self.keyid_key.get(key)?.map_or(Ok(None), |bytes| { + let mut cross_signing_key = serde_json::from_slice::(&bytes) + .map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?; + clean_signatures( + &mut cross_signing_key, + sender_user, + user_id, + allowed_signatures, + )?; + + Ok(Some(Raw::from_json( + serde_json::value::to_raw_value(&cross_signing_key) + .expect("Value to RawValue serialization"), + ))) + }) + } + fn get_master_key( &self, + sender_user: Option<&UserId>, user_id: &UserId, allowed_signatures: &dyn Fn(&UserId) -> bool, ) -> Result>> { self.userid_masterkeyid .get(user_id.as_bytes())? .map_or(Ok(None), |key| { - self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| { - let mut cross_signing_key = serde_json::from_slice::(&bytes) - .map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?; - clean_signatures(&mut cross_signing_key, user_id, allowed_signatures)?; - - Ok(Some(Raw::from_json( - serde_json::value::to_raw_value(&cross_signing_key) - .expect("Value to RawValue serialization"), - ))) - }) + self.get_key(&key, sender_user, user_id, allowed_signatures) }) } fn get_self_signing_key( &self, + sender_user: Option<&UserId>, user_id: &UserId, allowed_signatures: &dyn Fn(&UserId) -> bool, ) -> Result>> { self.userid_selfsigningkeyid .get(user_id.as_bytes())? .map_or(Ok(None), |key| { - self.keyid_key.get(&key)?.map_or(Ok(None), |bytes| { - let mut cross_signing_key = serde_json::from_slice::(&bytes) - .map_err(|_| Error::bad_database("CrossSigningKey in db is invalid."))?; - clean_signatures(&mut cross_signing_key, user_id, allowed_signatures)?; - - Ok(Some(Raw::from_json( - serde_json::value::to_raw_value(&cross_signing_key) - .expect("Value to RawValue serialization"), - ))) - }) + self.get_key(&key, sender_user, user_id, allowed_signatures) }) } @@ -929,6 +943,8 @@ impl service::users::Data for KeyValueDatabase { } } +impl KeyValueDatabase {} + /// Will only return with Some(username) if the password was not empty and the /// username could be successfully parsed. /// If utils::string_from_bytes(...) returns an error that username will be skipped diff --git a/src/service/pusher/mod.rs b/src/service/pusher/mod.rs index 5e4281d..315c5ef 100644 --- a/src/service/pusher/mod.rs +++ b/src/service/pusher/mod.rs @@ -13,10 +13,7 @@ use ruma::{ }, IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken, }, - events::{ - room::{name::RoomNameEventContent, power_levels::RoomPowerLevelsEventContent}, - StateEventType, TimelineEventType, - }, + events::{room::power_levels::RoomPowerLevelsEventContent, StateEventType, TimelineEventType}, push::{Action, PushConditionRoomCtx, PushFormat, Ruleset, Tweak}, serde::Raw, uint, RoomId, UInt, UserId, diff --git a/src/service/users/data.rs b/src/service/users/data.rs index 8553210..d01e070 100644 --- a/src/service/users/data.rs +++ b/src/service/users/data.rs @@ -136,14 +136,30 @@ pub trait Data: Send + Sync { device_id: &DeviceId, ) -> Result>>; + fn parse_master_key( + &self, + user_id: &UserId, + master_key: &Raw, + ) -> Result<(Vec, CrossSigningKey)>; + + fn get_key( + &self, + key: &[u8], + sender_user: Option<&UserId>, + user_id: &UserId, + allowed_signatures: &dyn Fn(&UserId) -> bool, + ) -> Result>>; + fn get_master_key( &self, + sender_user: Option<&UserId>, user_id: &UserId, allowed_signatures: &dyn Fn(&UserId) -> bool, ) -> Result>>; fn get_self_signing_key( &self, + sender_user: Option<&UserId>, user_id: &UserId, allowed_signatures: &dyn Fn(&UserId) -> bool, ) -> Result>>; diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index 6be5c89..2311c30 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -226,20 +226,43 @@ impl Service { self.db.get_device_keys(user_id, device_id) } + pub fn parse_master_key( + &self, + user_id: &UserId, + master_key: &Raw, + ) -> Result<(Vec, CrossSigningKey)> { + self.db.parse_master_key(user_id, master_key) + } + + pub fn get_key( + &self, + key: &[u8], + sender_user: Option<&UserId>, + user_id: &UserId, + allowed_signatures: &dyn Fn(&UserId) -> bool, + ) -> Result>> { + self.db + .get_key(key, sender_user, user_id, allowed_signatures) + } + pub fn get_master_key( &self, + sender_user: Option<&UserId>, user_id: &UserId, allowed_signatures: &dyn Fn(&UserId) -> bool, ) -> Result>> { - self.db.get_master_key(user_id, allowed_signatures) + self.db + .get_master_key(sender_user, user_id, allowed_signatures) } pub fn get_self_signing_key( &self, + sender_user: Option<&UserId>, user_id: &UserId, allowed_signatures: &dyn Fn(&UserId) -> bool, ) -> Result>> { - self.db.get_self_signing_key(user_id, allowed_signatures) + self.db + .get_self_signing_key(sender_user, user_id, allowed_signatures) } pub fn get_user_signing_key(&self, user_id: &UserId) -> Result>> { @@ -342,6 +365,7 @@ impl Service { /// Ensure that a user only sees signatures from themselves and the target user pub fn clean_signatures bool>( cross_signing_key: &mut serde_json::Value, + sender_user: Option<&UserId>, user_id: &UserId, allowed_signatures: F, ) -> Result<(), Error> { @@ -355,9 +379,9 @@ pub fn clean_signatures bool>( for (user, signature) in mem::replace(signatures, serde_json::Map::with_capacity(new_capacity)) { - let id = <&UserId>::try_from(user.as_str()) + let sid = <&UserId>::try_from(user.as_str()) .map_err(|_| Error::bad_database("Invalid user ID in database."))?; - if id == user_id || allowed_signatures(id) { + if sender_user == Some(user_id) || sid == user_id || allowed_signatures(sid) { signatures.insert(user, signature); } } -- cgit v1.2.3 From fa3b1fd9bd330169f91934257d3d5ca1a4398bf5 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Sun, 16 Jul 2023 13:37:40 -0700 Subject: update flake.lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'crane': 'github:ipetkov/crane/75f7d715f8088f741be9981405f6444e2d49efdd' (2023-06-13) → 'github:ipetkov/crane/8b08e96c9af8c6e3a2b69af5a7fa168750fcf88e' (2023-07-07) • Updated input 'crane/rust-overlay': 'github:oxalica/rust-overlay/c535b4f3327910c96dcf21851bbdd074d0760290' (2023-06-03) → 'github:oxalica/rust-overlay/f9b92316727af9e6c7fee4a761242f7f46880329' (2023-07-03) • Updated input 'fenix': 'github:nix-community/fenix/df0a6e4ec44b4a276acfa5a96d2a83cb2dfdc791' (2023-06-17) → 'github:nix-community/fenix/39096fe3f379036ff4a5fa198950b8e79defe939' (2023-07-16) • Updated input 'fenix/rust-analyzer-src': 'github:rust-lang/rust-analyzer/a5a71c75e62a0eaa1b42a376f7cf3d348cb5dec6' (2023-06-16) → 'github:rust-lang/rust-analyzer/996e054f1eb1dbfc8455ecabff0f6ff22ba7f7c8' (2023-07-15) • Updated input 'flake-utils': 'github:numtide/flake-utils/a1720a10a6cfe8234c0e93907ffe81be440f4cef' (2023-05-31) → 'github:numtide/flake-utils/919d646de7be200f3bf08cb76ae1f09402b6f9b4' (2023-07-11) • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/04af42f3b31dba0ef742d254456dc4c14eedac86' (2023-06-17) → 'github:NixOS/nixpkgs/8acef304efe70152463a6399f73e636bcc363813' (2023-07-15) --- flake.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/flake.lock b/flake.lock index b69bb8c..0065525 100644 --- a/flake.lock +++ b/flake.lock @@ -12,11 +12,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1686621798, - "narHash": "sha256-FUwWszmSiDzUdTk8f69xwMoYlhdPaLvDaIYOE/y6VXc=", + "lastModified": 1688772518, + "narHash": "sha256-ol7gZxwvgLnxNSZwFTDJJ49xVY5teaSvF7lzlo3YQfM=", "owner": "ipetkov", "repo": "crane", - "rev": "75f7d715f8088f741be9981405f6444e2d49efdd", + "rev": "8b08e96c9af8c6e3a2b69af5a7fa168750fcf88e", "type": "github" }, "original": { @@ -33,11 +33,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1687004852, - "narHash": "sha256-wRSUs+v8xtIJaFlWO5NLFQjkq5+eYhxHHXnZKsZ9DpQ=", + "lastModified": 1689488573, + "narHash": "sha256-diVASflKCCryTYv0djvMnP2444mFsIG0ge5pa7ahauQ=", "owner": "nix-community", "repo": "fenix", - "rev": "df0a6e4ec44b4a276acfa5a96d2a83cb2dfdc791", + "rev": "39096fe3f379036ff4a5fa198950b8e79defe939", "type": "github" }, "original": { @@ -67,11 +67,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", "owner": "numtide", "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", "type": "github" }, "original": { @@ -82,11 +82,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1686960236, - "narHash": "sha256-AYCC9rXNLpUWzD9hm+askOfpliLEC9kwAo7ITJc4HIw=", + "lastModified": 1689444953, + "narHash": "sha256-0o56bfb2LC38wrinPdCGLDScd77LVcr7CrH1zK7qvDg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "04af42f3b31dba0ef742d254456dc4c14eedac86", + "rev": "8acef304efe70152463a6399f73e636bcc363813", "type": "github" }, "original": { @@ -107,11 +107,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1686936697, - "narHash": "sha256-mCoPr1nNWKpsoGMBFaK/sswkLloRCZuoWi2a+OKs3vk=", + "lastModified": 1689441253, + "narHash": "sha256-4MSDZaFI4DOfsLIZYPMBl0snzWhX1/OqR/QHir382CY=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "a5a71c75e62a0eaa1b42a376f7cf3d348cb5dec6", + "rev": "996e054f1eb1dbfc8455ecabff0f6ff22ba7f7c8", "type": "github" }, "original": { @@ -133,11 +133,11 @@ ] }, "locked": { - "lastModified": 1685759304, - "narHash": "sha256-I3YBH6MS3G5kGzNuc1G0f9uYfTcNY9NYoRc3QsykLk4=", + "lastModified": 1688351637, + "narHash": "sha256-CLTufJ29VxNOIZ8UTg0lepsn3X03AmopmaLTTeHDCL4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "c535b4f3327910c96dcf21851bbdd074d0760290", + "rev": "f9b92316727af9e6c7fee4a761242f7f46880329", "type": "github" }, "original": { -- cgit v1.2.3 From abd8e1bf54ecd0f385d472914aff4ba2a5eeaf8c Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Sun, 16 Jul 2023 13:38:33 -0700 Subject: nixpkgs' rocksdb is now new enough :) This reverts commit abd0a014e852d41d25320f6ccd19ac1de4156f96. --- flake.nix | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index ef1a04b..369759f 100644 --- a/flake.nix +++ b/flake.nix @@ -43,6 +43,10 @@ sha256 = "sha256-gdYqng0y9iHYzYPAdkC/ka3DRny3La/S5G8ASj0Ayyc="; }; + # The system's RocksDB + ROCKSDB_INCLUDE_DIR = "${pkgs.rocksdb}/include"; + ROCKSDB_LIB_DIR = "${pkgs.rocksdb}/lib"; + # Shared between the package and the devShell nativeBuildInputs = (with pkgs.rustPlatform; [ bindgenHook @@ -57,7 +61,9 @@ inherit stdenv - nativeBuildInputs; + nativeBuildInputs + ROCKSDB_INCLUDE_DIR + ROCKSDB_LIB_DIR; }; devShells.default = (pkgs.mkShell.override { inherit stdenv; }) { @@ -65,6 +71,10 @@ # sources, and it can read this environment variable to do so RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library"; + inherit + ROCKSDB_INCLUDE_DIR + ROCKSDB_LIB_DIR; + # Development tools nativeBuildInputs = nativeBuildInputs ++ (with toolchain; [ cargo -- cgit v1.2.3 From 742331e054b3570e1f02f02162ee667afa1f8281 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Sun, 16 Jul 2023 13:39:13 -0700 Subject: Revert "only use musl on x86_64" This reverts commit 56f0f3dfa44834478a4157cb91f0c860f844953f. This shouldn't be needed anymore since [this][0] reached nixos-unstable. [0]: https://github.com/NixOS/nixpkgs/pull/242889 --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 369759f..eb3a31c 100644 --- a/flake.nix +++ b/flake.nix @@ -25,8 +25,8 @@ let pkgs = nixpkgs.legacyPackages.${system}; - # Use mold where possible - stdenv = if pkgs.stdenv.isLinux && pkgs.stdenv.isx86_64 then + # Use mold on Linux + stdenv = if pkgs.stdenv.isLinux then pkgs.stdenvAdapters.useMoldLinker pkgs.stdenv else pkgs.stdenv; -- cgit v1.2.3 From bd8fec3836158053714ebc4e9ed61a4451cf831b Mon Sep 17 00:00:00 2001 From: purplemeteorite Date: Fri, 21 Jul 2023 20:33:32 +0200 Subject: changed registry options 1. Recommended GitLab's own registry over Docker Hub. (Reason: https://gitlab.com/famedly/conduit/-/merge_requests/492#note_1457220261) 2. Added the development image :next to the list of options. 3. Displayed text for Docker Hub now contains "docker.io" as part of the link for easier copy-paste for podman users. Clicking on the link still takes to the website. --- docker/README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docker/README.md b/docker/README.md index 1b9e046..cd41291 100644 --- a/docker/README.md +++ b/docker/README.md @@ -9,16 +9,21 @@ To run Conduit with Docker you can either build the image yourself or pull it fr ### Use a registry -The image is available in the following registries: +OCI images for Conduit are available in the registries listed below. We recommend using the image tagged as `latest` from GitLab's own registry. + +| Registry | Image | Size | Notes | +| --------------- | --------------------------------------------------------------- | ----------------------------- | ---------------------- | +| GitLab Registry | [registry.gitlab.com/famedly/conduit/matrix-conduit:latest][gl] | ![Image Size][shield-latest] | Stable image. | +| Docker Hub | [docker.io/matrixconduit/matrix-conduit:latest][dh] | ![Image Size][shield-latest] | Stable image. | +| GitLab Registry | [registry.gitlab.com/famedly/conduit/matrix-conduit:next][gl] | ![Image Size][shield-next] | Development version. | +| Docker Hub | [docker.io/matrixconduit/matrix-conduit:next][dh] | ![Image Size][shield-next] | Development version. | -| Registry | Image | Size | -| --------------- | --------------------------------------------------------------- | --------------------- | -| Docker Hub | [matrixconduit/matrix-conduit:latest][dh] | ![Image Size][shield] | -| GitLab Registry | [registry.gitlab.com/famedly/conduit/matrix-conduit:latest][gl] | ![Image Size][shield] | [dh]: https://hub.docker.com/r/matrixconduit/matrix-conduit [gl]: https://gitlab.com/famedly/conduit/container_registry/2497937 -[shield]: https://img.shields.io/docker/image-size/matrixconduit/matrix-conduit/latest +[shield-latest]: https://img.shields.io/docker/image-size/matrixconduit/matrix-conduit/latest +[shield-next]: https://img.shields.io/docker/image-size/matrixconduit/matrix-conduit/next + Use ```bash @@ -60,7 +65,7 @@ docker run -d -p 8448:6167 \ -e CONDUIT_TRUSTED_SERVERS="[\"matrix.org\"]" \ -e CONDUIT_MAX_CONCURRENT_REQUESTS="100" \ -e CONDUIT_LOG="warn,rocket=off,_=off,sled=off" \ - --name conduit matrixconduit/matrix-conduit:latest + --name conduit ``` or you can use [docker-compose](#docker-compose). -- cgit v1.2.3 From 6ae5143ff5b5d009beaff58c2559027269e4792c Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Fri, 21 Jul 2023 12:12:37 -0700 Subject: only listen on IPv6 since that's what conduit does --- nix/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/README.md b/nix/README.md index f8537d5..bd6f096 100644 --- a/nix/README.md +++ b/nix/README.md @@ -179,7 +179,7 @@ in upstreams = { "backend_conduit" = { servers = { - "localhost:${toString config.services.matrix-conduit.settings.global.port}" = { }; + "[::1]:${toString config.services.matrix-conduit.settings.global.port}" = { }; }; }; }; -- cgit v1.2.3 From 82f31d6b721d6ca979cd9dc98277b251b6d4c3f3 Mon Sep 17 00:00:00 2001 From: x4u <14617923-x4u@users.noreply.gitlab.com> Date: Sun, 23 Jul 2023 14:21:36 +0800 Subject: Replace nogroup with dedicated user group --- DEPLOY.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index e5e1530..b743338 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -117,8 +117,7 @@ After=network.target [Service] Environment="CONDUIT_CONFIG=/etc/matrix-conduit/conduit.toml" User=conduit -Group=nogroup -# On RHEL: Group=nobody +Group=conduit Restart=always ExecStart=/usr/local/bin/matrix-conduit @@ -198,8 +197,7 @@ If you use the default database path you also need to run this: ```bash sudo mkdir -p /var/lib/matrix-conduit/ -sudo chown -R conduit:nogroup /var/lib/matrix-conduit/ -# On RHEL: sudo chown -R conduit:nobody /var/lib/matrix-conduit/ +sudo chown -R conduit:conduit /var/lib/matrix-conduit/ sudo chmod 700 /var/lib/matrix-conduit/ ``` -- cgit v1.2.3 From 8cf408e96689afc3a03afd1209cdc9cdc68330d3 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 23 Jul 2023 12:14:59 +0200 Subject: Fix up permissions of the database path Also apply the database creation and ownership change on every installation and upgrade. --- debian/postinst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/debian/postinst b/debian/postinst index 73e554b..dfa599d 100644 --- a/debian/postinst +++ b/debian/postinst @@ -19,11 +19,11 @@ case "$1" in _matrix-conduit fi - # Create the database path if it does not exist yet. - if [ ! -d "$CONDUIT_DATABASE_PATH" ]; then - mkdir -p "$CONDUIT_DATABASE_PATH" - chown _matrix-conduit "$CONDUIT_DATABASE_PATH" - fi + # Create the database path if it does not exist yet and fix up ownership + # and permissions. + mkdir -p "$CONDUIT_DATABASE_PATH" + chown _matrix-conduit "$CONDUIT_DATABASE_PATH" + chmod 700 "$CONDUIT_DATABASE_PATH" if [ ! -e "$CONDUIT_CONFIG_FILE" ]; then # Write the debconf values in the config. -- cgit v1.2.3 From 433dad6ac2d7cba9146a403cddafdacfef6ceacc Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 23 Jul 2023 12:24:37 +0200 Subject: Turn README.Debian into a markdown file It is common to have a markdown file per deployment subdirectory. Still install it as `README.Debian` to `/usr/share/doc/matrix-conduit` as per Debian policy. Also update the link in the main `README.md` file. --- Cargo.toml | 2 +- README.md | 2 +- debian/README.Debian | 29 ----------------------------- debian/README.md | 29 +++++++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 31 deletions(-) delete mode 100644 debian/README.Debian create mode 100644 debian/README.md diff --git a/Cargo.toml b/Cargo.toml index ae7de59..9196cf4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,7 +137,7 @@ instead of a server that has high scalability.""" section = "net" priority = "optional" assets = [ - ["debian/README.Debian", "usr/share/doc/matrix-conduit/", "644"], + ["debian/README.md", "usr/share/doc/matrix-conduit/README.Debian", "644"], ["README.md", "usr/share/doc/matrix-conduit/", "644"], ["target/release/conduit", "usr/sbin/matrix-conduit", "755"], ] diff --git a/README.md b/README.md index 8fabefd..52ea3c1 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Check out the [Conduit 1.0 Release Milestone](https://gitlab.com/famedly/conduit #### How can I deploy my own? - Simple install (this was tested the most): [DEPLOY.md](DEPLOY.md) -- Debian package: [debian/README.Debian](debian/README.Debian) +- Debian package: [debian/README.md](debian/README.md) - Nix/NixOS: [nix/README.md](nix/README.md) - Docker: [docker/README.md](docker/README.md) diff --git a/debian/README.Debian b/debian/README.Debian deleted file mode 100644 index 5f63b5c..0000000 --- a/debian/README.Debian +++ /dev/null @@ -1,29 +0,0 @@ -Conduit for Debian -================== - -Configuration -------------- - -When installed, Debconf generates the configuration of the homeserver -(host)name, the address and port it listens on. This configuration ends up in -/etc/matrix-conduit/conduit.toml. - -You can tweak more detailed settings by uncommenting and setting the variables -in /etc/matrix-conduit/conduit.toml. This involves settings such as the maximum -file size for download/upload, enabling federation, etc. - -Running -------- - -The package uses the matrix-conduit.service systemd unit file to start and -stop Conduit. It loads the configuration file mentioned above to set up the -environment before running the server. - -This package assumes by default that Conduit will be placed behind a reverse -proxy such as Apache or nginx. This default deployment entails just listening -on 127.0.0.1 and the free port 6167 and is reachable via a client using the URL -http://localhost:6167. - -At a later stage this packaging may support also setting up TLS and running -stand-alone. In this case, however, you need to set up some certificates and -renewal, for it to work properly. diff --git a/debian/README.md b/debian/README.md new file mode 100644 index 0000000..b0f8658 --- /dev/null +++ b/debian/README.md @@ -0,0 +1,29 @@ +Conduit for Debian +================== + +Configuration +------------- + +When installed, Debconf generates the configuration of the homeserver +(host)name, the address and port it listens on. This configuration ends up in +`/etc/matrix-conduit/conduit.toml`. + +You can tweak more detailed settings by uncommenting and setting the variables +in `/etc/matrix-conduit/conduit.toml`. This involves settings such as the maximum +file size for download/upload, enabling federation, etc. + +Running +------- + +The package uses the `matrix-conduit.service` systemd unit file to start and +stop Conduit. It loads the configuration file mentioned above to set up the +environment before running the server. + +This package assumes by default that Conduit will be placed behind a reverse +proxy such as Apache or nginx. This default deployment entails just listening +on `127.0.0.1` and the free port `6167` and is reachable via a client using the URL +. + +At a later stage this packaging may support also setting up TLS and running +stand-alone. In this case, however, you need to set up some certificates and +renewal, for it to work properly. -- cgit v1.2.3 From 3cd3d0e0ff30524c7531f0e35bb50604770c5403 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 23 Jul 2023 12:34:48 +0200 Subject: Add section about how to download/install/deploy This refers to `DEPLOY.md` as to not duplicate the information. --- debian/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/README.md b/debian/README.md index b0f8658..443be76 100644 --- a/debian/README.md +++ b/debian/README.md @@ -1,6 +1,14 @@ Conduit for Debian ================== +Installation +------------ + +Information about downloading, building and deploying the Debian package, see +the "Installing Conduit" section in [DEPLOY.md](../DEPLOY.md). +All following sections until "Setting up the Reverse Proxy" be ignored because +this is handled automatically by the packaging. + Configuration ------------- -- cgit v1.2.3 From b1a591a06ce40ba63da45bbdc7432ba63a005171 Mon Sep 17 00:00:00 2001 From: Paul van Tilburg Date: Sun, 23 Jul 2023 12:37:47 +0200 Subject: Also create the conduit (system) group The `chown` command mentioned later in `DEPLOY.md` needs this group to exist. Also make sure this account cannot be used to login with by disabling its password and its shell. This is similar to how the Debian `postinst` script does this. --- DEPLOY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPLOY.md b/DEPLOY.md index b743338..ec7dd46 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -81,7 +81,7 @@ you to make sure that the file permissions are correctly set up. In Debian or RHEL, you can use this command to create a Conduit user: ```bash -sudo adduser --system conduit --no-create-home +sudo adduser --system conduit --group --disable-login --no-create-home ``` ## Forwarding ports in the firewall or the router -- cgit v1.2.3 From caddc656fba15ef3e13f65f21a7e6f43eb42e786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 23 Jul 2023 21:57:11 +0200 Subject: slightly better sliding sync --- src/api/client_server/sync.rs | 120 ++++++++++++++++++++++++---- src/service/mod.rs | 7 +- src/service/rooms/state_accessor/mod.rs | 15 ++++ src/service/users/mod.rs | 137 +++++++++++++++++++++++++++++++- 4 files changed, 260 insertions(+), 19 deletions(-) diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index fed4fb7..8883c16 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -23,7 +23,7 @@ use ruma::{ uint, DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UInt, UserId, }; use std::{ - collections::{hash_map::Entry, BTreeMap, HashMap, HashSet}, + collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, sync::Arc, time::Duration, }; @@ -1174,8 +1174,7 @@ pub async fn sync_events_v4_route( ) -> Result> { let sender_user = body.sender_user.expect("user is authenticated"); let sender_device = body.sender_device.expect("user is authenticated"); - let body = dbg!(body.body); - + let mut body = dbg!(body.body); // Setup watchers, so if there's no response, we can wait for them let watcher = services().globals.watch(&sender_user, &sender_device); @@ -1188,7 +1187,21 @@ pub async fn sync_events_v4_route( .unwrap_or(0); let sincecount = PduCount::Normal(since); - let initial = since == 0; + if since == 0 { + if let Some(conn_id) = &body.conn_id { + services().users.forget_sync_request_connection( + sender_user.clone(), + sender_device.clone(), + conn_id.clone(), + ) + } + } + + let known_rooms = services().users.update_sync_request_with_cache( + sender_user.clone(), + sender_device.clone(), + &mut body, + ); let all_joined_rooms = services() .rooms @@ -1205,8 +1218,10 @@ pub async fn sync_events_v4_route( continue; } + let mut new_known_rooms = BTreeMap::new(); + lists.insert( - list_id, + list_id.clone(), sync_events::v4::SyncList { ops: list .ranges @@ -1219,14 +1234,27 @@ pub async fn sync_events_v4_route( let room_ids = all_joined_rooms [(u64::from(r.0) as usize)..=(u64::from(r.1) as usize)] .to_vec(); - todo_rooms.extend(room_ids.iter().cloned().map(|r| { + new_known_rooms.extend(room_ids.iter().cloned().map(|r| (r, true))); + for room_id in &room_ids { + let todo_room = todo_rooms.entry(room_id.clone()).or_insert(( + BTreeSet::new(), + 0, + true, + )); let limit = list .room_details .timeline_limit .map_or(10, u64::from) .min(100); - (r, (list.room_details.required_state.clone(), limit)) - })); + todo_room + .0 + .extend(list.room_details.required_state.iter().cloned()); + todo_room.1 = todo_room.1.min(limit); + if known_rooms.get(&list_id).and_then(|k| k.get(room_id)) != Some(&true) + { + todo_room.2 = false; + } + } sync_events::v4::SyncOp { op: SlidingOp::Sync, range: Some(r.clone()), @@ -1239,12 +1267,36 @@ pub async fn sync_events_v4_route( count: UInt::from(all_joined_rooms.len() as u32), }, ); + + if let Some(conn_id) = &body.conn_id { + services().users.update_sync_known_rooms( + sender_user.clone(), + sender_device.clone(), + conn_id.clone(), + list_id, + new_known_rooms, + ); + } + } + + for (room_id, room) in body.room_subscriptions { + let todo_room = todo_rooms + .entry(room_id.clone()) + .or_insert((BTreeSet::new(), 0, true)); + let limit = room.timeline_limit.map_or(10, u64::from).min(100); + todo_room.0.extend(room.required_state.iter().cloned()); + todo_room.1 = todo_room.1.min(limit); + todo_room.2 = false; } let mut rooms = BTreeMap::new(); - for (room_id, (required_state_request, timeline_limit)) in todo_rooms { + for (room_id, (required_state_request, timeline_limit, known)) in &todo_rooms { let (timeline_pdus, limited) = - load_timeline(&sender_user, &room_id, sincecount, timeline_limit)?; + load_timeline(&sender_user, &room_id, sincecount, *timeline_limit)?; + + if *known && timeline_pdus.is_empty() { + continue; + } let prev_batch = timeline_pdus .first() @@ -1256,7 +1308,14 @@ pub async fn sync_events_v4_route( } PduCount::Normal(c) => c.to_string(), })) - })?; + })? + .or_else(|| { + if since != 0 { + Some(since.to_string()) + } else { + None + } + }); let room_events: Vec<_> = timeline_pdus .iter() @@ -1279,8 +1338,41 @@ pub async fn sync_events_v4_route( rooms.insert( room_id.clone(), sync_events::v4::SlidingSyncRoom { - name: services().rooms.state_accessor.get_name(&room_id)?, - initial: Some(initial), + name: services() + .rooms + .state_accessor + .get_name(&room_id)? + .or_else(|| { + // Heroes + let mut names = services() + .rooms + .state_cache + .room_members(&room_id) + .filter_map(|r| r.ok()) + .filter(|member| member != &sender_user) + .map(|member| { + Ok::<_, Error>( + services() + .rooms + .state_accessor + .get_member(&room_id, &member)? + .and_then(|memberevent| memberevent.displayname) + .unwrap_or(member.to_string()), + ) + }) + .filter_map(|r| r.ok()) + .take(5) + .collect::>(); + if names.len() > 1 { + let last = names.pop().unwrap(); + Some(names.join(", ") + " and " + &last) + } else if names.len() == 1 { + Some(names.pop().unwrap()) + } else { + None + } + }), + initial: Some(*known), is_dm: None, invite_state: None, unread_notifications: UnreadNotificationsCount { @@ -1326,7 +1418,7 @@ pub async fn sync_events_v4_route( } Ok(dbg!(sync_events::v4::Response { - initial: initial, + initial: since == 0, txn_id: body.txn_id.clone(), pos: next_batch.to_string(), lists, diff --git a/src/service/mod.rs b/src/service/mod.rs index 56aed7f..f85da78 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,5 +1,5 @@ use std::{ - collections::HashMap, + collections::{BTreeMap, HashMap}, sync::{Arc, Mutex}, }; @@ -105,7 +105,10 @@ impl Services { }, transaction_ids: transaction_ids::Service { db }, uiaa: uiaa::Service { db }, - users: users::Service { db }, + users: users::Service { + db, + connections: Mutex::new(BTreeMap::new()), + }, account_data: account_data::Service { db }, admin: admin::Service::build(), key_backups: key_backups::Service { db }, diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index 9d071a5..435f4df 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -282,4 +282,19 @@ impl Service { .map_err(|_| Error::bad_database("Invalid room name event in database.")) }) } + + pub fn get_member( + &self, + room_id: &RoomId, + user_id: &UserId, + ) -> Result> { + services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomMember, user_id.as_str())? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map_err(|_| Error::bad_database("Invalid room member event in database.")) + }) + } } diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index 6be5c89..63ab9b7 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -1,20 +1,36 @@ mod data; -use std::{collections::BTreeMap, mem}; +use std::{ + collections::BTreeMap, + mem, + sync::{Arc, Mutex}, +}; pub use data::Data; use ruma::{ - api::client::{device::Device, error::ErrorKind, filter::FilterDefinition}, + api::client::{ + device::Device, + error::ErrorKind, + filter::FilterDefinition, + sync::sync_events::{self, v4::SyncRequestList}, + }, encryption::{CrossSigningKey, DeviceKeys, OneTimeKey}, events::AnyToDeviceEvent, serde::Raw, DeviceId, DeviceKeyAlgorithm, DeviceKeyId, OwnedDeviceId, OwnedDeviceKeyId, OwnedMxcUri, - OwnedUserId, RoomAliasId, UInt, UserId, + OwnedRoomId, OwnedUserId, RoomAliasId, UInt, UserId, }; use crate::{services, Error, Result}; +pub struct SlidingSyncCache { + lists: BTreeMap, + known_rooms: BTreeMap>, +} + pub struct Service { pub db: &'static dyn Data, + pub connections: + Mutex>>>, } impl Service { @@ -23,6 +39,121 @@ impl Service { self.db.exists(user_id) } + pub fn forget_sync_request_connection( + &self, + user_id: OwnedUserId, + device_id: OwnedDeviceId, + conn_id: String, + ) { + self.connections + .lock() + .unwrap() + .remove(&(user_id, device_id, conn_id)); + } + + pub fn update_sync_request_with_cache( + &self, + user_id: OwnedUserId, + device_id: OwnedDeviceId, + request: &mut sync_events::v4::Request, + ) -> BTreeMap> { + let Some(conn_id) = request.conn_id.clone() else { return BTreeMap::new(); }; + + let cache = &mut self.connections.lock().unwrap(); + let cached = Arc::clone( + cache + .entry((user_id, device_id, conn_id)) + .or_insert_with(|| { + Arc::new(Mutex::new(SlidingSyncCache { + lists: BTreeMap::new(), + known_rooms: BTreeMap::new(), + })) + }), + ); + let cached = &mut cached.lock().unwrap(); + drop(cache); + + for (list_id, list) in &mut request.lists { + if let Some(cached_list) = cached.lists.remove(list_id) { + if list.sort.is_empty() { + list.sort = cached_list.sort; + }; + if list.room_details.required_state.is_empty() { + list.room_details.required_state = cached_list.room_details.required_state; + }; + list.room_details.timeline_limit = list + .room_details + .timeline_limit + .or(cached_list.room_details.timeline_limit); + list.include_old_rooms = list + .include_old_rooms + .clone() + .or(cached_list.include_old_rooms); + match (&mut list.filters, cached_list.filters) { + (Some(list_filters), Some(cached_filters)) => { + list_filters.is_dm = list_filters.is_dm.or(cached_filters.is_dm); + if list_filters.spaces.is_empty() { + list_filters.spaces = cached_filters.spaces; + } + list_filters.is_encrypted = + list_filters.is_encrypted.or(cached_filters.is_encrypted); + list_filters.is_invite = + list_filters.is_invite.or(cached_filters.is_invite); + if list_filters.room_types.is_empty() { + list_filters.room_types = cached_filters.room_types; + } + if list_filters.not_room_types.is_empty() { + list_filters.not_room_types = cached_filters.not_room_types; + } + list_filters.room_name_like = list_filters + .room_name_like + .clone() + .or(cached_filters.room_name_like); + if list_filters.tags.is_empty() { + list_filters.tags = cached_filters.tags; + } + if list_filters.not_tags.is_empty() { + list_filters.not_tags = cached_filters.not_tags; + } + } + (_, Some(cached_filters)) => list.filters = Some(cached_filters), + (_, _) => {} + } + if list.bump_event_types.is_empty() { + list.bump_event_types = cached_list.bump_event_types; + }; + } + cached.lists.insert(list_id.clone(), list.clone()); + } + + cached.known_rooms.clone() + } + + pub fn update_sync_known_rooms( + &self, + user_id: OwnedUserId, + device_id: OwnedDeviceId, + conn_id: String, + list_id: String, + new_cached_rooms: BTreeMap, + ) { + let cache = &mut self.connections.lock().unwrap(); + let cached = Arc::clone( + cache + .entry((user_id, device_id, conn_id)) + .or_insert_with(|| { + Arc::new(Mutex::new(SlidingSyncCache { + lists: BTreeMap::new(), + known_rooms: BTreeMap::new(), + })) + }), + ); + let cached = &mut cached.lock().unwrap(); + drop(cache); + + cached.known_rooms.insert(list_id, new_cached_rooms); + } + /// Check if account is deactivated pub fn is_deactivated(&self, user_id: &UserId) -> Result { self.db.is_deactivated(user_id) -- cgit v1.2.3 From d220641d6453b8be767197f58c0bb32f255e2a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 24 Jul 2023 10:41:50 +0200 Subject: Sliding sync subscriptions, e2ee, to_device messages --- src/api/client_server/sync.rs | 294 +++++++++++++++++++++++++++++++++++++++--- src/service/users/mod.rs | 89 ++++++++++++- 2 files changed, 361 insertions(+), 22 deletions(-) diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 8883c16..527625a 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -463,7 +463,7 @@ async fn sync_helper( } for user_id in left_encrypted_users { - let still_share_encrypted_room = services() + let dont_share_encrypted_room = services() .rooms .user .get_shared_rooms(vec![sender_user.clone(), user_id.clone()])? @@ -481,7 +481,7 @@ async fn sync_helper( .all(|encrypted| !encrypted); // If the user doesn't share an encrypted room with the target anymore, we need to tell // them - if still_share_encrypted_room { + if dont_share_encrypted_room { device_list_left.insert(user_id); } } @@ -1197,6 +1197,7 @@ pub async fn sync_events_v4_route( } } + // Get sticky parameters from cache let known_rooms = services().users.update_sync_request_with_cache( sender_user.clone(), sender_device.clone(), @@ -1210,6 +1211,195 @@ pub async fn sync_events_v4_route( .filter_map(|r| r.ok()) .collect::>(); + if body.extensions.to_device.enabled.unwrap_or(false) { + services() + .users + .remove_to_device_events(&sender_user, &sender_device, since)?; + } + + let mut left_encrypted_users = HashSet::new(); // Users that have left any encrypted rooms the sender was in + let mut device_list_changes = HashSet::new(); + let mut device_list_left = HashSet::new(); + + if body.extensions.e2ee.enabled.unwrap_or(false) { + // Look for device list updates of this account + device_list_changes.extend( + services() + .users + .keys_changed(sender_user.as_ref(), since, None) + .filter_map(|r| r.ok()), + ); + + for room_id in &all_joined_rooms { + let current_shortstatehash = + if let Some(s) = services().rooms.state.get_room_shortstatehash(&room_id)? { + s + } else { + error!("Room {} has no state", room_id); + continue; + }; + + let since_shortstatehash = services() + .rooms + .user + .get_token_shortstatehash(&room_id, since)?; + + let since_sender_member: Option = since_shortstatehash + .and_then(|shortstatehash| { + services() + .rooms + .state_accessor + .state_get( + shortstatehash, + &StateEventType::RoomMember, + sender_user.as_str(), + ) + .transpose() + }) + .transpose()? + .and_then(|pdu| { + serde_json::from_str(pdu.content.get()) + .map_err(|_| Error::bad_database("Invalid PDU in database.")) + .ok() + }); + + let encrypted_room = services() + .rooms + .state_accessor + .state_get(current_shortstatehash, &StateEventType::RoomEncryption, "")? + .is_some(); + + if let Some(since_shortstatehash) = since_shortstatehash { + // Skip if there are only timeline changes + if since_shortstatehash == current_shortstatehash { + continue; + } + + let since_encryption = services().rooms.state_accessor.state_get( + since_shortstatehash, + &StateEventType::RoomEncryption, + "", + )?; + + let joined_since_last_sync = since_sender_member + .map_or(true, |member| member.membership != MembershipState::Join); + + let new_encrypted_room = encrypted_room && since_encryption.is_none(); + if encrypted_room { + let current_state_ids = services() + .rooms + .state_accessor + .state_full_ids(current_shortstatehash) + .await?; + let since_state_ids = services() + .rooms + .state_accessor + .state_full_ids(since_shortstatehash) + .await?; + + for (key, id) in current_state_ids { + if since_state_ids.get(&key) != Some(&id) { + let pdu = match services().rooms.timeline.get_pdu(&id)? { + Some(pdu) => pdu, + None => { + error!("Pdu in state not found: {}", id); + continue; + } + }; + if pdu.kind == TimelineEventType::RoomMember { + if let Some(state_key) = &pdu.state_key { + let user_id = + UserId::parse(state_key.clone()).map_err(|_| { + Error::bad_database("Invalid UserId in member PDU.") + })?; + + if user_id == sender_user { + continue; + } + + let new_membership = serde_json::from_str::< + RoomMemberEventContent, + >( + pdu.content.get() + ) + .map_err(|_| Error::bad_database("Invalid PDU in database."))? + .membership; + + match new_membership { + MembershipState::Join => { + // A new user joined an encrypted room + if !share_encrypted_room( + &sender_user, + &user_id, + &room_id, + )? { + device_list_changes.insert(user_id); + } + } + MembershipState::Leave => { + // Write down users that have left encrypted rooms we are in + left_encrypted_users.insert(user_id); + } + _ => {} + } + } + } + } + } + if joined_since_last_sync || new_encrypted_room { + // If the user is in a new encrypted room, give them all joined users + device_list_changes.extend( + services() + .rooms + .state_cache + .room_members(&room_id) + .flatten() + .filter(|user_id| { + // Don't send key updates from the sender to the sender + &sender_user != user_id + }) + .filter(|user_id| { + // Only send keys if the sender doesn't share an encrypted room with the target already + !share_encrypted_room(&sender_user, user_id, &room_id) + .unwrap_or(false) + }), + ); + } + } + } + // Look for device list updates in this room + device_list_changes.extend( + services() + .users + .keys_changed(room_id.as_ref(), since, None) + .filter_map(|r| r.ok()), + ); + } + for user_id in left_encrypted_users { + let dont_share_encrypted_room = services() + .rooms + .user + .get_shared_rooms(vec![sender_user.clone(), user_id.clone()])? + .filter_map(|r| r.ok()) + .filter_map(|other_room_id| { + Some( + services() + .rooms + .state_accessor + .room_state_get(&other_room_id, &StateEventType::RoomEncryption, "") + .ok()? + .is_some(), + ) + }) + .all(|encrypted| !encrypted); + // If the user doesn't share an encrypted room with the target anymore, we need to tell + // them + if dont_share_encrypted_room { + device_list_left.insert(user_id); + } + } + } + let mut lists = BTreeMap::new(); let mut todo_rooms = BTreeMap::new(); // and required state @@ -1249,7 +1439,7 @@ pub async fn sync_events_v4_route( todo_room .0 .extend(list.room_details.required_state.iter().cloned()); - todo_room.1 = todo_room.1.min(limit); + todo_room.1 = todo_room.1.max(limit); if known_rooms.get(&list_id).and_then(|k| k.get(room_id)) != Some(&true) { todo_room.2 = false; @@ -1279,18 +1469,51 @@ pub async fn sync_events_v4_route( } } - for (room_id, room) in body.room_subscriptions { + let mut known_subscription_rooms = BTreeMap::new(); + for (room_id, room) in dbg!(&body.room_subscriptions) { let todo_room = todo_rooms .entry(room_id.clone()) .or_insert((BTreeSet::new(), 0, true)); let limit = room.timeline_limit.map_or(10, u64::from).min(100); todo_room.0.extend(room.required_state.iter().cloned()); - todo_room.1 = todo_room.1.min(limit); - todo_room.2 = false; + todo_room.1 = todo_room.1.max(limit); + if known_rooms + .get("subscriptions") + .and_then(|k| k.get(room_id)) + != Some(&true) + { + todo_room.2 = false; + } + known_subscription_rooms.insert(room_id.clone(), true); + } + + for r in body.unsubscribe_rooms { + known_subscription_rooms.remove(&r); + body.room_subscriptions.remove(&r); + } + + if let Some(conn_id) = &body.conn_id { + services().users.update_sync_known_rooms( + sender_user.clone(), + sender_device.clone(), + conn_id.clone(), + "subscriptions".to_owned(), + known_subscription_rooms, + ); + } + + if let Some(conn_id) = &body.conn_id { + services().users.update_sync_subscriptions( + sender_user.clone(), + sender_device.clone(), + conn_id.clone(), + body.room_subscriptions, + ); } let mut rooms = BTreeMap::new(); for (room_id, (required_state_request, timeline_limit, known)) in &todo_rooms { + // TODO: per-room sync tokens let (timeline_pdus, limited) = load_timeline(&sender_user, &room_id, sincecount, *timeline_limit)?; @@ -1372,12 +1595,26 @@ pub async fn sync_events_v4_route( None } }), - initial: Some(*known), + initial: Some(!known), is_dm: None, invite_state: None, unread_notifications: UnreadNotificationsCount { - highlight_count: None, - notification_count: None, + highlight_count: Some( + services() + .rooms + .user + .highlight_count(&sender_user, &room_id)? + .try_into() + .expect("notification count can't go that high"), + ), + notification_count: Some( + services() + .rooms + .user + .notification_count(&sender_user, &room_id)? + .try_into() + .expect("notification count can't go that high"), + ), }, timeline: room_events, required_state, @@ -1399,7 +1636,7 @@ pub async fn sync_events_v4_route( .unwrap_or(0) as u32) .into(), ), - num_live: None, + num_live: None, // Count events in timeline greater than global sync counter }, ); } @@ -1424,17 +1661,44 @@ pub async fn sync_events_v4_route( lists, rooms, extensions: sync_events::v4::Extensions { - to_device: None, + to_device: if body.extensions.to_device.enabled.unwrap_or(false) { + Some(sync_events::v4::ToDevice { + events: services() + .users + .get_to_device_events(&sender_user, &sender_device)?, + next_batch: next_batch.to_string(), + }) + } else { + None + }, e2ee: sync_events::v4::E2EE { device_lists: DeviceLists { - changed: Vec::new(), - left: Vec::new(), + changed: device_list_changes.into_iter().collect(), + left: device_list_left.into_iter().collect(), }, - device_one_time_keys_count: BTreeMap::new(), + device_one_time_keys_count: services() + .users + .count_one_time_keys(&sender_user, &sender_device)?, + // Fallback keys are not yet supported device_unused_fallback_key_types: None, }, account_data: sync_events::v4::AccountData { - global: Vec::new(), + global: if body.extensions.account_data.enabled.unwrap_or(false) { + services() + .account_data + .changes_since(None, &sender_user, since)? + .into_iter() + .filter_map(|(_, v)| { + serde_json::from_str(v.json().get()) + .map_err(|_| { + Error::bad_database("Invalid account event in database.") + }) + .ok() + }) + .collect() + } else { + Vec::new() + }, rooms: BTreeMap::new(), }, receipts: sync_events::v4::Receipts { diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index 63ab9b7..786b42e 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -11,7 +11,10 @@ use ruma::{ device::Device, error::ErrorKind, filter::FilterDefinition, - sync::sync_events::{self, v4::SyncRequestList}, + sync::sync_events::{ + self, + v4::{ExtensionsConfig, SyncRequestList}, + }, }, encryption::{CrossSigningKey, DeviceKeys, OneTimeKey}, events::AnyToDeviceEvent, @@ -24,7 +27,9 @@ use crate::{services, Error, Result}; pub struct SlidingSyncCache { lists: BTreeMap, + subscriptions: BTreeMap, known_rooms: BTreeMap>, + extensions: ExtensionsConfig, } pub struct Service { @@ -66,7 +71,9 @@ impl Service { .or_insert_with(|| { Arc::new(Mutex::new(SlidingSyncCache { lists: BTreeMap::new(), + subscriptions: BTreeMap::new(), known_rooms: BTreeMap::new(), + extensions: ExtensionsConfig::default(), })) }), ); @@ -74,12 +81,13 @@ impl Service { drop(cache); for (list_id, list) in &mut request.lists { - if let Some(cached_list) = cached.lists.remove(list_id) { + if let Some(cached_list) = cached.lists.get(list_id) { if list.sort.is_empty() { - list.sort = cached_list.sort; + list.sort = cached_list.sort.clone(); }; if list.room_details.required_state.is_empty() { - list.room_details.required_state = cached_list.room_details.required_state; + list.room_details.required_state = + cached_list.room_details.required_state.clone(); }; list.room_details.timeline_limit = list .room_details @@ -88,8 +96,8 @@ impl Service { list.include_old_rooms = list .include_old_rooms .clone() - .or(cached_list.include_old_rooms); - match (&mut list.filters, cached_list.filters) { + .or(cached_list.include_old_rooms.clone()); + match (&mut list.filters, cached_list.filters.clone()) { (Some(list_filters), Some(cached_filters)) => { list_filters.is_dm = list_filters.is_dm.or(cached_filters.is_dm); if list_filters.spaces.is_empty() { @@ -120,15 +128,80 @@ impl Service { (_, _) => {} } if list.bump_event_types.is_empty() { - list.bump_event_types = cached_list.bump_event_types; + list.bump_event_types = cached_list.bump_event_types.clone(); }; } cached.lists.insert(list_id.clone(), list.clone()); } + cached + .subscriptions + .extend(request.room_subscriptions.clone().into_iter()); + request + .room_subscriptions + .extend(cached.subscriptions.clone().into_iter()); + + request.extensions.e2ee.enabled = request + .extensions + .e2ee + .enabled + .or(cached.extensions.e2ee.enabled); + + request.extensions.to_device.enabled = request + .extensions + .to_device + .enabled + .or(cached.extensions.to_device.enabled); + + request.extensions.account_data.enabled = request + .extensions + .account_data + .enabled + .or(cached.extensions.account_data.enabled); + request.extensions.account_data.lists = request + .extensions + .account_data + .lists + .clone() + .or(cached.extensions.account_data.lists.clone()); + request.extensions.account_data.rooms = request + .extensions + .account_data + .rooms + .clone() + .or(cached.extensions.account_data.rooms.clone()); + + cached.extensions = request.extensions.clone(); + cached.known_rooms.clone() } + pub fn update_sync_subscriptions( + &self, + user_id: OwnedUserId, + device_id: OwnedDeviceId, + conn_id: String, + subscriptions: BTreeMap, + ) { + let cache = &mut self.connections.lock().unwrap(); + let cached = Arc::clone( + cache + .entry((user_id, device_id, conn_id)) + .or_insert_with(|| { + Arc::new(Mutex::new(SlidingSyncCache { + lists: BTreeMap::new(), + subscriptions: BTreeMap::new(), + known_rooms: BTreeMap::new(), + extensions: ExtensionsConfig::default(), + })) + }), + ); + let cached = &mut cached.lock().unwrap(); + drop(cache); + + cached.subscriptions = subscriptions; + } + pub fn update_sync_known_rooms( &self, user_id: OwnedUserId, @@ -144,7 +217,9 @@ impl Service { .or_insert_with(|| { Arc::new(Mutex::new(SlidingSyncCache { lists: BTreeMap::new(), + subscriptions: BTreeMap::new(), known_rooms: BTreeMap::new(), + extensions: ExtensionsConfig::default(), })) }), ); -- cgit v1.2.3 From bf46829595450b69a83da8cada99786470a492b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 26 Jul 2023 08:33:27 +0200 Subject: fix: spaces with restricted rooms --- src/service/rooms/spaces/mod.rs | 63 ++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index 36fa1fc..e92fc07 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -16,7 +16,7 @@ use ruma::{ create::RoomCreateEventContent, guest_access::{GuestAccess, RoomGuestAccessEventContent}, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, - join_rules::{JoinRule, RoomJoinRulesEventContent}, + join_rules::{self, AllowRule, JoinRule, RoomJoinRulesEventContent}, topic::RoomTopicEventContent, }, StateEventType, @@ -30,7 +30,7 @@ use tracing::{debug, error, warn}; use crate::{services, Error, PduEvent, Result}; pub enum CachedJoinRule { - Simplified(SpaceRoomJoinRule), + //Simplified(SpaceRoomJoinRule), Full(JoinRule), } @@ -84,9 +84,9 @@ impl Service { { if let Some(cached) = cached { let allowed = match &cached.join_rule { - CachedJoinRule::Simplified(s) => { - self.handle_simplified_join_rule(s, sender_user, ¤t_room)? - } + //CachedJoinRule::Simplified(s) => { + //self.handle_simplified_join_rule(s, sender_user, ¤t_room)? + //} CachedJoinRule::Full(f) => { self.handle_join_rule(f, sender_user, ¤t_room)? } @@ -211,11 +211,34 @@ impl Service { .map(|c| c.room_id.clone()) .collect::>(); - if self.handle_simplified_join_rule( - &response.room.join_rule, - sender_user, - ¤t_room, - )? { + let join_rule = match response.room.join_rule { + SpaceRoomJoinRule::Invite => JoinRule::Invite, + SpaceRoomJoinRule::Knock => JoinRule::Knock, + SpaceRoomJoinRule::Private => JoinRule::Private, + SpaceRoomJoinRule::Restricted => { + JoinRule::Restricted(join_rules::Restricted { + allow: response + .room + .allowed_room_ids + .into_iter() + .map(|room| AllowRule::room_membership(room)) + .collect(), + }) + } + SpaceRoomJoinRule::KnockRestricted => { + JoinRule::KnockRestricted(join_rules::Restricted { + allow: response + .room + .allowed_room_ids + .into_iter() + .map(|room| AllowRule::room_membership(room)) + .collect(), + }) + } + SpaceRoomJoinRule::Public => JoinRule::Public, + _ => return Err(Error::BadServerResponse("Unknown join rule")), + }; + if self.handle_join_rule(&join_rule, sender_user, ¤t_room)? { if left_to_skip > 0 { left_to_skip -= 1; } else { @@ -231,7 +254,7 @@ impl Service { Some(CachedSpaceChunk { chunk, children, - join_rule: CachedJoinRule::Simplified(response.room.join_rule), + join_rule: CachedJoinRule::Full(join_rule), }), ); @@ -437,8 +460,22 @@ impl Service { } match join_rule { - JoinRule::Restricted(_) => { - // TODO: Check rules + JoinRule::Restricted(r) => { + for rule in &r.allow { + match rule { + join_rules::AllowRule::RoomMembership(rm) => { + if let Ok(true) = services() + .rooms + .state_cache + .is_joined(sender_user, &rm.room_id) + { + return Ok(true); + } + } + _ => {} + } + } + Ok(false) } JoinRule::KnockRestricted(_) => { -- cgit v1.2.3 From 54a115caf337c339f1dc44aaa298257038c6e9f6 Mon Sep 17 00:00:00 2001 From: uak <4626956-uak@users.noreply.gitlab.com> Date: Wed, 26 Jul 2023 18:53:19 +0000 Subject: Change link from docker-compose.override.traefik.yml to docker-compose.override.yml in README.md --- docker/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/README.md b/docker/README.md index c702832..aba101e 100644 --- a/docker/README.md +++ b/docker/README.md @@ -95,7 +95,7 @@ As a container user, you probably know about Traefik. It is a easy to use revers containerized app and services available through the web. With the two provided files, [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) (or [`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)) and -[`docker-compose.override.yml`](docker-compose.override.traefik.yml), it is equally easy to deploy +[`docker-compose.override.yml`](docker-compose.override.yml), it is equally easy to deploy and use Conduit, with a little caveat. If you already took a look at the files, then you should have seen the `well-known` service, and that is the little caveat. Traefik is simply a proxy and loadbalancer and is not able to serve any kind of content, but for Conduit to federate, we need to @@ -106,7 +106,7 @@ With the service `well-known` we use a single `nginx` container that will serve So...step by step: -1. Copy [`docker-compose.traefik.yml`](docker-compose.traefik.yml) and [`docker-compose.override.traefik.yml`](docker-compose.override.traefik.yml) from the repository and remove `.traefik` from the filenames. +1. Copy [`docker-compose.traefik.yml`](docker-compose.traefik.yml) and [`docker-compose.override.yml`](docker-compose.override.yml) from the repository and remove `.traefik` from the filename. 2. Open both files and modify/adjust them to your needs. Meaning, change the `CONDUIT_SERVER_NAME` and the volume host mappings according to your needs. 3. Create the `conduit.toml` config file, an example can be found [here](../conduit-example.toml), or set `CONDUIT_CONFIG=""` and configure Conduit per env vars. 4. Uncomment the `element-web` service if you want to host your own Element Web Client and create a `element_config.json`. -- cgit v1.2.3 From 291290db92f2720a298390c229bea81f3b56e3e9 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Wed, 26 Jul 2023 13:24:44 -0700 Subject: maximize fd limit --- Cargo.lock | 32 +++++++++++++++++++++++++++++++- Cargo.toml | 3 +++ src/main.rs | 21 +++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 3480c01..7ddf487 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,6 +382,7 @@ dependencies = [ "jsonwebtoken", "lazy_static", "lru-cache", + "nix", "num_cpus", "opentelemetry", "opentelemetry-jaeger", @@ -533,7 +534,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.9.0", "scopeguard", ] @@ -1471,6 +1472,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -1513,6 +1523,20 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", + "static_assertions", +] + [[package]] name = "nom" version = "7.1.3" @@ -2673,6 +2697,12 @@ dependencies = [ "der", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "subslice" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index 9196cf4..7a157f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,6 +104,9 @@ async-trait = "0.1.68" sd-notify = { version = "0.4.1", optional = true } +[target.'cfg(unix)'.dependencies] +nix = { version = "0.26.2", features = ["resource"] } + [features] default = ["conduit_bin", "backend_sqlite", "backend_rocksdb", "systemd"] #backend_sled = ["sled"] diff --git a/src/main.rs b/src/main.rs index 579eeb1..eb7e833 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,16 @@ static GLOBAL: Jemalloc = Jemalloc; #[tokio::main] async fn main() { + // This is needed for opening lots of file descriptors, which tends to + // happen more often when using RocksDB and making lots of federation + // connections at startup. The soft limit is usually 1024, and the hard + // limit is usually 512000; I've personally seen it hit >2000. + // + // * https://www.freedesktop.org/software/systemd/man/systemd.exec.html#id-1.12.2.1.17.6 + // * https://github.com/systemd/systemd/commit/0abf94923b4a95a7d89bc526efc84e7ca2b71741 + #[cfg(unix)] + maximize_fd_limit().expect("should be able to increase the soft limit to the hard limit"); + // Initialize DB let raw_config = Figment::new() @@ -550,3 +560,14 @@ fn method_to_filter(method: Method) -> MethodFilter { m => panic!("Unsupported HTTP method: {m:?}"), } } + +#[cfg(unix)] +fn maximize_fd_limit() -> Result<(), nix::errno::Errno> { + use nix::sys::resource::{getrlimit, setrlimit, Resource}; + + let res = Resource::RLIMIT_NOFILE; + + let (_, hard_limit) = getrlimit(res)?; + + setrlimit(res, hard_limit, hard_limit) +} -- cgit v1.2.3 From 9fb849806783c82934dc74d32849e194e224ed90 Mon Sep 17 00:00:00 2001 From: Charles Hall Date: Wed, 26 Jul 2023 15:32:36 -0700 Subject: relax recovery mode --- src/database/abstraction/rocksdb.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/database/abstraction/rocksdb.rs b/src/database/abstraction/rocksdb.rs index f0b5f2a..b40c439 100644 --- a/src/database/abstraction/rocksdb.rs +++ b/src/database/abstraction/rocksdb.rs @@ -49,6 +49,13 @@ fn db_options(max_open_files: i32, rocksdb_cache: &rocksdb::Cache) -> rocksdb::O db_opts.set_max_background_jobs(6); db_opts.set_bytes_per_sync(1048576); + // https://github.com/facebook/rocksdb/wiki/WAL-Recovery-Modes#ktoleratecorruptedtailrecords + // + // Unclean shutdowns of a Matrix homeserver are likely to be fine when + // recovered in this manner as it's likely any lost information will be + // restored via federation. + db_opts.set_wal_recovery_mode(rocksdb::DBRecoveryMode::TolerateCorruptedTailRecords); + let prefix_extractor = rocksdb::SliceTransform::create_fixed_prefix(1); db_opts.set_prefix_extractor(prefix_extractor); -- cgit v1.2.3 From 7990822f724c3a727e62ce8476f8da05ddfcd6fe Mon Sep 17 00:00:00 2001 From: Tobias Tom Date: Fri, 28 Jul 2023 16:26:40 +0100 Subject: It's ok not being able to find a .well-known response. --- src/api/server_server.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 2179b16..9a1b680 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -506,7 +506,8 @@ async fn request_well_known(destination: &str) -> Option { .await; debug!("Got well known response"); if let Err(e) = &response { - error!("Well known error: {e:?}"); + debug!("Well known error: {e:?}"); + return None; } let text = response.ok()?.text().await; debug!("Got well known response text"); -- cgit v1.2.3 From 7489e2c4f68cb35b3cb94f5a955940d3a565be36 Mon Sep 17 00:00:00 2001 From: purplemeteorite Date: Sat, 29 Jul 2023 08:14:38 +0200 Subject: moved docker-compose.yml into the docker folder --- docker-compose.yml | 53 ----------------------------------------------- docker/docker-compose.yml | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 53 deletions(-) delete mode 100644 docker-compose.yml create mode 100644 docker/docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index d9c32b5..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,53 +0,0 @@ -# Conduit -version: '3' - -services: - homeserver: - ### If you already built the Conduit image with 'docker build' or want to use a registry image, - ### then you are ready to go. - image: matrixconduit/matrix-conduit:latest - ### If you want to build a fresh image from the sources, then comment the image line and uncomment the - ### build lines. If you want meaningful labels in your built Conduit image, you should run docker-compose like this: - ### CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') VERSION=$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml) docker-compose up -d - # build: - # context: . - # args: - # CREATED: '2021-03-16T08:18:27Z' - # VERSION: '0.1.0' - # LOCAL: 'false' - # GIT_REF: origin/master - restart: unless-stopped - ports: - - 8448:6167 - volumes: - - db:/var/lib/matrix-conduit/ - environment: - CONDUIT_SERVER_NAME: your.server.name # EDIT THIS - CONDUIT_DATABASE_PATH: /var/lib/matrix-conduit/ - CONDUIT_DATABASE_BACKEND: rocksdb - CONDUIT_PORT: 6167 - CONDUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB - CONDUIT_ALLOW_REGISTRATION: 'true' - CONDUIT_ALLOW_FEDERATION: 'true' - CONDUIT_TRUSTED_SERVERS: '["matrix.org"]' - #CONDUIT_MAX_CONCURRENT_REQUESTS: 100 - #CONDUIT_LOG: warn,rocket=off,_=off,sled=off - CONDUIT_ADDRESS: 0.0.0.0 - CONDUIT_CONFIG: '' # Ignore this - # - ### Uncomment if you want to use your own Element-Web App. - ### Note: You need to provide a config.json for Element and you also need a second - ### Domain or Subdomain for the communication between Element and Conduit - ### Config-Docs: https://github.com/vector-im/element-web/blob/develop/docs/config.md - # element-web: - # image: vectorim/element-web:latest - # restart: unless-stopped - # ports: - # - 8009:80 - # volumes: - # - ./element_config.json:/app/config.json - # depends_on: - # - homeserver - -volumes: - db: diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..d9c32b5 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,53 @@ +# Conduit +version: '3' + +services: + homeserver: + ### If you already built the Conduit image with 'docker build' or want to use a registry image, + ### then you are ready to go. + image: matrixconduit/matrix-conduit:latest + ### If you want to build a fresh image from the sources, then comment the image line and uncomment the + ### build lines. If you want meaningful labels in your built Conduit image, you should run docker-compose like this: + ### CREATED=$(date -u +'%Y-%m-%dT%H:%M:%SZ') VERSION=$(grep -m1 -o '[0-9].[0-9].[0-9]' Cargo.toml) docker-compose up -d + # build: + # context: . + # args: + # CREATED: '2021-03-16T08:18:27Z' + # VERSION: '0.1.0' + # LOCAL: 'false' + # GIT_REF: origin/master + restart: unless-stopped + ports: + - 8448:6167 + volumes: + - db:/var/lib/matrix-conduit/ + environment: + CONDUIT_SERVER_NAME: your.server.name # EDIT THIS + CONDUIT_DATABASE_PATH: /var/lib/matrix-conduit/ + CONDUIT_DATABASE_BACKEND: rocksdb + CONDUIT_PORT: 6167 + CONDUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB + CONDUIT_ALLOW_REGISTRATION: 'true' + CONDUIT_ALLOW_FEDERATION: 'true' + CONDUIT_TRUSTED_SERVERS: '["matrix.org"]' + #CONDUIT_MAX_CONCURRENT_REQUESTS: 100 + #CONDUIT_LOG: warn,rocket=off,_=off,sled=off + CONDUIT_ADDRESS: 0.0.0.0 + CONDUIT_CONFIG: '' # Ignore this + # + ### Uncomment if you want to use your own Element-Web App. + ### Note: You need to provide a config.json for Element and you also need a second + ### Domain or Subdomain for the communication between Element and Conduit + ### Config-Docs: https://github.com/vector-im/element-web/blob/develop/docs/config.md + # element-web: + # image: vectorim/element-web:latest + # restart: unless-stopped + # ports: + # - 8009:80 + # volumes: + # - ./element_config.json:/app/config.json + # depends_on: + # - homeserver + +volumes: + db: -- cgit v1.2.3 From 081cc66edac5b1a2a6af92e4b735ea02b1848c39 Mon Sep 17 00:00:00 2001 From: purplemeteorite Date: Sat, 29 Jul 2023 08:26:34 +0200 Subject: fixed broken traefik links in docker README --- docker/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/README.md b/docker/README.md index cd41291..43f2996 100644 --- a/docker/README.md +++ b/docker/README.md @@ -117,7 +117,7 @@ As a container user, you probably know about Traefik. It is a easy to use revers containerized app and services available through the web. With the two provided files, [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) (or [`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)) and -[`docker-compose.override.yml`](docker-compose.override.traefik.yml), it is equally easy to deploy +[`docker-compose.override.yml`](docker-compose.override.yml), it is equally easy to deploy and use Conduit, with a little caveat. If you already took a look at the files, then you should have seen the `well-known` service, and that is the little caveat. Traefik is simply a proxy and loadbalancer and is not able to serve any kind of content, but for Conduit to federate, we need to @@ -128,7 +128,8 @@ With the service `well-known` we use a single `nginx` container that will serve So...step by step: -1. Copy [`docker-compose.traefik.yml`](docker-compose.traefik.yml) and [`docker-compose.override.traefik.yml`](docker-compose.override.traefik.yml) from the repository and remove `.traefik` from the filenames. +1. Copy [`docker-compose.for-traefik.yml`](docker-compose.for-traefik.yml) (or +[`docker-compose.with-traefik.yml`](docker-compose.with-traefik.yml)) and [`docker-compose.override.traefik.yml`](docker-compose.override.yml) from the repository and remove `.traefik` from the filenames. 2. Open both files and modify/adjust them to your needs. Meaning, change the `CONDUIT_SERVER_NAME` and the volume host mappings according to your needs. 3. Create the `conduit.toml` config file, an example can be found [here](../conduit-example.toml), or set `CONDUIT_CONFIG=""` and configure Conduit per env vars. 4. Uncomment the `element-web` service if you want to host your own Element Web Client and create a `element_config.json`. -- cgit v1.2.3 From 1f867a2c867c2ce84558e11e3dc8fa49060c21b4 Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Thu, 27 Jul 2023 16:23:24 +0000 Subject: Only print raw malformed JSON body in debug level Signed-off-by: girlbossceo --- src/api/ruma_wrapper/axum.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/api/ruma_wrapper/axum.rs b/src/api/ruma_wrapper/axum.rs index 069e12b..bbd4861 100644 --- a/src/api/ruma_wrapper/axum.rs +++ b/src/api/ruma_wrapper/axum.rs @@ -292,10 +292,8 @@ where debug!("{:?}", http_request); let body = T::try_from_http_request(http_request, &path_params).map_err(|e| { - warn!( - "try_from_http_request failed: {:?}\nJSON body: {:?}", - e, json_body - ); + warn!("try_from_http_request failed: {:?}", e); + debug!("JSON body: {:?}", json_body); Error::BadRequest(ErrorKind::BadJson, "Failed to deserialize request.") })?; -- cgit v1.2.3 From a0148a9996e4a3f031e80abed31f81e7b8d4a1f4 Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Thu, 27 Jul 2023 16:24:04 +0000 Subject: Print relevant room ID and ACL'd server in informational level These are room ACLs, not server ACLs. Causes confusion where people think their Conduit homeserver was ACL'd. Print where these are coming from in informational level. Signed-off-by: girlbossceo --- src/service/rooms/event_handler/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index ef5616e..89ac72e 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -1526,9 +1526,13 @@ impl Service { if acl_event_content.is_allowed(server_name) { Ok(()) } else { + info!( + "Server {} was denied by room ACL in {}", + server_name, room_id + ); Err(Error::BadRequest( ErrorKind::Forbidden, - "Server was denied by ACL", + "Server was denied by room ACL", )) } } -- cgit v1.2.3 From 863103450c876711e1d2dfead103f2bfa358a2aa Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Thu, 27 Jul 2023 17:02:57 +0000 Subject: Log the unknown login type in warning level Signed-off-by: girlbossceo --- src/api/client_server/session.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/client_server/session.rs b/src/api/client_server/session.rs index 8908fef..5ce62af 100644 --- a/src/api/client_server/session.rs +++ b/src/api/client_server/session.rs @@ -9,7 +9,7 @@ use ruma::{ UserId, }; use serde::Deserialize; -use tracing::info; +use tracing::{info, warn}; #[derive(Debug, Deserialize)] struct Claims { @@ -52,6 +52,7 @@ pub async fn login_route(body: Ruma) -> Result) -> Result { + warn!("Unsupported or unknown login type: {:?}", &body.login_info); return Err(Error::BadRequest( ErrorKind::Unknown, "Unsupported login type.", -- cgit v1.2.3 From cc5dcceacc38483209502d120b56407db9ad3055 Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Fri, 28 Jul 2023 23:40:10 +0000 Subject: Log the room ID, event ID, PDU, and event type where possible Signed-off-by: girlbossceo --- src/api/client_server/room.rs | 4 +++- src/api/client_server/state.rs | 16 +++++++++------- src/api/server_server.rs | 11 ++++++++--- src/service/rooms/state/mod.rs | 4 +++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/api/client_server/room.rs b/src/api/client_server/room.rs index 8c39b78..7bdccae 100644 --- a/src/api/client_server/room.rs +++ b/src/api/client_server/room.rs @@ -429,7 +429,9 @@ pub async fn get_room_event_route( .rooms .timeline .get_pdu(&body.event_id)? - .ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?; + .ok_or({ + warn!("Event not found, event ID: {:?}", &body.event_id); + Error::BadRequest(ErrorKind::NotFound, "Event not found.")})?; if !services().rooms.state_accessor.user_can_see_event( sender_user, diff --git a/src/api/client_server/state.rs b/src/api/client_server/state.rs index 8e4ceaf..5ea7e99 100644 --- a/src/api/client_server/state.rs +++ b/src/api/client_server/state.rs @@ -12,6 +12,7 @@ use ruma::{ serde::Raw, EventId, RoomId, UserId, }; +use tracing::log::warn; /// # `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}` /// @@ -129,10 +130,11 @@ pub async fn get_state_events_for_key_route( .rooms .state_accessor .room_state_get(&body.room_id, &body.event_type, &body.state_key)? - .ok_or(Error::BadRequest( - ErrorKind::NotFound, + .ok_or({ + warn!("State event {:?} not found in room {:?}", &body.event_type, &body.room_id); + Error::BadRequest(ErrorKind::NotFound, "State event not found.", - ))?; + )})?; Ok(get_state_events_for_key::v3::Response { content: serde_json::from_str(event.content.get()) @@ -165,10 +167,10 @@ pub async fn get_state_events_for_empty_key_route( .rooms .state_accessor .room_state_get(&body.room_id, &body.event_type, "")? - .ok_or(Error::BadRequest( - ErrorKind::NotFound, - "State event not found.", - ))?; + .ok_or({ + warn!("State event {:?} not found in room {:?}", &body.event_type, &body.room_id); + Error::BadRequest(ErrorKind::NotFound, + "State event not found.",)})?; Ok(get_state_events_for_key::v3::Response { content: serde_json::from_str(event.content.get()) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 9a1b680..95716e7 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -711,7 +711,8 @@ pub async fn send_transaction_message_route( let (event_id, value, room_id) = match r { Ok(t) => t, Err(e) => { - warn!("Could not parse pdu: {e}"); + warn!("Could not parse PDU: {e}"); + warn!("Full PDU: {:?}", &pdu); continue; } }; @@ -952,7 +953,9 @@ pub async fn get_event_route( .rooms .timeline .get_pdu_json(&body.event_id)? - .ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?; + .ok_or({ + warn!("Event not found, event ID: {:?}", &body.event_id); + Error::BadRequest(ErrorKind::NotFound, "Event not found.")})?; let room_id_str = event .get("room_id") @@ -1192,7 +1195,9 @@ pub async fn get_event_authorization_route( .rooms .timeline .get_pdu_json(&body.event_id)? - .ok_or(Error::BadRequest(ErrorKind::NotFound, "Event not found."))?; + .ok_or({ + warn!("Event not found, event ID: {:?}", &body.event_id); + Error::BadRequest(ErrorKind::NotFound, "Event not found.")})?; let room_id_str = event .get("room_id") diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index d782386..48e3d79 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -342,7 +342,9 @@ impl Service { .transpose()?; let room_version = create_event_content .map(|create_event| create_event.room_version) - .ok_or(Error::BadDatabase("Invalid room version"))?; + .ok_or({ + warn!("Invalid room version for room {room_id}"); + Error::BadDatabase("Invalid room version")})?; Ok(room_version) } -- cgit v1.2.3 From 3494d7759e0c371ce436ed34dcc87bd03a10ca70 Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Fri, 28 Jul 2023 23:47:00 +0000 Subject: Return "Hello from Conduit!" on the / route akin to Synapes's "It works!" page, removing an unnecessary warning about / route being unknown Signed-off-by: girlbossceo --- src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.rs b/src/main.rs index eb7e833..9b7528c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -433,6 +433,7 @@ fn routes() -> Router { "/_matrix/client/v3/rooms/:room_id/initialSync", get(initial_sync), ) + .route("/", get(it_works)) .fallback(not_found) } @@ -482,6 +483,10 @@ async fn initial_sync(_uri: Uri) -> impl IntoResponse { ) } +async fn it_works() -> &'static str { + "Hello from Conduit!" +} + trait RouterExt { fn ruma_route(self, handler: H) -> Self where -- cgit v1.2.3 From d7061e69841526f16d33b3c6739ef8c853d777b9 Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Sat, 29 Jul 2023 14:30:48 +0000 Subject: cargo fmt Signed-off-by: girlbossceo --- src/api/client_server/room.rs | 11 ++++------- src/api/client_server/state.rs | 19 ++++++++++++------- src/api/server_server.rs | 6 ++++-- src/service/globals/mod.rs | 10 ++++++---- src/service/rooms/state/mod.rs | 3 ++- src/service/users/mod.rs | 4 +++- 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/api/client_server/room.rs b/src/api/client_server/room.rs index 7bdccae..5c98028 100644 --- a/src/api/client_server/room.rs +++ b/src/api/client_server/room.rs @@ -425,13 +425,10 @@ pub async fn get_room_event_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - let event = services() - .rooms - .timeline - .get_pdu(&body.event_id)? - .ok_or({ - warn!("Event not found, event ID: {:?}", &body.event_id); - Error::BadRequest(ErrorKind::NotFound, "Event not found.")})?; + let event = services().rooms.timeline.get_pdu(&body.event_id)?.ok_or({ + warn!("Event not found, event ID: {:?}", &body.event_id); + Error::BadRequest(ErrorKind::NotFound, "Event not found.") + })?; if !services().rooms.state_accessor.user_can_see_event( sender_user, diff --git a/src/api/client_server/state.rs b/src/api/client_server/state.rs index 5ea7e99..6a37489 100644 --- a/src/api/client_server/state.rs +++ b/src/api/client_server/state.rs @@ -131,10 +131,12 @@ pub async fn get_state_events_for_key_route( .state_accessor .room_state_get(&body.room_id, &body.event_type, &body.state_key)? .ok_or({ - warn!("State event {:?} not found in room {:?}", &body.event_type, &body.room_id); - Error::BadRequest(ErrorKind::NotFound, - "State event not found.", - )})?; + warn!( + "State event {:?} not found in room {:?}", + &body.event_type, &body.room_id + ); + Error::BadRequest(ErrorKind::NotFound, "State event not found.") + })?; Ok(get_state_events_for_key::v3::Response { content: serde_json::from_str(event.content.get()) @@ -168,9 +170,12 @@ pub async fn get_state_events_for_empty_key_route( .state_accessor .room_state_get(&body.room_id, &body.event_type, "")? .ok_or({ - warn!("State event {:?} not found in room {:?}", &body.event_type, &body.room_id); - Error::BadRequest(ErrorKind::NotFound, - "State event not found.",)})?; + warn!( + "State event {:?} not found in room {:?}", + &body.event_type, &body.room_id + ); + Error::BadRequest(ErrorKind::NotFound, "State event not found.") + })?; Ok(get_state_events_for_key::v3::Response { content: serde_json::from_str(event.content.get()) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 95716e7..8c54e92 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -955,7 +955,8 @@ pub async fn get_event_route( .get_pdu_json(&body.event_id)? .ok_or({ warn!("Event not found, event ID: {:?}", &body.event_id); - Error::BadRequest(ErrorKind::NotFound, "Event not found.")})?; + Error::BadRequest(ErrorKind::NotFound, "Event not found.") + })?; let room_id_str = event .get("room_id") @@ -1197,7 +1198,8 @@ pub async fn get_event_authorization_route( .get_pdu_json(&body.event_id)? .ok_or({ warn!("Event not found, event ID: {:?}", &body.event_id); - Error::BadRequest(ErrorKind::NotFound, "Event not found.")})?; + Error::BadRequest(ErrorKind::NotFound, "Event not found.") + })?; let room_id_str = event .get("room_id") diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index 7d61829..44235b3 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -1,8 +1,8 @@ mod data; pub use data::Data; -use ruma::serde::Base64; use ruma::{ - OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedServerSigningKeyId, OwnedUserId, + serde::Base64, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedServerName, + OwnedServerSigningKeyId, OwnedUserId, }; use crate::api::server_server::FedDest; @@ -15,14 +15,16 @@ use ruma::{ }, DeviceId, RoomVersionId, ServerName, UserId, }; -use std::sync::atomic::{self, AtomicBool}; use std::{ collections::{BTreeMap, HashMap}, fs, future::Future, net::{IpAddr, SocketAddr}, path::PathBuf, - sync::{Arc, Mutex, RwLock}, + sync::{ + atomic::{self, AtomicBool}, + Arc, Mutex, RwLock, + }, time::{Duration, Instant}, }; use tokio::sync::{broadcast, watch::Receiver, Mutex as TokioMutex, Semaphore}; diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index 48e3d79..9790695 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -344,7 +344,8 @@ impl Service { .map(|create_event| create_event.room_version) .ok_or({ warn!("Invalid room version for room {room_id}"); - Error::BadDatabase("Invalid room version")})?; + Error::BadDatabase("Invalid room version") + })?; Ok(room_version) } diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index f5b914f..38aca80 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -62,7 +62,9 @@ impl Service { device_id: OwnedDeviceId, request: &mut sync_events::v4::Request, ) -> BTreeMap> { - let Some(conn_id) = request.conn_id.clone() else { return BTreeMap::new(); }; + let Some(conn_id) = request.conn_id.clone() else { + return BTreeMap::new(); + }; let cache = &mut self.connections.lock().unwrap(); let cached = Arc::clone( -- cgit v1.2.3 From da907451e77648b8fce022f0d7fa536a6f678267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sun, 23 Jul 2023 14:52:11 +0200 Subject: Admin commands to sign and verify jsons --- src/service/admin/mod.rs | 70 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index 9250a3e..6c3e3d0 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -1,7 +1,7 @@ use std::{ collections::BTreeMap, convert::{TryFrom, TryInto}, - sync::Arc, + sync::{Arc, RwLock}, time::Instant, }; @@ -163,6 +163,20 @@ enum AdminCommand { DisableRoom { room_id: Box }, /// Enables incoming federation handling for a room again. EnableRoom { room_id: Box }, + + /// Verify json signatures + /// [commandbody] + /// # ``` + /// # json here + /// # ``` + SignJson, + + /// Verify json signatures + /// [commandbody] + /// # ``` + /// # json here + /// # ``` + VerifyJson, } #[derive(Debug)] @@ -754,6 +768,60 @@ impl Service { ) } } + AdminCommand::SignJson => { + if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```" + { + let string = body[1..body.len() - 1].join("\n"); + match serde_json::from_str(&string) { + Ok(mut value) => { + ruma::signatures::sign_json( + services().globals.server_name().as_str(), + services().globals.keypair(), + &mut value, + ) + .expect("our request json is what ruma expects"); + let json_text = serde_json::to_string_pretty(&value) + .expect("canonical json is valid json"); + RoomMessageEventContent::text_plain(json_text) + } + Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")), + } + } else { + RoomMessageEventContent::text_plain( + "Expected code block in command body. Add --help for details.", + ) + } + } + AdminCommand::VerifyJson => { + if body.len() > 2 && body[0].trim() == "```" && body.last().unwrap().trim() == "```" + { + let string = body[1..body.len() - 1].join("\n"); + match serde_json::from_str(&string) { + Ok(value) => { + let pub_key_map = RwLock::new(BTreeMap::new()); + + services() + .rooms + .event_handler + .fetch_required_signing_keys(&value, &pub_key_map) + .await?; + + let pub_key_map = pub_key_map.read().unwrap(); + match ruma::signatures::verify_json(&pub_key_map, &value) { + Ok(_) => RoomMessageEventContent::text_plain("Signature correct"), + Err(e) => RoomMessageEventContent::text_plain(format!( + "Signature verification failed: {e}" + )), + } + } + Err(e) => RoomMessageEventContent::text_plain(format!("Invalid json: {e}")), + } + } else { + RoomMessageEventContent::text_plain( + "Expected code block in command body. Add --help for details.", + ) + } + } }; Ok(reply_message_content) -- cgit v1.2.3 From e2c914cc11f268bb6212e68e6b71b74255b24b97 Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Sat, 29 Jul 2023 19:17:12 +0000 Subject: fix: s/ok_or/ok_or_else in relevant places Signed-off-by: girlbossceo --- src/api/client_server/room.rs | 12 ++++++++---- src/api/client_server/state.rs | 4 ++-- src/api/server_server.rs | 4 ++-- src/service/rooms/state/mod.rs | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/api/client_server/room.rs b/src/api/client_server/room.rs index 5c98028..56bdf03 100644 --- a/src/api/client_server/room.rs +++ b/src/api/client_server/room.rs @@ -425,10 +425,14 @@ pub async fn get_room_event_route( ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); - let event = services().rooms.timeline.get_pdu(&body.event_id)?.ok_or({ - warn!("Event not found, event ID: {:?}", &body.event_id); - Error::BadRequest(ErrorKind::NotFound, "Event not found.") - })?; + let event = services() + .rooms + .timeline + .get_pdu(&body.event_id)? + .ok_or_else(|| { + warn!("Event not found, event ID: {:?}", &body.event_id); + Error::BadRequest(ErrorKind::NotFound, "Event not found.") + })?; if !services().rooms.state_accessor.user_can_see_event( sender_user, diff --git a/src/api/client_server/state.rs b/src/api/client_server/state.rs index 6a37489..d6d3939 100644 --- a/src/api/client_server/state.rs +++ b/src/api/client_server/state.rs @@ -130,7 +130,7 @@ pub async fn get_state_events_for_key_route( .rooms .state_accessor .room_state_get(&body.room_id, &body.event_type, &body.state_key)? - .ok_or({ + .ok_or_else(|| { warn!( "State event {:?} not found in room {:?}", &body.event_type, &body.room_id @@ -169,7 +169,7 @@ pub async fn get_state_events_for_empty_key_route( .rooms .state_accessor .room_state_get(&body.room_id, &body.event_type, "")? - .ok_or({ + .ok_or_else(|| { warn!( "State event {:?} not found in room {:?}", &body.event_type, &body.room_id diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 8c54e92..ca5b69d 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -953,7 +953,7 @@ pub async fn get_event_route( .rooms .timeline .get_pdu_json(&body.event_id)? - .ok_or({ + .ok_or_else(|| { warn!("Event not found, event ID: {:?}", &body.event_id); Error::BadRequest(ErrorKind::NotFound, "Event not found.") })?; @@ -1196,7 +1196,7 @@ pub async fn get_event_authorization_route( .rooms .timeline .get_pdu_json(&body.event_id)? - .ok_or({ + .ok_or_else(|| { warn!("Event not found, event ID: {:?}", &body.event_id); Error::BadRequest(ErrorKind::NotFound, "Event not found.") })?; diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index 9790695..16e0a04 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -342,7 +342,7 @@ impl Service { .transpose()?; let room_version = create_event_content .map(|create_event| create_event.room_version) - .ok_or({ + .ok_or_else(|| { warn!("Invalid room version for room {room_id}"); Error::BadDatabase("Invalid room version") })?; -- cgit v1.2.3 From b8c164dc6027844d665158dc8906dd5c89f9238b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Sat, 29 Jul 2023 20:01:38 +0200 Subject: feat: version checker --- DEPLOY.md | 1 + complement/Dockerfile | 1 + conduit-example.toml | 1 + debian/postinst | 1 + docker-compose.yml | 1 + docker/docker-compose.for-traefik.yml | 1 + docker/docker-compose.with-traefik.yml | 5 +-- src/config/mod.rs | 2 ++ src/database/key_value/globals.rs | 18 ++++++++++ src/database/mod.rs | 62 ++++++++++++++++++++++++++++++++-- src/service/globals/data.rs | 2 ++ src/service/globals/mod.rs | 14 ++++++++ 12 files changed, 105 insertions(+), 4 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index ec7dd46..4605a98 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -172,6 +172,7 @@ max_request_size = 20_000_000 # in bytes allow_registration = true allow_federation = true +allow_check_for_updates = true # Server to get public keys from. You probably shouldn't change this trusted_servers = ["matrix.org"] diff --git a/complement/Dockerfile b/complement/Dockerfile index 43416fa..50173a1 100644 --- a/complement/Dockerfile +++ b/complement/Dockerfile @@ -30,6 +30,7 @@ ENV CONDUIT_CONFIG=/workdir/conduit.toml RUN sed -i "s/port = 6167/port = 8008/g" conduit.toml RUN echo "allow_federation = true" >> conduit.toml +RUN echo "allow_check_for_updates = true" >> conduit.toml RUN echo "allow_encryption = true" >> conduit.toml RUN echo "allow_registration = true" >> conduit.toml RUN echo "log = \"warn,_=off,sled=off\"" >> conduit.toml diff --git a/conduit-example.toml b/conduit-example.toml index 6089aa5..836db65 100644 --- a/conduit-example.toml +++ b/conduit-example.toml @@ -39,6 +39,7 @@ max_request_size = 20_000_000 # in bytes allow_registration = true allow_federation = true +allow_check_for_updates = true # Enable the display name lightning bolt on registration. enable_lightning_bolt = true diff --git a/debian/postinst b/debian/postinst index dfa599d..69a766a 100644 --- a/debian/postinst +++ b/debian/postinst @@ -73,6 +73,7 @@ max_request_size = 20_000_000 # in bytes allow_registration = true allow_federation = true +allow_check_for_updates = true trusted_servers = ["matrix.org"] diff --git a/docker-compose.yml b/docker-compose.yml index d9c32b5..5bcf84f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,7 @@ services: CONDUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB CONDUIT_ALLOW_REGISTRATION: 'true' CONDUIT_ALLOW_FEDERATION: 'true' + CONDUIT_ALLOW_CHECK_FOR_UPDATES: 'true' CONDUIT_TRUSTED_SERVERS: '["matrix.org"]' #CONDUIT_MAX_CONCURRENT_REQUESTS: 100 #CONDUIT_LOG: warn,rocket=off,_=off,sled=off diff --git a/docker/docker-compose.for-traefik.yml b/docker/docker-compose.for-traefik.yml index 474299f..bed734f 100644 --- a/docker/docker-compose.for-traefik.yml +++ b/docker/docker-compose.for-traefik.yml @@ -29,6 +29,7 @@ services: CONDUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB CONDUIT_ALLOW_REGISTRATION: 'true' CONDUIT_ALLOW_FEDERATION: 'true' + CONDUIT_ALLOW_CHECK_FOR_UPDATES: 'true' CONDUIT_TRUSTED_SERVERS: '["matrix.org"]' #CONDUIT_MAX_CONCURRENT_REQUESTS: 100 #CONDUIT_LOG: warn,rocket=off,_=off,sled=off diff --git a/docker/docker-compose.with-traefik.yml b/docker/docker-compose.with-traefik.yml index 79ebef4..fda942b 100644 --- a/docker/docker-compose.with-traefik.yml +++ b/docker/docker-compose.with-traefik.yml @@ -35,8 +35,9 @@ services: # Available levels are: error, warn, info, debug, trace - more info at: https://docs.rs/env_logger/*/env_logger/#enabling-logging # CONDUIT_LOG: info # default is: "warn,_=off,sled=off" # CONDUIT_ALLOW_JAEGER: 'false' - # CONDUIT_ALLOW_ENCRYPTION: 'false' - # CONDUIT_ALLOW_FEDERATION: 'false' + # CONDUIT_ALLOW_ENCRYPTION: 'true' + # CONDUIT_ALLOW_FEDERATION: 'true' + # CONDUIT_ALLOW_CHECK_FOR_UPDATES: 'true' # CONDUIT_DATABASE_PATH: /srv/conduit/.local/share/conduit # CONDUIT_WORKERS: 10 # CONDUIT_MAX_REQUEST_SIZE: 20_000_000 # in bytes, ~20 MB diff --git a/src/config/mod.rs b/src/config/mod.rs index 4dad9f7..e2c2ff1 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -28,6 +28,8 @@ pub struct Config { pub db_cache_capacity_mb: f64, #[serde(default = "true_fn")] pub enable_lightning_bolt: bool, + #[serde(default = "true_fn")] + pub allow_check_for_updates: bool, #[serde(default = "default_conduit_cache_capacity_modifier")] pub conduit_cache_capacity_modifier: f64, #[serde(default = "default_rocksdb_max_open_files")] diff --git a/src/database/key_value/globals.rs b/src/database/key_value/globals.rs index 1e02459..11aa064 100644 --- a/src/database/key_value/globals.rs +++ b/src/database/key_value/globals.rs @@ -12,6 +12,7 @@ use ruma::{ use crate::{database::KeyValueDatabase, service, services, utils, Error, Result}; pub const COUNTER: &[u8] = b"c"; +pub const LAST_CHECK_FOR_UPDATES_COUNT: &[u8] = b"u"; #[async_trait] impl service::globals::Data for KeyValueDatabase { @@ -27,6 +28,23 @@ impl service::globals::Data for KeyValueDatabase { }) } + fn last_check_for_updates_id(&self) -> Result { + self.global + .get(LAST_CHECK_FOR_UPDATES_COUNT)? + .map_or(Ok(0_u64), |bytes| { + utils::u64_from_bytes(&bytes).map_err(|_| { + Error::bad_database("last check for updates count has invalid bytes.") + }) + }) + } + + fn update_check_for_updates_id(&self, id: u64) -> Result<()> { + self.global + .insert(LAST_CHECK_FOR_UPDATES_COUNT, &id.to_be_bytes())?; + + Ok(()) + } + async fn watch(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()> { let userid_bytes = user_id.as_bytes().to_vec(); let mut userid_prefix = userid_bytes.clone(); diff --git a/src/database/mod.rs b/src/database/mod.rs index 4e7bda6..b36347d 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -18,6 +18,7 @@ use ruma::{ CanonicalJsonValue, EventId, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId, }; +use serde::Deserialize; use std::{ collections::{BTreeMap, HashMap, HashSet}, fs::{self, remove_dir_all}, @@ -25,7 +26,9 @@ use std::{ mem::size_of, path::Path, sync::{Arc, Mutex, RwLock}, + time::Duration, }; +use tokio::time::interval; use tracing::{debug, error, info, warn}; @@ -982,6 +985,9 @@ impl KeyValueDatabase { services().sending.start_handler(); Self::start_cleanup_task().await; + if services().globals.allow_check_for_updates() { + Self::start_check_for_updates_task(); + } Ok(()) } @@ -998,9 +1004,61 @@ impl KeyValueDatabase { } #[tracing::instrument] - pub async fn start_cleanup_task() { - use tokio::time::interval; + pub fn start_check_for_updates_task() { + tokio::spawn(async move { + let timer_interval = Duration::from_secs(60 * 60); + let mut i = interval(timer_interval); + loop { + i.tick().await; + let _ = Self::try_handle_updates().await; + } + }); + } + async fn try_handle_updates() -> Result<()> { + let response = services() + .globals + .default_client() + .get("https://conduit.rs/check-for-updates/stable") + .send() + .await?; + + #[derive(Deserialize)] + struct CheckForUpdatesResponseEntry { + id: u64, + date: String, + message: String, + } + #[derive(Deserialize)] + struct CheckForUpdatesResponse { + updates: Vec, + } + + let response = serde_json::from_str::(&response.text().await?) + .map_err(|_| Error::BadServerResponse("Bad version check response"))?; + + let mut last_update_id = services().globals.last_check_for_updates_id()?; + for update in response.updates { + last_update_id = last_update_id.max(update.id); + if update.id > services().globals.last_check_for_updates_id()? { + println!("{}", update.message); + services() + .admin + .send_message(RoomMessageEventContent::text_plain(format!( + "@room: The following is a message from the Conduit developers. It was sent on '{}':\n\n{}", + update.date, update.message + ))) + } + } + services() + .globals + .update_check_for_updates_id(last_update_id)?; + + Ok(()) + } + + #[tracing::instrument] + pub async fn start_cleanup_task() { #[cfg(unix)] use tokio::signal::unix::{signal, SignalKind}; diff --git a/src/service/globals/data.rs b/src/service/globals/data.rs index 171b3fe..8a66751 100644 --- a/src/service/globals/data.rs +++ b/src/service/globals/data.rs @@ -13,6 +13,8 @@ use crate::Result; pub trait Data: Send + Sync { fn next_count(&self) -> Result; fn current_count(&self) -> Result; + fn last_check_for_updates_id(&self) -> Result; + fn update_check_for_updates_id(&self, id: u64) -> Result<()>; async fn watch(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()>; fn cleanup(&self) -> Result<()>; fn memory_usage(&self) -> String; diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index 44235b3..875a457 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -209,6 +209,16 @@ impl Service { self.db.current_count() } + #[tracing::instrument(skip(self))] + pub fn last_check_for_updates_id(&self) -> Result { + self.db.last_check_for_updates_id() + } + + #[tracing::instrument(skip(self))] + pub fn update_check_for_updates_id(&self, id: u64) -> Result<()> { + self.db.update_check_for_updates_id(id) + } + pub async fn watch(&self, user_id: &UserId, device_id: &DeviceId) -> Result<()> { self.db.watch(user_id, device_id).await } @@ -257,6 +267,10 @@ impl Service { self.config.enable_lightning_bolt } + pub fn allow_check_for_updates(&self) -> bool { + self.config.allow_check_for_updates + } + pub fn trusted_servers(&self) -> &[OwnedServerName] { &self.config.trusted_servers } -- cgit v1.2.3 From 83805c66e509b39b5d17d1a8d5033d9593711e84 Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Sun, 30 Jul 2023 17:30:16 +0000 Subject: sanitise potentially sensitive errors prevents errors like DB or I/O errors from leaking filesystem paths Co-authored-by: infamous Signed-off-by: girlbossceo --- src/api/server_server.rs | 2 +- src/utils/error.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/api/server_server.rs b/src/api/server_server.rs index ca5b69d..6d2da07 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -927,7 +927,7 @@ pub async fn send_transaction_message_route( Ok(send_transaction_message::v1::Response { pdus: resolved_map .into_iter() - .map(|(e, r)| (e, r.map_err(|e| e.to_string()))) + .map(|(e, r)| (e, r.map_err(|e| e.sanitized_error()))) .collect(), }) } diff --git a/src/utils/error.rs b/src/utils/error.rs index 4f044ca..7fafea1 100644 --- a/src/utils/error.rs +++ b/src/utils/error.rs @@ -138,6 +138,28 @@ impl Error { status_code, })) } + + /// Sanitizes public-facing errors that can leak sensitive information. + pub fn sanitized_error(&self) -> String { + let db_error = String::from("Database or I/O error occurred."); + + match self { + #[cfg(feature = "sled")] + Self::SledError { .. } => db_error, + #[cfg(feature = "sqlite")] + Self::SqliteError { .. } => db_error, + #[cfg(feature = "persy")] + Self::PersyError { .. } => db_error, + #[cfg(feature = "heed")] + Self::HeedError => db_error, + #[cfg(feature = "rocksdb")] + Self::RocksDbError { .. } => db_error, + Self::IoError { .. } => db_error, + Self::BadConfig { .. } => db_error, + Self::BadDatabase { .. } => db_error, + _ => self.to_string(), + } + } } #[cfg(feature = "persy")] -- cgit v1.2.3 From acfe381dd3064512272f8f47ea4dd388c04f1c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 31 Jul 2023 16:18:23 +0200 Subject: fix: threads get updated properly Workaround for element web while waiting for https://github.com/matrix-org/matrix-js-sdk/pull/3635 --- src/api/client_server/membership.rs | 2 +- src/api/client_server/room.rs | 3 +++ src/api/client_server/sync.rs | 3 ++- src/api/server_server.rs | 4 +-- src/database/key_value/rooms/timeline.rs | 2 ++ src/main.rs | 6 +++-- src/service/pdu.rs | 13 ++++++++++ src/service/rooms/event_handler/mod.rs | 42 ++++++++++++++++---------------- src/utils/error.rs | 4 +-- 9 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/api/client_server/membership.rs b/src/api/client_server/membership.rs index c9357b2..4a1f374 100644 --- a/src/api/client_server/membership.rs +++ b/src/api/client_server/membership.rs @@ -674,7 +674,7 @@ async fn join_room_by_id_helper( }; let pdu = PduEvent::from_id_val(&event_id, value.clone()).map_err(|e| { - warn!("{:?}: {}", value, e); + warn!("Invalid PDU in send_join response: {} {:?}", e, value); Error::BadServerResponse("Invalid PDU in send_join response.") })?; diff --git a/src/api/client_server/room.rs b/src/api/client_server/room.rs index 56bdf03..420dd50 100644 --- a/src/api/client_server/room.rs +++ b/src/api/client_server/room.rs @@ -445,6 +445,9 @@ pub async fn get_room_event_route( )); } + let mut event = (*event).clone(); + event.add_age()?; + Ok(get_room_event::v3::Response { event: event.to_room_event(), }) diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 527625a..7c6002e 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -20,8 +20,9 @@ use ruma::{ StateEventType, TimelineEventType, }, serde::Raw, - uint, DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UInt, UserId, + uint, DeviceId, OwnedDeviceId, OwnedEventId, OwnedUserId, RoomId, UInt, UserId, }; +use serde::Deserialize; use std::{ collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, sync::Arc, diff --git a/src/api/server_server.rs b/src/api/server_server.rs index ca5b69d..2220c4d 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -813,7 +813,7 @@ pub async fn send_transaction_message_route( .readreceipt_update(&user_id, &room_id, event)?; } else { // TODO fetch missing events - info!("No known event ids in read receipt: {:?}", user_updates); + debug!("No known event ids in read receipt: {:?}", user_updates); } } } @@ -1011,7 +1011,7 @@ pub async fn get_backfill_route( .as_ref() .expect("server is authenticated"); - info!("Got backfill request from: {}", sender_servername); + debug!("Got backfill request from: {}", sender_servername); if !services() .rooms diff --git a/src/database/key_value/rooms/timeline.rs b/src/database/key_value/rooms/timeline.rs index 74e3e5c..5ce2136 100644 --- a/src/database/key_value/rooms/timeline.rs +++ b/src/database/key_value/rooms/timeline.rs @@ -246,6 +246,7 @@ impl service::rooms::timeline::Data for KeyValueDatabase { if pdu.sender != user_id { pdu.remove_transaction_id()?; } + pdu.add_age()?; let count = pdu_count(&pdu_id)?; Ok((count, pdu)) }), @@ -272,6 +273,7 @@ impl service::rooms::timeline::Data for KeyValueDatabase { if pdu.sender != user_id { pdu.remove_transaction_id()?; } + pdu.add_age()?; let count = pdu_count(&pdu_id)?; Ok((count, pdu)) }), diff --git a/src/main.rs b/src/main.rs index 9b7528c..1975038 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,6 +85,8 @@ async fn main() { config.warn_deprecated(); + let log = format!("{},ruma_state_res=error,_=off,sled=off", config.log); + if config.allow_jaeger { opentelemetry::global::set_text_map_propagator(opentelemetry_jaeger::Propagator::new()); let tracer = opentelemetry_jaeger::new_agent_pipeline() @@ -94,7 +96,7 @@ async fn main() { .unwrap(); let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); - let filter_layer = match EnvFilter::try_new(&config.log) { + let filter_layer = match EnvFilter::try_new(&log) { Ok(s) => s, Err(e) => { eprintln!( @@ -121,7 +123,7 @@ async fn main() { } else { let registry = tracing_subscriber::Registry::default(); let fmt_layer = tracing_subscriber::fmt::Layer::new(); - let filter_layer = match EnvFilter::try_new(&config.log) { + let filter_layer = match EnvFilter::try_new(&log) { Ok(s) => s, Err(e) => { eprintln!("It looks like your config is invalid. The following error occured while parsing it: {e}"); diff --git a/src/service/pdu.rs b/src/service/pdu.rs index d24e174..4a170bc 100644 --- a/src/service/pdu.rs +++ b/src/service/pdu.rs @@ -103,6 +103,19 @@ impl PduEvent { Ok(()) } + pub fn add_age(&mut self) -> crate::Result<()> { + let mut unsigned: BTreeMap> = self + .unsigned + .as_ref() + .map_or_else(|| Ok(BTreeMap::new()), |u| serde_json::from_str(u.get())) + .map_err(|_| Error::bad_database("Invalid unsigned in pdu event"))?; + + unsigned.insert("age".to_owned(), to_raw_value(&1).unwrap()); + self.unsigned = Some(to_raw_value(&unsigned).expect("unsigned is valid")); + + Ok(()) + } + #[tracing::instrument(skip(self))] pub fn to_sync_room_event(&self) -> Raw { let mut json = json!({ diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index 89ac72e..c6e433c 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -357,7 +357,7 @@ impl Service { .await; // 6. Reject "due to auth events" if the event doesn't pass auth based on the auth events - info!( + debug!( "Auth check for {} based on auth events", incoming_pdu.event_id ); @@ -419,7 +419,7 @@ impl Service { )); } - info!("Validation successful."); + debug!("Validation successful."); // 7. Persist the event as an outlier. services() @@ -427,7 +427,7 @@ impl Service { .outlier .add_pdu_outlier(&incoming_pdu.event_id, &val)?; - info!("Added pdu as outlier."); + debug!("Added pdu as outlier."); Ok((Arc::new(incoming_pdu), val)) }) @@ -476,7 +476,7 @@ impl Service { // TODO: if we know the prev_events of the incoming event we can avoid the request and build // the state from a known point and resolve if > 1 prev_event - info!("Requesting state at event"); + debug!("Requesting state at event"); let mut state_at_incoming_event = None; if incoming_pdu.prev_events.len() == 1 { @@ -499,7 +499,7 @@ impl Service { }; if let Some(Ok(mut state)) = state { - info!("Using cached state"); + debug!("Using cached state"); let prev_pdu = services() .rooms .timeline @@ -523,7 +523,7 @@ impl Service { state_at_incoming_event = Some(state); } } else { - info!("Calculating state at event using state res"); + debug!("Calculating state at event using state res"); let mut extremity_sstatehashes = HashMap::new(); let mut okay = true; @@ -632,7 +632,7 @@ impl Service { } if state_at_incoming_event.is_none() { - info!("Calling /state_ids"); + debug!("Calling /state_ids"); // Call /state_ids to find out what the state at this pdu is. We trust the server's // response to some extend, but we still do a lot of checks on the events match services() @@ -647,7 +647,7 @@ impl Service { .await { Ok(res) => { - info!("Fetching state events at event."); + debug!("Fetching state events at event."); let state_vec = self .fetch_and_handle_outliers( origin, @@ -710,7 +710,7 @@ impl Service { let state_at_incoming_event = state_at_incoming_event.expect("we always set this to some above"); - info!("Starting auth check"); + debug!("Starting auth check"); // 11. Check the auth of the event passes based on the state of the event let check_result = state_res::event_auth::auth_check( &room_version, @@ -734,7 +734,7 @@ impl Service { "Event has failed auth check with state at the event.", )); } - info!("Auth check succeeded"); + debug!("Auth check succeeded"); // Soft fail check before doing state res let auth_events = services().rooms.state.get_auth_events( @@ -769,7 +769,7 @@ impl Service { // Now we calculate the set of extremities this room has after the incoming event has been // applied. We start with the previous extremities (aka leaves) - info!("Calculating extremities"); + debug!("Calculating extremities"); let mut extremities = services().rooms.state.get_forward_extremities(room_id)?; // Remove any forward extremities that are referenced by this incoming event's prev_events @@ -790,7 +790,7 @@ impl Service { ) }); - info!("Compressing state at event"); + debug!("Compressing state at event"); let state_ids_compressed = Arc::new( state_at_incoming_event .iter() @@ -804,7 +804,7 @@ impl Service { ); if incoming_pdu.state_key.is_some() { - info!("Preparing for stateres to derive new room state"); + debug!("Preparing for stateres to derive new room state"); // We also add state after incoming event to the fork states let mut state_after = state_at_incoming_event.clone(); @@ -822,7 +822,7 @@ impl Service { .await?; // Set the new room state to the resolved state - info!("Forcing new room state"); + debug!("Forcing new room state"); let (sstatehash, new, removed) = services() .rooms @@ -837,7 +837,7 @@ impl Service { } // 14. Check if the event passes auth based on the "current state" of the room, if not soft fail it - info!("Starting soft fail auth check"); + debug!("Starting soft fail auth check"); if soft_fail { services().rooms.timeline.append_incoming_pdu( @@ -861,7 +861,7 @@ impl Service { )); } - info!("Appending pdu to timeline"); + debug!("Appending pdu to timeline"); extremities.insert(incoming_pdu.event_id.clone()); // Now that the event has passed all auth it is added into the timeline. @@ -877,7 +877,7 @@ impl Service { &state_lock, )?; - info!("Appended incoming pdu"); + debug!("Appended incoming pdu"); // Event has passed all auth/stateres checks drop(state_lock); @@ -890,7 +890,7 @@ impl Service { room_version_id: &RoomVersionId, incoming_state: HashMap>, ) -> Result>> { - info!("Loading current room state ids"); + debug!("Loading current room state ids"); let current_sstatehash = services() .rooms .state @@ -917,7 +917,7 @@ impl Service { ); } - info!("Loading fork states"); + debug!("Loading fork states"); let fork_states: Vec<_> = fork_states .into_iter() @@ -935,7 +935,7 @@ impl Service { }) .collect(); - info!("Resolving state"); + debug!("Resolving state"); let lock = services().globals.stateres_mutex.lock(); let state = match state_res::resolve(room_version_id, &fork_states, auth_chain_sets, |id| { @@ -953,7 +953,7 @@ impl Service { drop(lock); - info!("State resolution done. Compressing state"); + debug!("State resolution done. Compressing state"); let new_room_state = state .into_iter() diff --git a/src/utils/error.rs b/src/utils/error.rs index 4f044ca..5ffb38c 100644 --- a/src/utils/error.rs +++ b/src/utils/error.rs @@ -9,7 +9,7 @@ use ruma::{ OwnedServerName, }; use thiserror::Error; -use tracing::{error, warn}; +use tracing::{error, info}; #[cfg(feature = "persy")] use persy::PersyError; @@ -131,7 +131,7 @@ impl Error { _ => (Unknown, StatusCode::INTERNAL_SERVER_ERROR), }; - warn!("{}: {}", status_code, message); + info!("Returning an error: {}: {}", status_code, message); RumaResponse(UiaaResponse::MatrixError(RumaError { body: ErrorBody::Standard { kind, message }, -- cgit v1.2.3 From 9ce1cad98319b9257f60b7cd0a3122c4e6f884a8 Mon Sep 17 00:00:00 2001 From: Maarten Steenhagen Date: Tue, 1 Aug 2023 10:58:07 +0000 Subject: Changed 'right' to 'appropriate' to avoid ambiguity (original could be read as right-hand-side) --- DEPLOY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPLOY.md b/DEPLOY.md index 4605a98..0d13160 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -10,7 +10,7 @@ Although you might be able to compile Conduit for Windows, we do recommend running it on a Linux server. We therefore only offer Linux binaries. -You may simply download the binary that fits your machine. Run `uname -m` to see what you need. Now copy the right url: +You may simply download the binary that fits your machine. Run `uname -m` to see what you need. Now copy the appropriate url: | CPU Architecture | Download stable version | Download development version | | ------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------- | -- cgit v1.2.3 From 3a6eee7019af07c10467b882dac01f84874f2e1c Mon Sep 17 00:00:00 2001 From: Maarten Steenhagen Date: Tue, 1 Aug 2023 11:03:31 +0000 Subject: Correct option error adduser in DEPLOY.md --- DEPLOY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPLOY.md b/DEPLOY.md index 4605a98..36b1e39 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -81,7 +81,7 @@ you to make sure that the file permissions are correctly set up. In Debian or RHEL, you can use this command to create a Conduit user: ```bash -sudo adduser --system conduit --group --disable-login --no-create-home +sudo adduser --system conduit --group --disabled-login --no-create-home ``` ## Forwarding ports in the firewall or the router -- cgit v1.2.3 From 5a7bade476d9fa91c7c59f858d9481097b819bf9 Mon Sep 17 00:00:00 2001 From: June Date: Tue, 1 Aug 2023 14:48:50 -1000 Subject: update base64 to 0.21.2 Signed-off-by: June --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/api/client_server/voip.rs | 3 ++- src/service/globals/mod.rs | 4 +++- src/service/sending/mod.rs | 24 +++++++++++------------- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ddf487..cdf1821 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,7 +368,7 @@ dependencies = [ "async-trait", "axum", "axum-server", - "base64 0.13.1", + "base64 0.21.2", "bytes", "clap", "crossbeam", diff --git a/Cargo.toml b/Cargo.toml index 7a157f4..9828162 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ thiserror = "1.0.40" # Used to generate thumbnails for images image = { version = "0.24.6", default-features = false, features = ["jpeg", "png", "gif"] } # Used to encode server public key -base64 = "0.13.1" +base64 = "0.21.2" # Used when hashing the state ring = "0.16.20" # Used when querying the SRV record of other servers diff --git a/src/api/client_server/voip.rs b/src/api/client_server/voip.rs index 4990c17..f0d91f7 100644 --- a/src/api/client_server/voip.rs +++ b/src/api/client_server/voip.rs @@ -1,4 +1,5 @@ use crate::{services, Result, Ruma}; +use base64::{engine::general_purpose, Engine as _}; use hmac::{Hmac, Mac}; use ruma::{api::client::voip::get_turn_server_info, SecondsSinceUnixEpoch}; use sha1::Sha1; @@ -28,7 +29,7 @@ pub async fn turn_server_route( .expect("HMAC can take key of any size"); mac.update(username.as_bytes()); - let password: String = base64::encode_config(mac.finalize().into_bytes(), base64::STANDARD); + let password: String = general_purpose::STANDARD.encode(mac.finalize().into_bytes()); (username, password) } else { diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index 875a457..e9bd0da 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -31,6 +31,8 @@ use tokio::sync::{broadcast, watch::Receiver, Mutex as TokioMutex, Semaphore}; use tracing::{error, info}; use trust_dns_resolver::TokioAsyncResolver; +use base64::{engine::general_purpose, Engine as _}; + type WellKnownMap = HashMap; type TlsNameMap = HashMap, u16)>; type RateLimitState = (Instant, u32); // Time if last failed try, number of failed tries @@ -367,7 +369,7 @@ impl Service { let mut r = PathBuf::new(); r.push(self.config.database_path.clone()); r.push("media"); - r.push(base64::encode_config(key, base64::URL_SAFE_NO_PAD)); + r.push(general_purpose::URL_SAFE_NO_PAD.encode(key)); r } diff --git a/src/service/sending/mod.rs b/src/service/sending/mod.rs index 14d83be..b441144 100644 --- a/src/service/sending/mod.rs +++ b/src/service/sending/mod.rs @@ -18,6 +18,8 @@ use crate::{ use federation::transactions::send_transaction_message; use futures_util::{stream::FuturesUnordered, StreamExt}; +use base64::{engine::general_purpose, Engine as _}; + use ruma::{ api::{ appservice, @@ -497,17 +499,14 @@ impl Service { })?, appservice::event::push_events::v1::Request { events: pdu_jsons, - txn_id: (&*base64::encode_config( - calculate_hash( - &events - .iter() - .map(|e| match e { - SendingEventType::Edu(b) | SendingEventType::Pdu(b) => &**b, - }) - .collect::>(), - ), - base64::URL_SAFE_NO_PAD, - )) + txn_id: (&*general_purpose::URL_SAFE_NO_PAD.encode(calculate_hash( + &events + .iter() + .map(|e| match e { + SendingEventType::Edu(b) | SendingEventType::Pdu(b) => &**b, + }) + .collect::>(), + ))) .into(), }, ) @@ -642,7 +641,7 @@ impl Service { pdus: pdu_jsons, edus: edu_jsons, origin_server_ts: MilliSecondsSinceUnixEpoch::now(), - transaction_id: (&*base64::encode_config( + transaction_id: (&*general_purpose::URL_SAFE_NO_PAD.encode( calculate_hash( &events .iter() @@ -651,7 +650,6 @@ impl Service { }) .collect::>(), ), - base64::URL_SAFE_NO_PAD, )) .into(), }, -- cgit v1.2.3 From fbb256dd91f8f6795f4273bcfcd98adaf04e7f2f Mon Sep 17 00:00:00 2001 From: June Date: Tue, 1 Aug 2023 15:09:55 -1000 Subject: bump rusqlite to 0.29.0 Signed-off-by: June --- Cargo.lock | 10 +++++----- Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ddf487..a234b79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1361,9 +1361,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.25.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" dependencies = [ "cc", "pkg-config", @@ -2305,11 +2305,11 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.3.2", "fallible-iterator", "fallible-streaming-iterator", "hashlink", diff --git a/Cargo.toml b/Cargo.toml index 7a157f4..e137494 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ opentelemetry = { version = "0.18.0", features = ["rt-tokio"] } opentelemetry-jaeger = { version = "0.17.0", features = ["rt-tokio"] } tracing-opentelemetry = "0.18.0" lru-cache = "0.1.2" -rusqlite = { version = "0.28.0", optional = true, features = ["bundled"] } +rusqlite = { version = "0.29.0", optional = true, features = ["bundled"] } parking_lot = { version = "0.12.1", optional = true } crossbeam = { version = "0.8.2", optional = true } num_cpus = "1.15.0" -- cgit v1.2.3 From fbd8090b0bf47ba1a4ed818c84e374b50d39c94a Mon Sep 17 00:00:00 2001 From: girlbossceo Date: Mon, 31 Jul 2023 01:02:52 +0000 Subject: log room ID for invalid room topic event errors Signed-off-by: girlbossceo --- src/api/client_server/directory.rs | 1 + src/service/rooms/spaces/mod.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/client_server/directory.rs b/src/api/client_server/directory.rs index a812dbc..50ae9f1 100644 --- a/src/api/client_server/directory.rs +++ b/src/api/client_server/directory.rs @@ -221,6 +221,7 @@ pub(crate) async fn get_public_rooms_filtered_helper( serde_json::from_str(s.content.get()) .map(|c: RoomTopicEventContent| Some(c.topic)) .map_err(|_| { + error!("Invalid room topic event in database for room {}", room_id); Error::bad_database("Invalid room topic event in database.") }) })?, diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index e92fc07..9b57d53 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -326,7 +326,10 @@ impl Service { .map_or(Ok(None), |s| { serde_json::from_str(s.content.get()) .map(|c: RoomTopicEventContent| Some(c.topic)) - .map_err(|_| Error::bad_database("Invalid room topic event in database.")) + .map_err(|_| { + error!("Invalid room topic event in database for room {}", room_id); + Error::bad_database("Invalid room topic event in database.") + }) })?, world_readable: services() .rooms -- cgit v1.2.3 From 06fccbc3405c943ed4ecd2f1ab7528101f2a891c Mon Sep 17 00:00:00 2001 From: June Date: Thu, 3 Aug 2023 14:51:39 -1000 Subject: debug log before and after nofile soft limit increases Signed-off-by: June --- src/main.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1975038..c74d6dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ use tower_http::{ trace::TraceLayer, ServiceBuilderExt as _, }; -use tracing::{error, info, warn}; +use tracing::{debug, error, info, warn}; use tracing_subscriber::{prelude::*, EnvFilter}; pub use conduit::*; // Re-export everything from the library crate @@ -54,17 +54,7 @@ static GLOBAL: Jemalloc = Jemalloc; #[tokio::main] async fn main() { - // This is needed for opening lots of file descriptors, which tends to - // happen more often when using RocksDB and making lots of federation - // connections at startup. The soft limit is usually 1024, and the hard - // limit is usually 512000; I've personally seen it hit >2000. - // - // * https://www.freedesktop.org/software/systemd/man/systemd.exec.html#id-1.12.2.1.17.6 - // * https://github.com/systemd/systemd/commit/0abf94923b4a95a7d89bc526efc84e7ca2b71741 - #[cfg(unix)] - maximize_fd_limit().expect("should be able to increase the soft limit to the hard limit"); - - // Initialize DB + // Initialize config let raw_config = Figment::new() .merge( @@ -135,6 +125,16 @@ async fn main() { tracing::subscriber::set_global_default(subscriber).unwrap(); } + // This is needed for opening lots of file descriptors, which tends to + // happen more often when using RocksDB and making lots of federation + // connections at startup. The soft limit is usually 1024, and the hard + // limit is usually 512000; I've personally seen it hit >2000. + // + // * https://www.freedesktop.org/software/systemd/man/systemd.exec.html#id-1.12.2.1.17.6 + // * https://github.com/systemd/systemd/commit/0abf94923b4a95a7d89bc526efc84e7ca2b71741 + #[cfg(unix)] + maximize_fd_limit().expect("should be able to increase the soft limit to the hard limit"); + info!("Loading database"); if let Err(error) = KeyValueDatabase::load_or_create(config).await { error!(?error, "The database couldn't be loaded or created"); @@ -569,12 +569,19 @@ fn method_to_filter(method: Method) -> MethodFilter { } #[cfg(unix)] +#[tracing::instrument(err)] fn maximize_fd_limit() -> Result<(), nix::errno::Errno> { use nix::sys::resource::{getrlimit, setrlimit, Resource}; let res = Resource::RLIMIT_NOFILE; - let (_, hard_limit) = getrlimit(res)?; + let (soft_limit, hard_limit) = getrlimit(res)?; + + debug!("Current nofile soft limit: {soft_limit}"); - setrlimit(res, hard_limit, hard_limit) + setrlimit(res, hard_limit, hard_limit)?; + + debug!("Increased nofile soft limit to {hard_limit}"); + + Ok(()) } -- cgit v1.2.3 From c1e2ffc0cdcf11a2d9763ab85af27e1a6f6f909a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 7 Aug 2023 13:55:44 +0200 Subject: improvement: maybe cross signing really works now --- src/api/client_server/keys.rs | 5 +++++ src/api/client_server/sync.rs | 3 +-- src/api/server_server.rs | 3 ++- src/database/key_value/users.rs | 5 ++++- src/service/rooms/state_cache/mod.rs | 17 +++++++++++------ src/service/users/data.rs | 1 + src/service/users/mod.rs | 16 +++++++++++----- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/api/client_server/keys.rs b/src/api/client_server/keys.rs index 3e03221..b847301 100644 --- a/src/api/client_server/keys.rs +++ b/src/api/client_server/keys.rs @@ -132,6 +132,7 @@ pub async fn upload_signing_keys_route( master_key, &body.self_signing_key, &body.user_signing_key, + true, // notify so that other users see the new keys )?; } @@ -375,6 +376,10 @@ pub(crate) async fn get_keys_helper bool>( } let json = serde_json::to_value(master_key).expect("to_value always works"); let raw = serde_json::from_value(json).expect("Raw::from_value always works"); + services().users.add_cross_signing_keys( + &user, &raw, &None, &None, + false, // Dont notify. A notification would trigger another key request resulting in an endless loop + )?; master_keys.insert(user, raw); } diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 7c6002e..527625a 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -20,9 +20,8 @@ use ruma::{ StateEventType, TimelineEventType, }, serde::Raw, - uint, DeviceId, OwnedDeviceId, OwnedEventId, OwnedUserId, RoomId, UInt, UserId, + uint, DeviceId, OwnedDeviceId, OwnedUserId, RoomId, UInt, UserId, }; -use serde::Deserialize; use std::{ collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, sync::Arc, diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 2220c4d..554361f 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -55,7 +55,7 @@ use std::{ time::{Duration, Instant, SystemTime}, }; -use tracing::{debug, error, info, warn}; +use tracing::{debug, error, warn}; /// Wraps either an literal IP address plus port, or a hostname plus complement /// (colon-plus-port if it was specified). @@ -917,6 +917,7 @@ pub async fn send_transaction_message_route( &master_key, &self_signing_key, &None, + true, )?; } } diff --git a/src/database/key_value/users.rs b/src/database/key_value/users.rs index 0301cda..2b09d68 100644 --- a/src/database/key_value/users.rs +++ b/src/database/key_value/users.rs @@ -449,6 +449,7 @@ impl service::users::Data for KeyValueDatabase { master_key: &Raw, self_signing_key: &Option>, user_signing_key: &Option>, + notify: bool, ) -> Result<()> { // TODO: Check signatures let mut prefix = user_id.as_bytes().to_vec(); @@ -530,7 +531,9 @@ impl service::users::Data for KeyValueDatabase { .insert(user_id.as_bytes(), &user_signing_key_key)?; } - self.mark_device_key_update(user_id)?; + if notify { + self.mark_device_key_update(user_id)?; + } Ok(()) } diff --git a/src/service/rooms/state_cache/mod.rs b/src/service/rooms/state_cache/mod.rs index 32afdd4..ef1ad61 100644 --- a/src/service/rooms/state_cache/mod.rs +++ b/src/service/rooms/state_cache/mod.rs @@ -14,6 +14,7 @@ use ruma::{ serde::Raw, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId, }; +use tracing::warn; use crate::{services, Error, Result}; @@ -88,8 +89,9 @@ impl Service { RoomAccountDataEventType::Tag, )? .map(|event| { - serde_json::from_str(event.get()).map_err(|_| { - Error::bad_database("Invalid account data event in db.") + serde_json::from_str(event.get()).map_err(|e| { + warn!("Invalid account data event in db: {e:?}"); + Error::BadDatabase("Invalid account data event in db.") }) }) { @@ -113,8 +115,9 @@ impl Service { GlobalAccountDataEventType::Direct.to_string().into(), )? .map(|event| { - serde_json::from_str::(event.get()).map_err(|_| { - Error::bad_database("Invalid account data event in db.") + serde_json::from_str::(event.get()).map_err(|e| { + warn!("Invalid account data event in db: {e:?}"); + Error::BadDatabase("Invalid account data event in db.") }) }) { @@ -155,8 +158,10 @@ impl Service { .into(), )? .map(|event| { - serde_json::from_str::(event.get()) - .map_err(|_| Error::bad_database("Invalid account data event in db.")) + serde_json::from_str::(event.get()).map_err(|e| { + warn!("Invalid account data event in db: {e:?}"); + Error::BadDatabase("Invalid account data event in db.") + }) }) .transpose()? .map_or(false, |ignored| { diff --git a/src/service/users/data.rs b/src/service/users/data.rs index d01e070..ddf941e 100644 --- a/src/service/users/data.rs +++ b/src/service/users/data.rs @@ -111,6 +111,7 @@ pub trait Data: Send + Sync { master_key: &Raw, self_signing_key: &Option>, user_signing_key: &Option>, + notify: bool, ) -> Result<()>; fn sign_key( diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index 38aca80..c345e56 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -66,7 +66,7 @@ impl Service { return BTreeMap::new(); }; - let cache = &mut self.connections.lock().unwrap(); + let mut cache = self.connections.lock().unwrap(); let cached = Arc::clone( cache .entry((user_id, device_id, conn_id)) @@ -185,7 +185,7 @@ impl Service { conn_id: String, subscriptions: BTreeMap, ) { - let cache = &mut self.connections.lock().unwrap(); + let mut cache = self.connections.lock().unwrap(); let cached = Arc::clone( cache .entry((user_id, device_id, conn_id)) @@ -212,7 +212,7 @@ impl Service { list_id: String, new_cached_rooms: BTreeMap, ) { - let cache = &mut self.connections.lock().unwrap(); + let mut cache = self.connections.lock().unwrap(); let cached = Arc::clone( cache .entry((user_id, device_id, conn_id)) @@ -398,9 +398,15 @@ impl Service { master_key: &Raw, self_signing_key: &Option>, user_signing_key: &Option>, + notify: bool, ) -> Result<()> { - self.db - .add_cross_signing_keys(user_id, master_key, self_signing_key, user_signing_key) + self.db.add_cross_signing_keys( + user_id, + master_key, + self_signing_key, + user_signing_key, + notify, + ) } pub fn sign_key( -- cgit v1.2.3 From d82c26f0a9a92d0193924ddc3d81b7b0a152862b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Mon, 7 Aug 2023 17:54:08 +0200 Subject: Avatars for sliding sync DMs --- Cargo.lock | 29 +++++------ Cargo.toml | 2 +- src/api/client_server/sync.rs | 86 +++++++++++++++++++++------------ src/service/rooms/state_accessor/mod.rs | 12 +++++ 4 files changed, 80 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ddf487..b357bb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1296,7 +1296,6 @@ checksum = "1d9a8bb6c7c71d151b25936b03e012a4c00daea99e3a3797c6ead66b0a0d55e2" dependencies = [ "const_panic", "konst_kernel", - "konst_proc_macros", "typewit", ] @@ -1309,12 +1308,6 @@ dependencies = [ "typewit", ] -[[package]] -name = "konst_proc_macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e28ab1dc35e09d60c2b8c90d12a9a8d9666c876c10a3739a3196db0103b6043" - [[package]] name = "lazy_static" version = "1.4.0" @@ -2146,7 +2139,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.8.2" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "assign", "js_int", @@ -2164,7 +2157,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.8.1" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "js_int", "ruma-common", @@ -2175,7 +2168,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.16.2" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "assign", "bytes", @@ -2192,7 +2185,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "base64 0.21.2", "bytes", @@ -2220,7 +2213,7 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "js_int", "ruma-common", @@ -2231,7 +2224,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "js_int", "thiserror", @@ -2240,7 +2233,7 @@ dependencies = [ [[package]] name = "ruma-identity-service-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "js_int", "ruma-common", @@ -2250,7 +2243,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.11.3" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "once_cell", "proc-macro-crate", @@ -2265,7 +2258,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.7.1" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "js_int", "ruma-common", @@ -2276,7 +2269,7 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.13.1" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "base64 0.21.2", "ed25519-dalek", @@ -2292,7 +2285,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.9.1" -source = "git+https://github.com/ruma/ruma?rev=07bc06038fded40d4e9180637f056d256f9a1fbc#07bc06038fded40d4e9180637f056d256f9a1fbc" +source = "git+https://github.com/ruma/ruma?rev=3bd58e3c899457c2d55c45268dcb8a65ae682d54#3bd58e3c899457c2d55c45268dcb8a65ae682d54" dependencies = [ "itertools", "js_int", diff --git a/Cargo.toml b/Cargo.toml index 7a157f4..9d1e9cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ tower-http = { version = "0.4.1", features = ["add-extension", "cors", "sensitiv # Used for matrix spec type definitions and helpers #ruma = { version = "0.4.0", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-pre-spec", "unstable-exhaustive-types"] } -ruma = { git = "https://github.com/ruma/ruma", rev = "07bc06038fded40d4e9180637f056d256f9a1fbc", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } +ruma = { git = "https://github.com/ruma/ruma", rev = "3bd58e3c899457c2d55c45268dcb8a65ae682d54", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } #ruma = { git = "https://github.com/timokoesters/ruma", rev = "4ec9c69bb7e09391add2382b3ebac97b6e8f4c64", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } #ruma = { path = "../ruma/crates/ruma", features = ["compat", "rand", "appservice-api-c", "client-api", "federation-api", "push-gateway-api-c", "state-res", "unstable-msc2448", "unstable-msc3575", "unstable-exhaustive-types", "ring-compat", "unstable-unspecified" ] } diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 527625a..a0edc43 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -1558,6 +1558,56 @@ pub async fn sync_events_v4_route( .map(|state| state.to_sync_state_event()) .collect(); + // Heroes + let heroes = services() + .rooms + .state_cache + .room_members(&room_id) + .filter_map(|r| r.ok()) + .filter(|member| member != &sender_user) + .map(|member| { + Ok::<_, Error>( + services() + .rooms + .state_accessor + .get_member(&room_id, &member)? + .map(|memberevent| { + ( + memberevent + .displayname + .unwrap_or_else(|| member.to_string()), + memberevent.avatar_url, + ) + }), + ) + }) + .filter_map(|r| r.ok()) + .filter_map(|o| o) + .take(5) + .collect::>(); + let name = if heroes.len() > 1 { + let last = heroes[0].0.clone(); + Some( + heroes[1..] + .iter() + .map(|h| h.0.clone()) + .collect::>() + .join(", ") + + " and " + + &last, + ) + } else if heroes.len() == 1 { + Some(heroes[0].0.clone()) + } else { + None + }; + + let avatar = if heroes.len() == 1 { + heroes[0].1.clone() + } else { + None + }; + rooms.insert( room_id.clone(), sync_events::v4::SlidingSyncRoom { @@ -1565,36 +1615,12 @@ pub async fn sync_events_v4_route( .rooms .state_accessor .get_name(&room_id)? - .or_else(|| { - // Heroes - let mut names = services() - .rooms - .state_cache - .room_members(&room_id) - .filter_map(|r| r.ok()) - .filter(|member| member != &sender_user) - .map(|member| { - Ok::<_, Error>( - services() - .rooms - .state_accessor - .get_member(&room_id, &member)? - .and_then(|memberevent| memberevent.displayname) - .unwrap_or(member.to_string()), - ) - }) - .filter_map(|r| r.ok()) - .take(5) - .collect::>(); - if names.len() > 1 { - let last = names.pop().unwrap(); - Some(names.join(", ") + " and " + &last) - } else if names.len() == 1 { - Some(names.pop().unwrap()) - } else { - None - } - }), + .or_else(|| name), + avatar: services() + .rooms + .state_accessor + .get_avatar(&room_id)? + .map_or(avatar, |a| a.url), initial: Some(!known), is_dm: None, invite_state: None, diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index 435f4df..a4a62fe 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -9,6 +9,7 @@ use lru_cache::LruCache; use ruma::{ events::{ room::{ + avatar::RoomAvatarEventContent, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, member::{MembershipState, RoomMemberEventContent}, name::RoomNameEventContent, @@ -283,6 +284,17 @@ impl Service { }) } + pub fn get_avatar(&self, room_id: &RoomId) -> Result> { + services() + .rooms + .state_accessor + .room_state_get(&room_id, &StateEventType::RoomAvatar, "")? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map_err(|_| Error::bad_database("Invalid room avatar event in database.")) + }) + } + pub fn get_member( &self, room_id: &RoomId, -- cgit v1.2.3 From c028e0553c541d954b50f82f8ea058c43d8b7d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 9 Aug 2023 18:27:30 +0200 Subject: feat: registration tokens --- README.md | 5 +---- src/api/client_server/account.rs | 23 ++++++++++++++++------- src/api/client_server/sync.rs | 8 ++++---- src/config/mod.rs | 1 + src/database/mod.rs | 4 ++++ src/service/uiaa/mod.rs | 11 +++++++++++ 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 52ea3c1..5e01c8c 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,7 @@ friends or company. #### Can I try it out? Yes! You can test our Conduit instance by opening a Matrix client ( or Element Android for -example) and registering on the `conduit.rs` homeserver. - -*Registration is currently disabled because of scammers. For an account please - message us (see contact section below).* +example) and registering on the `conduit.rs` homeserver. The registration token is "for_testing_only". Don't share personal information. Server hosting for conduit.rs is donated by the Matrix.org Foundation. diff --git a/src/api/client_server/account.rs b/src/api/client_server/account.rs index 1d7480a..4655130 100644 --- a/src/api/client_server/account.rs +++ b/src/api/client_server/account.rs @@ -74,7 +74,10 @@ pub async fn get_register_available_route( /// - Creates a new account and populates it with default account data /// - If `inhibit_login` is false: Creates a device and returns device id and access_token pub async fn register_route(body: Ruma) -> Result { - if !services().globals.allow_registration() && !body.from_appservice { + if !services().globals.allow_registration() + && !body.from_appservice + && services().globals.config.registration_token.is_none() + { return Err(Error::BadRequest( ErrorKind::Forbidden, "Registration has been disabled.", @@ -121,7 +124,11 @@ pub async fn register_route(body: Ruma) -> Result) -> Result Result> { let sender_user = body.sender_user.expect("user is authenticated"); let sender_device = body.sender_device.expect("user is authenticated"); - let mut body = dbg!(body.body); + let mut body = body.body; // Setup watchers, so if there's no response, we can wait for them let watcher = services().globals.watch(&sender_user, &sender_device); @@ -1470,7 +1470,7 @@ pub async fn sync_events_v4_route( } let mut known_subscription_rooms = BTreeMap::new(); - for (room_id, room) in dbg!(&body.room_subscriptions) { + for (room_id, room) in &body.room_subscriptions { let todo_room = todo_rooms .entry(room_id.clone()) .or_insert((BTreeSet::new(), 0, true)); @@ -1680,7 +1680,7 @@ pub async fn sync_events_v4_route( let _ = tokio::time::timeout(duration, watcher).await; } - Ok(dbg!(sync_events::v4::Response { + Ok(sync_events::v4::Response { initial: since == 0, txn_id: body.txn_id.clone(), pos: next_batch.to_string(), @@ -1735,5 +1735,5 @@ pub async fn sync_events_v4_route( }, }, delta_token: None, - })) + }) } diff --git a/src/config/mod.rs b/src/config/mod.rs index e2c2ff1..9128c52 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -46,6 +46,7 @@ pub struct Config { pub max_fetch_prev_events: u16, #[serde(default = "false_fn")] pub allow_registration: bool, + pub registration_token: Option, #[serde(default = "true_fn")] pub allow_encryption: bool, #[serde(default = "false_fn")] diff --git a/src/database/mod.rs b/src/database/mod.rs index b36347d..e247d9f 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -267,6 +267,10 @@ impl KeyValueDatabase { } }; + if config.registration_token == Some(String::new()) { + return Err(Error::bad_config("Registration token is empty")); + } + if config.max_request_size < 1024 { error!(?config.max_request_size, "Max request size is less than 1KB. Please increase it."); } diff --git a/src/service/uiaa/mod.rs b/src/service/uiaa/mod.rs index 147ce4d..ed39af9 100644 --- a/src/service/uiaa/mod.rs +++ b/src/service/uiaa/mod.rs @@ -96,6 +96,17 @@ impl Service { // Password was correct! Let's add it to `completed` uiaainfo.completed.push(AuthType::Password); } + AuthData::RegistrationToken(t) => { + if Some(t.token.trim()) == services().globals.config.registration_token.as_deref() { + uiaainfo.completed.push(AuthType::RegistrationToken); + } else { + uiaainfo.auth_error = Some(ruma::api::client::error::StandardErrorBody { + kind: ErrorKind::Forbidden, + message: "Invalid registration token.".to_owned(), + }); + return Ok((false, uiaainfo)); + } + } AuthData::Dummy(_) => { uiaainfo.completed.push(AuthType::Dummy); } -- cgit v1.2.3 From 183558150d1c2a022b9be60b22295f78d2326b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Wed, 9 Aug 2023 22:21:21 +0200 Subject: fix: don't show removed rooms in space --- src/service/rooms/spaces/mod.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index 9b57d53..53232f4 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -19,6 +19,7 @@ use ruma::{ join_rules::{self, AllowRule, JoinRule, RoomJoinRulesEventContent}, topic::RoomTopicEventContent, }, + space::child::SpaceChildEventContent, StateEventType, }, space::SpaceRoomJoinRule, @@ -124,11 +125,24 @@ impl Service { if event_type != StateEventType::SpaceChild { continue; } + + let pdu = services() + .rooms + .timeline + .get_pdu(&id)? + .ok_or_else(|| Error::bad_database("Event in space state not found"))?; + + if serde_json::from_str::(pdu.content.get()) + .ok() + .and_then(|c| c.via) + .map_or(true, |v| v.is_empty()) + { + continue; + } + if let Ok(room_id) = OwnedRoomId::try_from(state_key) { children_ids.push(room_id); - children_pdus.push(services().rooms.timeline.get_pdu(&id)?.ok_or_else( - || Error::bad_database("Event in space state not found"), - )?); + children_pdus.push(pdu); } } -- cgit v1.2.3 From fd9e52a559303989740cb64deb273eefea9d3958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 10 Aug 2023 11:45:31 +0200 Subject: More sanity checks --- src/service/rooms/event_handler/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index c6e433c..899f035 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -119,6 +119,7 @@ impl Service { let (incoming_pdu, val) = self .handle_outlier_pdu(origin, &create_event, event_id, room_id, value, pub_key_map) .await?; + self.check_room_id(room_id, &incoming_pdu)?; // 8. if not timeline event: stop if !is_timeline_event { @@ -338,6 +339,8 @@ impl Service { ) .map_err(|_| Error::bad_database("Event is not a valid PDU."))?; + self.check_room_id(room_id, &incoming_pdu)?; + // 4. fetch any missing auth events doing all checks listed here starting at 1. These are not timeline events // 5. Reject "due to auth events" if can't get all the auth events or some of the auth events are also rejected "due to auth events" // NOTE: Step 5 is not applied anymore because it failed too often @@ -373,6 +376,8 @@ impl Service { } }; + self.check_room_id(room_id, &auth_event)?; + match auth_events.entry(( auth_event.kind.to_string().into(), auth_event @@ -1178,6 +1183,8 @@ impl Service { .await .pop() { + self.check_room_id(room_id, &pdu)?; + if amount > services().globals.max_fetch_prev_events() { // Max limit reached warn!("Max prev event limit reached!"); @@ -1702,4 +1709,15 @@ impl Service { "Failed to find public key for server", )) } + + fn check_room_id(&self, room_id: &RoomId, pdu: &PduEvent) -> Result<()> { + if pdu.room_id != room_id { + warn!("Found event from room {} in room {}", pdu.room_id, room_id); + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "Event has wrong room id", + )); + } + Ok(()) + } } -- cgit v1.2.3 From 606b25b9e73b467f44912bf10d2d4c299e9dbd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 10 Aug 2023 17:26:55 +0200 Subject: improvement: more forgiving admin command syntax --- src/service/admin/mod.rs | 2 +- src/service/rooms/timeline/mod.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index 6c3e3d0..0fe5edf 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -287,7 +287,7 @@ impl Service { // Parse and process a message from the admin room async fn process_admin_message(&self, room_message: String) -> RoomMessageEventContent { - let mut lines = room_message.lines(); + let mut lines = room_message.lines().filter(|l| !l.trim().is_empty()); let command_line = lines.next().expect("each string has at least one line"); let body: Vec<_> = lines.collect(); diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 83c3010..25e1c54 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -456,7 +456,9 @@ impl Service { let server_user = format!("@conduit:{}", services().globals.server_name()); let to_conduit = body.starts_with(&format!("{server_user}: ")) - || body.starts_with(&format!("{server_user} ")); + || body.starts_with(&format!("{server_user} ")) + || body == format!("{server_user}:") + || body == format!("{server_user}"); // This will evaluate to false if the emergency password is set up so that // the administrator can execute commands as conduit -- cgit v1.2.3 From 19bfee1835ba89246ec9e3e703ceb5c2f8dc6711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 10 Aug 2023 17:45:58 +0200 Subject: improvement: matrix.org is default trusted server if unspecified --- src/config/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index 9128c52..a4d7cca 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -65,7 +65,7 @@ pub struct Config { #[serde(default)] pub proxy: ProxyConfig, pub jwt_secret: Option, - #[serde(default = "Vec::new")] + #[serde(default = "default_trusted_servers")] pub trusted_servers: Vec, #[serde(default = "default_log")] pub log: String, @@ -259,6 +259,10 @@ fn default_max_fetch_prev_events() -> u16 { 100_u16 } +fn default_trusted_servers() -> Vec { + vec![OwnedServerName::try_from("matrix.org").unwrap()] +} + fn default_log() -> String { "warn,state_res=warn,_=off,sled=off".to_owned() } -- cgit v1.2.3 From 5d16948030d72b6123890f3e1daf0a0b044efeaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20K=C3=B6sters?= Date: Thu, 10 Aug 2023 18:57:25 +0200 Subject: Bump version to v0.6.0 --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9d4be9..35a4208 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -363,7 +363,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "conduit" -version = "0.6.0-alpha" +version = "0.6.0" dependencies = [ "async-trait", "axum", diff --git a/Cargo.toml b/Cargo.toml index ecaa35c..15dc1da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ authors = ["timokoesters "] homepage = "https://conduit.rs" repository = "https://gitlab.com/famedly/conduit" readme = "README.md" -version = "0.6.0-alpha" +version = "0.6.0" edition = "2021" # When changing this, make sure to update the `flake.lock` file by running -- cgit v1.2.3