mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2025-06-26 17:46:36 +02:00
feat: Allow retrieving redacted message content (msc2815)
Still to do: - Handling the difference between content that we have deleted and content we never received - Deleting the original content on command or expiry Another question is if we have to store the full original content? Can we get by with just storing the 'content' field?
This commit is contained in:
parent
88ecf61d49
commit
46b1eeb2c8
4 changed files with 67 additions and 2 deletions
|
@ -1,7 +1,7 @@
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use conduwuit::{Err, Event, Result, err};
|
use conduwuit::{Err, Event, PduEvent, Result, err};
|
||||||
use futures::{FutureExt, TryFutureExt, future::try_join};
|
use futures::{FutureExt, TryFutureExt, future::try_join};
|
||||||
use ruma::api::client::room::get_room_event;
|
use ruma::api::client::{error::ErrorKind, room::get_room_event};
|
||||||
|
|
||||||
use crate::{Ruma, client::is_ignored_pdu};
|
use crate::{Ruma, client::is_ignored_pdu};
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ pub(crate) async fn get_room_event_route(
|
||||||
) -> Result<get_room_event::v3::Response> {
|
) -> Result<get_room_event::v3::Response> {
|
||||||
let event_id = &body.event_id;
|
let event_id = &body.event_id;
|
||||||
let room_id = &body.room_id;
|
let room_id = &body.room_id;
|
||||||
|
let sender_user = body.sender_user();
|
||||||
|
|
||||||
let event = services
|
let event = services
|
||||||
.rooms
|
.rooms
|
||||||
|
@ -33,6 +34,52 @@ pub(crate) async fn get_room_event_route(
|
||||||
return Err!(Request(Forbidden("You don't have permission to view this event.")));
|
return Err!(Request(Forbidden("You don't have permission to view this event.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let include_unredacted_content = body
|
||||||
|
.include_unredacted_content // User's file has this field name
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if include_unredacted_content && event.is_redacted() {
|
||||||
|
let is_server_admin = services
|
||||||
|
.users
|
||||||
|
.is_admin(sender_user)
|
||||||
|
.map(|is_admin| Ok(is_admin));
|
||||||
|
let can_redact_privilege = services
|
||||||
|
.rooms
|
||||||
|
.state_accessor
|
||||||
|
.user_can_redact(event_id, sender_user, room_id, false) // federation=false for local check
|
||||||
|
;
|
||||||
|
let (is_server_admin, can_redact_privilege) =
|
||||||
|
try_join(is_server_admin, can_redact_privilege).await?;
|
||||||
|
|
||||||
|
if !is_server_admin && !can_redact_privilege {
|
||||||
|
return Err!(Request(Forbidden(
|
||||||
|
"You don't have permission to view redacted content.",
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let pdu_id = match services.rooms.timeline.get_pdu_id(event_id).await {
|
||||||
|
| Ok(id) => id,
|
||||||
|
| Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let original_content = services
|
||||||
|
.rooms
|
||||||
|
.timeline
|
||||||
|
.get_original_pdu_content(&pdu_id)
|
||||||
|
.await?;
|
||||||
|
if let Some(original_content) = original_content {
|
||||||
|
// If the original content is available, we can return it.
|
||||||
|
// event.content = to_raw_value(&original_content)?;
|
||||||
|
event = PduEvent::from_id_val(event_id, original_content)?;
|
||||||
|
} else {
|
||||||
|
return Err(conduwuit::Error::BadRequest(
|
||||||
|
ErrorKind::UnredactedContentDeleted { content_keep_ms: None },
|
||||||
|
"The original unredacted content is not in the database.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
event.event_id() == event_id && event.room_id() == room_id,
|
event.event_id() == event_id && event.room_id() == room_id,
|
||||||
"Fetched PDU must match requested"
|
"Fetched PDU must match requested"
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub(crate) async fn get_supported_versions_route(
|
||||||
"v1.11".to_owned(),
|
"v1.11".to_owned(),
|
||||||
],
|
],
|
||||||
unstable_features: BTreeMap::from_iter([
|
unstable_features: BTreeMap::from_iter([
|
||||||
|
("fi.mau.msc2815".to_owned(), true),
|
||||||
("org.matrix.e2e_cross_signing".to_owned(), true),
|
("org.matrix.e2e_cross_signing".to_owned(), true),
|
||||||
("org.matrix.msc2285.stable".to_owned(), true), /* private read receipts (https://github.com/matrix-org/matrix-spec-proposals/pull/2285) */
|
("org.matrix.msc2285.stable".to_owned(), true), /* private read receipts (https://github.com/matrix-org/matrix-spec-proposals/pull/2285) */
|
||||||
("uk.half-shot.msc2666.query_mutual_rooms".to_owned(), true), /* query mutual rooms (https://github.com/matrix-org/matrix-spec-proposals/pull/2666) */
|
("uk.half-shot.msc2666.query_mutual_rooms".to_owned(), true), /* query mutual rooms (https://github.com/matrix-org/matrix-spec-proposals/pull/2666) */
|
||||||
|
|
|
@ -190,6 +190,14 @@ impl Data {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the original content of a redacted PDU.
|
||||||
|
pub(super) async fn get_original_pdu_content(
|
||||||
|
&self,
|
||||||
|
pdu_id: &RawPduId,
|
||||||
|
) -> Result<Option<CanonicalJsonObject>> {
|
||||||
|
self.pduid_originalcontent.get(pdu_id).await.deserialized()
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) async fn append_pdu(
|
pub(super) async fn append_pdu(
|
||||||
&self,
|
&self,
|
||||||
pdu_id: &RawPduId,
|
pdu_id: &RawPduId,
|
||||||
|
|
|
@ -270,6 +270,15 @@ impl Service {
|
||||||
self.db.store_redacted_pdu_content(pdu_id, pdu_json).await
|
self.db.store_redacted_pdu_content(pdu_id, pdu_json).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the original content of a redacted PDU.
|
||||||
|
#[tracing::instrument(skip(self), level = "debug")]
|
||||||
|
pub async fn get_original_pdu_content(
|
||||||
|
&self,
|
||||||
|
pdu_id: &RawPduId,
|
||||||
|
) -> Result<Option<CanonicalJsonObject>> {
|
||||||
|
self.db.get_original_pdu_content(pdu_id).await
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new persisted data unit and adds it to a room.
|
/// Creates a new persisted data unit and adds it to a room.
|
||||||
///
|
///
|
||||||
/// By this point the incoming event should be fully authenticated, no auth
|
/// By this point the incoming event should be fully authenticated, no auth
|
||||||
|
|
Loading…
Add table
Reference in a new issue