From a4e64383b72ae65556c6de6d0aba0d3e6bb5f540 Mon Sep 17 00:00:00 2001 From: Jade Ellis Date: Tue, 7 Apr 2026 14:40:10 +0100 Subject: [PATCH] refactor: Ruma upstraming, bake a little more --- Cargo.lock | 7 + Cargo.toml | 3 + src/admin/Cargo.toml | 1 + src/api/Cargo.toml | 1 + src/api/admin/rooms/ban.rs | 5 +- src/api/client/device.rs | 7 +- src/api/client/directory.rs | 11 +- src/api/client/membership/invite.rs | 5 +- src/api/client/membership/join.rs | 26 +- src/api/client/membership/knock.rs | 44 +- src/api/client/membership/leave.rs | 18 +- src/api/client/membership/members.rs | 60 +-- src/api/client/membership/mod.rs | 10 +- src/api/client/room/aliases.rs | 10 +- src/api/client/room/create.rs | 13 +- src/api/router/handler.rs | 2 +- src/core/Cargo.toml | 1 + src/core/error/err.rs | 10 +- src/core/error/mod.rs | 16 +- src/core/error/response.rs | 24 +- src/core/matrix/event/id.rs | 2 +- src/core/matrix/mod.rs | 2 +- src/core/matrix/pdu/redact.rs | 5 +- src/core/matrix/state_res/event_auth.rs | 62 ++- src/core/matrix/state_res/mod.rs | 79 ++-- src/core/matrix/state_res/power_levels.rs | 19 +- src/core/matrix/state_res/serde_backports.rs | 166 +++---- src/core/matrix/state_res/test_utils.rs | 20 +- src/core/matrix/versions.rs | 76 ++-- src/core/mod.rs | 4 +- src/core/utils/json.rs | 12 +- src/database/tests.rs | 8 +- src/router/Cargo.toml | 1 + src/router/router.rs | 2 +- src/ruminuwuity/Cargo.toml | 1 + src/ruminuwuity/admin/continuwuity/mod.rs | 2 +- .../admin/continuwuity/rooms/ban.rs | 32 +- .../admin/continuwuity/rooms/list.rs | 18 +- .../admin/continuwuity/rooms/mod.rs | 2 +- src/ruminuwuity/admin/get_suspended.rs | 83 ++-- src/ruminuwuity/admin/mod.rs | 2 +- src/ruminuwuity/admin/set_suspended.rs | 85 ++-- src/ruminuwuity/draupnir_antispam/mod.rs | 2 +- .../draupnir_antispam/user_may_invite.rs | 81 ++-- .../draupnir_antispam/user_may_join_room.rs | 81 ++-- src/ruminuwuity/invite_permission_config.rs | 428 +++++++++--------- .../meowlnir_antispam/accept_make_join.rs | 88 ++-- src/ruminuwuity/meowlnir_antispam/mod.rs | 2 +- .../meowlnir_antispam/user_may_invite.rs | 102 +++-- .../meowlnir_antispam/user_may_join_room.rs | 99 ++-- src/ruminuwuity/mod.rs | 2 +- src/ruminuwuity/policy/event.rs | 123 +++-- src/ruminuwuity/policy/mod.rs | 2 +- src/ruminuwuity/policy/policy_check.rs | 91 ++-- src/ruminuwuity/policy/policy_sign.rs | 90 ++-- src/ruminuwuity/policy/report_content.rs | 88 ++-- src/service/Cargo.toml | 1 + src/service/account_data/mod.rs | 14 +- src/service/admin/create.rs | 3 +- src/service/admin/mod.rs | 21 +- src/service/antispam/mod.rs | 11 +- src/service/emergency/mod.rs | 4 +- src/service/federation/execute.rs | 117 +++-- src/service/federation/mod.rs | 3 +- src/service/key_backups/mod.rs | 4 +- src/service/media/data.rs | 3 +- src/service/media/mod.rs | 2 +- src/service/media/mxc.rs | 52 +-- src/service/media/remote.rs | 67 ++- src/service/media/thumbnail.rs | 3 +- src/service/migrations.rs | 15 +- src/service/mod.rs | 6 +- src/service/presence/mod.rs | 5 +- src/service/presence/presence.rs | 5 +- src/service/pusher/mod.rs | 53 ++- src/service/rooms/alias/mod.rs | 6 +- .../fetch_and_handle_outliers.rs | 5 +- .../rooms/event_handler/fetch_state.rs | 5 +- .../event_handler/handle_incoming_pdu.rs | 3 +- .../rooms/event_handler/handle_outlier_pdu.rs | 4 +- src/service/rooms/event_handler/mod.rs | 2 +- .../rooms/event_handler/parse_incoming_pdu.rs | 3 +- .../rooms/event_handler/policy_server.rs | 24 +- .../rooms/event_handler/resolve_state.rs | 12 +- .../event_handler/upgrade_outlier_pdu.rs | 4 +- src/service/rooms/read_receipt/data.rs | 4 +- src/service/rooms/spaces/mod.rs | 49 +- src/service/rooms/spaces/pagination_token.rs | 2 +- src/service/rooms/spaces/tests.rs | 15 +- src/service/rooms/state/mod.rs | 18 +- src/service/rooms/state_accessor/mod.rs | 69 ++- .../rooms/state_accessor/server_can.rs | 8 +- src/service/rooms/state_accessor/state.rs | 4 +- src/service/rooms/state_accessor/user_can.rs | 25 +- src/service/rooms/state_cache/mod.rs | 12 +- src/service/rooms/threads/mod.rs | 10 +- src/service/rooms/timeline/append.rs | 19 +- src/service/rooms/timeline/backfill.rs | 46 +- src/service/rooms/timeline/build.rs | 2 +- src/service/rooms/timeline/create.rs | 10 +- src/service/sending/antispam.rs | 10 +- src/service/sending/appservice.rs | 11 +- src/service/sending/mod.rs | 56 ++- src/service/sending/sender.rs | 35 +- src/service/server_keys/get.rs | 3 +- src/service/server_keys/mod.rs | 2 +- src/service/server_keys/sign.rs | 8 +- src/service/server_keys/util.rs | 211 +++++---- src/service/server_keys/verify.rs | 3 +- src/service/sync/mod.rs | 7 +- src/service/threepid/mod.rs | 4 +- src/service/transactions/mod.rs | 5 +- src/service/uiaa/mod.rs | 61 +-- src/service/users/mod.rs | 8 +- src/web/Cargo.toml | 1 + 115 files changed, 1907 insertions(+), 1504 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3145fb69..f29688ff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -999,6 +999,7 @@ dependencies = [ name = "conduwuit_admin" version = "0.5.8" dependencies = [ + "assign", "clap", "conduwuit_api", "conduwuit_core", @@ -1022,6 +1023,7 @@ dependencies = [ name = "conduwuit_api" version = "0.5.8" dependencies = [ + "assign", "async-trait", "axum", "axum-client-ip", @@ -1068,6 +1070,7 @@ version = "0.5.8" dependencies = [ "argon2", "arrayvec", + "assign", "axum", "axum-extra", "bytes", @@ -1161,6 +1164,7 @@ dependencies = [ name = "conduwuit_router" version = "0.5.8" dependencies = [ + "assign", "axum", "axum-client-ip", "axum-server", @@ -1198,6 +1202,7 @@ name = "conduwuit_service" version = "0.5.8" dependencies = [ "askama", + "assign", "async-trait", "base64 0.22.1", "blurhash", @@ -1247,6 +1252,7 @@ name = "conduwuit_web" version = "0.5.8" dependencies = [ "askama", + "assign", "async-trait", "axum", "axum-extra", @@ -4846,6 +4852,7 @@ dependencies = [ name = "ruminuwuity" version = "0.5.7" dependencies = [ + "assign", "ruma", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 8dbe18591..01fddb573 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -342,6 +342,9 @@ version = "0.1.88" [workspace.dependencies.lru-cache] version = "0.1.2" +[workspace.dependencies.assign] +version = "1.1.1" + # Used for matrix spec type definitions and helpers [workspace.dependencies.ruma] # version = "0.14.1" diff --git a/src/admin/Cargo.toml b/src/admin/Cargo.toml index e79c036e3..9a93608b7 100644 --- a/src/admin/Cargo.toml +++ b/src/admin/Cargo.toml @@ -84,6 +84,7 @@ ctor.workspace = true futures.workspace = true lettre.workspace = true log.workspace = true +assign.workspace = true ruma.workspace = true serde_json.workspace = true serde-saphyr.workspace = true diff --git a/src/api/Cargo.toml b/src/api/Cargo.toml index ee84ed079..07ecb7a1d 100644 --- a/src/api/Cargo.toml +++ b/src/api/Cargo.toml @@ -88,6 +88,7 @@ lettre.workspace = true log.workspace = true rand.workspace = true reqwest.workspace = true +assign.workspace = true ruma.workspace = true ruminuwuity.workspace = true serde_html_form.workspace = true diff --git a/src/api/admin/rooms/ban.rs b/src/api/admin/rooms/ban.rs index 66abe5d64..a3a34d7dc 100644 --- a/src/api/admin/rooms/ban.rs +++ b/src/api/admin/rooms/ban.rs @@ -1,10 +1,7 @@ use axum::extract::State; use conduwuit::{Err, Result, info, utils::ReadyExt, warn}; use futures::{FutureExt, StreamExt}; -use ruma::{ - OwnedRoomAliasId, - events::room::message::RoomMessageEventContent, -}; +use ruma::{OwnedRoomAliasId, events::room::message::RoomMessageEventContent}; use ruminuwuity::admin::continuwuity::rooms; use crate::{Ruma, client::leave_room}; diff --git a/src/api/client/device.rs b/src/api/client/device.rs index 0bbc079ed..2296f0e24 100644 --- a/src/api/client/device.rs +++ b/src/api/client/device.rs @@ -81,7 +81,8 @@ pub(crate) async fn update_device_route( }; debug!( - "Creating new device for {sender_user} from appservice {} as device ID does not exist", + "Creating new device for {sender_user} from appservice {} as device ID does not \ + exist", appservice.registration.id ); @@ -121,9 +122,7 @@ pub(crate) async fn delete_device_route( let appservice = body.appservice_info.as_ref(); if appservice.is_some() { - debug!( - "Skipping UIAA for {sender_user} as this is from an appservice" - ); + debug!("Skipping UIAA for {sender_user} as this is from an appservice"); services .users .remove_device(sender_user, &body.device_id) diff --git a/src/api/client/directory.rs b/src/api/client/directory.rs index ae533225e..2d82566e3 100644 --- a/src/api/client/directory.rs +++ b/src/api/client/directory.rs @@ -17,7 +17,8 @@ future::{join, join4, join5}, }; use ruma::{ - OwnedRoomId, RoomId, ServerName, UInt, UserId, api::{ + OwnedRoomId, RoomId, ServerName, UInt, UserId, + api::{ client::{ directory::{ get_public_rooms, get_public_rooms_filtered, get_room_visibility, @@ -26,14 +27,18 @@ room, }, federation, - }, directory::{Filter, PublicRoomsChunk, RoomNetwork, RoomTypeFilter}, events::{ + }, + directory::{Filter, PublicRoomsChunk, RoomNetwork, RoomTypeFilter}, + events::{ StateEventType, room::{ create::RoomCreateEventContent, join_rules::{JoinRule, RoomJoinRulesEventContent}, power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}, }, - }, room::JoinRuleKind, uint + }, + room::JoinRuleKind, + uint, }; use tokio::join; diff --git a/src/api/client/membership/invite.rs b/src/api/client/membership/invite.rs index fc5cd4575..76da32c9d 100644 --- a/src/api/client/membership/invite.rs +++ b/src/api/client/membership/invite.rs @@ -8,7 +8,10 @@ use futures::FutureExt; use ruma::{ RoomId, UserId, - api::{client::membership::invite_user, federation::membership::{RawStrippedState, create_invite}}, + api::{ + client::membership::invite_user, + federation::membership::{RawStrippedState, create_invite}, + }, events::room::member::{MembershipState, RoomMemberEventContent}, }; use ruminuwuity::invite_permission_config::FilterLevel; diff --git a/src/api/client/membership/join.rs b/src/api/client/membership/join.rs index 469402864..05249a57f 100644 --- a/src/api/client/membership/join.rs +++ b/src/api/client/membership/join.rs @@ -208,10 +208,7 @@ pub(crate) async fn join_room_by_id_or_alias_route( ) .await?; - let addl_via_servers = services - .rooms - .state_cache - .servers_invite_via(&room_id); + let addl_via_servers = services.rooms.state_cache.servers_invite_via(&room_id); let addl_state_servers = services .rooms @@ -432,8 +429,7 @@ async fn join_room_by_id_helper_remote( join_event_stub.insert( "content".to_owned(), - to_canonical_value(join_content) - .expect("event is valid, we just created it"), + to_canonical_value(join_content).expect("event is valid, we just created it"), ); // We keep the "event_id" in the pdu only in v1 or @@ -462,10 +458,14 @@ async fn join_room_by_id_helper_remote( let mut join_event = join_event_stub; info!("Asking {remote_server} for send_join in room {room_id}"); - let send_join_request = federation::membership::create_join_event::v2::Request::new(room_id.to_owned(), event_id.clone(), services + let send_join_request = federation::membership::create_join_event::v2::Request::new( + room_id.to_owned(), + event_id.clone(), + services .sending .convert_to_outgoing_federation_event(join_event.clone()) - .await); + .await, + ); let send_join_response = match services .sending @@ -816,15 +816,15 @@ async fn make_join_request( servers.len() ); - let mut request = federation::membership::prepare_join_event::v1::Request::new(room_id.to_owned(), sender_user.to_owned()); + let mut request = federation::membership::prepare_join_event::v1::Request::new( + room_id.to_owned(), + sender_user.to_owned(), + ); request.ver = services.server.supported_room_versions().collect(); let make_join_response = services .sending - .send_federation_request( - remote_server, - request - ) + .send_federation_request(remote_server, request) .await; trace!("make_join response: {:?}", make_join_response); diff --git a/src/api/client/membership/knock.rs b/src/api/client/membership/knock.rs index bb640a146..cd9581db7 100644 --- a/src/api/client/membership/knock.rs +++ b/src/api/client/membership/knock.rs @@ -15,16 +15,20 @@ }; use futures::{FutureExt, StreamExt}; use ruma::{ - CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, RoomVersionId, UserId, api::{ + CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, OwnedServerName, + OwnedUserId, RoomId, RoomVersionId, UserId, + api::{ client::knock::knock_room, federation::{self}, - }, canonical_json::to_canonical_value, events::{ + }, + canonical_json::to_canonical_value, + events::{ StateEventType, room::{ join_rules::{AllowRule, JoinRule}, member::{MembershipState, RoomMemberEventContent}, }, - } + }, }; use service::{ Services, @@ -108,10 +112,7 @@ pub(crate) async fn knock_room_route( ) .await?; - let addl_via_servers = services - .rooms - .state_cache - .servers_invite_via(&room_id); + let addl_via_servers = services.rooms.state_cache.servers_invite_via(&room_id); let addl_state_servers = services .rooms @@ -416,8 +417,7 @@ async fn knock_room_helper_local( ); knock_event_stub.insert( "content".to_owned(), - to_canonical_value(content) - .expect("event is valid, we just created it"), + to_canonical_value(content).expect("event is valid, we just created it"), ); // In order to create a compatible ref hash (EventID) the `hashes` field needs @@ -540,8 +540,7 @@ async fn knock_room_helper_remote( knock_event_stub.insert( "content".to_owned(), - to_canonical_value(knock_content) - .expect("event is valid, we just created it"), + to_canonical_value(knock_content).expect("event is valid, we just created it"), ); // In order to create a compatible ref hash (EventID) the `hashes` field needs @@ -567,7 +566,7 @@ async fn knock_room_helper_remote( services .sending .convert_to_outgoing_federation_event(knock_event.clone()) - .await + .await, ); let send_knock_response = services @@ -594,13 +593,10 @@ async fn knock_room_helper_remote( .map(|event| { #[allow(deprecated)] let raw_value = match event { - federation::membership::RawStrippedState::Stripped(raw_state) => { - &raw_state.clone().into_json() - }, - federation::membership::RawStrippedState::Pdu(raw_value) => { - raw_value - }, - _ => panic!("unknown raw stripped state type"), + | federation::membership::RawStrippedState::Stripped(raw_state) => + &raw_state.clone().into_json(), + | federation::membership::RawStrippedState::Pdu(raw_value) => raw_value, + | _ => panic!("unknown raw stripped state type"), }; serde_json::from_str::(raw_value.get()) @@ -722,15 +718,15 @@ async fn make_knock_request( info!("Asking {remote_server} for make_knock ({make_knock_counter})"); - let mut request = federation::membership::prepare_knock_event::v1::Request::new(room_id.to_owned(), sender_user.to_owned()); + let mut request = federation::membership::prepare_knock_event::v1::Request::new( + room_id.to_owned(), + sender_user.to_owned(), + ); request.ver = services.server.supported_room_versions().collect(); let make_knock_response = services .sending - .send_federation_request( - remote_server, - request, - ) + .send_federation_request(remote_server, request) .await; trace!("make_knock response: {make_knock_response:?}"); diff --git a/src/api/client/membership/leave.rs b/src/api/client/membership/leave.rs index 211a61f87..f7a6d05bc 100644 --- a/src/api/client/membership/leave.rs +++ b/src/api/client/membership/leave.rs @@ -42,10 +42,7 @@ pub(crate) async fn leave_room_route( // Make a user leave all their joined rooms, rescinds knocks, forgets all rooms, // and ignores errors pub async fn leave_all_rooms(services: &Services, user_id: &UserId) { - let rooms_joined = services - .rooms - .state_cache - .rooms_joined(user_id); + let rooms_joined = services.rooms.state_cache.rooms_joined(user_id); let rooms_invited = services .rooms @@ -286,7 +283,10 @@ pub async fn remote_leave_room( .sending .send_federation_request( remote_server.as_ref(), - federation::membership::prepare_leave_event::v1::Request::new(room_id.to_owned(), user_id.to_owned()) + federation::membership::prepare_leave_event::v1::Request::new( + room_id.to_owned(), + user_id.to_owned(), + ), ) .await; @@ -387,10 +387,14 @@ pub async fn remote_leave_room( .sending .send_federation_request( &remote_server, - federation::membership::create_leave_event::v2::Request::new(room_id.to_owned(), event_id.clone(), services + federation::membership::create_leave_event::v2::Request::new( + room_id.to_owned(), + event_id.clone(), + services .sending .convert_to_outgoing_federation_event(leave_event.clone()) - .await), + .await, + ), ) .await?; diff --git a/src/api/client/membership/members.rs b/src/api/client/membership/members.rs index 72bcdbd8b..a9e0f17ef 100644 --- a/src/api/client/membership/members.rs +++ b/src/api/client/membership/members.rs @@ -44,17 +44,17 @@ pub(crate) async fn get_member_events_route( } let chunk = services - .rooms - .state_accessor - .room_state_full(&body.room_id) - .ready_filter_map(Result::ok) - .ready_filter(|((ty, _), _)| *ty == StateEventType::RoomMember) - .map(at!(1)) - .ready_filter_map(|pdu| membership_filter(pdu, membership, not_membership)) - .map(Event::into_format) - .collect() - .boxed() - .await; + .rooms + .state_accessor + .room_state_full(&body.room_id) + .ready_filter_map(Result::ok) + .ready_filter(|((ty, _), _)| *ty == StateEventType::RoomMember) + .map(at!(1)) + .ready_filter_map(|pdu| membership_filter(pdu, membership, not_membership)) + .map(Event::into_format) + .collect() + .boxed() + .await; Ok(get_member_events::v3::Response::new(chunk)) } @@ -79,23 +79,23 @@ pub(crate) async fn joined_members_route( } let joined = services - .rooms - .state_cache - .room_members(&body.room_id) - .broad_then(|user_id| async move { - let mut member = RoomMember::new(); - let (display_name, avatar_url) = join( - services.users.displayname(&user_id).ok(), - services.users.avatar_url(&user_id).ok(), - ) - .await; - member.display_name = display_name; - member.avatar_url = avatar_url; - - (user_id, member) - }) - .collect() + .rooms + .state_cache + .room_members(&body.room_id) + .broad_then(|user_id| async move { + let mut member = RoomMember::new(); + let (display_name, avatar_url) = join( + services.users.displayname(&user_id).ok(), + services.users.avatar_url(&user_id).ok(), + ) .await; + member.display_name = display_name; + member.avatar_url = avatar_url; + + (user_id, member) + }) + .collect() + .await; Ok(joined_members::v3::Response::new(joined)) } @@ -108,12 +108,14 @@ fn membership_filter( let evt_membership = pdu.get_content::().ok()?.membership; if let Some(membership_state_filter) = membership_state_filter - && *membership_state_filter != evt_membership { + && *membership_state_filter != evt_membership + { return None; } if let Some(not_membership_state_filter) = not_membership_state_filter - && *not_membership_state_filter == evt_membership { + && *not_membership_state_filter == evt_membership + { return None; } diff --git a/src/api/client/membership/mod.rs b/src/api/client/membership/mod.rs index ad38eabd8..0b6d0a906 100644 --- a/src/api/client/membership/mod.rs +++ b/src/api/client/membership/mod.rs @@ -48,11 +48,11 @@ pub(crate) async fn joined_rooms_route( body: Ruma, ) -> Result { let joined_rooms = services - .rooms - .state_cache - .rooms_joined(body.sender_user()) - .collect() - .await; + .rooms + .state_cache + .rooms_joined(body.sender_user()) + .collect() + .await; Ok(joined_rooms::v3::Response::new(joined_rooms)) } diff --git a/src/api/client/room/aliases.rs b/src/api/client/room/aliases.rs index b7de681ac..64ab722da 100644 --- a/src/api/client/room/aliases.rs +++ b/src/api/client/room/aliases.rs @@ -27,11 +27,11 @@ pub(crate) async fn get_room_aliases_route( } let aliases = services - .rooms - .alias - .local_aliases_for_room(&body.room_id) - .collect() - .await; + .rooms + .alias + .local_aliases_for_room(&body.room_id) + .collect() + .await; Ok(aliases::v3::Response::new(aliases)) } diff --git a/src/api/client/room/create.rs b/src/api/client/room/create.rs index 7051e081b..4a7652b73 100644 --- a/src/api/client/room/create.rs +++ b/src/api/client/room/create.rs @@ -9,7 +9,9 @@ use conduwuit_service::{Services, appservice::RegistrationInfo}; use futures::FutureExt; use ruma::{ - CanonicalJsonObject, Int, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomId, RoomVersionId, api::client::room::{self, create_room}, events::{ + CanonicalJsonObject, Int, OwnedRoomAliasId, OwnedRoomId, OwnedUserId, RoomId, RoomVersionId, + api::client::room::{self, create_room}, + events::{ TimelineEventType, room::{ canonical_alias::RoomCanonicalAliasEventContent, @@ -22,7 +24,10 @@ power_levels::RoomPowerLevelsEventContent, topic::RoomTopicEventContent, }, - }, int, room_version_rules::RoomIdFormatVersion, serde::{JsonObject, Raw} + }, + int, + room_version_rules::RoomIdFormatVersion, + serde::{JsonObject, Raw}, }; use ruminuwuity::invite_permission_config::FilterLevel; use serde_json::{json, value::to_raw_value}; @@ -80,8 +85,8 @@ pub(crate) async fn create_room_route( let room_version_rules = room_version.rules().unwrap(); let room_id: Option = match room_version_rules.room_id_format { - RoomIdFormatVersion::V1 => Some(RoomId::new_v1(services.globals.server_name())), - _ => None, + | RoomIdFormatVersion::V1 => Some(RoomId::new_v1(services.globals.server_name())), + | _ => None, }; // check if room ID doesn't already exist instead of erroring on auth check diff --git a/src/api/router/handler.rs b/src/api/router/handler.rs index 6d535c4c3..5ffd9f500 100644 --- a/src/api/router/handler.rs +++ b/src/api/router/handler.rs @@ -45,7 +45,7 @@ impl RumaHandler<($($tx,)* Ruma,)> for Fun { fn add_routes(&'static self, router: Router) -> Router { use ruma::api::path_builder::PathBuilder; - + Req::PATH_BUILDER .all_paths() .fold(router, |router, path| self.add_route(router, path)) diff --git a/src/core/Cargo.toml b/src/core/Cargo.toml index 0436511b8..44fdeb61d 100644 --- a/src/core/Cargo.toml +++ b/src/core/Cargo.toml @@ -90,6 +90,7 @@ rand_core = { version = "0.6.4", features = ["getrandom"] } regex.workspace = true reqwest.workspace = true sha2.workspace = true +assign.workspace = true ruma.workspace = true sanitize-filename.workspace = true serde_json.workspace = true diff --git a/src/core/error/err.rs b/src/core/error/err.rs index 39f6e33fe..131eea2ef 100644 --- a/src/core/error/err.rs +++ b/src/core/error/err.rs @@ -46,7 +46,7 @@ macro_rules! err { (Request(Forbidden($level:ident!($($args:tt)+)))) => {{ let mut buf = String::new(); $crate::error::Error::Request( - $crate::ruma::api::client::error::ErrorKind::forbidden(), + $crate::ruma::api::error::ErrorKind::Forbidden, $crate::err_log!(buf, $level, $($args)+), $crate::http::StatusCode::BAD_REQUEST ) @@ -54,7 +54,7 @@ macro_rules! err { (Request(Forbidden($($args:tt)+))) => { $crate::error::Error::Request( - $crate::ruma::api::client::error::ErrorKind::forbidden(), + $crate::ruma::api::error::ErrorKind::Forbidden, $crate::format_maybe!($($args)+), $crate::http::StatusCode::BAD_REQUEST ) @@ -63,7 +63,7 @@ macro_rules! err { (Request($variant:ident($level:ident!($($args:tt)+)))) => {{ let mut buf = String::new(); $crate::error::Error::Request( - $crate::ruma::api::client::error::ErrorKind::$variant, + $crate::ruma::api::error::ErrorKind::$variant, $crate::err_log!(buf, $level, $($args)+), $crate::http::StatusCode::BAD_REQUEST ) @@ -71,7 +71,7 @@ macro_rules! err { (Request($variant:ident($($args:tt)+))) => { $crate::error::Error::Request( - $crate::ruma::api::client::error::ErrorKind::$variant, + $crate::ruma::api::error::ErrorKind::$variant, $crate::format_maybe!($($args)+), $crate::http::StatusCode::BAD_REQUEST ) @@ -79,7 +79,7 @@ macro_rules! err { (Request($variant:ident($($args:tt)+), $status_code:ident)) => { $crate::error::Error::Request( - $crate::ruma::api::client::error::ErrorKind::$variant, + $crate::ruma::api::error::ErrorKind::$variant, $crate::format_maybe!($($args)+), $crate::http::StatusCode::$status_code, ) diff --git a/src/core/error/mod.rs b/src/core/error/mod.rs index 7659b7071..122a8f8eb 100644 --- a/src/core/error/mod.rs +++ b/src/core/error/mod.rs @@ -87,7 +87,7 @@ pub enum Error { #[error("Arithmetic operation failed: {0}")] Arithmetic(Cow<'static, str>), #[error("{0:?}: {1}")] - BadRequest(ruma::api::client::error::ErrorKind, &'static str), //TODO: remove + BadRequest(ruma::api::error::ErrorKind, &'static str), //TODO: remove #[error("{0}")] BadServerResponse(Cow<'static, str>), #[error(transparent)] @@ -103,7 +103,7 @@ pub enum Error { #[error("Feature '{0}' is not available on this server.")] FeatureDisabled(Cow<'static, str>), #[error("Remote server {0} responded with: {1}")] - Federation(ruma::OwnedServerName, ruma::api::client::error::Error), + Federation(ruma::OwnedServerName, ruma::api::error::Error), #[error("{0} in {1}")] InconsistentRoomState(&'static str, ruma::OwnedRoomId), #[error(transparent)] @@ -117,11 +117,13 @@ pub enum Error { #[error("from {0}: {1}")] Redaction(ruma::OwnedServerName, ruma::canonical_json::RedactionError), #[error("{0:?}: {1}")] - Request(ruma::api::client::error::ErrorKind, Cow<'static, str>, http::StatusCode), + Request(ruma::api::error::ErrorKind, Cow<'static, str>, http::StatusCode), #[error(transparent)] - Ruma(#[from] ruma::api::client::error::Error), + Ruma(#[from] ruma::api::error::Error), #[error(transparent)] - Signatures(#[from] ruma::signatures::Error), + SignatureJson(#[from] ruma::signatures::JsonError), + #[error(transparent)] + SignatureVerification(#[from] ruma::signatures::VerificationError), #[error(transparent)] StateRes(#[from] crate::state_res::Error), #[error("uiaa")] @@ -162,8 +164,8 @@ pub fn message(&self) -> String { /// Returns the Matrix error code / error kind #[inline] - pub fn kind(&self) -> ruma::api::client::error::ErrorKind { - use ruma::api::client::error::ErrorKind::{Unknown, Unrecognized}; + pub fn kind(&self) -> ruma::api::error::ErrorKind { + use ruma::api::error::ErrorKind::{Unknown, Unrecognized}; match self { | Self::Federation(_, error) | Self::Ruma(error) => diff --git a/src/core/error/response.rs b/src/core/error/response.rs index 8ccc465a3..563a57ac0 100644 --- a/src/core/error/response.rs +++ b/src/core/error/response.rs @@ -3,10 +3,8 @@ use http_body_util::Full; use ruma::api::{ OutgoingResponse, - client::{ - error::{ErrorBody, ErrorKind, StandardErrorBody}, - uiaa::UiaaResponse, - }, + client::uiaa::UiaaResponse, + error::{ErrorBody, ErrorKind, StandardErrorBody}, }; use super::Error; @@ -53,7 +51,7 @@ fn from(error: Error) -> Self { let body = ErrorBody::Standard(StandardErrorBody::new(error.kind(), error.message())); - Self::MatrixError(ruma::api::client::error::Error::new(error.status_code(), body)) + Self::MatrixError(ruma::api::error::Error::new(error.status_code(), body)) } } @@ -70,7 +68,7 @@ pub(super) fn bad_request_code(kind: &ErrorKind) -> StatusCode { match kind { // 429 - | LimitExceeded { .. } => StatusCode::TOO_MANY_REQUESTS, + | LimitExceeded(_) => StatusCode::TOO_MANY_REQUESTS, // 413 | TooLarge => StatusCode::PAYLOAD_TOO_LARGE, @@ -79,28 +77,26 @@ pub(super) fn bad_request_code(kind: &ErrorKind) -> StatusCode { | Unrecognized => StatusCode::METHOD_NOT_ALLOWED, // 404 - | NotFound => - StatusCode::NOT_FOUND, + | NotFound => StatusCode::NOT_FOUND, // 403 | GuestAccessForbidden | ThreepidAuthFailed | UserDeactivated | ThreepidDenied - | WrongRoomKeysVersion { .. } + | WrongRoomKeysVersion(_) | UserSuspended - | Forbidden { .. } => StatusCode::FORBIDDEN, + | Forbidden => StatusCode::FORBIDDEN, // 401 - | UnknownToken { .. } | MissingToken | Unauthorized | UserLocked => - StatusCode::UNAUTHORIZED, + | UnknownToken(_) | MissingToken | Unauthorized | UserLocked => StatusCode::UNAUTHORIZED, // 400 | _ => StatusCode::BAD_REQUEST, } } -pub(super) fn ruma_error_message(error: &ruma::api::client::error::Error) -> String { +pub(super) fn ruma_error_message(error: &ruma::api::error::Error) -> String { if let ErrorBody::Standard(StandardErrorBody { message, .. }) = &error.body { return message.clone(); } @@ -108,7 +104,7 @@ pub(super) fn ruma_error_message(error: &ruma::api::client::error::Error) -> Str format!("{error}") } -pub(super) fn ruma_error_kind(e: &ruma::api::client::error::Error) -> &ErrorKind { +pub(super) fn ruma_error_kind(e: &ruma::api::error::Error) -> &ErrorKind { e.error_kind().unwrap_or(&ErrorKind::Unknown) } diff --git a/src/core/matrix/event/id.rs b/src/core/matrix/event/id.rs index 653c86f65..9270e2a73 100644 --- a/src/core/matrix/event/id.rs +++ b/src/core/matrix/event/id.rs @@ -25,7 +25,7 @@ pub fn gen_event_id( room_version_id: &RoomVersionId, ) -> Result { let Some(rules) = room_version_id.rules() else { - return Err!("Cannot generate event ID for unknown room version {room_version_id}") + return Err!("Cannot generate event ID for unknown room version {room_version_id}"); }; let reference_hash = ruma::signatures::reference_hash(value, &rules)?; let event_id: OwnedEventId = format!("${reference_hash}").try_into()?; diff --git a/src/core/matrix/mod.rs b/src/core/matrix/mod.rs index 2fe86e277..d50247e4f 100644 --- a/src/core/matrix/mod.rs +++ b/src/core/matrix/mod.rs @@ -9,4 +9,4 @@ pub use event::{Event, TypeExt as EventTypeExt}; pub use pdu::{Pdu, PduBuilder, PduCount, PduEvent, PduId, RawPduId, ShortId}; pub use state_key::StateKey; -pub use state_res::{StateMap, TypeStateKey}; \ No newline at end of file +pub use state_res::{StateMap, TypeStateKey}; diff --git a/src/core/matrix/pdu/redact.rs b/src/core/matrix/pdu/redact.rs index a7965ccf8..768106d85 100644 --- a/src/core/matrix/pdu/redact.rs +++ b/src/core/matrix/pdu/redact.rs @@ -6,7 +6,7 @@ #[implement(super::Pdu)] pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: JsonValue) -> Result { let Some(rules) = room_version_id.rules() else { - return Err!("Cannot redact event for unknown room version {room_version_id}") + return Err!("Cannot redact event for unknown room version {room_version_id}"); }; self.unsigned = None; @@ -14,8 +14,7 @@ pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: JsonValue) -> let mut content = serde_json::from_str(self.content.get()) .map_err(|e| err!(Request(BadJson("Failed to deserialize content into type: {e}"))))?; - redact_content_in_place(&mut content, &rules.redaction, self.kind.to_string()) - .map_err(|e| Error::Redaction(self.sender.server_name().to_owned(), e))?; + redact_content_in_place(&mut content, &rules.redaction, self.kind.to_string()); let reason = serde_json::to_value(reason).expect("Failed to preserialize reason"); diff --git a/src/core/matrix/state_res/event_auth.rs b/src/core/matrix/state_res/event_auth.rs index de2b5d3f6..659385fbb 100644 --- a/src/core/matrix/state_res/event_auth.rs +++ b/src/core/matrix/state_res/event_auth.rs @@ -5,12 +5,16 @@ future::{OptionFuture, join, join3}, }; use ruma::{ - Int, OwnedUserId, RoomVersionId, UserId, events::room::{ + Int, OwnedUserId, RoomVersionId, UserId, + events::room::{ create::RoomCreateEventContent, join_rules::{JoinRule, RoomJoinRulesEventContent}, member::{MembershipState, ThirdPartyInvite}, power_levels::RoomPowerLevelsEventContent, - }, int, room_version_rules::{RoomIdFormatVersion, RoomVersionRules}, serde::Raw, + }, + int, + room_version_rules::{RoomIdFormatVersion, RoomVersionRules}, + serde::Raw, }; use serde::{ Deserialize, @@ -117,11 +121,11 @@ struct RoomMemberContentFields { // TODO: restore this once 3pid support isn't broken // if membership == MembershipState::Invite { - // if let Some(Ok(t_id)) = content.third_party_invite.map(|t| t.deserialize()) { - // let key = - // (StateEventType::RoomThirdPartyInvite, t_id.signed.token.into()); - // if !auth_types.contains(&key) { - // auth_types.push(key); + // if let Some(Ok(t_id)) = content.third_party_invite.map(|t| + // t.deserialize()) { let key = + // (StateEventType::RoomThirdPartyInvite, + // t_id.signed.token.into()); if !auth_types.contains(& + // key) { auth_types.push(key); // } // } // } @@ -214,13 +218,17 @@ pub async fn auth_check( return Ok(false); } - if room_version.room_id_format == RoomIdFormatVersion::V2 && incoming_event.room_id().is_some() { + if room_version.room_id_format == RoomIdFormatVersion::V2 + && incoming_event.room_id().is_some() + { warn!("room create event incorrectly claims to have a room ID when it should not"); return Ok(false); } if !room_version.authorization.use_room_create_sender - && !room_version.authorization.explicitly_privilege_room_creators + && !room_version + .authorization + .explicitly_privilege_room_creators { // If content has no creator field, reject if content.creator.is_none() { @@ -343,7 +351,7 @@ pub async fn auth_check( // Only in some room versions 6 and below if room_version.authorization.special_case_room_aliases { // 4. If type is m.room.aliases - if *incoming_event.event_type() == TimelineEventType::RoomAliases { + if *incoming_event.event_type() == TimelineEventType::from("m.room.aliases") { debug!("starting m.room.aliases check"); // If sender's domain doesn't matches state_key, reject @@ -493,7 +501,10 @@ pub async fn auth_check( if is_creator { int!(100) } else { int!(0) } }, }; - if room_version.authorization.explicitly_privilege_room_creators { + if room_version + .authorization + .explicitly_privilege_room_creators + { // If the user sent the create event, or is listed in additional_creators, just // give them Int::MAX if sender == room_create_event.sender() @@ -555,7 +566,10 @@ pub async fn auth_check( if *incoming_event.event_type() == TimelineEventType::RoomPowerLevels { debug!("starting m.room.power_levels check"); let mut creators = BTreeSet::new(); - if room_version.authorization.explicitly_privilege_room_creators { + if room_version + .authorization + .explicitly_privilege_room_creators + { creators.insert(create_event.sender().to_owned()); for creator in room_create_content.additional_creators.iter().flatten() { creators.insert(creator.deserialize()?); @@ -710,7 +724,10 @@ struct GetThirdPartyInvite { let mut creators = BTreeSet::new(); creators.insert(create_room.sender().to_owned()); - if room_version.authorization.explicitly_privilege_room_creators { + if room_version + .authorization + .explicitly_privilege_room_creators + { // Explicitly privilege room creators // If the sender sent the create event, or in additional_creators, give them // Int::MAX. Same case for target. @@ -878,7 +895,8 @@ struct GetThirdPartyInvite { trace!(sender=%sender, "sender is invited or already joined to room, allowing join"); true }, - | JoinRule::KnockRestricted(_) if !room_version.authorization.knock_restricted_join_rule => + | JoinRule::KnockRestricted(_) + if !room_version.authorization.knock_restricted_join_rule => { warn!( "Join rule is knock_restricted but room version does not support it" @@ -1508,15 +1526,17 @@ fn verify_third_party_invite( #[cfg(test)] mod tests { - use ruma::{events::{ - StateEventType, TimelineEventType, - room::{ - join_rules::{ - AllowRule, JoinRule, Restricted, RoomJoinRulesEventContent, + use ruma::{ + events::{ + StateEventType, TimelineEventType, + room::{ + join_rules::{AllowRule, JoinRule, Restricted, RoomJoinRulesEventContent}, + member::{MembershipState, RoomMemberEventContent}, }, - member::{MembershipState, RoomMemberEventContent}, }, - }, room::RoomMembership, room_version_rules::RoomVersionRules}; + room::RoomMembership, + room_version_rules::RoomVersionRules, + }; use serde_json::value::to_raw_value as to_raw_json_value; use crate::{ diff --git a/src/core/matrix/state_res/mod.rs b/src/core/matrix/state_res/mod.rs index 4db1996ce..5da383be3 100644 --- a/src/core/matrix/state_res/mod.rs +++ b/src/core/matrix/state_res/mod.rs @@ -25,13 +25,14 @@ StateEventType, TimelineEventType, room::member::{MembershipState, RoomMemberEventContent}, }, - int, room_version_rules::{RoomIdFormatVersion, RoomVersionRules, StateResolutionVersion}, + int, + room_version_rules::{RoomIdFormatVersion, RoomVersionRules, StateResolutionVersion}, }; use serde_json::from_str as from_json_str; pub(crate) use self::error::Error; -use self::power_levels::PowerLevelsContentFields; pub use self::event_auth::{auth_check, auth_types_for_event}; +use self::power_levels::PowerLevelsContentFields; use crate::{ debug, debug_error, err, matrix::{Event, StateKey}, @@ -106,19 +107,21 @@ pub async fn resolve<'a, Pdu, Sets, SetIter, Hasher, Fetch, FetchFut, Exists, Ex debug!(count = conflicting.len(), "conflicting events"); trace!(map = ?conflicting, "conflicting events"); - let (conflicted_state_subgraph, initial_state) = - if let StateResolutionVersion::V2(v2_rules) = stateres_version && v2_rules.consider_conflicted_state_subgraph { - let csg = calculate_conflicted_subgraph(&conflicting, event_fetch) - .await - .ok_or_else(|| { - Error::InvalidPdu("Failed to calculate conflicted subgraph".to_owned()) - })?; - debug!(count = csg.len(), "conflicted subgraph"); - trace!(set = ?csg, "conflicted subgraph"); - (csg, HashMap::new()) - } else { - (HashSet::new(), unconflicted.clone()) - }; + let (conflicted_state_subgraph, initial_state) = if let StateResolutionVersion::V2(v2_rules) = + stateres_version + && v2_rules.consider_conflicted_state_subgraph + { + let csg = calculate_conflicted_subgraph(&conflicting, event_fetch) + .await + .ok_or_else(|| { + Error::InvalidPdu("Failed to calculate conflicted subgraph".to_owned()) + })?; + debug!(count = csg.len(), "conflicted subgraph"); + trace!(set = ?csg, "conflicted subgraph"); + (csg, HashMap::new()) + } else { + (HashSet::new(), unconflicted.clone()) + }; // `all_conflicted` contains unique items // synapse says `full_set = {eid for eid in full_conflicted_set if eid in @@ -974,10 +977,14 @@ mod tests { use maplit::{hashmap, hashset}; use rand::seq::SliceRandom; use ruma::{ - MilliSecondsSinceUnixEpoch, OwnedEventId, RoomVersionId, events::{ + MilliSecondsSinceUnixEpoch, OwnedEventId, RoomVersionId, + events::{ StateEventType, TimelineEventType, room::join_rules::{JoinRule, RoomJoinRulesEventContent}, - }, int, room_version_rules::RoomVersionRules, uint + }, + int, + room_version_rules::RoomVersionRules, + uint, }; use serde_json::{json, value::to_raw_value as to_raw_json_value}; @@ -1423,13 +1430,18 @@ async fn test_event_map_none() { }) .collect(); - let resolved = - match super::resolve(&RoomVersionRules::V2, &state_sets, &auth_chain, &fetcher, &exists) - .await - { - | Ok(state) => state, - | Err(e) => panic!("{e}"), - }; + let resolved = match super::resolve( + &RoomVersionRules::V2, + &state_sets, + &auth_chain, + &fetcher, + &exists, + ) + .await + { + | Ok(state) => state, + | Err(e) => panic!("{e}"), + }; assert_eq!(expected, resolved); } @@ -1536,13 +1548,18 @@ async fn ban_with_auth_chains2() { let fetcher = |id: OwnedEventId| ready(ev_map.get(&id).cloned()); let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some()); - let resolved = - match super::resolve(&RoomVersionRules::V6, &state_sets, &auth_chain, &fetcher, &exists) - .await - { - | Ok(state) => state, - | Err(e) => panic!("{e}"), - }; + let resolved = match super::resolve( + &RoomVersionRules::V6, + &state_sets, + &auth_chain, + &fetcher, + &exists, + ) + .await + { + | Ok(state) => state, + | Err(e) => panic!("{e}"), + }; debug!( resolved = ?resolved diff --git a/src/core/matrix/state_res/power_levels.rs b/src/core/matrix/state_res/power_levels.rs index 6d5bdeba0..16eb93864 100644 --- a/src/core/matrix/state_res/power_levels.rs +++ b/src/core/matrix/state_res/power_levels.rs @@ -1,13 +1,16 @@ use std::collections::BTreeMap; use ruma::{ - Int, OwnedUserId, UserId, events::{TimelineEventType, room::power_levels::RoomPowerLevelsEventContent}, power_levels::{NotificationPowerLevels, default_power_level}, room_version_rules::{AuthorizationRules, RoomVersionRules}, serde::deserialize_v1_powerlevel + Int, OwnedUserId, UserId, + events::{TimelineEventType, room::power_levels::RoomPowerLevelsEventContent}, + power_levels::{NotificationPowerLevels, default_power_level}, + room_version_rules::{AuthorizationRules, RoomVersionRules}, + serde::deserialize_v1_powerlevel, }; -use super::serde_backports::*; use serde::Deserialize; use serde_json::{Error, from_str as from_json_str}; -use super::Result; +use super::{Result, serde_backports::*}; use crate::error; #[derive(Deserialize)] @@ -44,7 +47,10 @@ struct IntRoomPowerLevelsEventContent { } impl IntRoomPowerLevelsEventContent { - fn to_room_power_levels_content(self, auth_rules: &AuthorizationRules) -> RoomPowerLevelsEventContent { + fn to_room_power_levels_content( + self, + auth_rules: &AuthorizationRules, + ) -> RoomPowerLevelsEventContent { let IntRoomPowerLevelsEventContent { ban, events, @@ -105,7 +111,10 @@ pub(crate) fn deserialize_power_levels( } } -fn deserialize_integer_power_levels(content: &str, auth_rules: &AuthorizationRules) -> Option { +fn deserialize_integer_power_levels( + content: &str, + auth_rules: &AuthorizationRules, +) -> Option { match from_json_str::(content) { | Ok(content) => Some(content.to_room_power_levels_content(auth_rules)), | Err(_) => { diff --git a/src/core/matrix/state_res/serde_backports.rs b/src/core/matrix/state_res/serde_backports.rs index ac9b4d3bb..188190d15 100644 --- a/src/core/matrix/state_res/serde_backports.rs +++ b/src/core/matrix/state_res/serde_backports.rs @@ -1,120 +1,120 @@ -//! These functions are copied from an old version of Ruma. power_levels.rs uses them to lazily deserialize power level events. -//! Upstream Ruma uses a much more elegant approach in its state resolution code, which we may want +//! These functions are copied from an old version of Ruma. power_levels.rs uses +//! them to lazily deserialize power level events. Upstream Ruma uses a much +//! more elegant approach in its state resolution code, which we may want //! to look into at some point. -use std::marker::PhantomData; -use std::fmt; +use std::{fmt, marker::PhantomData}; -use serde::{Deserialize, Deserializer, de::{MapAccess, Visitor}}; use ruma::{Int, serde::deserialize_v1_powerlevel}; +use serde::{ + Deserialize, Deserializer, + de::{MapAccess, Visitor}, +}; -/// Take a Map with values of either an integer number or a string and deserialize -/// those to integer numbers in a Vec of sorted pairs. +/// Take a Map with values of either an integer number or a string and +/// deserialize those to integer numbers in a Vec of sorted pairs. /// /// To be used like this: /// `#[serde(deserialize_with = "vec_deserialize_v1_powerlevel_values")]` pub fn vec_deserialize_v1_powerlevel_values<'de, D, T>(de: D) -> Result, D::Error> where - D: Deserializer<'de>, - T: Deserialize<'de> + Ord, + D: Deserializer<'de>, + T: Deserialize<'de> + Ord, { - #[repr(transparent)] - struct IntWrap(Int); + #[repr(transparent)] + struct IntWrap(Int); - impl<'de> Deserialize<'de> for IntWrap { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserialize_v1_powerlevel(deserializer).map(IntWrap) - } - } + impl<'de> Deserialize<'de> for IntWrap { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserialize_v1_powerlevel(deserializer).map(IntWrap) + } + } - struct IntMapVisitor { - _phantom: PhantomData, - } + struct IntMapVisitor { + _phantom: PhantomData, + } - impl IntMapVisitor { - fn new() -> Self { - Self { _phantom: PhantomData } - } - } + impl IntMapVisitor { + fn new() -> Self { Self { _phantom: PhantomData } } + } - impl<'de, T> Visitor<'de> for IntMapVisitor - where - T: Deserialize<'de> + Ord, - { - type Value = Vec<(T, Int)>; + impl<'de, T> Visitor<'de> for IntMapVisitor + where + T: Deserialize<'de> + Ord, + { + type Value = Vec<(T, Int)>; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("a map with integers or strings as values") - } + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map with integers or strings as values") + } - fn visit_map>(self, mut map: A) -> Result { - let mut res = Vec::new(); - if let Some(hint) = map.size_hint() { - res.reserve(hint); - } + fn visit_map>(self, mut map: A) -> Result { + let mut res = Vec::new(); + if let Some(hint) = map.size_hint() { + res.reserve(hint); + } - while let Some((k, IntWrap(v))) = map.next_entry()? { - res.push((k, v)); - } + while let Some((k, IntWrap(v))) = map.next_entry()? { + res.push((k, v)); + } - res.sort_unstable(); - res.dedup_by(|a, b| a.0 == b.0); + res.sort_unstable(); + res.dedup_by(|a, b| a.0 == b.0); - Ok(res) - } - } + Ok(res) + } + } - de.deserialize_map(IntMapVisitor::new()) + de.deserialize_map(IntMapVisitor::new()) } -/// Take a Map with integer values and deserialize those to a Vec of sorted pairs +/// Take a Map with integer values and deserialize those to a Vec of sorted +/// pairs /// /// To be used like this: /// `#[serde(deserialize_with = "vec_deserialize_int_powerlevel_values")]` pub fn vec_deserialize_int_powerlevel_values<'de, D, T>(de: D) -> Result, D::Error> where - D: Deserializer<'de>, - T: Deserialize<'de> + Ord, + D: Deserializer<'de>, + T: Deserialize<'de> + Ord, { - struct IntMapVisitor { - _phantom: PhantomData, - } + struct IntMapVisitor { + _phantom: PhantomData, + } - impl IntMapVisitor { - fn new() -> Self { - Self { _phantom: PhantomData } - } - } + impl IntMapVisitor { + fn new() -> Self { Self { _phantom: PhantomData } } + } - impl<'de, T> Visitor<'de> for IntMapVisitor - where - T: Deserialize<'de> + Ord, - { - type Value = Vec<(T, Int)>; + impl<'de, T> Visitor<'de> for IntMapVisitor + where + T: Deserialize<'de> + Ord, + { + type Value = Vec<(T, Int)>; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("a map with integers as values") - } + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map with integers as values") + } - fn visit_map>(self, mut map: A) -> Result { - let mut res = Vec::new(); - if let Some(hint) = map.size_hint() { - res.reserve(hint); - } + fn visit_map>(self, mut map: A) -> Result { + let mut res = Vec::new(); + if let Some(hint) = map.size_hint() { + res.reserve(hint); + } - while let Some(item) = map.next_entry()? { - res.push(item); - } + while let Some(item) = map.next_entry()? { + res.push(item); + } - res.sort_unstable(); - res.dedup_by(|a, b| a.0 == b.0); + res.sort_unstable(); + res.dedup_by(|a, b| a.0 == b.0); - Ok(res) - } - } + Ok(res) + } + } - de.deserialize_map(IntMapVisitor::new()) -} \ No newline at end of file + de.deserialize_map(IntMapVisitor::new()) +} diff --git a/src/core/matrix/state_res/test_utils.rs b/src/core/matrix/state_res/test_utils.rs index dad28717e..8cadd4815 100644 --- a/src/core/matrix/state_res/test_utils.rs +++ b/src/core/matrix/state_res/test_utils.rs @@ -6,13 +6,18 @@ use futures::future::ready; use ruma::{ - EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, ServerSignatures, UserId, event_id, events::{ + EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, ServerSignatures, + UserId, event_id, + events::{ TimelineEventType, room::{ join_rules::{JoinRule, RoomJoinRulesEventContent}, member::{MembershipState, RoomMemberEventContent}, }, - }, int, room_id, room_version_rules::RoomVersionRules, uint, user_id + }, + int, room_id, + room_version_rules::RoomVersionRules, + uint, user_id, }; use serde_json::{ json, @@ -130,9 +135,14 @@ pub(crate) async fn do_check( let event_map = &event_map; let fetch = |id: OwnedEventId| ready(event_map.get(&id).cloned()); let exists = |id: OwnedEventId| ready(event_map.get(&id).is_some()); - let resolved = - super::resolve(&RoomVersionRules::V6, state_sets, &auth_chain_sets, &fetch, &exists) - .await; + let resolved = super::resolve( + &RoomVersionRules::V6, + state_sets, + &auth_chain_sets, + &fetch, + &exists, + ) + .await; match resolved { | Ok(state) => state, diff --git a/src/core/matrix/versions.rs b/src/core/matrix/versions.rs index 4524ce1c8..2d8bd673b 100644 --- a/src/core/matrix/versions.rs +++ b/src/core/matrix/versions.rs @@ -1,44 +1,44 @@ use std::collections::BTreeMap; pub fn versions() -> Vec { - vec![ - "r0.0.1".to_owned(), - "r0.1.0".to_owned(), - "r0.2.0".to_owned(), - "r0.3.0".to_owned(), - "r0.4.0".to_owned(), - "r0.5.0".to_owned(), - "r0.6.0".to_owned(), - "r0.6.1".to_owned(), - "v1.1".to_owned(), - "v1.2".to_owned(), - "v1.3".to_owned(), - "v1.4".to_owned(), - "v1.5".to_owned(), - "v1.8".to_owned(), - "v1.11".to_owned(), - "v1.12".to_owned(), - "v1.13".to_owned(), - "v1.14".to_owned(), - ] + vec![ + "r0.0.1".to_owned(), + "r0.1.0".to_owned(), + "r0.2.0".to_owned(), + "r0.3.0".to_owned(), + "r0.4.0".to_owned(), + "r0.5.0".to_owned(), + "r0.6.0".to_owned(), + "r0.6.1".to_owned(), + "v1.1".to_owned(), + "v1.2".to_owned(), + "v1.3".to_owned(), + "v1.4".to_owned(), + "v1.5".to_owned(), + "v1.8".to_owned(), + "v1.11".to_owned(), + "v1.12".to_owned(), + "v1.13".to_owned(), + "v1.14".to_owned(), + ] } pub fn unstable_features() -> BTreeMap { - BTreeMap::from_iter([ - ("org.matrix.e2e_cross_signing".to_owned(), true), - ("org.matrix.msc2285.stable".to_owned(), true), /* private read receipts (https://github.com/matrix-org/matrix-spec-proposals/pull/2285) */ - ("uk.half-shot.msc2666.query_mutual_rooms".to_owned(), true), /* query mutual rooms (https://github.com/matrix-org/matrix-spec-proposals/pull/2666) */ - ("org.matrix.msc2836".to_owned(), true), /* threading/threads (https://github.com/matrix-org/matrix-spec-proposals/pull/2836) */ - ("org.matrix.msc2946".to_owned(), true), /* spaces/hierarchy summaries (https://github.com/matrix-org/matrix-spec-proposals/pull/2946) */ - ("org.matrix.msc3026.busy_presence".to_owned(), true), /* busy presence status (https://github.com/matrix-org/matrix-spec-proposals/pull/3026) */ - ("org.matrix.msc3827".to_owned(), true), /* filtering of /publicRooms by room type (https://github.com/matrix-org/matrix-spec-proposals/pull/3827) */ - ("org.matrix.msc3952_intentional_mentions".to_owned(), true), /* intentional mentions (https://github.com/matrix-org/matrix-spec-proposals/pull/3952) */ - ("org.matrix.msc3916.stable".to_owned(), true), /* authenticated media (https://github.com/matrix-org/matrix-spec-proposals/pull/3916) */ - ("org.matrix.msc4180".to_owned(), true), /* stable flag for 3916 (https://github.com/matrix-org/matrix-spec-proposals/pull/4180) */ - ("uk.tcpip.msc4133".to_owned(), true), /* Extending User Profile API with Key:Value Pairs (https://github.com/matrix-org/matrix-spec-proposals/pull/4133) */ - ("us.cloke.msc4175".to_owned(), true), /* Profile field for user time zone (https://github.com/matrix-org/matrix-spec-proposals/pull/4175) */ - ("org.matrix.simplified_msc3575".to_owned(), true), /* Simplified Sliding sync (https://github.com/matrix-org/matrix-spec-proposals/pull/4186) */ - ("uk.timedout.msc4323".to_owned(), true), /* agnostic suspend (https://github.com/matrix-org/matrix-spec-proposals/pull/4323) */ - ("org.matrix.msc4155".to_owned(), true), /* invite filtering (https://github.com/matrix-org/matrix-spec-proposals/pull/4155) */ - ]) -} \ No newline at end of file + BTreeMap::from_iter([ + ("org.matrix.e2e_cross_signing".to_owned(), true), + ("org.matrix.msc2285.stable".to_owned(), true), /* private read receipts (https://github.com/matrix-org/matrix-spec-proposals/pull/2285) */ + ("uk.half-shot.msc2666.query_mutual_rooms".to_owned(), true), /* query mutual rooms (https://github.com/matrix-org/matrix-spec-proposals/pull/2666) */ + ("org.matrix.msc2836".to_owned(), true), /* threading/threads (https://github.com/matrix-org/matrix-spec-proposals/pull/2836) */ + ("org.matrix.msc2946".to_owned(), true), /* spaces/hierarchy summaries (https://github.com/matrix-org/matrix-spec-proposals/pull/2946) */ + ("org.matrix.msc3026.busy_presence".to_owned(), true), /* busy presence status (https://github.com/matrix-org/matrix-spec-proposals/pull/3026) */ + ("org.matrix.msc3827".to_owned(), true), /* filtering of /publicRooms by room type (https://github.com/matrix-org/matrix-spec-proposals/pull/3827) */ + ("org.matrix.msc3952_intentional_mentions".to_owned(), true), /* intentional mentions (https://github.com/matrix-org/matrix-spec-proposals/pull/3952) */ + ("org.matrix.msc3916.stable".to_owned(), true), /* authenticated media (https://github.com/matrix-org/matrix-spec-proposals/pull/3916) */ + ("org.matrix.msc4180".to_owned(), true), /* stable flag for 3916 (https://github.com/matrix-org/matrix-spec-proposals/pull/4180) */ + ("uk.tcpip.msc4133".to_owned(), true), /* Extending User Profile API with Key:Value Pairs (https://github.com/matrix-org/matrix-spec-proposals/pull/4133) */ + ("us.cloke.msc4175".to_owned(), true), /* Profile field for user time zone (https://github.com/matrix-org/matrix-spec-proposals/pull/4175) */ + ("org.matrix.simplified_msc3575".to_owned(), true), /* Simplified Sliding sync (https://github.com/matrix-org/matrix-spec-proposals/pull/4186) */ + ("uk.timedout.msc4323".to_owned(), true), /* agnostic suspend (https://github.com/matrix-org/matrix-spec-proposals/pull/4323) */ + ("org.matrix.msc4155".to_owned(), true), /* invite filtering (https://github.com/matrix-org/matrix-spec-proposals/pull/4155) */ + ]) +} diff --git a/src/core/mod.rs b/src/core/mod.rs index d33289678..bd597c369 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -38,9 +38,7 @@ macro_rules! mod_dtor { version, version::{name, version}, }; -pub use matrix::{ - Event, EventTypeExt, Pdu, PduCount, PduEvent, PduId, pdu, state_res, -}; +pub use matrix::{Event, EventTypeExt, Pdu, PduCount, PduEvent, PduId, pdu, state_res}; pub use parking_lot::{Mutex as SyncMutex, RwLock as SyncRwLock}; pub use server::Server; pub use utils::{implement, result, result::Result}; diff --git a/src/core/utils/json.rs b/src/core/utils/json.rs index df4ccd13a..66d0c027b 100644 --- a/src/core/utils/json.rs +++ b/src/core/utils/json.rs @@ -1,6 +1,6 @@ use std::{fmt, marker::PhantomData, str::FromStr}; -use ruma::{CanonicalJsonError, CanonicalJsonObject, canonical_json::try_from_json_map}; +use ruma::{CanonicalJsonError, CanonicalJsonObject, canonical_json::to_canonical_value}; use crate::Result; @@ -11,12 +11,12 @@ pub fn to_canonical_object( value: T, ) -> Result { - use CanonicalJsonError::SerDe; - use serde::ser::Error; + use ruma::CanonicalJsonValue; - match serde_json::to_value(value).map_err(SerDe)? { - | serde_json::Value::Object(map) => try_from_json_map(map), - | _ => Err(SerDe(serde_json::Error::custom("Value must be an object"))), + match to_canonical_value(value)? { + | CanonicalJsonValue::Object(map) => Ok(map), + | _ => Err(to_canonical_value(1.0_f32).unwrap_err()), /* Hack to return a + * CanonicalJsonError */ } } diff --git a/src/database/tests.rs b/src/database/tests.rs index 758c0cdc9..7131691bd 100644 --- a/src/database/tests.rs +++ b/src/database/tests.rs @@ -4,7 +4,10 @@ use conduwuit::{ arrayvec::ArrayVec, - ruma::{EventId, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId, room_id, serde::Raw, user_id}, + ruma::{ + EventId, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId, room_id, serde::Raw, + user_id, + }, }; use serde::Serialize; @@ -439,7 +442,8 @@ fn serde_tuple_option_some_some() { aa.push(0xFF); aa.extend_from_slice(user_id.as_bytes()); - let bb: (Option, Option) = (Some(room_id.to_owned()), Some(user_id.to_owned())); + let bb: (Option, Option) = + (Some(room_id.to_owned()), Some(user_id.to_owned())); let bbs = serialize_to_vec(&bb).expect("failed to serialize tuple"); assert_eq!(aa, bbs); diff --git a/src/router/Cargo.toml b/src/router/Cargo.toml index a69eef39e..fcf41e104 100644 --- a/src/router/Cargo.toml +++ b/src/router/Cargo.toml @@ -111,6 +111,7 @@ http-body-util.workspace = true hyper.workspace = true hyper-util.workspace = true log.workspace = true +assign.workspace = true ruma.workspace = true rustls.workspace = true rustls.optional = true diff --git a/src/router/router.rs b/src/router/router.rs index 766a19316..453892dc0 100644 --- a/src/router/router.rs +++ b/src/router/router.rs @@ -4,7 +4,7 @@ use conduwuit::Error; use conduwuit_service::{Services, state, state::Guard}; use http::{StatusCode, Uri}; -use ruma::api::client::error::ErrorKind; +use ruma::api::error::ErrorKind; pub(crate) fn build(services: &Arc) -> (Router, Guard) { let router = Router::::new(); diff --git a/src/ruminuwuity/Cargo.toml b/src/ruminuwuity/Cargo.toml index 0079678f4..2cd86e93c 100644 --- a/src/ruminuwuity/Cargo.toml +++ b/src/ruminuwuity/Cargo.toml @@ -20,6 +20,7 @@ unstable-msc3202 = [] unstable-msc4203 = [] [dependencies] +assign.workspace = true ruma.workspace = true serde = { workspace = true } serde_json = { workspace = true } diff --git a/src/ruminuwuity/admin/continuwuity/mod.rs b/src/ruminuwuity/admin/continuwuity/mod.rs index 7de0b163e..5d505fa82 100644 --- a/src/ruminuwuity/admin/continuwuity/mod.rs +++ b/src/ruminuwuity/admin/continuwuity/mod.rs @@ -1 +1 @@ -pub mod rooms; \ No newline at end of file +pub mod rooms; diff --git a/src/ruminuwuity/admin/continuwuity/rooms/ban.rs b/src/ruminuwuity/admin/continuwuity/rooms/ban.rs index 78a4e4769..5600ab0df 100644 --- a/src/ruminuwuity/admin/continuwuity/rooms/ban.rs +++ b/src/ruminuwuity/admin/continuwuity/rooms/ban.rs @@ -1,5 +1,9 @@ pub mod v1 { - use ruma::{OwnedRoomAliasId, OwnedRoomId, OwnedUserId, api::{auth_scheme::AccessToken, request, response}, metadata}; + use ruma::{ + OwnedRoomAliasId, OwnedRoomId, OwnedUserId, + api::{auth_scheme::AccessToken, request, response}, + metadata, + }; metadata! { method: PUT, @@ -16,10 +20,10 @@ pub struct Request { pub room_id: OwnedRoomId, /// Whether to ban (true) or unban (false) the room. - /// If true, and the room is not banned, all local users will be evacuated - /// and prevented from re-joining. - /// If false, and the room is unbanned, local users will be allowed to re-join. - /// No-ops are no-ops. + /// If true, and the room is not banned, all local users will be + /// evacuated and prevented from re-joining. + /// If false, and the room is unbanned, local users will be allowed to + /// re-join. No-ops are no-ops. pub banned: bool, } @@ -27,24 +31,26 @@ pub struct Request { pub struct Response { pub kicked_users: Vec, pub failed_kicked_users: Vec, - pub local_aliases: Vec + pub local_aliases: Vec, } impl Request { - #[must_use] - pub fn new(room_id: OwnedRoomId, banned: bool) -> Self { - Self { room_id, banned } - } + #[must_use] + pub fn new(room_id: OwnedRoomId, banned: bool) -> Self { Self { room_id, banned } } } impl Response { - #[must_use] + #[must_use] pub fn new( kicked_users: Vec, failed_kicked_users: Vec, local_aliases: Vec, ) -> Self { - Self { kicked_users, failed_kicked_users, local_aliases } + Self { + kicked_users, + failed_kicked_users, + local_aliases, + } } } -} \ No newline at end of file +} diff --git a/src/ruminuwuity/admin/continuwuity/rooms/list.rs b/src/ruminuwuity/admin/continuwuity/rooms/list.rs index 9f73a2105..2552d6a21 100644 --- a/src/ruminuwuity/admin/continuwuity/rooms/list.rs +++ b/src/ruminuwuity/admin/continuwuity/rooms/list.rs @@ -1,6 +1,8 @@ pub mod v1 { use ruma::{ - OwnedRoomId, api::{auth_scheme::AccessToken, request, response}, metadata + OwnedRoomId, + api::{auth_scheme::AccessToken, request, response}, + metadata, }; metadata! { @@ -22,16 +24,12 @@ pub struct Response { } impl Request { - #[must_use] - pub fn new() -> Self { - Self::default() - } + #[must_use] + pub fn new() -> Self { Self::default() } } impl Response { - #[must_use] - pub fn new(rooms: Vec) -> Self { - Self { rooms } - } + #[must_use] + pub fn new(rooms: Vec) -> Self { Self { rooms } } } -} \ No newline at end of file +} diff --git a/src/ruminuwuity/admin/continuwuity/rooms/mod.rs b/src/ruminuwuity/admin/continuwuity/rooms/mod.rs index fde322e30..accb6f6a6 100644 --- a/src/ruminuwuity/admin/continuwuity/rooms/mod.rs +++ b/src/ruminuwuity/admin/continuwuity/rooms/mod.rs @@ -1,2 +1,2 @@ -pub mod list; pub mod ban; +pub mod list; diff --git a/src/ruminuwuity/admin/get_suspended.rs b/src/ruminuwuity/admin/get_suspended.rs index 0fc6056e6..222f40f6e 100644 --- a/src/ruminuwuity/admin/get_suspended.rs +++ b/src/ruminuwuity/admin/get_suspended.rs @@ -3,51 +3,50 @@ //! Check the suspension status of a target user pub mod v1 { - //! `/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{userID}` ([msc]) - //! - //! [msc]: https://github.com/matrix-org/matrix-spec-proposals/pull/4323 + //! `/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{userID}` + //! ([msc]) + //! + //! [msc]: https://github.com/matrix-org/matrix-spec-proposals/pull/4323 - use ruma::{ - OwnedUserId, api::{auth_scheme::AccessToken, request, response}, metadata - }; + use ruma::{ + OwnedUserId, + api::{auth_scheme::AccessToken, request, response}, + metadata, + }; - metadata! { - method: GET, - rate_limited: false, - authentication: AccessToken, - history: { - unstable => "/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{user_id}", - } - } + metadata! { + method: GET, + rate_limited: false, + authentication: AccessToken, + history: { + unstable => "/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{user_id}", + } + } - /// Request type for the get & set user suspension status endpoint. - #[request(error = ruma::api::client::Error)] - pub struct Request { - /// The user to look up. - #[ruma_api(path)] - pub user_id: OwnedUserId, - } + /// Request type for the get & set user suspension status endpoint. + #[request(error = ruma::api::error::Error)] + pub struct Request { + /// The user to look up. + #[ruma_api(path)] + pub user_id: OwnedUserId, + } - /// Response type for the suspension endpoints - #[response(error = ruma::api::client::Error)] - pub struct Response { - /// Whether the user is currently suspended. - pub suspended: bool, - } + /// Response type for the suspension endpoints + #[response(error = ruma::api::error::Error)] + pub struct Response { + /// Whether the user is currently suspended. + pub suspended: bool, + } - impl Request { - /// Creates a new `Request` with the given user id. - #[must_use] - pub fn new(user_id: OwnedUserId) -> Self { - Self { user_id } - } - } + impl Request { + /// Creates a new `Request` with the given user id. + #[must_use] + pub fn new(user_id: OwnedUserId) -> Self { Self { user_id } } + } - impl Response { - /// Creates a new `Response` with the given suspension status. - #[must_use] - pub fn new(suspended: bool) -> Self { - Self { suspended } - } - } -} \ No newline at end of file + impl Response { + /// Creates a new `Response` with the given suspension status. + #[must_use] + pub fn new(suspended: bool) -> Self { Self { suspended } } + } +} diff --git a/src/ruminuwuity/admin/mod.rs b/src/ruminuwuity/admin/mod.rs index 470de8177..991abc208 100644 --- a/src/ruminuwuity/admin/mod.rs +++ b/src/ruminuwuity/admin/mod.rs @@ -1,3 +1,3 @@ pub mod continuwuity; pub mod get_suspended; -pub mod set_suspended; \ No newline at end of file +pub mod set_suspended; diff --git a/src/ruminuwuity/admin/set_suspended.rs b/src/ruminuwuity/admin/set_suspended.rs index 9d6e9be09..319dc0a01 100644 --- a/src/ruminuwuity/admin/set_suspended.rs +++ b/src/ruminuwuity/admin/set_suspended.rs @@ -3,53 +3,52 @@ //! Set the suspension status of a target user pub mod v1 { - //! `/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{userID}` ([msc]) - //! - //! [msc]: https://github.com/matrix-org/matrix-spec-proposals/pull/4323 + //! `/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{userID}` + //! ([msc]) + //! + //! [msc]: https://github.com/matrix-org/matrix-spec-proposals/pull/4323 - use ruma::{ - OwnedUserId, api::{auth_scheme::AccessToken, request, response}, metadata - }; + use ruma::{ + OwnedUserId, + api::{auth_scheme::AccessToken, request, response}, + metadata, + }; - metadata! { - method: PUT, - rate_limited: false, - authentication: AccessToken, - history: { - unstable => "/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{user_id}", - } - } + metadata! { + method: PUT, + rate_limited: false, + authentication: AccessToken, + history: { + unstable => "/_matrix/client/unstable/uk.timedout.msc4323/admin/suspend/{user_id}", + } + } - /// Request type for the set user suspension status endpoint. - #[request(error = ruma::api::client::Error)] - pub struct Request { - /// The user to look up. - #[ruma_api(path)] - pub user_id: OwnedUserId, + /// Request type for the set user suspension status endpoint. + #[request(error = ruma::api::error::Error)] + pub struct Request { + /// The user to look up. + #[ruma_api(path)] + pub user_id: OwnedUserId, - pub suspended: bool, - } + pub suspended: bool, + } - /// Response type for the suspension endpoints - #[response(error = ruma::api::client::Error)] - pub struct Response { - /// Whether the user is currently suspended. - pub suspended: bool, - } + /// Response type for the suspension endpoints + #[response(error = ruma::api::error::Error)] + pub struct Response { + /// Whether the user is currently suspended. + pub suspended: bool, + } - impl Request { - /// Creates a new `Request` with the given user id. - #[must_use] - pub fn new(user_id: OwnedUserId, suspended: bool) -> Self { - Self { user_id, suspended } - } - } + impl Request { + /// Creates a new `Request` with the given user id. + #[must_use] + pub fn new(user_id: OwnedUserId, suspended: bool) -> Self { Self { user_id, suspended } } + } - impl Response { - /// Creates a new `Response` with the given suspension status. - #[must_use] - pub fn new(suspended: bool) -> Self { - Self { suspended } - } - } -} \ No newline at end of file + impl Response { + /// Creates a new `Response` with the given suspension status. + #[must_use] + pub fn new(suspended: bool) -> Self { Self { suspended } } + } +} diff --git a/src/ruminuwuity/draupnir_antispam/mod.rs b/src/ruminuwuity/draupnir_antispam/mod.rs index e81dc6fd2..8ed47461f 100644 --- a/src/ruminuwuity/draupnir_antispam/mod.rs +++ b/src/ruminuwuity/draupnir_antispam/mod.rs @@ -1,2 +1,2 @@ pub mod user_may_invite; -pub mod user_may_join_room; \ No newline at end of file +pub mod user_may_join_room; diff --git a/src/ruminuwuity/draupnir_antispam/user_may_invite.rs b/src/ruminuwuity/draupnir_antispam/user_may_invite.rs index 524313ae8..d488c3143 100644 --- a/src/ruminuwuity/draupnir_antispam/user_may_invite.rs +++ b/src/ruminuwuity/draupnir_antispam/user_may_invite.rs @@ -1,50 +1,51 @@ //! `POST /api/1/spam_check/user_may_invite` //! -//! Checks that a user may invite the given user to the given room via Draupnir anti-spam +//! Checks that a user may invite the given user to the given room via Draupnir +//! anti-spam pub mod v1 { - use ruma::{ - OwnedRoomId, OwnedUserId, api::{auth_scheme::AppserviceToken, request, response}, metadata - }; + use ruma::{ + OwnedRoomId, OwnedUserId, + api::{auth_scheme::AppserviceToken, request, response}, + metadata, + }; - metadata! { - method: POST, - rate_limited: false, - authentication: AppserviceToken, - history: { - 1.0 => "/api/1/spam_check/user_may_invite", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: AppserviceToken, + history: { + 1.0 => "/api/1/spam_check/user_may_invite", + } + } - /// Request type for the `user_may_invite` callback. - #[request] - pub struct Request { - /// The room the invitee is being invited to - pub room_id: OwnedRoomId, - /// The user sending the invite - pub inviter: OwnedUserId, - /// The user being invited - pub invitee: OwnedUserId, - } + /// Request type for the `user_may_invite` callback. + #[request] + pub struct Request { + /// The room the invitee is being invited to + pub room_id: OwnedRoomId, + /// The user sending the invite + pub inviter: OwnedUserId, + /// The user being invited + pub invitee: OwnedUserId, + } - /// Response type for the `user_may_invite` callback. - #[response] - #[derive(Default)] - pub struct Response; + /// Response type for the `user_may_invite` callback. + #[response] + #[derive(Default)] + pub struct Response; - impl Request { - /// Creates a new empty `Request`. - #[must_use] - pub fn new(room_id: OwnedRoomId, inviter: OwnedUserId, invitee: OwnedUserId) -> Self { - Self { room_id, inviter, invitee } - } - } + impl Request { + /// Creates a new empty `Request`. + #[must_use] + pub fn new(room_id: OwnedRoomId, inviter: OwnedUserId, invitee: OwnedUserId) -> Self { + Self { room_id, inviter, invitee } + } + } - impl Response { - /// Creates a new empty `Response`. - #[must_use] - pub fn new() -> Self { - Self::default() - } - } + impl Response { + /// Creates a new empty `Response`. + #[must_use] + pub fn new() -> Self { Self::default() } + } } diff --git a/src/ruminuwuity/draupnir_antispam/user_may_join_room.rs b/src/ruminuwuity/draupnir_antispam/user_may_join_room.rs index 5bb2b0bf0..ddd0a8990 100644 --- a/src/ruminuwuity/draupnir_antispam/user_may_join_room.rs +++ b/src/ruminuwuity/draupnir_antispam/user_may_join_room.rs @@ -1,50 +1,51 @@ //! `POST /api/1/spam_check/user_may_join_room` //! -//! Endpoint that checks whether a user may join a given room via Draupnir anti-spam +//! Endpoint that checks whether a user may join a given room via Draupnir +//! anti-spam pub mod v1 { - use ruma::{ - OwnedRoomId, OwnedUserId, api::{auth_scheme::AppserviceToken, request, response}, metadata - }; + use ruma::{ + OwnedRoomId, OwnedUserId, + api::{auth_scheme::AppserviceToken, request, response}, + metadata, + }; - metadata! { - method: POST, - rate_limited: false, - authentication: AppserviceToken, - history: { - 1.0 => "/api/1/spam_check/user_may_join_room", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: AppserviceToken, + history: { + 1.0 => "/api/1/spam_check/user_may_join_room", + } + } - /// Request type for the `user_may_join_room` callback. - #[request] - pub struct Request { - /// The user trying to join a room - pub user: OwnedUserId, - /// The room the user is trying to join - pub room: OwnedRoomId, - /// Whether the user was invited to this room - pub is_invited: bool, - } + /// Request type for the `user_may_join_room` callback. + #[request] + pub struct Request { + /// The user trying to join a room + pub user: OwnedUserId, + /// The room the user is trying to join + pub room: OwnedRoomId, + /// Whether the user was invited to this room + pub is_invited: bool, + } - /// Response type for the `user_may_join_room` callback. - #[response] - #[derive(Default)] - pub struct Response; + /// Response type for the `user_may_join_room` callback. + #[response] + #[derive(Default)] + pub struct Response; - impl Request { - /// Creates a new empty `Request`. - #[must_use] - pub fn new(user: OwnedUserId, room: OwnedRoomId, is_invited: bool) -> Self { - Self { user, room, is_invited } - } - } + impl Request { + /// Creates a new empty `Request`. + #[must_use] + pub fn new(user: OwnedUserId, room: OwnedRoomId, is_invited: bool) -> Self { + Self { user, room, is_invited } + } + } - impl Response { - /// Creates a new empty `Response`. - #[must_use] - pub fn new() -> Self { - Self::default() - } - } + impl Response { + /// Creates a new empty `Response`. + #[must_use] + pub fn new() -> Self { Self::default() } + } } diff --git a/src/ruminuwuity/invite_permission_config.rs b/src/ruminuwuity/invite_permission_config.rs index 64bd08c41..ed37b753c 100644 --- a/src/ruminuwuity/invite_permission_config.rs +++ b/src/ruminuwuity/invite_permission_config.rs @@ -1,247 +1,271 @@ //! Types for invite filtering ([MSC4155]). -//! +//! //! MSC4155: https://github.com/matrix-org/matrix-spec-proposals/pull/4155 -use ruma::{ServerName, UserId}; -use ruma::exports::ruma_macros::EventContent; +use ruma::{ServerName, UserId, exports::ruma_macros::EventContent}; use serde::{Deserialize, Serialize}; use wildmatch::WildMatch; -/// Represents a user's level of filtering on actions from another user or server. -/// "Ignore" and "block" are defined in [MSC4283]. +/// Represents a user's level of filtering on actions from another user or +/// server. "Ignore" and "block" are defined in [MSC4283]. /// /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FilterLevel { - Allow, - Ignore, - Block, + Allow, + Ignore, + Block, } #[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "m.invite_permission_config", kind = GlobalAccountData)] pub struct InvitePermissionConfigEventContent { - /// A global on/off toggle for all rules - #[serde(default = "ruma::serde::default_true")] - pub enabled: bool, - - /// A list of globs matching users which are allowed to send an invite. - /// Entries in this list supersede entries in the ignored and blocked lists. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub allowed_users: Vec, - /// A list of globs matching users whose invites should be ignored (as defined in [MSC4283]). - /// - /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub ignored_users: Vec, - /// A list of globs matching users whose invites should be blocked (as defined in [MSC4283]). - /// Invites from blocked users should be refused with the M_INVITE_BLOCKED status code. - /// - /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub blocked_users: Vec, + /// A global on/off toggle for all rules + #[serde(default = "ruma::serde::default_true")] + pub enabled: bool, + /// A list of globs matching users which are allowed to send an invite. + /// Entries in this list supersede entries in the ignored and blocked lists. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub allowed_users: Vec, + /// A list of globs matching users whose invites should be ignored (as + /// defined in [MSC4283]). + /// + /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub ignored_users: Vec, + /// A list of globs matching users whose invites should be blocked (as + /// defined in [MSC4283]). Invites from blocked users should be refused + /// with the M_INVITE_BLOCKED status code. + /// + /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub blocked_users: Vec, - /// A list of globs matching servers which are allowed to send an invite. - /// Entries in this list supersede entries in the ignored and blocked lists. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub allowed_servers: Vec, - /// A list of globs matching servers whose invites should be ignored (as defined in [MSC4283]). - /// - /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub ignored_servers: Vec, - /// A list of globs matching servers whose invites should be blocked (as defined in [MSC4283]). - /// Invites from blocked servers should be refused with the M_INVITE_BLOCKED status code. - /// - /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub blocked_servers: Vec, + /// A list of globs matching servers which are allowed to send an invite. + /// Entries in this list supersede entries in the ignored and blocked lists. + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub allowed_servers: Vec, + /// A list of globs matching servers whose invites should be ignored (as + /// defined in [MSC4283]). + /// + /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub ignored_servers: Vec, + /// A list of globs matching servers whose invites should be blocked (as + /// defined in [MSC4283]). Invites from blocked servers should be refused + /// with the M_INVITE_BLOCKED status code. + /// + /// MSC4283: https://github.com/matrix-org/matrix-spec-proposals/pull/4283 + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub blocked_servers: Vec, } impl InvitePermissionConfigEventContent { - /// Creates a new `InvitePermissionConfigEventContent` from six lists of globs. - #[must_use] - pub fn new( - enabled: bool, - allowed_users: Vec, - ignored_users: Vec, - blocked_users: Vec, - allowed_servers: Vec, - ignored_servers: Vec, - blocked_servers: Vec, - ) -> Self { - Self { - enabled, - allowed_users, - ignored_users, - blocked_users, - allowed_servers, - ignored_servers, - blocked_servers, - } - } + /// Creates a new `InvitePermissionConfigEventContent` from six lists of + /// globs. + #[must_use] + pub fn new( + enabled: bool, + allowed_users: Vec, + ignored_users: Vec, + blocked_users: Vec, + allowed_servers: Vec, + ignored_servers: Vec, + blocked_servers: Vec, + ) -> Self { + Self { + enabled, + allowed_users, + ignored_users, + blocked_users, + allowed_servers, + ignored_servers, + blocked_servers, + } + } - /// Test the filters against a user id. This function will check both the - /// user rules _and_ the server rules. - #[must_use] - #[allow(clippy::if_same_then_else)] - pub fn user_filter_level(&self, user: &UserId) -> FilterLevel { - if !self.enabled { - FilterLevel::Allow - } else if Self::matches(&self.allowed_users, user.as_str()) { - FilterLevel::Allow - } else if Self::matches(&self.ignored_users, user.as_str()) { - FilterLevel::Ignore - } else if Self::matches(&self.blocked_users, user.as_str()) { - FilterLevel::Block - } else { - self.server_filter_level(user.server_name()) - } - } + /// Test the filters against a user id. This function will check both the + /// user rules _and_ the server rules. + #[must_use] + #[allow(clippy::if_same_then_else)] + pub fn user_filter_level(&self, user: &UserId) -> FilterLevel { + if !self.enabled { + FilterLevel::Allow + } else if Self::matches(&self.allowed_users, user.as_str()) { + FilterLevel::Allow + } else if Self::matches(&self.ignored_users, user.as_str()) { + FilterLevel::Ignore + } else if Self::matches(&self.blocked_users, user.as_str()) { + FilterLevel::Block + } else { + self.server_filter_level(user.server_name()) + } + } - /// Test the filters against a server name. Port numbers are ignored. - #[must_use] - pub fn server_filter_level(&self, server: &ServerName) -> FilterLevel { - if !self.enabled { - FilterLevel::Allow - } else { - let server = server.host(); - if Self::matches(&self.allowed_servers, server) { - FilterLevel::Allow - } else if Self::matches(&self.ignored_servers, server) { - FilterLevel::Ignore - } else if Self::matches(&self.blocked_servers, server) { - FilterLevel::Block - } else { - FilterLevel::Allow - } - } - } + /// Test the filters against a server name. Port numbers are ignored. + #[must_use] + pub fn server_filter_level(&self, server: &ServerName) -> FilterLevel { + if !self.enabled { + FilterLevel::Allow + } else { + let server = server.host(); + if Self::matches(&self.allowed_servers, server) { + FilterLevel::Allow + } else if Self::matches(&self.ignored_servers, server) { + FilterLevel::Ignore + } else if Self::matches(&self.blocked_servers, server) { + FilterLevel::Block + } else { + FilterLevel::Allow + } + } + } - fn matches(a: &[String], s: &str) -> bool { - a.iter().map(String::as_str).any(|a| WildMatch::new(a).matches(s)) - } + fn matches(a: &[String], s: &str) -> bool { + a.iter() + .map(String::as_str) + .any(|a| WildMatch::new(a).matches(s)) + } } #[cfg(test)] mod tests { - use ruma::{ServerName, UserId, events::GlobalAccountDataEvent}; - use serde_json::{from_value as from_json_value, json}; + use ruma::{ServerName, UserId, events::GlobalAccountDataEvent}; + use serde_json::{from_value as from_json_value, json}; - use crate::invite_permission_config::{FilterLevel, InvitePermissionConfigEventContent}; + use crate::invite_permission_config::{FilterLevel, InvitePermissionConfigEventContent}; - fn user_id(id: &str) -> &UserId { - <&UserId>::try_from(id).unwrap() - } + fn user_id(id: &str) -> &UserId { <&UserId>::try_from(id).unwrap() } - fn server_name(name: &str) -> &ServerName { - <&ServerName>::try_from(name).unwrap() - } + fn server_name(name: &str) -> &ServerName { <&ServerName>::try_from(name).unwrap() } - #[test] - fn default_values() { - let data = json!({ - "content": {}, - "type": "org.matrix.msc4155.invite_permission_config" - }); + #[test] + fn default_values() { + let data = json!({ + "content": {}, + "type": "org.matrix.msc4155.invite_permission_config" + }); - let event: GlobalAccountDataEvent = from_json_value(data).unwrap(); - assert!(event.content.enabled); - assert!(event.content.allowed_users.is_empty()); - assert!(event.content.ignored_users.is_empty()); - assert!(event.content.blocked_users.is_empty()); - assert!(event.content.allowed_servers.is_empty()); - assert!(event.content.ignored_servers.is_empty()); - assert!(event.content.blocked_servers.is_empty()); - assert_eq!(event.content.user_filter_level(user_id("@alice:example.com")), FilterLevel::Allow); - assert_eq!(event.content.server_filter_level(server_name("example.com")), FilterLevel::Allow); - } + let event: GlobalAccountDataEvent = + from_json_value(data).unwrap(); + assert!(event.content.enabled); + assert!(event.content.allowed_users.is_empty()); + assert!(event.content.ignored_users.is_empty()); + assert!(event.content.blocked_users.is_empty()); + assert!(event.content.allowed_servers.is_empty()); + assert!(event.content.ignored_servers.is_empty()); + assert!(event.content.blocked_servers.is_empty()); + assert_eq!( + event + .content + .user_filter_level(user_id("@alice:example.com")), + FilterLevel::Allow + ); + assert_eq!( + event + .content + .server_filter_level(server_name("example.com")), + FilterLevel::Allow + ); + } - #[test] - fn block_the_world() { - let event = InvitePermissionConfigEventContent { - enabled: true, - blocked_servers: vec!["*".to_owned()], - ..Default::default() - }; + #[test] + fn block_the_world() { + let event = InvitePermissionConfigEventContent { + enabled: true, + blocked_servers: vec!["*".to_owned()], + ..Default::default() + }; - assert_eq!(event.user_filter_level(user_id("@alice:foo.com:8080")), FilterLevel::Block); - assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Block); - } + assert_eq!(event.user_filter_level(user_id("@alice:foo.com:8080")), FilterLevel::Block); + assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Block); + } - #[test] - fn only_goodguys() { - let event = InvitePermissionConfigEventContent { - enabled: true, - allowed_servers: vec!["goodguys.org".to_owned()], - blocked_servers: vec!["*".to_owned()], - ..Default::default() - }; + #[test] + fn only_goodguys() { + let event = InvitePermissionConfigEventContent { + enabled: true, + allowed_servers: vec!["goodguys.org".to_owned()], + blocked_servers: vec!["*".to_owned()], + ..Default::default() + }; - assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org:8080")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Block); - } + assert_eq!( + event.user_filter_level(user_id("@alice:goodguys.org:8080")), + FilterLevel::Allow + ); + assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); + assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Block); + } - #[test] - fn exclude_badguys() { - let event = InvitePermissionConfigEventContent { - enabled: true, - blocked_servers: vec!["badguys.org".to_owned()], - ..Default::default() - }; + #[test] + fn exclude_badguys() { + let event = InvitePermissionConfigEventContent { + enabled: true, + blocked_servers: vec!["badguys.org".to_owned()], + ..Default::default() + }; - assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@kevin:badguys.org:8080")), FilterLevel::Block); - assert_eq!(event.user_filter_level(user_id("@kevin:badguys.org")), FilterLevel::Block); - } + assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); + assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Allow); + assert_eq!( + event.user_filter_level(user_id("@kevin:badguys.org:8080")), + FilterLevel::Block + ); + assert_eq!(event.user_filter_level(user_id("@kevin:badguys.org")), FilterLevel::Block); + } - #[test] - fn only_goodguys_except_for_kevin() { - let event = InvitePermissionConfigEventContent { - enabled: true, - blocked_users: vec!["@kevin:goodguys.org".to_owned()], - allowed_servers: vec!["goodguys.org".to_owned()], - blocked_servers: vec!["*".to_owned()], - ..Default::default() - }; + #[test] + fn only_goodguys_except_for_kevin() { + let event = InvitePermissionConfigEventContent { + enabled: true, + blocked_users: vec!["@kevin:goodguys.org".to_owned()], + allowed_servers: vec!["goodguys.org".to_owned()], + blocked_servers: vec!["*".to_owned()], + ..Default::default() + }; - assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@kevin:goodguys.org")), FilterLevel::Block); - assert_eq!(event.user_filter_level(user_id("@kevin:badguys.org")), FilterLevel::Block); - } + assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); + assert_eq!(event.user_filter_level(user_id("@kevin:goodguys.org")), FilterLevel::Block); + assert_eq!(event.user_filter_level(user_id("@kevin:badguys.org")), FilterLevel::Block); + } - #[test] - fn no_badguys_except_for_alice() { - let event = InvitePermissionConfigEventContent { - enabled: true, - allowed_users: vec!["@alice:badguys.org".to_owned()], - blocked_servers: vec!["badguys.org".to_owned()], - ..Default::default() - }; + #[test] + fn no_badguys_except_for_alice() { + let event = InvitePermissionConfigEventContent { + enabled: true, + allowed_users: vec!["@alice:badguys.org".to_owned()], + blocked_servers: vec!["badguys.org".to_owned()], + ..Default::default() + }; - assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@alice:badguys.org")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@kevin:badguys.org")), FilterLevel::Block); - } + assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); + assert_eq!(event.user_filter_level(user_id("@alice:badguys.org")), FilterLevel::Allow); + assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Allow); + assert_eq!(event.user_filter_level(user_id("@kevin:badguys.org")), FilterLevel::Block); + } - #[test] - fn only_goodguys_and_ignore_reallybadguys() { - let event = InvitePermissionConfigEventContent { - enabled: true, - allowed_servers: vec!["goodguys.org".to_owned()], - ignored_servers: vec!["reallybadguys.org".to_owned()], - blocked_servers: vec!["*".to_owned()], - ..Default::default() - }; + #[test] + fn only_goodguys_and_ignore_reallybadguys() { + let event = InvitePermissionConfigEventContent { + enabled: true, + allowed_servers: vec!["goodguys.org".to_owned()], + ignored_servers: vec!["reallybadguys.org".to_owned()], + blocked_servers: vec!["*".to_owned()], + ..Default::default() + }; - assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org:8080")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); - assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Block); - assert_eq!(event.user_filter_level(user_id("@kevin:reallybadguys.org")), FilterLevel::Ignore); - } -} \ No newline at end of file + assert_eq!( + event.user_filter_level(user_id("@alice:goodguys.org:8080")), + FilterLevel::Allow + ); + assert_eq!(event.user_filter_level(user_id("@alice:goodguys.org")), FilterLevel::Allow); + assert_eq!(event.user_filter_level(user_id("@bob:bar.com")), FilterLevel::Block); + assert_eq!( + event.user_filter_level(user_id("@kevin:reallybadguys.org")), + FilterLevel::Ignore + ); + } +} diff --git a/src/ruminuwuity/meowlnir_antispam/accept_make_join.rs b/src/ruminuwuity/meowlnir_antispam/accept_make_join.rs index d9fa5ef56..a5b30fcf7 100644 --- a/src/ruminuwuity/meowlnir_antispam/accept_make_join.rs +++ b/src/ruminuwuity/meowlnir_antispam/accept_make_join.rs @@ -7,53 +7,53 @@ //! - https://mau.dev/maunium/synapse/-/blob/52741d3/synapse/handlers/event_auth.py#L280-292 pub mod v1 { - use ruma::{ - OwnedRoomId, OwnedUserId, api::{auth_scheme::AppserviceToken, request, response}, metadata - }; + use ruma::{ + OwnedRoomId, OwnedUserId, + api::{auth_scheme::AppserviceToken, request, response}, + metadata, + }; - metadata! { - method: POST, - rate_limited: false, - authentication: AppserviceToken, - history: { - 1.0 => "/_meowlnir/antispam/{management_room_id}/accept_make_join", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: AppserviceToken, + history: { + 1.0 => "/_meowlnir/antispam/{management_room_id}/accept_make_join", + } + } - /// Request type for the `accept_make_join` callback. - #[request] - pub struct Request { - /// The relevant management room - #[ruma_api(path)] - pub management_room_id: OwnedRoomId, - /// The user trying to join a room - pub user: OwnedUserId, - /// The room the user is trying to join - pub room: OwnedRoomId, - } + /// Request type for the `accept_make_join` callback. + #[request] + pub struct Request { + /// The relevant management room + #[ruma_api(path)] + pub management_room_id: OwnedRoomId, + /// The user trying to join a room + pub user: OwnedUserId, + /// The room the user is trying to join + pub room: OwnedRoomId, + } - /// Response type for the `accept_make_join` callback. - #[response] - #[derive(Default)] - pub struct Response; + /// Response type for the `accept_make_join` callback. + #[response] + #[derive(Default)] + pub struct Response; - impl Request { - /// Creates a new empty `Request`. - #[must_use] - pub fn new( - management_room_id: OwnedRoomId, - user: OwnedUserId, - room: OwnedRoomId, - ) -> Self { - Self { management_room_id, user, room } - } - } + impl Request { + /// Creates a new empty `Request`. + #[must_use] + pub fn new( + management_room_id: OwnedRoomId, + user: OwnedUserId, + room: OwnedRoomId, + ) -> Self { + Self { management_room_id, user, room } + } + } - impl Response { - /// Creates a new empty `Response`. - #[must_use] - pub fn new() -> Self { - Self::default() - } - } + impl Response { + /// Creates a new empty `Response`. + #[must_use] + pub fn new() -> Self { Self::default() } + } } diff --git a/src/ruminuwuity/meowlnir_antispam/mod.rs b/src/ruminuwuity/meowlnir_antispam/mod.rs index e0d02480b..e8f787e79 100644 --- a/src/ruminuwuity/meowlnir_antispam/mod.rs +++ b/src/ruminuwuity/meowlnir_antispam/mod.rs @@ -1,4 +1,4 @@ pub mod user_may_invite; pub mod user_may_join_room; -pub mod accept_make_join; \ No newline at end of file +pub mod accept_make_join; diff --git a/src/ruminuwuity/meowlnir_antispam/user_may_invite.rs b/src/ruminuwuity/meowlnir_antispam/user_may_invite.rs index 91289c753..eef3c2026 100644 --- a/src/ruminuwuity/meowlnir_antispam/user_may_invite.rs +++ b/src/ruminuwuity/meowlnir_antispam/user_may_invite.rs @@ -1,58 +1,64 @@ //! `POST /_meowlnir/antispam/*/user_may_invite` //! -//! Checks that a user may invite the given user to the given room via Meowlnir anti-spam +//! Checks that a user may invite the given user to the given room via Meowlnir +//! anti-spam pub mod v1 { - use ruma::{ - OwnedRoomId, OwnedUserId, api::{auth_scheme::AppserviceToken, request, response}, metadata - }; + use ruma::{ + OwnedRoomId, OwnedUserId, + api::{auth_scheme::AppserviceToken, request, response}, + metadata, + }; - metadata! { - method: POST, - rate_limited: false, - authentication: AppserviceToken, - history: { - 1.0 => "/_meowlnir/antispam/{management_room_id}/user_may_invite", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: AppserviceToken, + history: { + 1.0 => "/_meowlnir/antispam/{management_room_id}/user_may_invite", + } + } - /// Request type for the `user_may_invite` callback. - #[request] - pub struct Request { - /// The relevant management room - #[ruma_api(path)] - pub management_room_id: OwnedRoomId, - /// The user sending the invite - pub inviter: OwnedUserId, - /// The user being invited - pub invitee: OwnedUserId, - /// The room the invitee is being invited to - pub room_id: OwnedRoomId, - } + /// Request type for the `user_may_invite` callback. + #[request] + pub struct Request { + /// The relevant management room + #[ruma_api(path)] + pub management_room_id: OwnedRoomId, + /// The user sending the invite + pub inviter: OwnedUserId, + /// The user being invited + pub invitee: OwnedUserId, + /// The room the invitee is being invited to + pub room_id: OwnedRoomId, + } - /// Response type for the `user_may_invite` callback. - #[response] - #[derive(Default)] - pub struct Response; + /// Response type for the `user_may_invite` callback. + #[response] + #[derive(Default)] + pub struct Response; - impl Request { - /// Creates a new empty `Request`. - #[must_use] - pub fn new( - management_room_id: OwnedRoomId, - inviter: OwnedUserId, - invitee: OwnedUserId, - room_id: OwnedRoomId, - ) -> Self { - Self { management_room_id, inviter, invitee, room_id } - } - } + impl Request { + /// Creates a new empty `Request`. + #[must_use] + pub fn new( + management_room_id: OwnedRoomId, + inviter: OwnedUserId, + invitee: OwnedUserId, + room_id: OwnedRoomId, + ) -> Self { + Self { + management_room_id, + inviter, + invitee, + room_id, + } + } + } - impl Response { - /// Creates a new empty `Response`. - #[must_use] - pub fn new() -> Self { - Self::default() - } - } + impl Response { + /// Creates a new empty `Response`. + #[must_use] + pub fn new() -> Self { Self::default() } + } } diff --git a/src/ruminuwuity/meowlnir_antispam/user_may_join_room.rs b/src/ruminuwuity/meowlnir_antispam/user_may_join_room.rs index 606a94a42..15b9edc4b 100644 --- a/src/ruminuwuity/meowlnir_antispam/user_may_join_room.rs +++ b/src/ruminuwuity/meowlnir_antispam/user_may_join_room.rs @@ -3,56 +3,61 @@ //! Endpoint to track invite joins via Meowlnir anti-spam pub mod v1 { - use ruma::{ - OwnedRoomId, OwnedUserId, api::{auth_scheme::AppserviceToken, request, response}, metadata - }; + use ruma::{ + OwnedRoomId, OwnedUserId, + api::{auth_scheme::AppserviceToken, request, response}, + metadata, + }; - metadata! { - method: POST, - rate_limited: false, - authentication: AppserviceToken, - history: { - 1.0 => "/_meowlnir/antispam/{management_room_id}/user_may_join_room", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: AppserviceToken, + history: { + 1.0 => "/_meowlnir/antispam/{management_room_id}/user_may_join_room", + } + } - /// Request type for the `user_may_join_room` callback. - #[request] - pub struct Request { - /// The relevant management room - #[ruma_api(path)] - pub management_room_id: OwnedRoomId, - /// The user trying to join a room - pub user: OwnedUserId, - /// The room the user is trying to join - pub room: OwnedRoomId, - /// Whether the user was invited to this room - pub is_invited: bool, - } + /// Request type for the `user_may_join_room` callback. + #[request] + pub struct Request { + /// The relevant management room + #[ruma_api(path)] + pub management_room_id: OwnedRoomId, + /// The user trying to join a room + pub user: OwnedUserId, + /// The room the user is trying to join + pub room: OwnedRoomId, + /// Whether the user was invited to this room + pub is_invited: bool, + } - /// Response type for the `user_may_join_room` callback. - #[response] - #[derive(Default)] - pub struct Response; + /// Response type for the `user_may_join_room` callback. + #[response] + #[derive(Default)] + pub struct Response; - impl Request { - /// Creates a new empty `Request`. - #[must_use] - pub fn new( - management_room_id: OwnedRoomId, - user: OwnedUserId, - room: OwnedRoomId, - is_invited: bool, - ) -> Self { - Self { management_room_id, user, room, is_invited } - } - } + impl Request { + /// Creates a new empty `Request`. + #[must_use] + pub fn new( + management_room_id: OwnedRoomId, + user: OwnedUserId, + room: OwnedRoomId, + is_invited: bool, + ) -> Self { + Self { + management_room_id, + user, + room, + is_invited, + } + } + } - impl Response { - /// Creates a new empty `Response`. - #[must_use] - pub fn new() -> Self { - Self::default() - } - } + impl Response { + /// Creates a new empty `Response`. + #[must_use] + pub fn new() -> Self { Self::default() } + } } diff --git a/src/ruminuwuity/mod.rs b/src/ruminuwuity/mod.rs index 7406f840d..9c98031db 100644 --- a/src/ruminuwuity/mod.rs +++ b/src/ruminuwuity/mod.rs @@ -2,6 +2,6 @@ pub mod admin; pub mod draupnir_antispam; +pub mod invite_permission_config; pub mod meowlnir_antispam; pub mod policy; -pub mod invite_permission_config; \ No newline at end of file diff --git a/src/ruminuwuity/policy/event.rs b/src/ruminuwuity/policy/event.rs index a044a2f87..be57a18d7 100644 --- a/src/ruminuwuity/policy/event.rs +++ b/src/ruminuwuity/policy/event.rs @@ -2,99 +2,90 @@ //! //! [`org.matrix.msc4284.policy`]: https://github.com/matrix-org/matrix-spec-proposals/pull/4284 -use ruma::exports::ruma_macros::EventContent; +use ruma::{events::EmptyStateKey, exports::ruma_macros::EventContent}; use serde::{Deserialize, Serialize}; -use ruma::events::EmptyStateKey; - #[derive(Clone, Debug, Deserialize, Serialize, EventContent, Default)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[ruma_event(type = "org.matrix.msc4284.policy", kind = State, state_key_type = EmptyStateKey)] pub struct RoomPolicyEventContent { - /// The server name of the room's policy server. - /// - /// If the value is empty or unreachable, the policy server should be ignored. - pub via: Option, - /// The public key this policy server will sign with. - pub public_key: Option + /// The server name of the room's policy server. + /// + /// If the value is empty or unreachable, the policy server should be + /// ignored. + pub via: Option, + /// The public key this policy server will sign with. + pub public_key: Option, } impl RoomPolicyEventContent { - /// Create an empty `RoomPolicyEventContent`. - #[must_use] - pub fn new() -> Self { - Self::default() - } + /// Create an empty `RoomPolicyEventContent`. + #[must_use] + pub fn new() -> Self { Self::default() } } #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct PolicyServerResponseContent { - /// The policy server's verdict. Either `ok` or `spam`. - pub recommendation: String, + /// The policy server's verdict. Either `ok` or `spam`. + pub recommendation: String, } impl PolicyServerResponseContent { - /// Create a new `PolicyServerResponseContent` with the given recommendation. - #[must_use] - pub fn new(recommendation: String) -> Self { - Self { recommendation } - } + /// Create a new `PolicyServerResponseContent` with the given + /// recommendation. + #[must_use] + pub fn new(recommendation: String) -> Self { Self { recommendation } } } impl From for PolicyServerResponseContent { - fn from(recommendation: String) -> Self { - Self::new(recommendation) - } + fn from(recommendation: String) -> Self { Self::new(recommendation) } } #[cfg(test)] mod tests { - use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; + use ruma::events::OriginalStateEvent; + use serde_json::{from_value as from_json_value, json, to_value as to_json_value}; - use super::RoomPolicyEventContent; - use ruma::events::OriginalStateEvent; + use super::RoomPolicyEventContent; - #[test] - fn serialization() { - let content = RoomPolicyEventContent { - via: Some("example.com".to_owned()), - public_key: Some("6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s".to_owned()) - }; + #[test] + fn serialization() { + let content = RoomPolicyEventContent { + via: Some("example.com".to_owned()), + public_key: Some("6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s".to_owned()), + }; - let actual = to_json_value(content).unwrap(); - let expected = json!({ - "via": "example.com", - "public_key": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s" - }); + let actual = to_json_value(content).unwrap(); + let expected = json!({ + "via": "example.com", + "public_key": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s" + }); - assert_eq!(actual, expected); - } + assert_eq!(actual, expected); + } - #[test] - fn deserialization() { - let json_data = json!({ - "content": { - "via": "example.com", - "public_key": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s" - }, - "event_id": "123:example.com", - "origin_server_ts": 1, - "room_id": "!123456:example.com", - "sender": "@carl:example.com", - "state_key": "", - "type": "org.matrix.msc4284.policy" - }); + #[test] + fn deserialization() { + let json_data = json!({ + "content": { + "via": "example.com", + "public_key": "6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s" + }, + "event_id": "123:example.com", + "origin_server_ts": 1, + "room_id": "!123456:example.com", + "sender": "@carl:example.com", + "state_key": "", + "type": "org.matrix.msc4284.policy" + }); - let content = from_json_value::>(json_data) - .unwrap() - .content; - assert_eq!( - content.via, - Some("example.com".to_owned()) - ); - assert_eq!( - content.public_key, - Some("6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s".to_owned()) - ); - } + let content = from_json_value::>(json_data) + .unwrap() + .content; + assert_eq!(content.via, Some("example.com".to_owned())); + assert_eq!( + content.public_key, + Some("6yhHGKhCiXTSEN2ksjV7kX_N6rBQZ3Xb-M7LlC6NS-s".to_owned()) + ); + } } diff --git a/src/ruminuwuity/policy/mod.rs b/src/ruminuwuity/policy/mod.rs index 7b60a5d78..c3950c19b 100644 --- a/src/ruminuwuity/policy/mod.rs +++ b/src/ruminuwuity/policy/mod.rs @@ -1,4 +1,4 @@ +pub mod event; pub mod policy_check; pub mod policy_sign; pub mod report_content; -pub mod event; \ No newline at end of file diff --git a/src/ruminuwuity/policy/policy_check.rs b/src/ruminuwuity/policy/policy_check.rs index 592655d7e..0becc77b0 100644 --- a/src/ruminuwuity/policy/policy_check.rs +++ b/src/ruminuwuity/policy/policy_check.rs @@ -4,57 +4,56 @@ //! This is now a fallback behaviour that will be removed later. pub mod unstable { - //! `/policy/unstable/org.matrix.msc4284` ([spec]) - //! - //! [spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/4284 + //! `/policy/unstable/org.matrix.msc4284` ([spec]) + //! + //! [spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/4284 - use ruma::{ - OwnedEventId, api::{federation::authentication::ServerSignatures, request, response}, metadata - }; - use serde_json::value::RawValue as RawJsonValue; + use ruma::{ + OwnedEventId, + api::{federation::authentication::ServerSignatures, request, response}, + metadata, + }; + use serde_json::value::RawValue as RawJsonValue; - metadata! { - method: POST, - rate_limited: false, - authentication: ServerSignatures, - history: { - unstable => "/_matrix/policy/unstable/org.matrix.msc4284/event/{event_id}/check", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: ServerSignatures, + history: { + unstable => "/_matrix/policy/unstable/org.matrix.msc4284/event/{event_id}/check", + } + } - /// Response type for the `check` endpoint. - #[response] - pub struct Response { - /// Either `ok` or `spam`, indicating the policy server's recommendation. - pub recommendation: String, - } + /// Response type for the `check` endpoint. + #[response] + pub struct Response { + /// Either `ok` or `spam`, indicating the policy server's + /// recommendation. + pub recommendation: String, + } - impl Response { - /// Creates a new `Response` with the given recommendation. - #[must_use] - pub fn new(recommendation: String) -> Self { - Self { recommendation } - } - } + impl Response { + /// Creates a new `Response` with the given recommendation. + #[must_use] + pub fn new(recommendation: String) -> Self { Self { recommendation } } + } - /// Request type for the `check` endpoint. - #[request] - pub struct Request { - /// The event ID to check. - #[ruma_api(path)] - pub event_id: OwnedEventId, + /// Request type for the `check` endpoint. + #[request] + pub struct Request { + /// The event ID to check. + #[ruma_api(path)] + pub event_id: OwnedEventId, - /// The PDU body (optional) - #[ruma_api(body)] - #[serde(skip_serializing_if = "Option::is_none")] - pub pdu: Option>, - } + /// The PDU body (optional) + #[ruma_api(body)] + #[serde(skip_serializing_if = "Option::is_none")] + pub pdu: Option>, + } - impl Request { - /// Creates a new `Request` with the given event ID. - #[must_use] - pub fn new(event_id: OwnedEventId) -> Self { - Self { event_id, pdu: None } - } - } + impl Request { + /// Creates a new `Request` with the given event ID. + #[must_use] + pub fn new(event_id: OwnedEventId) -> Self { Self { event_id, pdu: None } } + } } diff --git a/src/ruminuwuity/policy/policy_sign.rs b/src/ruminuwuity/policy/policy_sign.rs index 8e8c9ae29..40b946b2d 100644 --- a/src/ruminuwuity/policy/policy_sign.rs +++ b/src/ruminuwuity/policy/policy_sign.rs @@ -3,53 +3,53 @@ //! Asks a policy server to sign our event pub mod unstable { - //! `/policy/unstable/org.matrix.msc4284` ([spec]) - //! - //! [spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/4284 - use ruma::{ - ServerSignatures, - api::{federation::authentication::ServerSignatures as ServerSignaturesAuth, request, response}, metadata - }; - use serde_json::value::RawValue as RawJsonValue; + //! `/policy/unstable/org.matrix.msc4284` ([spec]) + //! + //! [spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/4284 + use ruma::{ + ServerSignatures, + api::{ + federation::authentication::ServerSignatures as ServerSignaturesAuth, request, + response, + }, + metadata, + }; + use serde_json::value::RawValue as RawJsonValue; - metadata! { - method: POST, - rate_limited: false, - authentication: ServerSignaturesAuth, - history: { - unstable => "/_matrix/policy/unstable/org.matrix.msc4284/sign", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: ServerSignaturesAuth, + history: { + unstable => "/_matrix/policy/unstable/org.matrix.msc4284/sign", + } + } - /// Response type for the `sign` endpoint. - #[response] - pub struct Response { - /// The signatures returned from the policy server (if provided) - #[ruma_api(body)] - pub signatures: Option - } + /// Response type for the `sign` endpoint. + #[response] + pub struct Response { + /// The signatures returned from the policy server (if provided) + #[ruma_api(body)] + pub signatures: Option, + } - impl Response { - /// Creates a new `Response` with the given recommendation. - #[must_use] - pub fn new(signatures: Option) -> Self { - Self { signatures } - } - } + impl Response { + /// Creates a new `Response` with the given recommendation. + #[must_use] + pub fn new(signatures: Option) -> Self { Self { signatures } } + } - /// Request type for the `sign` endpoint. - #[request] - pub struct Request { - /// The PDU body (in canonical JSON) - #[ruma_api(body)] - pub pdu: Box, - } + /// Request type for the `sign` endpoint. + #[request] + pub struct Request { + /// The PDU body (in canonical JSON) + #[ruma_api(body)] + pub pdu: Box, + } - impl Request { - /// Creates a new `Request` with the given event JSON - #[must_use] - pub fn new(pdu: Box) -> Self { - Self { pdu } - } - } -} \ No newline at end of file + impl Request { + /// Creates a new `Request` with the given event JSON + #[must_use] + pub fn new(pdu: Box) -> Self { Self { pdu } } + } +} diff --git a/src/ruminuwuity/policy/report_content.rs b/src/ruminuwuity/policy/report_content.rs index 959981920..3bf8b79d0 100644 --- a/src/ruminuwuity/policy/report_content.rs +++ b/src/ruminuwuity/policy/report_content.rs @@ -3,56 +3,56 @@ //! Send a request to report an event originating from another server. pub mod msc3843 { - //! `MSC3843` ([MSC]) - //! - //! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/3843 + //! `MSC3843` ([MSC]) + //! + //! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/3843 - use ruma::{ - OwnedEventId, OwnedRoomId, api::{federation::authentication::ServerSignatures, request, response}, metadata - }; + use ruma::{ + OwnedEventId, OwnedRoomId, + api::{federation::authentication::ServerSignatures, request, response}, + metadata, + }; - metadata! { - method: POST, - rate_limited: false, - authentication: ServerSignatures, - history: { - unstable => "/_matrix/federation/unstable/org.matrix.msc3843/rooms/{room_id}/report/{event_id}", - } - } + metadata! { + method: POST, + rate_limited: false, + authentication: ServerSignatures, + history: { + unstable => "/_matrix/federation/unstable/org.matrix.msc3843/rooms/{room_id}/report/{event_id}", + } + } - /// Request type for the `report_content` endpoint. - #[request] - pub struct Request { - /// The room ID that the reported event was sent in. - #[ruma_api(path)] - pub room_id: OwnedRoomId, + /// Request type for the `report_content` endpoint. + #[request] + pub struct Request { + /// The room ID that the reported event was sent in. + #[ruma_api(path)] + pub room_id: OwnedRoomId, - /// The event being reported. - #[ruma_api(path)] - pub event_id: OwnedEventId, + /// The event being reported. + #[ruma_api(path)] + pub event_id: OwnedEventId, - /// The reason that the event is being reported. - pub reason: String, - } + /// The reason that the event is being reported. + pub reason: String, + } - /// Response type for the `report_content` endpoint. - #[response] - #[derive(Default)] - pub struct Response; + /// Response type for the `report_content` endpoint. + #[response] + #[derive(Default)] + pub struct Response; - impl Request { - /// Creates a `Request` with the given room ID, event ID and reason. - #[must_use] - pub fn new(room_id: OwnedRoomId, event_id: OwnedEventId, reason: String) -> Self { - Self { room_id, event_id, reason } - } - } + impl Request { + /// Creates a `Request` with the given room ID, event ID and reason. + #[must_use] + pub fn new(room_id: OwnedRoomId, event_id: OwnedEventId, reason: String) -> Self { + Self { room_id, event_id, reason } + } + } - impl Response { - /// Creates a new empty `Response`. - #[must_use] - pub fn new() -> Self { - Self::default() - } - } + impl Response { + /// Creates a new empty `Response`. + #[must_use] + pub fn new() -> Self { Self::default() } + } } diff --git a/src/service/Cargo.toml b/src/service/Cargo.toml index 79e349b0c..885d8dbb6 100644 --- a/src/service/Cargo.toml +++ b/src/service/Cargo.toml @@ -107,6 +107,7 @@ nonzero_ext.workspace = true rand.workspace = true regex.workspace = true reqwest.workspace = true +assign.workspace = true ruma.workspace = true ruminuwuity.workspace = true rustyline-async.workspace = true diff --git a/src/service/account_data/mod.rs b/src/service/account_data/mod.rs index 12dedbaad..9fb17adaa 100644 --- a/src/service/account_data/mod.rs +++ b/src/service/account_data/mod.rs @@ -7,10 +7,12 @@ use database::{Deserialized, Handle, Ignore, Json, Map}; use futures::{Stream, StreamExt, TryFutureExt}; use ruma::{ - OwnedRoomId, OwnedUserId, RoomId, UserId, events::{ - AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, - GlobalAccountDataEventType, RoomAccountDataEventType, - }, serde::Raw + OwnedRoomId, OwnedUserId, RoomId, UserId, + events::{ + AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, GlobalAccountDataEventType, + RoomAccountDataEventType, + }, + serde::Raw, }; use serde::Deserialize; @@ -147,7 +149,9 @@ pub fn changes_since<'a>( .stream_from(&first_possible) .ignore_err() .ready_take_while(move |((room_id_, user_id_, count, _), _): &(Key, _)| { - room_id == room_id_.as_deref() && user_id == user_id_ && to.is_none_or(|to| *count <= to) + room_id == room_id_.as_deref() + && user_id == user_id_ + && to.is_none_or(|to| *count <= to) }) .map(move |(_, v)| { match room_id { diff --git a/src/service/admin/create.rs b/src/service/admin/create.rs index 0069e8752..381ed383c 100644 --- a/src/service/admin/create.rs +++ b/src/service/admin/create.rs @@ -85,7 +85,8 @@ pub async fn create_admin_room(services: &Services) -> Result { // 3. Power levels let users = BTreeMap::from_iter([(server_user.into(), 69420.into())]); - let mut power_levels_content = RoomPowerLevelsEventContent::new(&room_version.rules().unwrap().authorization); + let mut power_levels_content = + RoomPowerLevelsEventContent::new(&room_version.rules().unwrap().authorization); power_levels_content.users = users; services diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index c44b1b3d2..29a0435ca 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -30,7 +30,11 @@ }; use tokio::sync::RwLock; -use crate::{Dep, account_data, globals, media::{MXC_LENGTH, mxc::Mxc}, rooms::{self, state::RoomMutexGuard}}; +use crate::{ + Dep, account_data, globals, + media::{MXC_LENGTH, mxc::Mxc}, + rooms::{self, state::RoomMutexGuard}, +}; pub struct Service { services: Services, @@ -61,7 +65,7 @@ pub struct CommandInput { pub command: String, pub reply_id: Option, pub source: InvocationSource, - pub sender: Option>, + pub sender: Option, } /// Where a command is being invoked from. @@ -205,7 +209,10 @@ pub async fn text_or_file( metadata.mimetype = Some("text/markdown".to_owned()); metadata.size = Some(UInt::new_saturating(size_u64)); - let mut content = FileMessageEventContent::plain("Output was too large to send as text.".to_owned(), file); + let mut content = FileMessageEventContent::plain( + "Output was too large to send as text.".to_owned(), + file, + ); content.filename = Some("output.md".to_owned()); content.info = Some(Box::new(metadata)); @@ -313,7 +320,7 @@ pub fn command_with_sender( command: String, reply_id: Option, source: InvocationSource, - sender: Box, + sender: OwnedUserId, ) -> Result<()> { self.channel .0 @@ -448,13 +455,13 @@ pub async fn get_admin_room(&self) -> Result { } async fn handle_response(&self, content: RoomMessageEventContent) -> Result<()> { - let Some(Relation::Reply { in_reply_to }) = content.relates_to.as_ref() else { + let Some(Relation::Reply(reply )) = content.relates_to.as_ref() else { return Ok(()); }; - let Ok(pdu) = self.services.timeline.get_pdu(&in_reply_to.event_id).await else { + let Ok(pdu) = self.services.timeline.get_pdu(&reply.in_reply_to.event_id).await else { error!( - event_id = ?in_reply_to.event_id, + event_id = ?reply.in_reply_to.event_id, "Missing admin command in_reply_to event" ); return Ok(()); diff --git a/src/service/antispam/mod.rs b/src/service/antispam/mod.rs index 98cb69f0f..59b362fa1 100644 --- a/src/service/antispam/mod.rs +++ b/src/service/antispam/mod.rs @@ -2,7 +2,10 @@ use async_trait::async_trait; use conduwuit::{Result, config::Antispam, debug}; -use ruma::{OwnedRoomId, OwnedUserId, api::{auth_scheme::AppserviceToken, path_builder::VersionHistory}}; +use ruma::{ + OwnedRoomId, OwnedUserId, + api::{auth_scheme::AppserviceToken, path_builder::VersionHistory}, +}; use ruminuwuity::{draupnir_antispam, meowlnir_antispam}; use crate::{client, config, sending, service::Dep}; @@ -38,7 +41,11 @@ async fn send_antispam_request( request: T, ) -> Result where - T: ruma::api::OutgoingRequest + Debug + Send, + T: ruma::api::OutgoingRequest< + Authentication = AppserviceToken, + PathBuilder = VersionHistory, + > + Debug + + Send, { sending::antispam::send_antispam_request( &self.services.client.appservice, diff --git a/src/service/emergency/mod.rs b/src/service/emergency/mod.rs index aaf1b547a..f741c9e05 100644 --- a/src/service/emergency/mod.rs +++ b/src/service/emergency/mod.rs @@ -72,7 +72,9 @@ async fn set_emergency_access(&self) -> Result { None, server_user, GlobalAccountDataEventType::PushRules.to_string().into(), - &serde_json::to_value(&GlobalAccountDataEvent::new(PushRulesEventContent::new(ruleset))) + &serde_json::to_value(&GlobalAccountDataEvent::new(PushRulesEventContent::new( + ruleset, + ))) .expect("to json value always works"), ) .await?; diff --git a/src/service/federation/execute.rs b/src/service/federation/execute.rs index aadf204dd..7c253008b 100644 --- a/src/service/federation/execute.rs +++ b/src/service/federation/execute.rs @@ -2,13 +2,23 @@ use bytes::Bytes; use conduwuit::{ - Err, Error, Result, debug, debug_error, debug_warn, err, implement, trace, utils::response::LimitReadExt, matrix::versions::{unstable_features, versions}, }; + Err, Error, Result, debug, debug_error, debug_warn, err, implement, + matrix::versions::{unstable_features, versions}, + trace, + utils::response::LimitReadExt, +}; use ipaddress::IPAddress; use reqwest::{Client, Method, Request, Response, Url}; use ruma::{ - CanonicalJsonObject, CanonicalJsonValue, ServerName, ServerSigningKeyId, api::{ - EndpointError, IncomingResponse, Metadata, OutgoingRequest, SupportedVersions, auth_scheme::{AuthScheme, NoAuthentication, SendAccessToken}, client::error::Error as RumaError, federation::authentication::{ServerSignatures, ServerSignaturesInput, XMatrix}, path_builder::{PathBuilder, SinglePath, VersionHistory} - }, serde::Base64 + CanonicalJsonObject, CanonicalJsonValue, ServerName, ServerSigningKeyId, + api::{ + EndpointError, IncomingResponse, Metadata, OutgoingRequest, SupportedVersions, + auth_scheme::{AuthScheme, NoAuthentication, SendAccessToken}, + error::Error as RumaError, + federation::authentication::{ServerSignatures, ServerSignaturesInput, XMatrix}, + path_builder::{PathBuilder, SinglePath, VersionHistory}, + }, + serde::Base64, }; use crate::{SUPPORTED_VERSIONS, resolver::actual::ActualDest}; @@ -18,7 +28,11 @@ #[tracing::instrument(skip_all, name = "request", level = "debug")] pub async fn execute<'i, T>(&self, dest: &ServerName, request: T) -> Result where - T: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, + T: OutgoingRequest< + Authentication = ServerSignatures, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { let client = &self.services.client.federation; self.execute_signed(client, dest, request).await @@ -33,27 +47,46 @@ pub async fn execute_synapse<'i, T>( request: T, ) -> Result where - T: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, + T: OutgoingRequest< + Authentication = ServerSignatures, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { let client = &self.services.client.synapse; self.execute_signed(client, dest, request).await } #[implement(super::Service)] -pub async fn execute_unauthenticated<'i, T>(&self, dest: &ServerName, request: T) -> Result -where - T: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, +pub async fn execute_unauthenticated<'i, T>( + &self, + dest: &ServerName, + request: T, +) -> Result +where + T: OutgoingRequest< + Authentication = NoAuthentication, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { let client = &self.services.client.federation; - let authentication = SendAccessToken::None; - - self.execute_on(client, dest, request, authentication).await + + self.execute_on(client, dest, request, ()).await } #[implement(super::Service)] -pub async fn execute_signed<'i, T>(&self, client: &Client, dest: &ServerName, request: T) -> Result +pub async fn execute_signed<'i, T>( + &self, + client: &Client, + dest: &ServerName, + request: T, +) -> Result where - T: OutgoingRequest::: FederationPathBuilderInput>> + Send, + T: OutgoingRequest< + Authentication = ServerSignatures, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Send, { let authentication = ServerSignaturesInput::new( self.services.server.name.clone(), @@ -65,11 +98,7 @@ pub async fn execute_signed<'i, T>(&self, client: &Client, dest: &ServerName, re } #[implement(super::Service)] -#[tracing::instrument( - name = "fed", - level = "info", - skip(self, client, request, authentication), - )] +#[tracing::instrument(name = "fed", level = "info", skip(self, client, request, authentication))] pub async fn execute_on<'i, T, PathBuilderInput>( &self, client: &Client, @@ -78,8 +107,8 @@ pub async fn execute_on<'i, T, PathBuilderInput>( authentication: ::Input<'_>, ) -> Result where - T: OutgoingRequest:: = PathBuilderInput>> + Send, - PathBuilderInput: FederationPathBuilderInput + T: OutgoingRequest = PathBuilderInput>> + Send, + PathBuilderInput: FederationPathBuilderInput, { if !self.services.server.config.allow_federation { return Err!(Config("allow_federation", "Federation is disabled.")); @@ -90,14 +119,12 @@ pub async fn execute_on<'i, T, PathBuilderInput>( } let actual = self.services.resolver.get_actual_dest(dest).await?; - - let request = Request::try_from( - request.try_into_http_request::>( - actual.string().as_str(), - authentication, - PathBuilderInput::create(), - )? - )?; + + let request = Request::try_from(request.try_into_http_request::>( + actual.string().as_str(), + authentication, + PathBuilderInput::create(), + )?)?; self.validate_url(request.url())?; self.services.server.check_running()?; @@ -248,17 +275,23 @@ fn handle_error( Err(e.into()) } -/// A trait for the input types of acceptable path builders for outgoing federation requests. -/// -/// Ruma uses Rust's type system to encode the versioning scheme of endpoints in the Matrix spec. -/// Every endpoint has a `PathBuilder` associated type, which has an `Input` associated type. -/// Endpoints with multiple versions have `VersionHistory` as their `PathBuilder`, which has `SupportedVersions` -/// as its `Input` type. Endpoints with no version have `SinglePath` as their `PathBuilder`, which has `()` as its `Input` type. -/// Both `SupportedVersions` and `()` can be created out of thin air using static data (or no data at all). This property -/// is what the `FederationPathBuilderInput` trait represents. -/// -/// This trait allows the federation sender service's functions to accept requests for either versioned or unversioned endpoints, -/// by requiring that the `Input` of the `PathBuilder` of the endpoint implements `FederationPathBuilderInput`. +/// A trait for the input types of acceptable path builders for outgoing +/// federation requests. +/// +/// Ruma uses Rust's type system to encode the versioning scheme of endpoints in +/// the Matrix spec. Every endpoint has a `PathBuilder` associated type, which +/// has an `Input` associated type. Endpoints with multiple versions have +/// `VersionHistory` as their `PathBuilder`, which has `SupportedVersions` +/// as its `Input` type. Endpoints with no version have `SinglePath` as their +/// `PathBuilder`, which has `()` as its `Input` type. Both `SupportedVersions` +/// and `()` can be created out of thin air using static data (or no data at +/// all). This property is what the `FederationPathBuilderInput` trait +/// represents. +/// +/// This trait allows the federation sender service's functions to accept +/// requests for either versioned or unversioned endpoints, by requiring that +/// the `Input` of the `PathBuilder` of the endpoint implements +/// `FederationPathBuilderInput`. pub(crate) trait FederationPathBuilderInput { fn create() -> Self; } @@ -268,7 +301,5 @@ fn create() -> Self {} } impl FederationPathBuilderInput for Cow<'_, SupportedVersions> { - fn create() -> Self { - Cow::Borrowed(&SUPPORTED_VERSIONS) - } + fn create() -> Self { Cow::Borrowed(&SUPPORTED_VERSIONS) } } diff --git a/src/service/federation/mod.rs b/src/service/federation/mod.rs index 8dfab52a7..ddf01c0b7 100644 --- a/src/service/federation/mod.rs +++ b/src/service/federation/mod.rs @@ -1,9 +1,8 @@ mod execute; -pub(crate) use execute::FederationPathBuilderInput; - use std::sync::Arc; use conduwuit::{Result, Server}; +pub(crate) use execute::FederationPathBuilderInput; use crate::{Dep, client, moderation, resolver, server_keys}; diff --git a/src/service/key_backups/mod.rs b/src/service/key_backups/mod.rs index 616a66b58..747c61e41 100644 --- a/src/service/key_backups/mod.rs +++ b/src/service/key_backups/mod.rs @@ -7,7 +7,9 @@ use database::{Deserialized, Ignore, Interfix, Json, Map}; use futures::StreamExt; use ruma::{ - OwnedRoomId, OwnedUserId, RoomId, UserId, api::client::backup::{BackupAlgorithm, KeyBackupData, RoomKeyBackup}, serde::Raw + OwnedRoomId, OwnedUserId, RoomId, UserId, + api::client::backup::{BackupAlgorithm, KeyBackupData, RoomKeyBackup}, + serde::Raw, }; use crate::{Dep, globals}; diff --git a/src/service/media/data.rs b/src/service/media/data.rs index fcf75c3a7..7416464f8 100644 --- a/src/service/media/data.rs +++ b/src/service/media/data.rs @@ -8,9 +8,8 @@ use futures::StreamExt; use ruma::{OwnedMxcUri, OwnedUserId, UserId, http_headers::ContentDisposition}; -use crate::media::mxc::Mxc; - use super::{preview::UrlPreviewData, thumbnail::Dim}; +use crate::media::mxc::Mxc; pub(crate) struct Data { mediaid_file: Arc, diff --git a/src/service/media/mod.rs b/src/service/media/mod.rs index fb4e7d6d7..3b0689df5 100644 --- a/src/service/media/mod.rs +++ b/src/service/media/mod.rs @@ -1,7 +1,7 @@ pub mod blurhash; -pub mod mxc; mod data; pub(super) mod migrations; +pub mod mxc; mod preview; mod remote; mod tests; diff --git a/src/service/media/mxc.rs b/src/service/media/mxc.rs index 02a3e65f0..a7d3bed93 100644 --- a/src/service/media/mxc.rs +++ b/src/service/media/mxc.rs @@ -6,49 +6,49 @@ /// A structured, valid MXC URI #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Mxc<'a> { - /// ServerName part of the MXC URI - pub server_name: &'a ServerName, + /// ServerName part of the MXC URI + pub server_name: &'a ServerName, - /// MediaId part of the MXC URI - pub media_id: &'a str, + /// MediaId part of the MXC URI + pub media_id: &'a str, } impl fmt::Display for Mxc<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "mxc://{}/{}", self.server_name, self.media_id) - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "mxc://{}/{}", self.server_name, self.media_id) + } } impl<'a> TryFrom<&'a MxcUri> for Mxc<'a> { - type Error = MxcUriError; + type Error = MxcUriError; - fn try_from(s: &'a MxcUri) -> Result { - let (server_name, media_id) = s.parts()?; + fn try_from(s: &'a MxcUri) -> Result { + let (server_name, media_id) = s.parts()?; - Ok(Self { server_name, media_id }) - } + Ok(Self { server_name, media_id }) + } } impl<'a> TryFrom<&'a str> for Mxc<'a> { - type Error = MxcUriError; + type Error = MxcUriError; - fn try_from(s: &'a str) -> Result { - let s: &MxcUri = s.into(); - s.try_into() - } + fn try_from(s: &'a str) -> Result { + let s: &MxcUri = s.into(); + s.try_into() + } } impl<'a> TryFrom<&'a OwnedMxcUri> for Mxc<'a> { - type Error = MxcUriError; + type Error = MxcUriError; - fn try_from(s: &'a OwnedMxcUri) -> Result { - let s: &MxcUri = s.as_ref(); - s.try_into() - } + fn try_from(s: &'a OwnedMxcUri) -> Result { + let s: &MxcUri = s.as_ref(); + s.try_into() + } } impl Serialize for Mxc<'_> { - fn serialize(&self, s: S) -> Result { - s.serialize_str(self.to_string().as_str()) - } -} \ No newline at end of file + fn serialize(&self, s: S) -> Result { + s.serialize_str(self.to_string().as_str()) + } +} diff --git a/src/service/media/remote.rs b/src/service/media/remote.rs index 242f85f23..7fafe0015 100644 --- a/src/service/media/remote.rs +++ b/src/service/media/remote.rs @@ -6,17 +6,23 @@ }; use http::header::{CONTENT_DISPOSITION, CONTENT_TYPE, HeaderValue}; use ruma::{ - ServerName, UserId, api::{ - Metadata, OutgoingRequest, auth_scheme::NoAuthentication, client::{ - error::ErrorKind::{NotFound, Unrecognized}, - media, - }, federation::{self, authenticated_media::{Content, FileOrLocation}, authentication::ServerSignatures}, path_builder::PathBuilder - } + ServerName, UserId, + api::{ + Metadata, OutgoingRequest, + auth_scheme::{NoAccessToken, NoAuthentication}, + client::media, + error::ErrorKind::{NotFound, Unrecognized}, + federation::{ + self, + authenticated_media::{Content, FileOrLocation}, + authentication::ServerSignatures, + }, + path_builder::PathBuilder, + }, }; -use crate::{federation::FederationPathBuilderInput, media::mxc::Mxc}; - use super::{Dim, FileMeta}; +use crate::{federation::FederationPathBuilderInput, media::mxc::Mxc}; #[implement(super::Service)] pub async fn fetch_remote_thumbnail( @@ -134,7 +140,12 @@ async fn fetch_thumbnail_unauthenticated( ) -> Result { use media::get_content_thumbnail::v3::{Request, Response}; - let mut request = Request::new(mxc.media_id.into(), mxc.server_name.into(), dim.width.into(), dim.height.into()); + let mut request = Request::new( + mxc.media_id.into(), + mxc.server_name.into(), + dim.width.into(), + dim.height.into(), + ); request.allow_redirect = true; request.allow_remote = true; request.animated = Some(true); @@ -143,7 +154,9 @@ async fn fetch_thumbnail_unauthenticated( let Response { file, content_type, content_disposition, .. - } = self.federation_request_unauthenticated(mxc, server, request).await?; + } = self + .federation_request_legacy_media(mxc, server, request) + .await?; let content = Content::new(file, content_type.unwrap(), content_disposition.unwrap()); @@ -168,7 +181,9 @@ async fn fetch_content_unauthenticated( let Response { file, content_type, content_disposition, .. - } = self.federation_request_unauthenticated(mxc, server, request).await?; + } = self + .federation_request_legacy_media(mxc, server, request) + .await?; let content = Content::new(file, content_type.unwrap(), content_disposition.unwrap()); @@ -300,7 +315,11 @@ async fn federation_request<'i, Request>( request: Request, ) -> Result where - Request: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, + Request: OutgoingRequest< + Authentication = ServerSignatures, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { self.services .sending @@ -309,18 +328,22 @@ async fn federation_request<'i, Request>( } #[implement(super::Service)] -async fn federation_request_unauthenticated<'i, Request>( +async fn federation_request_legacy_media<'i, Request>( &self, mxc: &Mxc<'_>, server: Option<&ServerName>, request: Request, ) -> Result where - Request: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, + Request: OutgoingRequest< + Authentication = NoAccessToken, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { self.services .sending - .send_unauthenticated_request(server.unwrap_or(mxc.server_name), request) + .send_legacy_media_request(server.unwrap_or(mxc.server_name), request) .await } @@ -335,7 +358,12 @@ pub async fn fetch_remote_thumbnail_legacy( media_id: &body.media_id, }; - let mut request = media::get_content_thumbnail::v3::Request::new(body.media_id.clone(), body.server_name.clone(), body.width, body.height); + let mut request = media::get_content_thumbnail::v3::Request::new( + body.media_id.clone(), + body.server_name.clone(), + body.width, + body.height, + ); request.method = body.method.clone(); request.allow_remote = body.allow_remote; request.allow_redirect = body.allow_redirect; @@ -347,7 +375,7 @@ pub async fn fetch_remote_thumbnail_legacy( let response = self .services .sending - .send_unauthenticated_request(mxc.server_name, request) + .send_legacy_media_request(mxc.server_name, request) .await?; let dim = Dim::from_ruma(body.width, body.height, body.method.clone())?; @@ -372,7 +400,8 @@ pub async fn fetch_remote_content_legacy( allow_redirect: bool, timeout_ms: Duration, ) -> Result { - let mut request = media::get_content::v3::Request::new(mxc.media_id.into(), mxc.server_name.into()); + let mut request = + media::get_content::v3::Request::new(mxc.media_id.into(), mxc.server_name.into()); request.allow_remote = true; request.allow_redirect = allow_redirect; request.timeout_ms = timeout_ms; @@ -382,7 +411,7 @@ pub async fn fetch_remote_content_legacy( let response = self .services .sending - .send_unauthenticated_request(mxc.server_name, request) + .send_legacy_media_request(mxc.server_name, request) .await?; let content_disposition = make_content_disposition( diff --git a/src/service/media/thumbnail.rs b/src/service/media/thumbnail.rs index be6469b93..162ac0ba0 100644 --- a/src/service/media/thumbnail.rs +++ b/src/service/media/thumbnail.rs @@ -14,9 +14,8 @@ io::{AsyncReadExt, AsyncWriteExt}, }; -use crate::media::mxc::Mxc; - use super::{FileMeta, data::Metadata}; +use crate::media::mxc::Mxc; /// Dimension specification for a thumbnail. #[derive(Debug)] diff --git a/src/service/migrations.rs b/src/service/migrations.rs index ac8ef519a..27094e905 100644 --- a/src/service/migrations.rs +++ b/src/service/migrations.rs @@ -270,13 +270,7 @@ async fn migrate(services: &Services) -> Result<()> { { let patterns = services.globals.forbidden_alias_names(); if !patterns.is_empty() { - for room_id in services - .rooms - .metadata - .iter_ids() - .collect::>() - .await - { + for room_id in services.rooms.metadata.iter_ids().collect::>().await { services .rooms .alias @@ -479,12 +473,7 @@ async fn retroactively_fix_bad_data_from_roomuserid_joined(services: &Services) let db = &services.db; let _cork = db.cork_and_sync(); - let room_ids = services - .rooms - .metadata - .iter_ids() - .collect::>() - .await; + let room_ids = services.rooms.metadata.iter_ids().collect::>().await; for room_id in &room_ids { debug_info!("Fixing room {room_id}"); diff --git a/src/service/mod.rs b/src/service/mod.rs index b8c5b9f59..964916109 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -49,9 +49,9 @@ conduwuit::mod_dtor! {} use std::sync::LazyLock; + use conduwuit::matrix::versions::{unstable_features, versions}; use ruma::api::SupportedVersions; -pub static SUPPORTED_VERSIONS: LazyLock = LazyLock::new(|| { - SupportedVersions::from_parts(&versions(), &unstable_features()) -}); \ No newline at end of file +pub static SUPPORTED_VERSIONS: LazyLock = + LazyLock::new(|| SupportedVersions::from_parts(&versions(), &unstable_features())); diff --git a/src/service/presence/mod.rs b/src/service/presence/mod.rs index 7ae74d6eb..9c89eadd6 100644 --- a/src/service/presence/mod.rs +++ b/src/service/presence/mod.rs @@ -193,10 +193,7 @@ pub async fn unset_all_presence(&self) { | _ => continue, }; - if matches!( - presence.presence, - PresenceState::Offline - ) { + if matches!(presence.presence, PresenceState::Offline) { trace!(%user_id, ?presence, "Skipping user"); continue; } diff --git a/src/service/presence/presence.rs b/src/service/presence/presence.rs index 846fc1459..247608eca 100644 --- a/src/service/presence/presence.rs +++ b/src/service/presence/presence.rs @@ -54,9 +54,6 @@ pub(super) async fn to_presence_event( content.displayname = users.displayname(user_id).await.ok(); content.avatar_url = users.avatar_url(user_id).await.ok(); - PresenceEvent { - sender: user_id.to_owned(), - content, - } + PresenceEvent { sender: user_id.to_owned(), content } } } diff --git a/src/service/pusher/mod.rs b/src/service/pusher/mod.rs index e300edc2c..c93c17637 100644 --- a/src/service/pusher/mod.rs +++ b/src/service/pusher/mod.rs @@ -11,17 +11,30 @@ use futures::{Stream, StreamExt}; use ipaddress::IPAddress; use ruma::{ - DeviceId, OwnedDeviceId, RoomId, UInt, UserId, api::{ - IncomingResponse, MatrixVersion, OutgoingRequest, auth_scheme::{NoAuthentication, SendAccessToken}, client::push::{Pusher, PusherKind, set_pusher}, path_builder::SinglePath, push_gateway::send_event_notification::{ + DeviceId, OwnedDeviceId, RoomId, UInt, UserId, + api::{ + IncomingResponse, MatrixVersion, OutgoingRequest, + auth_scheme::{NoAccessToken, NoAuthentication, SendAccessToken}, + client::push::{Pusher, PusherKind, set_pusher}, + path_builder::SinglePath, + push_gateway::send_event_notification::{ self, v1::{Device, Notification, NotificationCounts, NotificationPriority}, - } - }, events::{ + }, + }, + events::{ AnySyncTimelineEvent, StateEventType, TimelineEventType, - room::{create::RoomCreateEventContent, power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}}, - }, push::{ - Action, PushConditionPowerLevelsCtx, PushConditionRoomCtx, PushFormat, Ruleset, Tweak, - }, room_version_rules::{AuthorizationRules, RoomPowerLevelsRules, RoomVersionRules}, serde::Raw, uint + room::{ + create::RoomCreateEventContent, + power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}, + }, + }, + push::{ + Action, HighlightTweakValue, PushConditionPowerLevelsCtx, PushConditionRoomCtx, PushFormat, Ruleset, Tweak + }, + room_version_rules::{AuthorizationRules, RoomPowerLevelsRules, RoomVersionRules}, + serde::Raw, + uint, }; use crate::{Dep, client, config, globals, rooms, sending, users}; @@ -189,7 +202,9 @@ pub fn get_pushkeys<'a>( #[tracing::instrument(skip(self, dest, request))] pub async fn send_request(&self, dest: &str, request: T) -> Result where - T: OutgoingRequest + Debug + Send, + T: OutgoingRequest + + Debug + + Send, { const VERSIONS: [MatrixVersion; 1] = [MatrixVersion::V1_0]; @@ -197,7 +212,7 @@ pub async fn send_request(&self, dest: &str, request: T) -> Result(&dest, SendAccessToken::None, ()) + .try_into_http_request::(&dest, (), ()) .map_err(|e| { err!(BadServerResponse(warn!( "Failed to find destination {dest} for push gateway: {e}" @@ -307,7 +322,13 @@ pub async fn send_push_notice( let serialized = event.to_format(); for action in self - .get_actions(user, &ruleset, power_levels.clone(), &serialized, event.room_id().unwrap()) + .get_actions( + user, + &ruleset, + power_levels.clone(), + &serialized, + event.room_id().unwrap(), + ) .await { let n = match action { @@ -363,7 +384,13 @@ pub async fn get_actions<'a>( .await .unwrap_or_else(|_| user.localpart().to_owned()); - let ctx = PushConditionRoomCtx::new(room_id.to_owned(), room_joined_count, user.to_owned(), user_display_name).with_power_levels(power_levels); + let ctx = PushConditionRoomCtx::new( + room_id.to_owned(), + room_joined_count, + user.to_owned(), + user_display_name, + ) + .with_power_levels(power_levels); ruleset.get_actions(pdu, &ctx).await } @@ -442,7 +469,7 @@ async fn send_notice( if *event.kind() == TimelineEventType::RoomEncrypted || tweaks .iter() - .any(|t| matches!(t, Tweak::Highlight(true) | Tweak::Sound(_))) + .any(|t| matches!(t, Tweak::Highlight(HighlightTweakValue::Yes) | Tweak::Sound(_))) { notify.prio = NotificationPriority::High; } else { diff --git a/src/service/rooms/alias/mod.rs b/src/service/rooms/alias/mod.rs index d9bb873ab..ee30de916 100644 --- a/src/service/rooms/alias/mod.rs +++ b/src/service/rooms/alias/mod.rs @@ -9,10 +9,12 @@ use database::{Deserialized, Ignore, Interfix, Map}; use futures::{Stream, StreamExt, TryFutureExt}; use ruma::{ - OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomAliasId, RoomId, RoomOrAliasId, UserId, events::{ + OwnedRoomAliasId, OwnedRoomId, OwnedServerName, OwnedUserId, RoomAliasId, RoomId, + RoomOrAliasId, UserId, + events::{ StateEventType, room::power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}, - } + }, }; use crate::{Dep, admin, appservice, appservice::RegistrationInfo, globals, rooms, sending}; diff --git a/src/service/rooms/event_handler/fetch_and_handle_outliers.rs b/src/service/rooms/event_handler/fetch_and_handle_outliers.rs index 39468e8df..1ecdb82b2 100644 --- a/src/service/rooms/event_handler/fetch_and_handle_outliers.rs +++ b/src/service/rooms/event_handler/fetch_and_handle_outliers.rs @@ -109,7 +109,10 @@ pub(super) async fn fetch_and_handle_outliers<'a, Pdu, Events>( match self .services .sending - .send_federation_request(origin, get_event::v1::Request::new((*next_id).to_owned())) + .send_federation_request( + origin, + get_event::v1::Request::new((*next_id).to_owned()), + ) .await { | Ok(res) => { diff --git a/src/service/rooms/event_handler/fetch_state.rs b/src/service/rooms/event_handler/fetch_state.rs index 1f48908c3..790b4ec9e 100644 --- a/src/service/rooms/event_handler/fetch_state.rs +++ b/src/service/rooms/event_handler/fetch_state.rs @@ -31,7 +31,10 @@ pub(super) async fn fetch_state( let res = self .services .sending - .send_federation_request(origin, get_room_state_ids::v1::Request::new(event_id.to_owned(), room_id.to_owned())) + .send_federation_request( + origin, + get_room_state_ids::v1::Request::new(event_id.to_owned(), room_id.to_owned()), + ) .await .inspect_err(|e| debug_warn!("Fetching state for event failed: {e}"))?; diff --git a/src/service/rooms/event_handler/handle_incoming_pdu.rs b/src/service/rooms/event_handler/handle_incoming_pdu.rs index fcbcec46d..ee8d15a09 100644 --- a/src/service/rooms/event_handler/handle_incoming_pdu.rs +++ b/src/service/rooms/event_handler/handle_incoming_pdu.rs @@ -182,7 +182,8 @@ pub async fn handle_incoming_pdu<'a>( // copied from https://github.com/element-hq/synapse/blob/7e4588a/synapse/handlers/federation_event.py#L255-L300 if value.get("type").and_then(|t| t.as_str()) == Some("m.room.member") { if let Some(pdu) = - should_rescind_invite(&self.services, &mut value.clone(), &sender, room_id).await? + should_rescind_invite(&self.services, &mut value.clone(), &sender, room_id) + .await? { debug_info!( "Invite to {room_id} appears to have been rescinded by {sender}, marking as \ diff --git a/src/service/rooms/event_handler/handle_outlier_pdu.rs b/src/service/rooms/event_handler/handle_outlier_pdu.rs index 9a0f8c138..58564d901 100644 --- a/src/service/rooms/event_handler/handle_outlier_pdu.rs +++ b/src/service/rooms/event_handler/handle_outlier_pdu.rs @@ -42,7 +42,9 @@ pub(super) async fn handle_outlier_pdu<'a, Pdu>( // 2. Check signatures, otherwise drop // 3. check content hash, redact if doesn't match let room_version = get_room_version(create_event)?; - let room_rules = room_version.rules().expect("room version should have defined rules"); + let room_rules = room_version + .rules() + .expect("room version should have defined rules"); let mut incoming_pdu = match self .services .server_keys diff --git a/src/service/rooms/event_handler/mod.rs b/src/service/rooms/event_handler/mod.rs index ed4c288f1..cf7a153b0 100644 --- a/src/service/rooms/event_handler/mod.rs +++ b/src/service/rooms/event_handler/mod.rs @@ -119,4 +119,4 @@ fn get_room_version(create_event: &Pdu) -> Result { let room_version = content.room_version; Ok(room_version) -} \ No newline at end of file +} diff --git a/src/service/rooms/event_handler/parse_incoming_pdu.rs b/src/service/rooms/event_handler/parse_incoming_pdu.rs index b8f7661eb..a416a528e 100644 --- a/src/service/rooms/event_handler/parse_incoming_pdu.rs +++ b/src/service/rooms/event_handler/parse_incoming_pdu.rs @@ -5,7 +5,8 @@ matrix::event::{gen_event_id, gen_event_id_canonical_json}, }; use itertools::Itertools; -use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, RoomVersionId}; +use ruma::{ + CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedRoomId, RoomVersionId, }; use serde_json::value::RawValue as RawJsonValue; type Parsed = (OwnedRoomId, OwnedEventId, CanonicalJsonObject); diff --git a/src/service/rooms/event_handler/policy_server.rs b/src/service/rooms/event_handler/policy_server.rs index 7fe8eedb0..5d3a609a1 100644 --- a/src/service/rooms/event_handler/policy_server.rs +++ b/src/service/rooms/event_handler/policy_server.rs @@ -10,16 +10,17 @@ warn, }; use ruma::{ - CanonicalJsonObject, CanonicalJsonValue, KeyId, OwnedKeyId, RoomId, ServerName, SigningKeyId, events::StateEventType + CanonicalJsonObject, CanonicalJsonValue, KeyId, OwnedKeyId, RoomId, ServerName, SigningKeyId, + events::StateEventType, }; use ruminuwuity::policy::{ - policy_check::unstable::Request as PolicyCheckRequest, + event::RoomPolicyEventContent, policy_check::unstable::Request as PolicyCheckRequest, policy_sign::unstable::Request as PolicySignRequest, - event::RoomPolicyEventContent }; use serde_json::value::RawValue; -static POLICY_EVENT_TYPE_UNSTABLE: LazyLock = LazyLock::new(|| StateEventType::from("org.matrix.msc4284.policy")); +static POLICY_EVENT_TYPE_UNSTABLE: LazyLock = + LazyLock::new(|| StateEventType::from("org.matrix.msc4284.policy")); /// Asks a remote policy server if the event is allowed. /// @@ -88,7 +89,12 @@ pub async fn ask_policy_server( return Ok(true); }, }; - if !self.services.state_cache.server_in_room(&via, room_id).await { + if !self + .services + .state_cache + .server_in_room(&via, room_id) + .await + { debug!( via = %via, "Policy server is not in the room, skipping spam check" @@ -132,15 +138,13 @@ pub async fn ask_policy_server( via = %via, "Checking event for spam with policy server via legacy check" ); - + let mut request = PolicyCheckRequest::new(pdu.event_id().to_owned()); request.pdu = Some(outgoing); - + let response = tokio::time::timeout( Duration::from_secs(self.services.server.config.policy_server_request_timeout), - self.services - .sending - .send_federation_request(&via, request), + self.services.sending.send_federation_request(&via, request), ) .await; let response = match response { diff --git a/src/service/rooms/event_handler/resolve_state.rs b/src/service/rooms/event_handler/resolve_state.rs index ea97eb44e..ba3fe994b 100644 --- a/src/service/rooms/event_handler/resolve_state.rs +++ b/src/service/rooms/event_handler/resolve_state.rs @@ -112,7 +112,13 @@ pub async fn state_resolution<'a, StateSets>( { let event_fetch = |event_id| self.event_fetch(event_id); let event_exists = |event_id| self.event_exists(event_id); - state_res::resolve(room_version_rules, state_sets, auth_chain_sets, &event_fetch, &event_exists) - .map_err(|e| err!(error!("State resolution failed: {e:?}"))) - .await + state_res::resolve( + room_version_rules, + state_sets, + auth_chain_sets, + &event_fetch, + &event_exists, + ) + .map_err(|e| err!(error!("State resolution failed: {e:?}"))) + .await } diff --git a/src/service/rooms/event_handler/upgrade_outlier_pdu.rs b/src/service/rooms/event_handler/upgrade_outlier_pdu.rs index 78f877865..957c52829 100644 --- a/src/service/rooms/event_handler/upgrade_outlier_pdu.rs +++ b/src/service/rooms/event_handler/upgrade_outlier_pdu.rs @@ -53,7 +53,9 @@ pub(super) async fn upgrade_outlier_to_timeline_pdu( ); let timer = Instant::now(); let room_version_id = get_room_version(create_event)?; - let room_version_rules = room_version_id.rules().expect("room version should have defined rules"); + let room_version_rules = room_version_id + .rules() + .expect("room version should have defined rules"); // 10. Fetch missing state and auth chain events by calling /state_ids at // backwards extremities doing all the checks in this list starting at 1. diff --git a/src/service/rooms/read_receipt/data.rs b/src/service/rooms/read_receipt/data.rs index 5058af4dd..bcffd708c 100644 --- a/src/service/rooms/read_receipt/data.rs +++ b/src/service/rooms/read_receipt/data.rs @@ -7,7 +7,9 @@ use database::{Deserialized, Json, Map}; use futures::{Stream, StreamExt}; use ruma::{ - CanonicalJsonObject, OwnedRoomId, OwnedUserId, RoomId, UserId, events::{AnySyncEphemeralRoomEvent, receipt::ReceiptEvent}, serde::Raw + CanonicalJsonObject, OwnedRoomId, OwnedUserId, RoomId, UserId, + events::{AnySyncEphemeralRoomEvent, receipt::ReceiptEvent}, + serde::Raw, }; use crate::{Dep, globals}; diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index 61a9ca236..7bcd6f455 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -17,16 +17,17 @@ use futures::{FutureExt, Stream, StreamExt, TryFutureExt, pin_mut, stream::FuturesUnordered}; use lru_cache::LruCache; use ruma::{ - OwnedEventId, OwnedRoomId, OwnedServerName, RoomId, ServerName, UserId, api::{ + OwnedEventId, OwnedRoomId, OwnedServerName, RoomId, ServerName, UserId, + api::{ client::space::SpaceHierarchyRoomsChunk, - federation::{ - self, - space::SpaceHierarchyParentSummary, - }, - }, events::{ + federation::{self, space::SpaceHierarchyParentSummary}, + }, + events::{ StateEventType, space::child::{HierarchySpaceChildEvent, SpaceChildEventContent}, - }, room::{JoinRuleSummary, RoomSummary}, serde::Raw, + }, + room::{JoinRuleSummary, RoomSummary}, + serde::Raw, }; use tokio::sync::{Mutex, MutexGuard}; @@ -299,11 +300,7 @@ async fn get_room_summary( let join_rule = self.services.state_accessor.get_join_rules(room_id).await; let is_accessible_child = self - .is_accessible_child( - room_id, - &join_rule.clone().into(), - identifier, - ) + .is_accessible_child(room_id, &join_rule.clone().into(), identifier) .await; if !is_accessible_child { @@ -375,7 +372,7 @@ async fn get_room_summary( join_rule.clone().into(), guest_can_join, num_joined_members.try_into().unwrap_or_default(), - world_readable + world_readable, ); summary.canonical_alias = canonical_alias; summary.name = name; @@ -426,13 +423,17 @@ async fn is_accessible_child( | JoinRuleSummary::Public | JoinRuleSummary::Knock | JoinRuleSummary::KnockRestricted(_) => true, - | JoinRuleSummary::Restricted(restricted_summary) => { - (&restricted_summary.allowed_room_ids).stream().any(async |room| match identifier { - | Identifier::UserId(user) => self.services.state_cache.is_joined(user, room).await, - | Identifier::ServerName(server) => self.services.state_cache.server_in_room(server, room).await, - }).await - }, - _ => false + | JoinRuleSummary::Restricted(restricted_summary) => + (&restricted_summary.allowed_room_ids) + .stream() + .any(async |room| match identifier { + | Identifier::UserId(user) => + self.services.state_cache.is_joined(user, room).await, + | Identifier::ServerName(server) => + self.services.state_cache.server_in_room(server, room).await, + }) + .await, + | _ => false, } } @@ -463,10 +464,10 @@ async fn cache_insert( summary: RoomSummary, ) { let children_state = self - .get_space_child_events(&summary.room_id) - .map(Event::into_format) - .collect() - .await; + .get_space_child_events(&summary.room_id) + .map(Event::into_format) + .collect() + .await; let summary = SpaceHierarchyParentSummary::new(summary, children_state); cache.insert(current_room.to_owned(), Some(CachedSpaceHierarchySummary { summary })); diff --git a/src/service/rooms/spaces/pagination_token.rs b/src/service/rooms/spaces/pagination_token.rs index d97b7a2fa..00475109a 100644 --- a/src/service/rooms/spaces/pagination_token.rs +++ b/src/service/rooms/spaces/pagination_token.rs @@ -4,7 +4,7 @@ }; use conduwuit::{Error, Result}; -use ruma::{UInt, api::client::error::ErrorKind}; +use ruma::{UInt, api::error::ErrorKind}; use crate::rooms::short::ShortRoomId; diff --git a/src/service/rooms/spaces/tests.rs b/src/service/rooms/spaces/tests.rs index 4f14627f7..42cc7aab5 100644 --- a/src/service/rooms/spaces/tests.rs +++ b/src/service/rooms/spaces/tests.rs @@ -1,7 +1,10 @@ use std::str::FromStr; use ruma::{ - UInt, api::federation::space::SpaceHierarchyParentSummary, owned_room_id, owned_server_name, room::{JoinRuleSummary, RoomSummary}, + UInt, + api::federation::space::SpaceHierarchyParentSummary, + owned_room_id, owned_server_name, + room::{JoinRuleSummary, RoomSummary}, }; use crate::rooms::spaces::{PaginationToken, get_parent_children_via}; @@ -9,7 +12,13 @@ #[test] fn get_summary_children() { let summary = SpaceHierarchyParentSummary::new( - RoomSummary::new(owned_room_id!("!root:example.org"), JoinRuleSummary::Public, true, UInt::from(1_u32), true), + RoomSummary::new( + owned_room_id!("!root:example.org"), + JoinRuleSummary::Public, + true, + UInt::from(1_u32), + true, + ), vec![ serde_json::from_str( r#"{ @@ -55,7 +64,7 @@ fn get_summary_children() { }"#, ) .unwrap(), - ] + ], ); assert_eq!( diff --git a/src/service/rooms/state/mod.rs b/src/service/rooms/state/mod.rs index 8731b86f8..e4ca06688 100644 --- a/src/service/rooms/state/mod.rs +++ b/src/service/rooms/state/mod.rs @@ -17,10 +17,13 @@ FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt, future::join_all, pin_mut, }; use ruma::{ - EventId, OwnedEventId, OwnedRoomId, RoomId, RoomVersionId, UserId, events::{ + EventId, OwnedEventId, OwnedRoomId, RoomId, RoomVersionId, UserId, + events::{ AnyStrippedStateEvent, StateEventType, TimelineEventType, room::create::RoomCreateEventContent, - }, room_version_rules::RoomVersionRules, serde::Raw + }, + room_version_rules::RoomVersionRules, + serde::Raw, }; use crate::{ @@ -107,7 +110,7 @@ pub async fn force_state( .then(|shorteventid| { self.services .short - .get_eventid_from_short::>(shorteventid) + .get_eventid_from_short::(shorteventid) }) .ignore_err(); @@ -426,8 +429,13 @@ pub async fn get_auth_events( return Ok(HashMap::new()); }; - let auth_types = - state_res::auth_types_for_event(kind, sender, state_key, content, room_version_rules)?; + let auth_types = state_res::auth_types_for_event( + kind, + sender, + state_key, + content, + room_version_rules, + )?; debug!(?auth_types, "Auth types for event"); let sauthevents: HashMap<_, _> = auth_types .iter() diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index 3dacb082e..92f0adc7f 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -9,12 +9,25 @@ use conduwuit::{Event, Result, err}; use database::Map; use ruma::{ - EventEncryptionAlgorithm, JsOption, OwnedRoomAliasId, OwnedUserId, RoomId, UserId, events::{ + EventEncryptionAlgorithm, JsOption, OwnedRoomAliasId, OwnedUserId, RoomId, UserId, + events::{ StateEventType, room::{ - avatar::RoomAvatarEventContent, canonical_alias::RoomCanonicalAliasEventContent, create::{RoomCreateEvent, RoomCreateEventContent}, encryption::RoomEncryptionEventContent, guest_access::{GuestAccess, RoomGuestAccessEventContent}, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, join_rules::{JoinRule, RoomJoinRulesEventContent}, member::RoomMemberEventContent, name::RoomNameEventContent, pinned_events::RoomPinnedEventsEventContent, power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}, topic::RoomTopicEventContent + avatar::RoomAvatarEventContent, + canonical_alias::RoomCanonicalAliasEventContent, + create::{RoomCreateEvent, RoomCreateEventContent}, + encryption::RoomEncryptionEventContent, + guest_access::{GuestAccess, RoomGuestAccessEventContent}, + history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, + join_rules::{JoinRule, RoomJoinRulesEventContent}, + member::RoomMemberEventContent, + name::RoomNameEventContent, + pinned_events::RoomPinnedEventsEventContent, + power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}, + topic::RoomTopicEventContent, }, - }, room::RoomType + }, + room::RoomType, }; use crate::{Dep, rooms}; @@ -152,12 +165,25 @@ pub async fn is_encrypted_room(&self, room_id: &RoomId) -> bool { .is_ok() } - /// Get a set of the room's creators. This will always contain a single user for room versions 11 and earlier. + /// Get a set of the room's creators. This will always contain a single user + /// for room versions 11 and earlier. pub async fn get_room_creators(&self, room_id: &RoomId) -> HashSet { - let room_version_rules = self.services.state.get_room_version(room_id).await.expect("room should have a version").rules().expect("room version should be known"); + let room_version_rules = self + .services + .state + .get_room_version(room_id) + .await + .expect("room should have a version") + .rules() + .expect("room version should be known"); - let create_event = self.room_state_get(room_id, &StateEventType::RoomCreate, "").await.expect("room should have a create event"); - let create_content: RoomCreateEventContent = create_event.get_content().expect("create event content should be valid"); + let create_event = self + .room_state_get(room_id, &StateEventType::RoomCreate, "") + .await + .expect("room should have a create event"); + let create_content: RoomCreateEventContent = create_event + .get_content() + .expect("create event content should be valid"); let mut creators = HashSet::new(); if room_version_rules.authorization.use_room_create_sender { @@ -174,15 +200,30 @@ pub async fn get_room_creators(&self, room_id: &RoomId) -> HashSet creators } - /// Get the room's power levels. This will never fail -- if the room has no power level state event, - /// the default power levels for the room's version will be returned. + /// Get the room's power levels. This will never fail -- if the room has no + /// power level state event, the default power levels for the room's + /// version will be returned. pub async fn get_room_power_levels(&self, room_id: &RoomId) -> RoomPowerLevels { - let room_version_rules = self.services.state.get_room_version(room_id).await.expect("room should have a version").rules().expect("room version should be known"); - let creators = self.get_room_creators(room_id).await; - let power_levels_event: RoomPowerLevelsEventContent = self.room_state_get_content(room_id, &StateEventType::RoomPowerLevels, "") + let room_version_rules = self + .services + .state + .get_room_version(room_id) .await - .unwrap_or_else(|_| RoomPowerLevelsEventContent::new(&room_version_rules.authorization)); + .expect("room should have a version") + .rules() + .expect("room version should be known"); + let creators = self.get_room_creators(room_id).await; + let power_levels_event: RoomPowerLevelsEventContent = self + .room_state_get_content(room_id, &StateEventType::RoomPowerLevels, "") + .await + .unwrap_or_else(|_| { + RoomPowerLevelsEventContent::new(&room_version_rules.authorization) + }); - RoomPowerLevels::new(power_levels_event.into(), &room_version_rules.authorization, creators) + RoomPowerLevels::new( + power_levels_event.into(), + &room_version_rules.authorization, + creators, + ) } } diff --git a/src/service/rooms/state_accessor/server_can.rs b/src/service/rooms/state_accessor/server_can.rs index f4886b6ef..b992007aa 100644 --- a/src/service/rooms/state_accessor/server_can.rs +++ b/src/service/rooms/state_accessor/server_can.rs @@ -44,17 +44,13 @@ pub async fn server_can_see_event( | HistoryVisibility::Invited => { // Allow if any member on requesting server was AT LEAST invited, else deny current_server_members - .any(async |member| { - self.user_was_invited(shortstatehash, &member).await - }) + .any(async |member| self.user_was_invited(shortstatehash, &member).await) .await }, | HistoryVisibility::Joined => { // Allow if any member on requested server was joined, else deny current_server_members - .any(async |member| { - self.user_was_joined(shortstatehash, &member).await - }) + .any(async |member| self.user_was_joined(shortstatehash, &member).await) .await }, | HistoryVisibility::WorldReadable | HistoryVisibility::Shared | _ => true, diff --git a/src/service/rooms/state_accessor/state.rs b/src/service/rooms/state_accessor/state.rs index e96fb2e56..8aabbfcf2 100644 --- a/src/service/rooms/state_accessor/state.rs +++ b/src/service/rooms/state_accessor/state.rs @@ -316,7 +316,9 @@ pub fn state_full( shortstatehash: ShortStateHash, ) -> impl Stream + Send + '_ { self.state_full_pdus(shortstatehash) - .ready_filter_map(|pdu| Some(((pdu.kind().to_string().into(), pdu.state_key()?.into()), pdu))) + .ready_filter_map(|pdu| { + Some(((pdu.kind().to_string().into(), pdu.state_key()?.into()), pdu)) + }) } #[implement(super::Service)] diff --git a/src/service/rooms/state_accessor/user_can.rs b/src/service/rooms/state_accessor/user_can.rs index 699dec685..7b1050d2e 100644 --- a/src/service/rooms/state_accessor/user_can.rs +++ b/src/service/rooms/state_accessor/user_can.rs @@ -44,13 +44,22 @@ pub async fn user_can_redact( ))); } - let create_event = self.room_state_get(room_id, &StateEventType::RoomCreate, "").await?; + let create_event = self + .room_state_get(room_id, &StateEventType::RoomCreate, "") + .await?; let create_event_content: RoomCreateEventContent = create_event.get_content().unwrap(); - let room_version_rules = create_event_content.room_version.rules().expect("room version should have defined rules"); - if room_version_rules.authorization.explicitly_privilege_room_creators { + let room_version_rules = create_event_content + .room_version + .rules() + .expect("room version should have defined rules"); + if room_version_rules + .authorization + .explicitly_privilege_room_creators + { let sender_owned = sender.to_owned(); // NOTE: we don't check the pre-v11 `creator` field because no room version has - // `explicitly_privilege_room_creators` and `use_room_create_sender` set at the same time + // `explicitly_privilege_room_creators` and `use_room_create_sender` set at the + // same time if sender == create_event.sender() || create_event_content .additional_creators @@ -60,7 +69,6 @@ pub async fn user_can_redact( } } - let power_levels = self.get_room_power_levels(room_id).await; if power_levels.user_can_redact_event_of_other(sender) { @@ -69,14 +77,13 @@ pub async fn user_can_redact( if power_levels.user_can_redact_own_event(sender) { let is_own_event = match redacting_event { - Ok(redacting_event) => { + | Ok(redacting_event) => if federation { redacting_event.sender().server_name() == sender.server_name() } else { redacting_event.sender() == sender - } - }, - _ => false + }, + | _ => false, }; return Ok(is_own_event); diff --git a/src/service/rooms/state_cache/mod.rs b/src/service/rooms/state_cache/mod.rs index 6a15dfb80..4620b2509 100644 --- a/src/service/rooms/state_cache/mod.rs +++ b/src/service/rooms/state_cache/mod.rs @@ -12,7 +12,9 @@ use database::{Deserialized, Ignore, Interfix, Map}; use futures::{Stream, StreamExt, future::join5, pin_mut}; use ruma::{ - OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId, events::{AnyStrippedStateEvent, room::member::MembershipState}, serde::Raw + OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId, + events::{AnyStrippedStateEvent, room::member::MembershipState}, + serde::Raw, }; use crate::{Dep, account_data, appservice::RegistrationInfo, config, globals, rooms, users}; @@ -415,7 +417,9 @@ pub async fn invite_state( .qry(&key) .await .deserialized() - .and_then(|val: Raw>| val.deserialize_as_unchecked().map_err(Into::into)) + .and_then(|val: Raw>| { + val.deserialize_as_unchecked().map_err(Into::into) + }) } #[implement(Service)] @@ -431,7 +435,9 @@ pub async fn knock_state( .qry(&key) .await .deserialized() - .and_then(|val: Raw>| val.deserialize_as_unchecked().map_err(Into::into)) + .and_then(|val: Raw>| { + val.deserialize_as_unchecked().map_err(Into::into) + }) } #[implement(Service)] diff --git a/src/service/rooms/threads/mod.rs b/src/service/rooms/threads/mod.rs index 19ff1d720..4809e38f0 100644 --- a/src/service/rooms/threads/mod.rs +++ b/src/service/rooms/threads/mod.rs @@ -11,7 +11,9 @@ use conduwuit_database::{Deserialized, Map}; use futures::{Stream, StreamExt}; use ruma::{ - CanonicalJsonValue, EventId, OwnedUserId, RoomId, UserId, api::client::threads::get_threads::v1::IncludeThreads, events::relation::BundledThread, serde::Raw, uint + CanonicalJsonValue, EventId, OwnedUserId, RoomId, UserId, + api::client::threads::get_threads::v1::IncludeThreads, events::relation::BundledThread, + serde::Raw, uint, }; use serde_json::json; @@ -100,7 +102,11 @@ pub async fn add_to_thread(&self, root_event_id: &EventId, event: &E) -> Resu ); } else { // New thread - let relations = BundledThread::new(Raw::from_json(event.content().to_owned()), uint!(1), true); + let relations = BundledThread::new( + Raw::from_json(event.content().to_owned()), + uint!(1), + true, + ); let content = serde_json::to_value(relations).expect("to_value always works"); diff --git a/src/service/rooms/timeline/append.rs b/src/service/rooms/timeline/append.rs index 08139511f..fd93b4d12 100644 --- a/src/service/rooms/timeline/append.rs +++ b/src/service/rooms/timeline/append.rs @@ -18,10 +18,7 @@ events::{ GlobalAccountDataEventType, TimelineEventType, push_rules::PushRulesEvent, - room::{ - encrypted::Relation, - redaction::RoomRedactionEventContent, - }, + room::{encrypted::Relation, redaction::RoomRedactionEventContent}, }, push::{Action, Ruleset, Tweak}, }; @@ -204,7 +201,11 @@ pub async fn append_pdu<'a, Leaves>( drop(insert_lock); // See if the event matches any known pushers via power level - let power_levels = self.services.state_accessor.get_room_power_levels(room_id).await; + let power_levels = self + .services + .state_accessor + .get_room_power_levels(room_id) + .await; let mut push_target: HashSet<_> = self .services .state_cache @@ -251,7 +252,7 @@ pub async fn append_pdu<'a, Leaves>( { match action { | Action::Notify => notify = true, - | Action::SetTweak(Tweak::Highlight(true)) => { + | Action::SetTweak(Tweak::Highlight(ruma::push::HighlightTweakValue::Yes)) => { highlight = true; }, | _ => {}, @@ -366,10 +367,12 @@ pub async fn append_pdu<'a, Leaves>( if let Ok(content) = pdu.get_content::() { match content.relates_to { - | Relation::Reply { in_reply_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 - if let Ok(related_pducount) = self.get_pdu_count(&in_reply_to.event_id).await { + if let Ok(related_pducount) = + self.get_pdu_count(&in_reply_to.in_reply_to.event_id).await + { self.services .pdu_metadata .add_relation(count2, related_pducount); diff --git a/src/service/rooms/timeline/backfill.rs b/src/service/rooms/timeline/backfill.rs index 53b69617b..403048b87 100644 --- a/src/service/rooms/timeline/backfill.rs +++ b/src/service/rooms/timeline/backfill.rs @@ -12,10 +12,16 @@ }; use futures::{FutureExt, Stream, StreamExt}; use ruma::{ - CanonicalJsonObject, EventId, Int, OwnedServerName, RoomId, ServerName, api::federation, events::{ + CanonicalJsonObject, EventId, Int, OwnedServerName, RoomId, ServerName, + api::federation, + events::{ StateEventType, TimelineEventType, - room::{create::RoomCreateEventContent, power_levels::{RoomPowerLevelsEventContent, UserPowerLevel}}, - }, uint + room::{ + create::RoomCreateEventContent, + power_levels::{RoomPowerLevelsEventContent, UserPowerLevel}, + }, + }, + uint, }; use serde_json::value::RawValue as RawJsonValue; @@ -66,7 +72,11 @@ pub async fn backfill_if_required(&self, room_id: &RoomId, from: PduCount) -> Re .sending .send_federation_request( &backfill_server, - federation::backfill::get_backfill::v1::Request::new(room_id.to_owned(), vec![first_pdu.1.event_id().to_owned()], uint!(100)) + federation::backfill::get_backfill::v1::Request::new( + room_id.to_owned(), + vec![first_pdu.1.event_id().to_owned()], + uint!(100), + ), ) .await; match response { @@ -125,7 +135,10 @@ pub async fn get_remote_pdu(&self, room_id: &RoomId, event_id: &EventId) -> Resu let value = self .services .sending - .send_federation_request(&backfill_server, federation::event::get_event::v1::Request::new(event_id.to_owned())) + .send_federation_request( + &backfill_server, + federation::event::get_event::v1::Request::new(event_id.to_owned()), + ) .await .and_then(|response| { serde_json::from_str::(response.pdu.get()).map_err(|e| { @@ -220,7 +233,11 @@ pub async fn backfill_pdu(&self, origin: &ServerName, pdu: Box) -> async fn candidate_backfill_servers(&self, room_id: &RoomId) -> HashSet { let mut candidate_backfill_servers = HashSet::new(); - let power_levels = self.services.state_accessor.get_room_power_levels(room_id).await; + let power_levels = self + .services + .state_accessor + .get_room_power_levels(room_id) + .await; // Insert servers of room creators if let Some(creators) = &power_levels.rules.privileged_creators { @@ -237,19 +254,30 @@ async fn candidate_backfill_servers(&self, room_id: &RoomId) -> HashSet { trace!(%room_id, "Looking up existing room ID"); self.services @@ -114,7 +114,7 @@ pub async fn create_event( | None => { trace!("No room ID, assuming room creation"); room_version_from_event( - RoomId::new(self.services.globals.server_name()), + RoomId::new_v1(self.services.globals.server_name()), &event_type.clone(), &content.clone(), )? @@ -261,7 +261,7 @@ pub async fn create_event( pdu.event_id, pdu.room_id.as_ref().map_or("None", |id| id.as_str()) ); - Ok((pdu, room_version_id)) + Ok((pdu, room_version)) } #[implement(super::Service)] @@ -276,7 +276,7 @@ pub async fn create_hash_and_sign_event( if !self.services.globals.user_is_local(sender) { return Err!(Request(Forbidden("Sender must be a local user"))); } - let (mut pdu, room_version_id) = self + let (mut pdu, room_version) = self .create_event(pdu_builder, sender, room_id, mutex_lock) .await?; // Hash and sign @@ -292,7 +292,7 @@ pub async fn create_hash_and_sign_event( .hash_and_sign_event(&mut pdu_json, &room_version) { return match e { - | Error::Signatures(ruma::signatures::Error::PduSize) => { + | Error::SignatureJson(ruma::signatures::JsonError::PduTooLarge) => { Err!(Request(TooLarge("Message/PDU is too long (exceeds 65535 bytes)"))) }, | _ => Err!(Request(Unknown(warn!("Signing event failed: {e}")))), diff --git a/src/service/sending/antispam.rs b/src/service/sending/antispam.rs index 47c7eaef9..796e08ba4 100644 --- a/src/service/sending/antispam.rs +++ b/src/service/sending/antispam.rs @@ -3,7 +3,11 @@ use bytes::BytesMut; use conduwuit::{Err, Result, debug_error, err, utils, utils::response::LimitReadExt, warn}; use reqwest::Client; -use ruma::api::{IncomingResponse, MatrixVersion, OutgoingRequest, auth_scheme::{AppserviceToken, SendAccessToken}, path_builder::VersionHistory}; +use ruma::api::{ + IncomingResponse, MatrixVersion, OutgoingRequest, + auth_scheme::{AppserviceToken, SendAccessToken}, + path_builder::VersionHistory, +}; use crate::SUPPORTED_VERSIONS; @@ -15,7 +19,9 @@ pub(crate) async fn send_antispam_request( request: T, ) -> Result where - T: OutgoingRequest:: + Debug + Send, + T: OutgoingRequest + + Debug + + Send, { const VERSIONS: [MatrixVersion; 1] = [MatrixVersion::V1_15]; let http_request = request diff --git a/src/service/sending/appservice.rs b/src/service/sending/appservice.rs index 37aef8c96..73bfa5ed0 100644 --- a/src/service/sending/appservice.rs +++ b/src/service/sending/appservice.rs @@ -5,7 +5,10 @@ Err, Result, debug_error, err, implement, trace, utils, utils::response::LimitReadExt, warn, }; use ruma::api::{ - IncomingResponse, MatrixVersion, OutgoingRequest, appservice::Registration, auth_scheme::{AccessToken, SendAccessToken}, path_builder::SinglePath, + IncomingResponse, MatrixVersion, OutgoingRequest, + appservice::Registration, + auth_scheme::{AccessToken, SendAccessToken}, + path_builder::SinglePath, }; /// Sends a request to an appservice @@ -33,11 +36,7 @@ pub async fn send_appservice_request( let hs_token = registration.hs_token.as_str(); let mut http_request = request - .try_into_http_request::( - &dest, - SendAccessToken::Appservice(hs_token), - (), - ) + .try_into_http_request::(&dest, SendAccessToken::Appservice(hs_token), ()) .map_err(|e| { err!(BadServerResponse( warn!(appservice = %registration.id, "Failed to find destination {dest}: {e:?}") diff --git a/src/service/sending/mod.rs b/src/service/sending/mod.rs index e2d427db4..a49f8d84b 100644 --- a/src/service/sending/mod.rs +++ b/src/service/sending/mod.rs @@ -19,7 +19,13 @@ warn, }; use futures::{FutureExt, Stream, StreamExt}; -use ruma::{OwnedServerName, RoomId, ServerName, UserId, api::{OutgoingRequest, auth_scheme::NoAuthentication, federation::authentication::ServerSignatures, path_builder::PathBuilder}}; +use ruma::{ + OwnedServerName, RoomId, ServerName, UserId, + api::{ + OutgoingRequest, auth_scheme::{NoAuthentication, NoAccessToken, SendAccessToken}, + federation::authentication::ServerSignatures, path_builder::PathBuilder, + }, +}; use tokio::{task, task::JoinSet}; use self::data::Data; @@ -28,7 +34,10 @@ sender::{EDU_LIMIT, PDU_LIMIT}, }; use crate::{ - Dep, account_data, client, federation::{self, FederationPathBuilderInput}, globals, presence, pusher, rooms::{self, timeline::RawPduId}, + Dep, account_data, client, + federation::{self, FederationPathBuilderInput}, + globals, presence, pusher, + rooms::{self, timeline::RawPduId}, users, }; @@ -239,10 +248,7 @@ pub async fn send_edu_servers(&self, servers: S, serialized: EduBuf) -> Resul { let requests = servers .map(|server| { - ( - Destination::Federation(server), - SendingEvent::Edu(serialized.clone()), - ) + (Destination::Federation(server), SendingEvent::Edu(serialized.clone())) }) .collect::>() .await; @@ -294,7 +300,11 @@ pub async fn send_federation_request<'i, T>( request: T, ) -> Result where - T: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, + T: OutgoingRequest< + Authentication = ServerSignatures, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { self.services.federation.execute(dest, request).await } @@ -307,7 +317,11 @@ pub async fn send_synapse_request<'i, T>( request: T, ) -> Result where - T: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, + T: OutgoingRequest< + Authentication = ServerSignatures, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { self.services .federation @@ -323,13 +337,37 @@ pub async fn send_unauthenticated_request<'i, T>( request: T, ) -> Result where - T: OutgoingRequest::: FederationPathBuilderInput>> + Debug + Send, + T: OutgoingRequest< + Authentication = NoAuthentication, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, { self.services .federation .execute_unauthenticated(dest, request) .await } + /// Send an unauthenticated federation request with no X-Matrix header. + #[inline] + pub async fn send_legacy_media_request<'i, T>( + &self, + dest: &ServerName, + request: T, + ) -> Result + where + T: OutgoingRequest< + Authentication = NoAccessToken, + PathBuilder: PathBuilder: FederationPathBuilderInput>, + > + Debug + + Send, + { + + self.services + .federation + .execute_on(&self.services.client.federation, dest, request, SendAccessToken::None) + .await + } /// Clean up queued sending event data /// diff --git a/src/service/sending/sender.rs b/src/service/sending/sender.rs index 3362ba6f0..21d5c5547 100644 --- a/src/service/sending/sender.rs +++ b/src/service/sending/sender.rs @@ -438,7 +438,11 @@ async fn select_edus_device_changes( // Empty prev id forces synapse to resync; because synapse resyncs, // we can just insert placeholder data - let edu = Edu::DeviceListUpdate(DeviceListUpdateContent::new(user_id, device_id!("placeholder").to_owned(), uint!(1))); + let edu = Edu::DeviceListUpdate(DeviceListUpdateContent::new( + user_id, + device_id!("placeholder").to_owned(), + uint!(1), + )); let mut buf = EduBuf::new(); serde_json::to_writer(&mut buf, &edu) @@ -605,7 +609,14 @@ async fn select_edus_presence( continue; }; - let mut update = PresenceUpdate::new(user_id.to_owned(), presence_event.content.presence, presence_event.content.last_active_ago.unwrap_or_else(|| uint!(0))); + let mut update = PresenceUpdate::new( + user_id.to_owned(), + presence_event.content.presence, + presence_event + .content + .last_active_ago + .unwrap_or_else(|| uint!(0)), + ); update.currently_active = presence_event.content.currently_active.unwrap_or_default(); update.status_msg = presence_event.content.status_msg; @@ -619,7 +630,8 @@ async fn select_edus_presence( return None; } - let presence_content = Edu::Presence(PresenceContent::new(presence_updates.into_values().collect())); + let presence_content = + Edu::Presence(PresenceContent::new(presence_updates.into_values().collect())); let mut buf = EduBuf::new(); serde_json::to_writer(&mut buf, &presence_content) @@ -699,17 +711,12 @@ async fn send_events_dest_appservice( //debug_assert!(pdu_jsons.len() + edu_jsons.len() > 0, "sending empty // transaction"); - let mut request = ruma::api::appservice::event::push_events::v1::Request::new(txn_id.into(), pdu_jsons); + let mut request = + ruma::api::appservice::event::push_events::v1::Request::new(txn_id.into(), pdu_jsons); request.ephemeral = edu_jsons; request.to_device = Vec::new(); // TODO - match self - .send_appservice_request( - appservice, - request, - ) - .await - { + match self.send_appservice_request(appservice, request).await { | Ok(_) => Ok(Destination::Appservice(id)), | Err(e) => Err((Destination::Appservice(id), e)), } @@ -829,7 +836,11 @@ async fn send_events_dest_federation( let txn_hash = calculate_hash(preimage); let txn_id = &*URL_SAFE_NO_PAD.encode(txn_hash); - let mut request = send_transaction_message::v1::Request::new(txn_id.into(), self.server.name.clone(), MilliSecondsSinceUnixEpoch::now()); + let mut request = send_transaction_message::v1::Request::new( + txn_id.into(), + self.server.name.clone(), + MilliSecondsSinceUnixEpoch::now(), + ); request.pdus = pdus; request.edus = edus; diff --git a/src/service/server_keys/get.rs b/src/service/server_keys/get.rs index ac8aca0e4..70fa676cc 100644 --- a/src/service/server_keys/get.rs +++ b/src/service/server_keys/get.rs @@ -6,9 +6,8 @@ api::federation::discovery::VerifyKey, }; -use crate::server_keys::util::required_keys; - use super::{PubKeyMap, PubKeys, extract_key}; +use crate::server_keys::util::required_keys; #[implement(super::Service)] pub async fn get_event_keys( diff --git a/src/service/server_keys/mod.rs b/src/service/server_keys/mod.rs index eb398ecbb..ff25f97b6 100644 --- a/src/service/server_keys/mod.rs +++ b/src/service/server_keys/mod.rs @@ -3,8 +3,8 @@ mod keypair; mod request; mod sign; -mod verify; mod util; +mod verify; use std::{collections::BTreeMap, sync::Arc, time::Duration}; diff --git a/src/service/server_keys/sign.rs b/src/service/server_keys/sign.rs index 4af198ee4..128dba171 100644 --- a/src/service/server_keys/sign.rs +++ b/src/service/server_keys/sign.rs @@ -18,5 +18,11 @@ pub fn hash_and_sign_event( use ruma::signatures::hash_and_sign_event; let server_name = self.services.globals.server_name().as_str(); - hash_and_sign_event(server_name, self.keypair(), object, &room_version.rules().unwrap().redaction).map_err(Into::into) + hash_and_sign_event( + server_name, + self.keypair(), + object, + &room_version.rules().unwrap().redaction, + ) + .map_err(Into::into) } diff --git a/src/service/server_keys/util.rs b/src/service/server_keys/util.rs index 8a521129d..98d6ec982 100644 --- a/src/service/server_keys/util.rs +++ b/src/service/server_keys/util.rs @@ -1,117 +1,160 @@ use std::collections::{BTreeMap, BTreeSet}; -use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedServerName, OwnedServerSigningKeyId, RoomVersionId, UserId, canonical_json::JsonType, signatures::{Error, JsonError, ParseError}}; +use ruma::{ + CanonicalJsonObject, CanonicalJsonValue, IdParseError, OwnedEventId, OwnedServerName, OwnedServerSigningKeyId, RoomVersionId, UserId, canonical_json::JsonType, signatures::{JsonError, VerificationError} +}; -/// Whether the given event is an `m.room.member` invite that was created as the result of a -/// third-party invite. +/// Whether the given event is an `m.room.member` invite that was created as the +/// result of a third-party invite. /// -/// Returns an error if the object has not the expected format of an `m.room.member` event. -pub(super) fn is_invite_via_third_party_id(object: &CanonicalJsonObject) -> Result { - let Some(CanonicalJsonValue::String(raw_type)) = object.get("type") else { - return Err(JsonError::NotOfType { target: "type".to_owned(), of_type: JsonType::String }.into()); - }; +/// Returns an error if the object has not the expected format of an +/// `m.room.member` event. +pub(super) fn is_invite_via_third_party_id(object: &CanonicalJsonObject) -> Result { + let Some(CanonicalJsonValue::String(raw_type)) = object.get("type") else { + return Err(JsonError::NotOfType { + target: "type".to_owned(), + of_type: JsonType::String, + } + .into()); + }; - if raw_type != "m.room.member" { - return Ok(false); - } + if raw_type != "m.room.member" { + return Ok(false); + } - let Some(CanonicalJsonValue::Object(content)) = object.get("content") else { - return Err(JsonError::NotOfType { target: "content".to_owned(), of_type: JsonType::Object }.into()); - }; + let Some(CanonicalJsonValue::Object(content)) = object.get("content") else { + return Err(JsonError::NotOfType { + target: "content".to_owned(), + of_type: JsonType::Object, + } + .into()); + }; - let Some(CanonicalJsonValue::String(membership)) = content.get("membership") else { - return Err(JsonError::NotOfType { target: "membership".to_owned(), of_type: JsonType::String }.into()); - }; + let Some(CanonicalJsonValue::String(membership)) = content.get("membership") else { + return Err(JsonError::NotOfType { + target: "membership".to_owned(), + of_type: JsonType::String, + } + .into()); + }; - if membership != "invite" { - return Ok(false); - } + if membership != "invite" { + return Ok(false); + } - match content.get("third_party_invite") { - Some(CanonicalJsonValue::Object(_)) => Ok(true), - None => Ok(false), - _ => Err(JsonError::NotOfType { target: "third_party_invite".to_owned(), of_type: JsonType::Object }.into()), - } + match content.get("third_party_invite") { + | Some(CanonicalJsonValue::Object(_)) => Ok(true), + | None => Ok(false), + | _ => Err(JsonError::NotOfType { + target: "third_party_invite".to_owned(), + of_type: JsonType::Object, + } + .into()), + } } /// Extracts the server names to check signatures for given event. /// -/// Respects the rules for [validating signatures on received events] for populating the result: +/// Respects the rules for [validating signatures on received events] for +/// populating the result: /// -/// - Add the server of the sender, except if it's an invite event that results from a third-party -/// invite. +/// - Add the server of the sender, except if it's an invite event that results +/// from a third-party invite. /// - For room versions 1 and 2, add the server of the `event_id`. -/// - For room versions that support restricted join rules, if it's a join event with a -/// `join_authorised_via_users_server`, add the server of that user. +/// - For room versions that support restricted join rules, if it's a join event +/// with a `join_authorised_via_users_server`, add the server of that user. /// /// [validating signatures on received events]: https://spec.matrix.org/latest/server-server-api/#validating-hashes-and-signatures-on-received-events pub fn servers_to_check_signatures( - object: &CanonicalJsonObject, - version: &RoomVersionId, -) -> Result, Error> { - let mut servers_to_check = BTreeSet::new(); + object: &CanonicalJsonObject, + version: &RoomVersionId, +) -> Result, VerificationError> { + let mut servers_to_check = BTreeSet::new(); - if !is_invite_via_third_party_id(object)? { - match object.get("sender") { - Some(CanonicalJsonValue::String(raw_sender)) => { - let user_id = <&UserId>::try_from(raw_sender.as_str()) - .map_err(|e| Error::from(ParseError::UserId(e)))?; + if !is_invite_via_third_party_id(object)? { + match object.get("sender") { + | Some(CanonicalJsonValue::String(raw_sender)) => { + let user_id = <&UserId>::try_from(raw_sender.as_str()).map_err(|source| {VerificationError::ParseIdentifier { + identifier_type: "user ID", + source, + } + })?; - servers_to_check.insert(user_id.server_name().to_owned()); - } - _ => return Err(JsonError::NotOfType { target: "sender".to_owned(), of_type: JsonType::String }.into()), - }; - } + servers_to_check.insert(user_id.server_name().to_owned()); + }, + | _ => + return Err(JsonError::NotOfType { + target: "sender".to_owned(), + of_type: JsonType::String, + } + .into()), + }; + } - match version { - RoomVersionId::V1 | RoomVersionId::V2 => match object.get("event_id") { - Some(CanonicalJsonValue::String(raw_event_id)) => { - let event_id: OwnedEventId = - raw_event_id.parse().map_err(|e| Error::from(ParseError::EventId(e)))?; + match version { + | RoomVersionId::V1 | RoomVersionId::V2 => match object.get("event_id") { + | Some(CanonicalJsonValue::String(raw_event_id)) => { + let event_id: OwnedEventId = raw_event_id.parse().map_err(|source| { + VerificationError::ParseIdentifier { + identifier_type: "event ID", + source, + } + })?; - let server_name = event_id - .server_name() - .ok_or_else(|| ParseError::ServerNameFromEventId(event_id.to_owned()))? - .to_owned(); + let server_name = event_id + .server_name() + .ok_or_else(|| VerificationError::ParseIdentifier { + identifier_type: "event ID", + source: IdParseError::InvalidServerName, + })? + .to_owned(); - servers_to_check.insert(server_name); - } - _ => { - return Err(JsonError::JsonFieldMissingFromObject("event_id".to_owned()).into()); - } - }, - RoomVersionId::V3 - | RoomVersionId::V4 - | RoomVersionId::V5 - | RoomVersionId::V6 - | RoomVersionId::V7 => {} - // TODO: And for all future versions that have join_authorised_via_users_server - RoomVersionId::V8 | RoomVersionId::V9 | RoomVersionId::V10 | RoomVersionId::V11 | RoomVersionId::V12 => { - if let Some(authorized_user) = object - .get("content") - .and_then(|c| c.as_object()) - .and_then(|c| c.get("join_authorised_via_users_server")) - { - let authorized_user = authorized_user.as_str().ok_or_else(|| -> Error { - JsonError::NotOfType { target: "join_authorised_via_users_server".to_owned(), of_type: JsonType::String }.into() - })?; - let authorized_user = <&UserId>::try_from(authorized_user) - .map_err(|e| Error::from(ParseError::UserId(e)))?; + servers_to_check.insert(server_name); + }, + | _ => { + return Err(JsonError::MissingField { path: "event_id".to_owned() }.into()); + }, + }, + | RoomVersionId::V3 + | RoomVersionId::V4 + | RoomVersionId::V5 + | RoomVersionId::V6 + | RoomVersionId::V7 => {}, + // TODO: And for all future versions that have join_authorised_via_users_server + | RoomVersionId::V8 + | RoomVersionId::V9 + | RoomVersionId::V10 + | RoomVersionId::V11 + | RoomVersionId::V12 => { + if let Some(authorized_user) = object + .get("content") + .and_then(|c| c.as_object()) + .and_then(|c| c.get("join_authorised_via_users_server")) + { + let authorized_user = authorized_user.as_str().ok_or_else(|| -> JsonError { + JsonError::NotOfType { + target: "join_authorised_via_users_server".to_owned(), + of_type: JsonType::String, + } + .into() + })?; + let authorized_user = <&UserId>::try_from(authorized_user) + .map_err(|source| VerificationError::ParseIdentifier { identifier_type: "user ID", source })?; - servers_to_check.insert(authorized_user.server_name().to_owned()); - } - } - _ => unimplemented!(), - } + servers_to_check.insert(authorized_user.server_name().to_owned()); + } + }, + | _ => unimplemented!(), + } - Ok(servers_to_check) + Ok(servers_to_check) } /// Extracts the server names and key ids to check signatures for given event. pub fn required_keys( object: &CanonicalJsonObject, version: &RoomVersionId, -) -> Result>, Error> { +) -> Result>, VerificationError> { use CanonicalJsonValue::Object; let mut map = BTreeMap::>::new(); let Some(Object(signatures)) = object.get("signatures") else { @@ -132,4 +175,4 @@ pub fn required_keys( } Ok(map) -} \ No newline at end of file +} diff --git a/src/service/server_keys/verify.rs b/src/service/server_keys/verify.rs index f7e35e267..6f3f5b0d4 100644 --- a/src/service/server_keys/verify.rs +++ b/src/service/server_keys/verify.rs @@ -63,7 +63,8 @@ pub async fn verify_event( ) -> Result { let room_version = room_version.unwrap_or(&RoomVersionId::V12); let keys = self.get_event_keys(event, room_version).await?; - ruma::signatures::verify_event(&keys, event, &room_version.rules().unwrap()).map_err(Into::into) + ruma::signatures::verify_event(&keys, event, &room_version.rules().unwrap()) + .map_err(Into::into) } #[implement(super::Service)] diff --git a/src/service/sync/mod.rs b/src/service/sync/mod.rs index d96242d2f..3bf54a34c 100644 --- a/src/service/sync/mod.rs +++ b/src/service/sync/mod.rs @@ -7,12 +7,7 @@ use conduwuit::{Result, Server, SyncMutex}; use database::Map; -use ruma::{ - OwnedDeviceId, OwnedRoomId, OwnedUserId, - api::client::sync::sync_events::{ - v5, - }, -}; +use ruma::{OwnedDeviceId, OwnedRoomId, OwnedUserId, api::client::sync::sync_events::v5}; use crate::{Dep, rooms}; diff --git a/src/service/threepid/mod.rs b/src/service/threepid/mod.rs index dcc0b58ab..09e8dce4d 100644 --- a/src/service/threepid/mod.rs +++ b/src/service/threepid/mod.rs @@ -5,9 +5,7 @@ use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter}; use lettre::{Address, message::Mailbox}; use nonzero_ext::nonzero; -use ruma::{ - ClientSecret, OwnedClientSecret, OwnedSessionId, SessionId, api::client::error::ErrorKind, -}; +use ruma::{ClientSecret, OwnedClientSecret, OwnedSessionId, SessionId, api::error::ErrorKind}; mod session; diff --git a/src/service/transactions/mod.rs b/src/service/transactions/mod.rs index 97f36eb97..01dc27e55 100644 --- a/src/service/transactions/mod.rs +++ b/src/service/transactions/mod.rs @@ -13,10 +13,7 @@ use database::{Handle, Map}; use ruma::{ DeviceId, OwnedServerName, OwnedTransactionId, TransactionId, UserId, - api::{ - client::error::ErrorKind::LimitExceeded, - federation::transactions::send_transaction_message, - }, + api::{error::ErrorKind::LimitExceeded, federation::transactions::send_transaction_message}, }; use tokio::sync::watch::{Receiver, Sender}; diff --git a/src/service/uiaa/mod.rs b/src/service/uiaa/mod.rs index 083704560..3e7d83583 100644 --- a/src/service/uiaa/mod.rs +++ b/src/service/uiaa/mod.rs @@ -8,18 +8,18 @@ use lettre::Address; use ruma::{ UserId, - api::client::{ - error::{ErrorKind, StandardErrorBody}, - uiaa::{ + api::{ + client::uiaa::{ AuthData, AuthFlow, AuthType, EmailIdentity, Password, ReCaptcha, RegistrationToken, - ThirdpartyIdCredentials, UiaaInfo, UserIdentifier, + ThirdpartyIdCredentials, UiaaInfo, UserIdentifier, MatrixUserIdentifier }, + error::{ErrorKind, StandardErrorBody}, }, }; use serde_json::value::RawValue; use tokio::sync::Mutex; -use crate::{Dep, config, globals, registration_tokens, threepid, users}; +use crate::{Dep, config, globals, registration_tokens, rooms::user, threepid, users}; pub struct Service { services: Services, @@ -190,7 +190,7 @@ async fn create_session( let mut uiaa_sessions = self.uiaa_sessions.lock().await; let session_id = utils::random_string(Self::SESSION_ID_LENGTH); - let mut info = UiaaInfo::new(flows, params); + let mut info = assign::assign!(UiaaInfo::new(flows), {params: Some(params)}); info.session = Some(session_id.clone()); uiaa_sessions.insert(session_id, UiaaSession { @@ -339,13 +339,10 @@ async fn check_stage( #[allow(clippy::useless_let_if_seq)] | AuthData::Password(Password { identifier, password, .. }) => { let user_id_or_localpart = match identifier { - | Some(UserIdentifier::UserIdOrLocalpart(username)) => username.to_owned(), - | Some(UserIdentifier::Email { address }) => { + | Some(UserIdentifier::Matrix(MatrixUserIdentifier{user})) => user.to_owned(), + | Some(UserIdentifier::Email(address)) => { let Ok(email) = Address::try_from(address.to_owned()) else { - return Err(StandardErrorBody { - kind: ErrorKind::InvalidParam, - message: "Email is malformed".to_owned(), - }); + return Err(StandardErrorBody::new(ErrorKind::InvalidParam, "Email is malformed".to_owned())); }; if let Some(localpart) = @@ -355,27 +352,18 @@ async fn check_stage( localpart } else { - return Err(StandardErrorBody { - kind: ErrorKind::forbidden(), - message: "Invalid identifier or password".to_owned(), - }); + return Err(StandardErrorBody::new(ErrorKind::Forbidden, "Invalid identifier or password".to_owned())); } }, | _ => - return Err(StandardErrorBody { - kind: ErrorKind::Unrecognized, - message: "Identifier type not recognized".to_owned(), - }), + return Err(StandardErrorBody::new(ErrorKind::Unrecognized, "Identifier type not recognized".to_owned())), }; let Ok(user_id) = UserId::parse_with_server_name( user_id_or_localpart, self.services.globals.server_name(), ) else { - return Err(StandardErrorBody { - kind: ErrorKind::InvalidParam, - message: "User ID is malformed".to_owned(), - }); + return Err(StandardErrorBody::new(ErrorKind::InvalidParam, "User ID is malformed".to_owned())); }; // Check if password is correct @@ -408,29 +396,20 @@ async fn check_stage( Ok(AuthType::Password) } else { - Err(StandardErrorBody { - kind: ErrorKind::forbidden(), - message: "Invalid identifier or password".to_owned(), - }) + Err(StandardErrorBody::new(ErrorKind::Forbidden, "Invalid identifier or password".to_owned())) } }, | AuthData::ReCaptcha(ReCaptcha { response, .. }) => { let Some(ref private_site_key) = self.services.config.recaptcha_private_site_key else { - return Err(StandardErrorBody { - kind: ErrorKind::forbidden(), - message: "ReCaptcha is not configured".to_owned(), - }); + return Err(StandardErrorBody::new(ErrorKind::Forbidden, "ReCaptcha is not configured".to_owned())); }; match recaptcha_verify::verify_v3(private_site_key, response, None).await { | Ok(()) => Ok(AuthType::ReCaptcha), | Err(e) => { error!("ReCaptcha verification failed: {e:?}"); - Err(StandardErrorBody { - kind: ErrorKind::forbidden(), - message: "ReCaptcha verification failed".to_owned(), - }) + Err(StandardErrorBody::new(ErrorKind::Forbidden, "ReCaptcha verification failed".to_owned())) }, } }, @@ -449,17 +428,11 @@ async fn check_stage( Ok(AuthType::RegistrationToken) } else { - Err(StandardErrorBody { - kind: ErrorKind::forbidden(), - message: "Invalid registration token".to_owned(), - }) + Err(StandardErrorBody::new(ErrorKind::Forbidden, "Invalid registration token".to_owned())) } }, | AuthData::Terms(_) => Ok(AuthType::Terms), - | _ => Err(StandardErrorBody { - kind: ErrorKind::Unrecognized, - message: "Unsupported stage type".into(), - }), + | _ => Err(StandardErrorBody::new(ErrorKind::Unrecognized, "Unsupported stage type".into())), } .map(|auth_type| (auth_type, identity)) } diff --git a/src/service/users/mod.rs b/src/service/users/mod.rs index 734884675..c7a32a701 100644 --- a/src/service/users/mod.rs +++ b/src/service/users/mod.rs @@ -19,11 +19,13 @@ use ruma::{ DeviceId, KeyId, MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OneTimeKeyId, OneTimeKeyName, OwnedDeviceId, OwnedKeyId, OwnedMxcUri, OwnedUserId, RoomId, UInt, UserId, - api::client::{device::Device, error::ErrorKind, filter::FilterDefinition}, + api::{ + client::{device::Device, filter::FilterDefinition}, + error::ErrorKind, + }, encryption::{CrossSigningKey, DeviceKeys, OneTimeKey}, events::{ - AnyToDeviceEvent, GlobalAccountDataEventType, - ignored_user_list::IgnoredUserListEvent, + AnyToDeviceEvent, GlobalAccountDataEventType, ignored_user_list::IgnoredUserListEvent, }, serde::Raw, uint, diff --git a/src/web/Cargo.toml b/src/web/Cargo.toml index bfc1e6dd9..845a30ff4 100644 --- a/src/web/Cargo.toml +++ b/src/web/Cargo.toml @@ -30,6 +30,7 @@ base64.workspace = true futures.workspace = true tracing.workspace = true rand.workspace = true +assign.workspace = true ruma.workspace = true thiserror.workspace = true tower-http.workspace = true