From 2fa28296603bb98b9bb408fa9b7c8a0cd73c3ce8 Mon Sep 17 00:00:00 2001 From: Ginger Date: Mon, 13 Apr 2026 10:23:25 -0400 Subject: [PATCH] refactor: Fix errors in `api/server/invite.rs` --- src/api/server/invite.rs | 72 +++++++++++++------------ src/service/rooms/state_cache/update.rs | 18 +++++-- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/src/api/server/invite.rs b/src/api/server/invite.rs index beb0c4883..e059052fb 100644 --- a/src/api/server/invite.rs +++ b/src/api/server/invite.rs @@ -8,8 +8,11 @@ warn, }; use ruma::{ - CanonicalJsonValue, OwnedUserId, UserId, - api::{client::error::ErrorKind, federation::membership::create_invite}, + CanonicalJsonValue, UserId, + api::{ + error::{ErrorKind, IncompatibleRoomVersionErrorData}, + federation::membership::{RawStrippedState, create_invite}, + }, events::room::member::{MembershipState, RoomMemberEventContent}, serde::JsonObject, }; @@ -34,11 +37,15 @@ pub(crate) async fn create_invite_route( if !services.server.supported_room_version(&body.room_version) { return Err(Error::BadRequest( - ErrorKind::IncompatibleRoomVersion { room_version: body.room_version.clone() }, + ErrorKind::IncompatibleRoomVersion(IncompatibleRoomVersionErrorData::new( + body.room_version.clone(), + )), "Server does not support this room version.", )); } + let room_version_rules = body.room_version.rules().unwrap(); + if let Some(server) = body.room_id.server_name() { if services.moderation.is_remote_server_forbidden(server) { return Err!(Request(Forbidden("Server is banned on this homeserver."))); @@ -91,21 +98,24 @@ pub(crate) async fn create_invite_route( } // Ensure the sending user isn't a lying bozo - let sender_server = signed_event + let sender_user = signed_event .get("sender") - .try_into() - .map(UserId::server_name) - .map_err(|e| err!(Request(InvalidParam("Invalid sender property: {e}"))))?; - if sender_server != body.origin() { + .and_then(|v| v.as_str()) + .map(UserId::parse) + .and_then(Result::ok) + .ok_or_else(|| err!(Request(InvalidParam("Invalid sender property"))))?; + + if sender_user.server_name() != body.origin() { return Err!(Request(Forbidden("Sender's server does not match the origin server.",))); } // Ensure the target user belongs to this server - let recipient_user: OwnedUserId = signed_event + let recipient_user = signed_event .get("state_key") - .try_into() - .map(UserId::to_owned) - .map_err(|e| err!(Request(InvalidParam("Invalid state_key property: {e}"))))?; + .and_then(|v| v.as_str()) + .map(UserId::parse) + .and_then(Result::ok) + .ok_or_else(|| err!(Request(InvalidParam("Invalid state_key property"))))?; if !services .globals @@ -123,20 +133,15 @@ pub(crate) async fn create_invite_route( services .server_keys - .hash_and_sign_event(&mut signed_event, &body.room_version) + .hash_and_sign_event(&mut signed_event, &room_version_rules) .map_err(|e| err!(Request(InvalidParam("Failed to sign event: {e}"))))?; // Generate event id - let event_id = gen_event_id(&signed_event, &body.room_version)?; + let event_id = gen_event_id(&signed_event, &room_version_rules)?; // Add event_id back signed_event.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.to_string())); - let sender_user: &UserId = signed_event - .get("sender") - .try_into() - .map_err(|e| err!(Request(InvalidParam("Invalid sender property: {e}"))))?; - if services.rooms.metadata.is_banned(&body.room_id).await && !services.users.is_admin(&recipient_user).await { @@ -167,7 +172,7 @@ pub(crate) async fn create_invite_route( let pdu: PduEvent = serde_json::from_value(event.into()) .map_err(|e| err!(Request(BadJson("Invalid invite event PDU: {e}"))))?; - invite_state.push(pdu.to_format()); + invite_state.push(RawStrippedState::Pdu(pdu.content.clone())); // If we are active in the room, the remote server will notify us about the // join/invite through /send. If we are not in the room, we need to manually @@ -185,8 +190,8 @@ pub(crate) async fn create_invite_route( .mark_as_invited( &recipient_user, &body.room_id, - sender_user, - Some(invite_state), + &sender_user, + invite_state, body.via.clone(), ) .await?; @@ -199,14 +204,15 @@ pub(crate) async fn create_invite_route( for appservice in services.appservice.read().await.values() { if appservice.is_user_match(&recipient_user) { - let request = ruma::api::appservice::event::push_events::v1::Request { - events: vec![pdu.to_format()], - txn_id: general_purpose::URL_SAFE_NO_PAD - .encode(sha256::hash(pdu.event_id.as_bytes())) - .into(), - ephemeral: Vec::new(), - to_device: Vec::new(), - }; + let transaction_id = general_purpose::URL_SAFE_NO_PAD + .encode(sha256::hash(pdu.event_id.as_bytes())) + .into(); + + let request = ruma::api::appservice::event::push_events::v1::Request::new( + transaction_id, + vec![pdu.to_format()], + ); + services .sending .send_appservice_request(appservice.registration.clone(), request) @@ -224,10 +230,10 @@ pub(crate) async fn create_invite_route( } } - Ok(create_invite::v2::Response { - event: services + Ok(create_invite::v2::Response::new( + services .sending .convert_to_outgoing_federation_event(signed_event) .await, - }) + )) } diff --git a/src/service/rooms/state_cache/update.rs b/src/service/rooms/state_cache/update.rs index 042cd43f1..ae842c526 100644 --- a/src/service/rooms/state_cache/update.rs +++ b/src/service/rooms/state_cache/update.rs @@ -5,6 +5,7 @@ use futures::StreamExt; use ruma::{ OwnedServerName, RoomId, UserId, + api::federation::membership::RawStrippedState, events::{ AnyStrippedStateEvent, GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType, @@ -118,8 +119,17 @@ pub async fn update_membership( self.mark_as_joined(user_id, room_id); }, | MembershipState::Invite => { - let last_state = self.services.state.summary_stripped(pdu, room_id).await; - self.mark_as_invited(user_id, room_id, pdu.sender(), Some(last_state), None) + #[allow(deprecated)] + let last_state = self + .services + .state + .summary_stripped(pdu, room_id) + .await + .into_iter() + .map(RawStrippedState::Stripped) + .collect(); + + self.mark_as_invited(user_id, room_id, pdu.sender(), last_state, None) .await?; }, | MembershipState::Leave | MembershipState::Ban => { @@ -332,7 +342,7 @@ pub async fn mark_as_invited( user_id: &UserId, room_id: &RoomId, sender_user: &UserId, - last_state: Option>>, + last_state: Vec, invite_via: Option>, ) -> Result<()> { // return an error for blocked invites. ignored invites aren't handled here @@ -356,7 +366,7 @@ pub async fn mark_as_invited( self.db .userroomid_invitestate - .raw_put(&userroom_id, Json(last_state.unwrap_or_default())); + .raw_put(&userroom_id, Json(last_state)); self.db .roomuserid_invitecount .raw_aput::<8, _, _>(&roomuser_id, self.services.globals.next_count().unwrap());