Skip to content

Commit

Permalink
feat: disallow events with unexpected fields via the http api (#363)
Browse files Browse the repository at this point in the history
* feat: disallow events with unexpected fields via the http api

* review comments
  • Loading branch information
stbrody authored May 30, 2024
1 parent 9fbc34c commit f1c2a6f
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 5 deletions.
29 changes: 25 additions & 4 deletions api/src/server/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ where
R: AsyncRead + Send + Unpin,
S: EventStore,
{
let (event_cid, event) = event_from_car(reader).await?;
let (event_cid, event) = event_from_car(reader, true).await?;
event_id_for_event(event_cid, event, network, store).await
}

async fn event_from_car<R>(reader: R) -> Result<(Cid, unvalidated::Event<Ipld>)>
async fn event_from_car<R>(
reader: R,
deny_unexpected_fields: bool,
) -> Result<(Cid, unvalidated::Event<Ipld>)>
where
R: AsyncRead + Send + Unpin,
{
Expand All @@ -42,7 +45,17 @@ where
.ok_or_else(|| anyhow!("Event CAR data missing block for root CID"))?;
let raw_event: unvalidated::RawEvent<Ipld> =
serde_ipld_dagcbor::from_slice(event_bytes).context("decoding event")?;
// TODO(stbrody) add check for round-trip-ability to catch extra fields.

if deny_unexpected_fields {
// Re-serialize the event and compare the bytes. This indirectly checks that there were no
// unexpected fields in the event sent by the client.
let event_bytes_reserialized = serde_ipld_dagcbor::to_vec(&raw_event)?;
if !event_bytes.eq(&event_bytes_reserialized) {
bail!(
"Event bytes do not round-trip. This most likely means the event contains unexpected fields."
);
}
}

match raw_event {
unvalidated::RawEvent::Time(event) => Ok((event_cid, unvalidated::Event::Time(event))),
Expand All @@ -56,7 +69,15 @@ where
.ok_or_else(|| anyhow!("Signed Event CAR data missing block for payload"))?;
let payload: unvalidated::Payload<Ipld> =
serde_ipld_dagcbor::from_slice(payload_bytes).context("decoding payload")?;
// TODO(stbrody) add check for round-trip-ability to catch extra fields.

if deny_unexpected_fields {
// Re-serialize the payload and compare the bytes. This indirectly checks that there
// were no unexpected fields in the event sent by the client.
let payload_bytes_reserialized = serde_ipld_dagcbor::to_vec(&payload)?;
if !payload_bytes.eq(&payload_bytes_reserialized) {
bail!("Signed event payload bytes do not round-trip. This most likely means the event contains unexpected fields.");
}
}

Ok((
event_cid,
Expand Down
1 change: 0 additions & 1 deletion event/src/unvalidated/payload/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Payload<D> {
header: Header,
#[serde(skip_serializing_if = "Option::is_none")]
data: Option<D>,
}

Expand Down

0 comments on commit f1c2a6f

Please sign in to comment.