Skip to main content

tuwunel_service/server_keys/
sign.rs

1//! Local signing and event-ID generation helpers.
2//!
3//! Events are content-hashed and signed with the server's active Ed25519 key.
4//! Event-ID placement follows the selected room version's event format.
5
6use ruma::{CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, RoomVersionId};
7use tuwunel_core::{
8	Result, err, implement,
9	matrix::{event::gen_event_id, room_version},
10};
11
12/// Generates an event ID, content hash, and local signature in place.
13///
14/// Any existing `event_id` is removed first. Legacy room versions generate and
15/// insert the ID before signing; newer versions derive it after signing and then
16/// insert it into the returned object.
17#[implement(super::Service)]
18pub fn gen_id_hash_and_sign_event(
19	&self,
20	object: &mut CanonicalJsonObject,
21	room_version_id: &RoomVersionId,
22) -> Result<OwnedEventId> {
23	object.remove("event_id");
24
25	if room_version::rules(room_version_id)?
26		.event_format
27		.require_event_id
28	{
29		self.gen_id_hash_and_sign_event_v1(object, room_version_id)
30	} else {
31		self.gen_id_hash_and_sign_event_v3(object, room_version_id)
32	}
33}
34
35/// Generates and inserts an event ID before signing a legacy-format event.
36///
37/// The explicit ID participates in the content hash and signature for room
38/// versions whose event format requires it.
39#[implement(super::Service)]
40fn gen_id_hash_and_sign_event_v1(
41	&self,
42	object: &mut CanonicalJsonObject,
43	room_version_id: &RoomVersionId,
44) -> Result<OwnedEventId> {
45	let event_id = gen_event_id(object, room_version_id)?;
46
47	object.insert("event_id".into(), CanonicalJsonValue::String(event_id.clone().into()));
48
49	self.services
50		.server_keys
51		.hash_and_sign_event(object, room_version_id)?;
52
53	Ok(event_id)
54}
55
56/// Signs a modern-format event before deriving and inserting its event ID.
57///
58/// The derived ID therefore reflects the signed event representation used by
59/// room versions that omit an explicit ID during signing.
60#[implement(super::Service)]
61fn gen_id_hash_and_sign_event_v3(
62	&self,
63	object: &mut CanonicalJsonObject,
64	room_version_id: &RoomVersionId,
65) -> Result<OwnedEventId> {
66	self.services
67		.server_keys
68		.hash_and_sign_event(object, room_version_id)?;
69
70	let event_id = gen_event_id(object, room_version_id)?;
71
72	object.insert("event_id".into(), CanonicalJsonValue::String(event_id.clone().into()));
73
74	Ok(event_id)
75}
76
77/// Adds a content hash and local server signature to an event object.
78///
79/// Signing uses the room version's redaction rules. Oversized PDUs are mapped to
80/// a request-too-large error and other signing failures to an unknown request
81/// error.
82#[implement(super::Service)]
83pub fn hash_and_sign_event(
84	&self,
85	object: &mut CanonicalJsonObject,
86	room_version_id: &RoomVersionId,
87) -> Result {
88	use ruma::signatures::{add_content_hash_to_event, sign_event};
89
90	let server_name = &self.services.server.name;
91	let room_version_rules = room_version::rules(room_version_id)?;
92
93	let map_err = |e: ruma::signatures::JsonError| {
94		use ruma::signatures::JsonError::PduTooLarge;
95		match e {
96			| PduTooLarge => {
97				err!(Request(TooLarge("PDU exceeds 65535 bytes")))
98			},
99			| _ => err!(Request(Unknown(warn!("Signing event failed: {e}")))),
100		}
101	};
102
103	add_content_hash_to_event(object).map_err(map_err)?;
104	sign_event(server_name.as_str(), self.keypair(), object, &room_version_rules.redaction)
105		.map_err(map_err)
106}
107
108/// Signs an arbitrary canonical JSON object with the local server key.
109///
110/// The signature is inserted under the configured local server name without
111/// adding an event content hash.
112#[implement(super::Service)]
113pub fn sign_json(&self, object: &mut CanonicalJsonObject) -> Result {
114	use ruma::signatures::sign_json;
115
116	let server_name = self.services.globals.server_name().as_str();
117
118	sign_json(server_name, self.keypair(), object).map_err(Into::into)
119}