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 id;
mod raw_id;
mod redact;
#[cfg(test)]
mod tests;
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())
.await?;
match room_version_id {
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
if let Some(redact_id) = 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;
let event_id = match room_version_id {
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => pdu.redacts(),
| _ => {
let content: RoomRedactionEventContent = pdu.get_content()?;
if let Some(redact_id) = &content.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?;
}
content = pdu.get_content()?;
content.redacts.as_deref()
},
};
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 =>

View File

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