Add optional redacted_because insertion to redaction

This commit is contained in:
Jonas Platte 2022-12-19 12:10:39 +01:00
parent 4f821d39ce
commit 284b797e05
No known key found for this signature in database
GPG Key ID: AAA7A61F696C3E0C
3 changed files with 62 additions and 7 deletions

View File

@ -8,6 +8,11 @@ use serde_json::Value as JsonValue;
mod value; mod value;
use crate::RoomVersionId; use crate::RoomVersionId;
#[cfg(feature = "events")]
use crate::{
events::room::redaction::{OriginalRoomRedactionEvent, OriginalSyncRoomRedactionEvent},
serde::Raw,
};
pub use self::value::{CanonicalJsonObject, CanonicalJsonValue}; pub use self::value::{CanonicalJsonObject, CanonicalJsonValue};
@ -116,6 +121,36 @@ pub fn to_canonical_value<T: Serialize>(
serde_json::to_value(value).map_err(CanonicalJsonError::SerDe)?.try_into() serde_json::to_value(value).map_err(CanonicalJsonError::SerDe)?.try_into()
} }
/// The value to put in `unsigned.redacted_because`.
///
/// See `From` implementations for ways to create an instance of this type.
#[derive(Clone, Debug)]
pub struct RedactedBecause(CanonicalJsonObject);
impl From<CanonicalJsonObject> for RedactedBecause {
fn from(obj: CanonicalJsonObject) -> Self {
Self(obj)
}
}
#[cfg(feature = "events")]
impl TryFrom<&Raw<OriginalRoomRedactionEvent>> for RedactedBecause {
type Error = serde_json::Error;
fn try_from(value: &Raw<OriginalRoomRedactionEvent>) -> Result<Self, Self::Error> {
value.deserialize_as().map(Self)
}
}
#[cfg(feature = "events")]
impl TryFrom<&Raw<OriginalSyncRoomRedactionEvent>> for RedactedBecause {
type Error = serde_json::Error;
fn try_from(value: &Raw<OriginalSyncRoomRedactionEvent>) -> Result<Self, Self::Error> {
value.deserialize_as().map(Self)
}
}
/// Redacts an event using the rules specified in the Matrix client-server specification. /// Redacts an event using the rules specified in the Matrix client-server specification.
/// ///
/// This is part of the process of signing an event. /// This is part of the process of signing an event.
@ -127,7 +162,10 @@ pub fn to_canonical_value<T: Serialize>(
/// ///
/// # Parameters /// # Parameters
/// ///
/// * object: A JSON object to redact. /// * `object`: A JSON object to redact.
/// * `version`: The room version, determines which keys to keep for a few event types.
/// * `redacted_because`: If this is set, an `unsigned` object with a `redacted_because` field set
/// to the given value is added to the event after redaction.
/// ///
/// # Errors /// # Errors
/// ///
@ -140,8 +178,9 @@ pub fn to_canonical_value<T: Serialize>(
pub fn redact( pub fn redact(
mut object: CanonicalJsonObject, mut object: CanonicalJsonObject,
version: &RoomVersionId, version: &RoomVersionId,
redacted_because: Option<RedactedBecause>,
) -> Result<CanonicalJsonObject, RedactionError> { ) -> Result<CanonicalJsonObject, RedactionError> {
redact_in_place(&mut object, version)?; redact_in_place(&mut object, version, redacted_because)?;
Ok(object) Ok(object)
} }
@ -153,6 +192,7 @@ pub fn redact(
pub fn redact_in_place( pub fn redact_in_place(
event: &mut CanonicalJsonObject, event: &mut CanonicalJsonObject,
version: &RoomVersionId, version: &RoomVersionId,
redacted_because: Option<RedactedBecause>,
) -> Result<(), RedactionError> { ) -> Result<(), RedactionError> {
// Get the content keys here even if they're only needed inside the branch below, because we // Get the content keys here even if they're only needed inside the branch below, because we
// can't teach rust that this is a disjoint borrow with `get_mut("content")`. // can't teach rust that this is a disjoint borrow with `get_mut("content")`.
@ -181,6 +221,14 @@ pub fn redact_in_place(
} }
} }
if let Some(redacted_because) = redacted_because {
let unsigned = CanonicalJsonObject::from_iter([(
"redacted_because".to_owned(),
redacted_because.0.into(),
)]);
event.insert("unsigned".to_owned(), unsigned.into());
}
Ok(()) Ok(())
} }

View File

@ -1,6 +1,6 @@
use std::{collections::BTreeMap, fmt}; use std::{collections::BTreeMap, fmt};
use js_int::Int; use js_int::{Int, UInt};
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize}; use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_json::{to_string as to_json_string, Value as JsonValue}; use serde_json::{to_string as to_json_string, Value as JsonValue};
@ -236,7 +236,7 @@ macro_rules! variant_impls {
($variant:ident($ty:ty)) => { ($variant:ident($ty:ty)) => {
impl From<$ty> for CanonicalJsonValue { impl From<$ty> for CanonicalJsonValue {
fn from(val: $ty) -> Self { fn from(val: $ty) -> Self {
Self::$variant(val) Self::$variant(val.into())
} }
} }
@ -263,9 +263,16 @@ macro_rules! variant_impls {
variant_impls!(Bool(bool)); variant_impls!(Bool(bool));
variant_impls!(Integer(Int)); variant_impls!(Integer(Int));
variant_impls!(String(String)); variant_impls!(String(String));
variant_impls!(String(&str));
variant_impls!(Array(Vec<CanonicalJsonValue>)); variant_impls!(Array(Vec<CanonicalJsonValue>));
variant_impls!(Object(CanonicalJsonObject)); variant_impls!(Object(CanonicalJsonObject));
impl From<UInt> for CanonicalJsonValue {
fn from(value: UInt) -> Self {
Self::Integer(value.into())
}
}
impl Serialize for CanonicalJsonValue { impl Serialize for CanonicalJsonValue {
#[inline] #[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@ -321,7 +321,7 @@ pub fn reference_hash(
value: &CanonicalJsonObject, value: &CanonicalJsonObject,
version: &RoomVersionId, version: &RoomVersionId,
) -> Result<String, Error> { ) -> Result<String, Error> {
let redacted_value = redact(value.clone(), version)?; let redacted_value = redact(value.clone(), version, None)?;
let json = let json =
canonical_json_with_fields_to_remove(&redacted_value, REFERENCE_HASH_FIELDS_TO_REMOVE)?; canonical_json_with_fields_to_remove(&redacted_value, REFERENCE_HASH_FIELDS_TO_REMOVE)?;
@ -458,7 +458,7 @@ where
_ => return Err(JsonError::not_of_type("hashes", JsonType::Object)), _ => return Err(JsonError::not_of_type("hashes", JsonType::Object)),
}; };
let mut redacted = redact(object.clone(), version)?; let mut redacted = redact(object.clone(), version, None)?;
sign_json(entity_id, key_pair, &mut redacted)?; sign_json(entity_id, key_pair, &mut redacted)?;
@ -539,7 +539,7 @@ pub fn verify_event(
object: &CanonicalJsonObject, object: &CanonicalJsonObject,
version: &RoomVersionId, version: &RoomVersionId,
) -> Result<Verified, Error> { ) -> Result<Verified, Error> {
let redacted = redact(object.clone(), version)?; let redacted = redact(object.clone(), version, None)?;
let hash = match object.get("hashes") { let hash = match object.get("hashes") {
Some(hashes_value) => match hashes_value { Some(hashes_value) => match hashes_value {