diff --git a/src/core/matrix/pdu/format.rs b/src/core/matrix/pdu/format.rs index deb08a8c..eab8db4f 100644 --- a/src/core/matrix/pdu/format.rs +++ b/src/core/matrix/pdu/format.rs @@ -6,6 +6,7 @@ use ruma::{ use crate::{ Result, extract_variant, is_equal_to, matrix::{PduEvent, room_version}, + state_res::{self}, }; pub fn into_outgoing_federation( @@ -95,6 +96,8 @@ pub fn from_incoming_federation( pdu_json.insert("event_id".into(), CanonicalJsonValue::String(event_id.into())); } + state_res::check_pdu_format(pdu_json, &room_rules.event_format)?; + PduEvent::from_val(pdu_json) } diff --git a/src/core/matrix/state_res/event_format.rs b/src/core/matrix/state_res/event_format.rs index d69f59b9..69dacef9 100644 --- a/src/core/matrix/state_res/event_format.rs +++ b/src/core/matrix/state_res/event_format.rs @@ -37,9 +37,7 @@ pub fn check_pdu_format(pdu: &CanonicalJsonObject, rules: &EventFormatRules) -> .map_err(|e| err!(Request(BadJson("Failed to serialize canonical JSON: {e}"))))?; if json.len() > MAX_PDU_BYTES { - return Err!(Request(InvalidParam( - "PDU is larger than maximum of {MAX_PDU_BYTES} bytes" - ))); + return Err!(Request(TooLarge("PDU is larger than maximum of {MAX_PDU_BYTES} bytes"))); } // Check the presence, type and length of the `type` field. @@ -133,7 +131,7 @@ fn extract_optional_string_field<'a>( match object.get(field) { | Some(CanonicalJsonValue::String(value)) => if value.len() > ID_MAX_BYTES { - Err!(Request(InvalidParam( + Err!(Request(TooLarge( "invalid `{field}` field in PDU: string length is larger than maximum of \ {ID_MAX_BYTES} bytes" ))) @@ -177,7 +175,7 @@ fn extract_required_array_field<'a>( match object.get(field) { | Some(CanonicalJsonValue::Array(value)) => if value.len() > max_len { - Err!(Request(InvalidParam( + Err!(Request(TooLarge( "invalid `{field}` field in PDU: array length is larger than maximum of \ {max_len}" ))) diff --git a/src/service/membership/join.rs b/src/service/membership/join.rs index aeac074a..7633e4b6 100644 --- a/src/service/membership/join.rs +++ b/src/service/membership/join.rs @@ -225,6 +225,8 @@ pub async fn join_remote( .server_keys .gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?; + state_res::check_pdu_format(&join_event_stub, &room_version_rules.event_format)?; + // It has enough fields to be called a proper event now let mut join_event = join_event_stub; @@ -634,6 +636,8 @@ pub async fn join_local( )); } + let room_version_rules = room_version::rules(&room_version_id)?; + let mut join_event_stub: CanonicalJsonObject = serde_json::from_str(make_join_response.event.get()).map_err(|e| { err!(BadServerResponse("Invalid make_join event json received from server: {e:?}")) @@ -699,6 +703,8 @@ pub async fn join_local( .server_keys .gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?; + state_res::check_pdu_format(&join_event_stub, &room_version_rules.event_format)?; + // It has enough fields to be called a proper event now let join_event = join_event_stub; diff --git a/src/service/membership/leave.rs b/src/service/membership/leave.rs index 5e67f0ec..662ebfe3 100644 --- a/src/service/membership/leave.rs +++ b/src/service/membership/leave.rs @@ -11,8 +11,9 @@ use ruma::{ }; use tuwunel_core::{ Err, Result, debug_info, debug_warn, err, implement, - matrix::PduCount, + matrix::{PduCount, room_version}, pdu::PduBuilder, + state_res, utils::{self, FutureBoolExt, future::ReadyBoolExt}, warn, }; @@ -278,6 +279,8 @@ async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result { ))); } + let room_version_rules = room_version::rules(&room_version_id)?; + let mut leave_event_stub = serde_json::from_str::( make_leave_response.event.get(), ) @@ -312,6 +315,8 @@ async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result { .server_keys .gen_id_hash_and_sign_event(&mut leave_event_stub, &room_version_id)?; + state_res::check_pdu_format(&leave_event_stub, &room_version_rules.event_format)?; + // It has enough fields to be called a proper event now let leave_event = leave_event_stub; diff --git a/src/service/rooms/event_handler/handle_outlier_pdu.rs b/src/service/rooms/event_handler/handle_outlier_pdu.rs index dbfe0d89..8e47e3b7 100644 --- a/src/service/rooms/event_handler/handle_outlier_pdu.rs +++ b/src/service/rooms/event_handler/handle_outlier_pdu.rs @@ -68,6 +68,8 @@ pub(super) async fn handle_outlier_pdu( let room_rules = room_version::rules(room_version)?; + state_res::check_pdu_format(&pdu_json, &room_rules.event_format)?; + // Now that we have checked the signature and hashes we can make mutations and // convert to our PduEvent type. let event = from_incoming_federation(room_id, event_id, &mut pdu_json, &room_rules)?; diff --git a/src/service/rooms/event_handler/upgrade_outlier_pdu.rs b/src/service/rooms/event_handler/upgrade_outlier_pdu.rs index eedd1eb6..dbc4d840 100644 --- a/src/service/rooms/event_handler/upgrade_outlier_pdu.rs +++ b/src/service/rooms/event_handler/upgrade_outlier_pdu.rs @@ -52,6 +52,8 @@ pub(super) async fn upgrade_outlier_to_timeline_pdu( let timer = Instant::now(); let room_rules = room_version::rules(room_version)?; + state_res::check_pdu_format(&val, &room_rules.event_format)?; + // 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. // These are not timeline events. diff --git a/src/service/rooms/timeline/create.rs b/src/service/rooms/timeline/create.rs index bfd43e4e..2aeb193c 100644 --- a/src/service/rooms/timeline/create.rs +++ b/src/service/rooms/timeline/create.rs @@ -187,17 +187,7 @@ pub async fn create_hash_and_sign_event( pdu.event_id = self .services .server_keys - .gen_id_hash_and_sign_event(&mut pdu_json, &room_version) - .map_err(|e| { - use Error::Signatures; - use ruma::signatures::Error::PduSize; - match e { - | Signatures(PduSize) => { - err!(Request(TooLarge("PDU exceeds 65535 bytes"))) - }, - | _ => err!(Request(Unknown(warn!("Signing event failed: {e}")))), - } - })?; + .gen_id_hash_and_sign_event(&mut pdu_json, &room_version)?; // Room id is event id for V12+ if matches!(version_rules.room_id_format, RoomIdFormatVersion::V2) @@ -207,6 +197,8 @@ pub async fn create_hash_and_sign_event( pdu_json.insert("room_id".into(), CanonicalJsonValue::String(pdu.room_id.clone().into())); } + state_res::check_pdu_format(&pdu_json, &version_rules.event_format)?; + // Generate short event id let _shorteventid = self .services diff --git a/src/service/server_keys/sign.rs b/src/service/server_keys/sign.rs index ecedccd2..4ad7a296 100644 --- a/src/service/server_keys/sign.rs +++ b/src/service/server_keys/sign.rs @@ -1,6 +1,6 @@ use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, RoomVersionId}; use tuwunel_core::{ - Result, implement, + Result, err, implement, matrix::{event::gen_event_id, room_version}, }; @@ -73,7 +73,15 @@ pub fn hash_and_sign_event( object, &room_version_rules.redaction, ) - .map_err(Into::into) + .map_err(|e| { + use ruma::signatures::Error::PduSize; + match e { + | PduSize => { + err!(Request(TooLarge("PDU exceeds 65535 bytes"))) + }, + | _ => err!(Request(Unknown(warn!("Signing event failed: {e}")))), + } + }) } #[implement(super::Service)]