fix: Move helper to helpers.rs, rename field, don't recurse unsigned in redacted_because

Renamed `redacted_because_id` to `org.continuwuity.redacted_by` for proper namespacing; `get_unsigned_context` now lives in helpers.rs instead of `mod.rs`. The helper function also now explicitly wipes `unsigned` for `redacted_because` to avoid leaks (see comment).
This commit is contained in:
timedout committed 2026-09-27 17:32:46 +01:00
1 parent 89eecd2bf7
commit 05ee24df7d
5 files changed
+129 -154

No files matched your search

+1 -1
View File
@@ -26,7 +26,7 @@ impl super::Pdu {
if let Some(event_id) = redacted_because {
self.unsigned = to_raw_value(&json!({
"redacted_because_id": event_id,
"org.continuwuity.redacted_by": event_id,
}))
.expect("Failed to serialize unsigned")
.into();
+3 -4
View File
@@ -64,7 +64,7 @@ fn nonsense_sticky_object_does_not_reject_the_pdu() {
#[test]
fn redaction_removes_stickiness() {
let mut pdu = sticky_pdu(&serde_json::json!({ "duration_ms": 300_000 }));
pdu.redact(&ruma::RoomVersionId::V11, serde_json::json!({}))
pdu.redact(&ruma::RoomVersionId::V11, None)
.expect("redaction succeeds");
assert!(pdu.sticky.is_none());
@@ -74,7 +74,7 @@ fn redaction_removes_stickiness() {
fn sticky_ttl_is_added_to_unsigned() {
let mut pdu = sticky_pdu(&serde_json::json!({ "duration_ms": 300_000 }));
pdu.origin_server_ts = ruma::MilliSecondsSinceUnixEpoch::now().get();
pdu.add_sticky_duration_ttl().expect("ttl is added");
pdu.set_unsigned(None, None, None, None);
let unsigned: serde_json::Value =
serde_json::from_str(pdu.unsigned.as_deref().expect("unsigned is set").get())
@@ -88,8 +88,7 @@ fn sticky_ttl_is_added_to_unsigned() {
#[test]
fn no_ttl_for_events_that_are_not_sticky() {
let mut pdu = sticky_pdu(&serde_json::json!({ "duration_ms": "nonsense" }));
pdu.add_sticky_duration_ttl().expect("ttl is skipped");
let pdu = sticky_pdu(&serde_json::json!({ "duration_ms": "nonsense" }));
assert!(pdu.unsigned.is_none());
}
+19 -58
View File
@@ -5,10 +5,10 @@ use ruma::{
events::{AnyTimelineEvent, room::member::MembershipState},
serde::Raw,
};
use serde_json::value::{RawValue as RawJsonValue, Value as JsonValue, to_raw_value};
use serde_json::value::{RawValue as RawJsonValue, to_raw_value};
use super::{Pdu, sticky};
use crate::{Event, Result, err, result::LogErr};
use crate::Event;
type Unsigned = BTreeMap<String, Box<RawJsonValue>>;
@@ -26,17 +26,18 @@ impl Pdu {
redacted_because: Option<Raw<AnyTimelineEvent>>,
) {
// See: https://spec.matrix.org/v1.19/client-server-api/#definition-clientevent_unsigneddata
let Some(mut unsigned) = self
.unsigned()
.and_then(|u| serde_json::from_str::<Unsigned>(u.get()).ok())
else {
let Some(mut unsigned) = self.unsigned().map_or_else(
|| Some(Unsigned::new()),
|u| serde_json::from_str::<Unsigned>(u.get()).ok(),
) else {
return;
};
let now: ruma::Int = MilliSecondsSinceUnixEpoch::now().get().into();
let now = MilliSecondsSinceUnixEpoch::now().get();
let now_i: ruma::Int = now.into();
unsigned.insert(
"age".to_owned(),
to_raw_value(&now.saturating_sub(self.origin_server_ts.into())).unwrap(),
to_raw_value(&now_i.saturating_sub(self.origin_server_ts.into())).unwrap(),
);
if let Some(membership) = membership {
@@ -51,7 +52,7 @@ impl Pdu {
);
}
if let Some(redacted_because) = redacted_because {
unsigned.remove("redacted_because_id");
unsigned.remove("org.continuwuity.redacted_by");
unsigned.insert(
"redacted_because".to_owned(),
to_raw_value(&redacted_because)
@@ -63,57 +64,17 @@ impl Pdu {
if user_id.is_none_or(|u| u != self.sender()) {
unsigned.remove("transaction_id");
}
self.add_sticky_duration_ttl().log_err().ok();
}
pub fn add_sticky_duration_ttl(&mut self) -> Result {
use BTreeMap as Map;
let now = u64::from(MilliSecondsSinceUnixEpoch::now().get());
let Some(expires_at) = self
if let Some(expires_at) = self
.sticky
.as_deref()
.and_then(|sticky| sticky::expires_at(self.origin_server_ts, sticky, now))
else {
return Ok(());
};
let mut unsigned: Map<&str, Box<RawJsonValue>> = self
.unsigned
.as_deref()
.map(RawJsonValue::get)
.map_or_else(|| Ok(Map::new()), serde_json::from_str)
.map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
unsigned.insert(sticky::TTL_UNSIGNED_KEY, to_raw_value(&expires_at.saturating_sub(now))?);
self.unsigned = Some(to_raw_value(&unsigned)?);
Ok(())
}
pub fn add_relation(&mut self, name: &str, pdu: Option<&Self>) -> Result {
use serde_json::Map;
let mut unsigned: Map<String, JsonValue> = self
.unsigned
.as_deref()
.map(RawJsonValue::get)
.map_or_else(|| Ok(Map::new()), serde_json::from_str)
.map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
let pdu = pdu
.map(serde_json::to_value)
.transpose()?
.unwrap_or_else(|| JsonValue::Object(Map::new()));
unsigned
.entry("m.relations")
.or_insert(JsonValue::Object(Map::new()))
.as_object_mut()
.map(|object| object.insert(name.to_owned(), pdu));
self.unsigned = Some(to_raw_value(&unsigned)?);
Ok(())
.and_then(|sticky| sticky::expires_at(self.origin_server_ts, sticky, u64::from(now)))
{
unsigned.insert(
sticky::TTL_UNSIGNED_KEY.to_owned(),
to_raw_value(&expires_at.saturating_sub(u64::from(now)))
.expect("sticky event TTL must be a valid JSON value for unsigned"),
);
}
}
}