Skip to content

Commit 4c3e55c

Browse files
committed
api: Reject non-object event content on /send and /state.
Per spec, event content is required to be a JSON object. The send endpoints accepted any valid JSON value, including bare strings and arrays. Signed-off-by: Jason Volk <jason@zemos.net>
1 parent 050b222 commit 4c3e55c

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

crates/ruma-client-api/src/message/send_message_event.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ pub mod v3 {
5151

5252
/// The event content to send.
5353
#[ruma_api(body)]
54+
#[serde(deserialize_with = "ruma_common::serde::deserialize_raw_object")]
5455
pub body: Raw<AnyMessageLikeEventContent>,
5556

5657
/// Timestamp to use for the `origin_server_ts` of the event.

crates/ruma-client-api/src/state/send_state_event.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,16 @@ pub mod v3 {
181181
let request_query: RequestQuery =
182182
serde_html_form::from_str(request.uri().query().unwrap_or(""))?;
183183

184-
let body = serde_json::from_slice(request.body().as_ref())?;
184+
let body: Raw<AnyStateEventContent> = serde_json::from_slice(request.body().as_ref())?;
185+
if !body.json().get().trim_start().starts_with('{') {
186+
return Err(ruma_common::api::error::DeserializationError::Json(
187+
serde::de::Error::invalid_type(
188+
serde::de::Unexpected::Other("non-object value"),
189+
&"a JSON object",
190+
),
191+
)
192+
.into());
193+
}
185194

186195
Ok(Self { room_id, event_type, state_key, body, timestamp: request_query.timestamp })
187196
}

crates/ruma-common/src/serde.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,25 @@ where
167167
deserializer.deserialize_seq(SkipInvalid(PhantomData))
168168
}
169169

170+
/// Deserialize a `Raw<T>` and reject any value whose top-level JSON shape is
171+
/// not an object. Use as `#[serde(deserialize_with =
172+
/// "ruma_common::serde::deserialize_raw_object")]` on request body fields where the Matrix spec
173+
/// mandates an object (e.g., `Raw<EventContent>` for `/_matrix/client/.../send` endpoints).
174+
pub fn deserialize_raw_object<'de, T, D>(deserializer: D) -> Result<crate::serde::Raw<T>, D::Error>
175+
where
176+
D: Deserializer<'de>,
177+
{
178+
use serde::de::Error;
179+
let raw = <crate::serde::Raw<T> as Deserialize>::deserialize(deserializer)?;
180+
if !raw.json().get().trim_start().starts_with('{') {
181+
return Err(D::Error::invalid_type(
182+
serde::de::Unexpected::Other("non-object value"),
183+
&"a JSON object",
184+
));
185+
}
186+
Ok(raw)
187+
}
188+
170189
pub use ruma_macros::{
171190
_FakeDeriveSerde, AsRefStr, AsStrAsRefStr, DebugAsRefStr, DeserializeFromCowStr,
172191
DisplayAsRefStr, EqAsRefStr, FromString, OrdAsRefStr, SerializeAsRefStr, StringEnum,

0 commit comments

Comments
 (0)