diff --git a/src/api/client_server/message.rs b/src/api/client_server/message.rs index d332bcff606fcca808b4ccd956dd8f4c3cd358e9..32a2100385a582e198aca6ceecbd703b73d6d720 100644 --- a/src/api/client_server/message.rs +++ b/src/api/client_server/message.rs @@ -9,6 +9,7 @@ }, events::{StateEventType, TimelineEventType}, }; +use serde_json::from_str; use std::{ collections::{BTreeMap, HashSet}, sync::Arc, @@ -48,6 +49,52 @@ pub async fn send_message_event_route( )); } + // certain event types require certain fields to be valid in request bodies. + // this helps prevent attempting to handle events that we can't deserialise later so don't waste resources on it. + // + // see https://spec.matrix.org/v1.9/client-server-api/#events-2 for what's required per event type. + match body.event_type.to_string().into() { + TimelineEventType::RoomMessage => { + let body_field = body.body.body.get_field::<String>("body"); + let msgtype_field = body.body.body.get_field::<String>("msgtype"); + + if body_field.is_err() { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "'body' field in JSON request is invalid", + )); + } + + if msgtype_field.is_err() { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "'msgtype' field in JSON request is invalid", + )); + } + } + TimelineEventType::RoomName => { + let name_field = body.body.body.get_field::<String>("name"); + + if name_field.is_err() { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "'name' field in JSON request is invalid", + )); + } + } + TimelineEventType::RoomTopic => { + let topic_field = body.body.body.get_field::<String>("topic"); + + if topic_field.is_err() { + return Err(Error::BadRequest( + ErrorKind::InvalidParam, + "'topic' field in JSON request is invalid", + )); + } + } + _ => {} // event may be custom/experimental or can be empty don't do anything with it + }; + // Check if this is a new transaction id if let Some(response) = services() @@ -79,7 +126,7 @@ pub async fn send_message_event_route( .build_and_append_pdu( PduBuilder { event_type: body.event_type.to_string().into(), - content: serde_json::from_str(body.body.body.json().get()) + content: from_str(body.body.body.json().get()) .map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?, unsigned: Some(unsigned), state_key: None, diff --git a/src/api/server_server.rs b/src/api/server_server.rs index 1570b54161fbe4f43da7cce85daf6eea53cfe98a..41c215d8dd6737876a426c748b5f6da39b7e1b82 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -1822,8 +1822,10 @@ pub async fn create_invite_route( )); } - let mut signed_event = utils::to_canonical_object(&body.event) - .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invite event is invalid."))?; + let mut signed_event = utils::to_canonical_object(&body.event).map_err(|e| { + error!("Failed to convert invite event to canonical JSON: {}", e); + Error::BadRequest(ErrorKind::InvalidParam, "Invite event is invalid.") + })?; ruma::signatures::hash_and_sign_event( services().globals.server_name().as_str(), diff --git a/src/service/rooms/timeline/mod.rs b/src/service/rooms/timeline/mod.rs index 11f1d701b1f6a2bc456388b5d65b7c9d95f68163..be65815a34730334e5d9b1faea594d3c623921ee 100644 --- a/src/service/rooms/timeline/mod.rs +++ b/src/service/rooms/timeline/mod.rs @@ -260,8 +260,17 @@ pub async fn append_pdu<'a>( unsigned.insert( "prev_content".to_owned(), CanonicalJsonValue::Object( - utils::to_canonical_object(prev_state.content.clone()) - .expect("event is valid, we just created it"), + utils::to_canonical_object(prev_state.content.clone()).map_err( + |e| { + error!( + "Failed to convert prev_state to canonical JSON: {}", + e + ); + Error::bad_database( + "Failed to convert prev_state to canonical JSON.", + ) + }, + )?, ), ); } @@ -802,7 +811,7 @@ struct RoomCreate { |k, s| auth_events.get(&(k.clone(), s.to_owned())), ) .map_err(|e| { - error!("Auth check for PDU {:?} failed: {:?}", &pdu, e); + error!("Auth check failed: {:?}", e); Error::bad_database("Auth check failed.") })?; @@ -815,7 +824,7 @@ struct RoomCreate { // Hash and sign let mut pdu_json = utils::to_canonical_object(&pdu).map_err(|e| { - error!("Failed to convert PDU {:?} to canonical JSON: {}", &pdu, e); + error!("Failed to convert PDU to canonical JSON: {}", e); Error::bad_database("Failed to convert PDU to canonical JSON.") })?; @@ -1105,7 +1114,10 @@ pub fn redact_pdu(&self, event_id: &EventId, reason: &PduEvent) -> Result<()> { pdu.redact(room_version_id, reason)?; self.replace_pdu( &pdu_id, - &utils::to_canonical_object(&pdu).expect("PDU is an object"), + &utils::to_canonical_object(&pdu).map_err(|e| { + error!("Failed to convert PDU to canonical JSON: {}", e); + Error::bad_database("Failed to convert PDU to canonical JSON.") + })?, &pdu, )?; }