Add v1/v2 support to gen_event_id() scheme. (#12)

Add v1/v2 and improve reference and content hashing suite. (#12)

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk
2025-08-31 17:17:53 +00:00
parent 6a583a359e
commit 13c9385ef7
2 changed files with 90 additions and 15 deletions

View File

@@ -1,4 +1,4 @@
use ruma::{CanonicalJsonObject, OwnedEventId, RoomVersionId};
use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, RoomVersionId};
use serde_json::value::RawValue as RawJsonValue;
use crate::{Result, debug_error, err, matrix::room_version};
@@ -20,13 +20,36 @@ pub fn gen_event_id_canonical_json(
Ok((event_id, value))
}
/// Generates a correct eventId for the incoming pdu.
/// Generates a correct eventId for the PDU. For v1/v2 incoming PDU's the
/// value's event_id is passed through. For all outgoing PDU's and for v3+
/// incoming PDU's it is generated.
pub fn gen_event_id(
value: &CanonicalJsonObject,
room_version_id: &RoomVersionId,
) -> Result<OwnedEventId> {
let room_version_rules = room_version::rules(room_version_id)?;
let require_event_id = room_version_rules.event_format.require_event_id;
// We don't actually generate any event_id for incoming events in v1/v2 rooms,
// just pass them through.
if let Some(event_id) = require_event_id
.then(|| value.get("event_id"))
.flatten()
.and_then(CanonicalJsonValue::as_str)
.map(OwnedEventId::try_from)
.transpose()?
{
return Ok(event_id);
}
// For outgoing v1/v2 add the server part. This has to be our origin but we
// can't assert that here.
let server_name = require_event_id
.then(|| value.get("origin"))
.flatten()
.and_then(CanonicalJsonValue::as_str);
let reference_hash = ruma::signatures::reference_hash(value, &room_version_rules)?;
OwnedEventId::from_parts('$', &reference_hash, None).map_err(Into::into)
OwnedEventId::from_parts('$', &reference_hash, server_name).map_err(Into::into)
}

View File

@@ -1,28 +1,71 @@
use ruma::{CanonicalJsonObject, RoomVersionId};
use tuwunel_core::{Result, err, implement};
use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, RoomVersionId};
use tuwunel_core::{
Result, implement,
matrix::{event::gen_event_id, room_version},
};
#[implement(super::Service)]
pub fn sign_json(&self, object: &mut CanonicalJsonObject) -> Result {
use ruma::signatures::sign_json;
pub fn gen_id_hash_and_sign_event(
&self,
object: &mut CanonicalJsonObject,
room_version_id: &RoomVersionId,
) -> Result<OwnedEventId> {
object.remove("event_id");
let server_name = self.services.globals.server_name().as_str();
sign_json(server_name, self.keypair(), object).map_err(Into::into)
if room_version::rules(room_version_id)?
.event_format
.require_event_id
{
self.gen_id_hash_and_sign_event_v1(object, room_version_id)
} else {
self.gen_id_hash_and_sign_event_v3(object, room_version_id)
}
}
#[implement(super::Service)]
fn gen_id_hash_and_sign_event_v1(
&self,
object: &mut CanonicalJsonObject,
room_version_id: &RoomVersionId,
) -> Result<OwnedEventId> {
let event_id = gen_event_id(object, room_version_id)?;
object.insert("event_id".into(), CanonicalJsonValue::String(event_id.clone().into()));
self.services
.server_keys
.hash_and_sign_event(object, room_version_id)?;
Ok(event_id)
}
#[implement(super::Service)]
fn gen_id_hash_and_sign_event_v3(
&self,
object: &mut CanonicalJsonObject,
room_version_id: &RoomVersionId,
) -> Result<OwnedEventId> {
self.services
.server_keys
.hash_and_sign_event(object, room_version_id)?;
let event_id = gen_event_id(object, room_version_id)?;
object.insert("event_id".into(), CanonicalJsonValue::String(event_id.clone().into()));
Ok(event_id)
}
#[implement(super::Service)]
pub fn hash_and_sign_event(
&self,
object: &mut CanonicalJsonObject,
room_version: &RoomVersionId,
room_version_id: &RoomVersionId,
) -> Result {
use ruma::signatures::hash_and_sign_event;
let server_name = &self.services.server.name;
let room_version_rules = room_version.rules().ok_or_else(|| {
err!(Request(UnsupportedRoomVersion(
"Cannot hash and sign event for unknown room version {room_version:?}."
)))
})?;
let room_version_rules = room_version::rules(room_version_id)?;
hash_and_sign_event(
server_name.as_str(),
@@ -32,3 +75,12 @@ pub fn hash_and_sign_event(
)
.map_err(Into::into)
}
#[implement(super::Service)]
pub fn sign_json(&self, object: &mut CanonicalJsonObject) -> Result {
use ruma::signatures::sign_json;
let server_name = self.services.globals.server_name().as_str();
sign_json(server_name, self.keypair(), object).map_err(Into::into)
}