Non-reserializing redaction

This commit is contained in:
dasha_uwu
2026-01-20 23:19:08 +05:00
committed by Jason Volk
parent 0c9a3abb71
commit 8000fcce9e
4 changed files with 44 additions and 79 deletions

View File

@@ -4,7 +4,6 @@ pub mod format;
mod hashes; mod hashes;
mod id; mod id;
mod raw_id; mod raw_id;
mod redact;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
mod unsigned; mod unsigned;

View File

@@ -1,35 +0,0 @@
use ruma::{RoomVersionId, canonical_json::redact_content_in_place};
use serde_json::{Value as JsonValue, json, value::to_raw_value};
use crate::{Error, Result, err, implement};
#[implement(super::Pdu)]
pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: JsonValue) -> Result {
self.unsigned = None;
let mut content = serde_json::from_str(self.content.get())
.map_err(|e| err!(Request(BadJson("Failed to deserialize content into type: {e}"))))?;
let room_version_rules = room_version_id.rules().ok_or_else(|| {
err!(Request(UnsupportedRoomVersion(
"Cannot redact event for unknown room version {room_version_id:?}."
)))
})?;
redact_content_in_place(&mut content, &room_version_rules.redaction, self.kind.to_string())
.map_err(|e| Error::Redaction(self.sender.server_name().to_owned(), e))?;
let reason = serde_json::to_value(reason).expect("Failed to preserialize reason");
let redacted_because = json!({
"redacted_because": reason,
});
self.unsigned = to_raw_value(&redacted_because)
.expect("Failed to serialize unsigned")
.into();
self.content = to_raw_value(&content).expect("Failed to serialize content");
Ok(())
}

View File

@@ -218,32 +218,23 @@ async fn append_pdu_effects(
.get_room_version(pdu.room_id()) .get_room_version(pdu.room_id())
.await?; .await?;
match room_version_id { let content: RoomRedactionEventContent;
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => { let event_id = match room_version_id {
if let Some(redact_id) = pdu.redacts() | V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => pdu.redacts(),
&& self
.services
.state_accessor
.user_can_redact(redact_id, pdu.sender(), pdu.room_id(), false)
.await?
{
self.redact_pdu(redact_id, pdu, shortroomid)
.await?;
}
},
| _ => { | _ => {
let content: RoomRedactionEventContent = pdu.get_content()?; content = pdu.get_content()?;
if let Some(redact_id) = &content.redacts content.redacts.as_deref()
&& self
.services
.state_accessor
.user_can_redact(redact_id, pdu.sender(), pdu.room_id(), false)
.await?
{
self.redact_pdu(redact_id, pdu, shortroomid)
.await?;
}
}, },
};
if let Some(redact_id) = event_id
&& self
.services
.state_accessor
.user_can_redact(redact_id, pdu.sender(), pdu.room_id(), false)
.await?
{
self.redact_pdu(redact_id, pdu, shortroomid)
.await?;
} }
}, },
| TimelineEventType::SpaceChild => | TimelineEventType::SpaceChild =>

View File

@@ -1,11 +1,9 @@
use ruma::EventId; use ruma::{
use tuwunel_core::{ EventId, RoomId,
Result, err, implement, canonical_json::{RedactedBecause, redact_in_place},
matrix::event::Event,
utils::{self},
}; };
use tuwunel_core::{Result, err, implement, matrix::event::Event};
use super::ExtractBody;
use crate::rooms::short::ShortRoomId; use crate::rooms::short::ShortRoomId;
/// Replace a PDU with the redacted form. /// Replace a PDU with the redacted form.
@@ -17,39 +15,51 @@ pub async fn redact_pdu<Pdu: Event + Send + Sync>(
reason: &Pdu, reason: &Pdu,
shortroomid: ShortRoomId, shortroomid: ShortRoomId,
) -> Result { ) -> Result {
// TODO: Don't reserialize, keep original json
let Ok(pdu_id) = self.get_pdu_id(event_id).await else { let Ok(pdu_id) = self.get_pdu_id(event_id).await else {
// If event does not exist, just noop // If event does not exist, just noop
// TODO this is actually wrong!
return Ok(()); return Ok(());
}; };
let mut pdu = self let mut pdu = self
.get_pdu_from_id(&pdu_id) .get_pdu_json_from_id(&pdu_id)
.await .await
.map(Event::into_pdu)
.map_err(|e| { .map_err(|e| {
err!(Database(error!(?pdu_id, ?event_id, ?e, "PDU ID points to invalid PDU."))) err!(Database(error!(?pdu_id, ?event_id, ?e, "PDU ID points to invalid PDU.")))
})?; })?;
if let Ok(content) = pdu.get_content::<ExtractBody>() let body = pdu["content"]
&& let Some(body) = content.body .as_object()
{ .unwrap()
.get("body")
.and_then(|body| body.as_str());
if let Some(body) = body {
self.services self.services
.search .search
.deindex_pdu(shortroomid, &pdu_id, &body); .deindex_pdu(shortroomid, &pdu_id, body);
} }
let room_id = RoomId::parse(pdu["room_id"].as_str().unwrap()).unwrap();
let room_version_id = self let room_version_id = self
.services .services
.state .state
.get_room_version(pdu.room_id()) .get_room_version(room_id)
.await?; .await?;
pdu.redact(&room_version_id, reason.to_value())?; let room_version_rules = room_version_id.rules().ok_or_else(|| {
err!(Request(UnsupportedRoomVersion(
let obj = utils::to_canonical_object(&pdu).map_err(|e| { "Cannot redact event for unknown room version {room_version_id:?}."
err!(Database(error!(?event_id, ?e, "Failed to convert PDU to canonical JSON"))) )))
})?; })?;
self.replace_pdu(&pdu_id, &obj).await redact_in_place(
&mut pdu,
&room_version_rules.redaction,
Some(RedactedBecause::from_json(reason.to_canonical_object())),
)
.map_err(|err| err!("invalid event: {err}"))?;
self.replace_pdu(&pdu_id, &pdu).await
} }