Support v1/v2 conditions for join/leave, creation and other operations. (#12)
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
@@ -103,6 +103,10 @@ impl Pdu {
|
||||
let event_id = CanonicalJsonValue::String(event_id.into());
|
||||
json.insert("event_id".into(), event_id);
|
||||
|
||||
Self::from_val(&json)
|
||||
}
|
||||
|
||||
pub fn from_val(json: &CanonicalJsonObject) -> Result<Self> {
|
||||
serde_json::to_value(json)
|
||||
.and_then(serde_json::from_value)
|
||||
.map_err(Into::into)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use ruma::{
|
||||
CanonicalJsonObject, CanonicalJsonValue, EventId, RoomVersionId,
|
||||
CanonicalJsonObject, CanonicalJsonValue, EventId, RoomId, RoomVersionId,
|
||||
room_version_rules::{EventsReferenceFormatVersion, RoomVersionRules},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Result, err, extract_variant, is_equal_to,
|
||||
Result, extract_variant, is_equal_to,
|
||||
matrix::{PduEvent, room_version},
|
||||
};
|
||||
|
||||
@@ -69,6 +69,7 @@ fn mutate_outgoing_reference_format(value: &mut CanonicalJsonValue) {
|
||||
}
|
||||
|
||||
pub fn from_incoming_federation(
|
||||
room_id: &RoomId,
|
||||
event_id: &EventId,
|
||||
pdu_json: &mut CanonicalJsonObject,
|
||||
room_rules: &RoomVersionRules,
|
||||
@@ -82,10 +83,19 @@ pub fn from_incoming_federation(
|
||||
}
|
||||
}
|
||||
|
||||
pdu_json.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.into()));
|
||||
if !room_rules
|
||||
.event_format
|
||||
.require_room_create_room_id
|
||||
&& pdu_json["type"] == "m.room.create"
|
||||
{
|
||||
pdu_json.insert("room_id".into(), CanonicalJsonValue::String(room_id.as_str().into()));
|
||||
}
|
||||
|
||||
serde_json::from_value::<PduEvent>(serde_json::to_value(&pdu_json)?)
|
||||
.map_err(|e| err!(Request(BadJson(debug_warn!("Event is not a valid PDU: {e}")))))
|
||||
if !room_rules.event_format.require_event_id {
|
||||
pdu_json.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.into()));
|
||||
}
|
||||
|
||||
PduEvent::from_val(pdu_json)
|
||||
}
|
||||
|
||||
fn mutate_incoming_reference_format(value: &mut CanonicalJsonValue) {
|
||||
|
||||
@@ -17,11 +17,8 @@ use ruma::{
|
||||
};
|
||||
use tuwunel_core::{
|
||||
Err, Result, debug, debug_error, debug_info, debug_warn, err, error, implement, info,
|
||||
matrix::{
|
||||
event::{gen_event_id, gen_event_id_canonical_json},
|
||||
room_version,
|
||||
},
|
||||
pdu::{PduBuilder, PduEvent},
|
||||
matrix::{event::gen_event_id_canonical_json, room_version},
|
||||
pdu::{PduBuilder, format::from_incoming_federation},
|
||||
state_res, trace,
|
||||
utils::{self, IterStream, ReadyExt},
|
||||
warn,
|
||||
@@ -152,6 +149,8 @@ pub async fn join_remote(
|
||||
));
|
||||
}
|
||||
|
||||
let room_version_rules = room_version::rules(&room_version_id)?;
|
||||
|
||||
let mut join_event_stub: CanonicalJsonObject =
|
||||
serde_json::from_str(make_join_response.event.get()).map_err(|e| {
|
||||
err!(BadServerResponse(warn!(
|
||||
@@ -221,27 +220,10 @@ pub async fn join_remote(
|
||||
.expect("event is valid, we just created it"),
|
||||
);
|
||||
|
||||
// We keep the "event_id" in the pdu only in v1 or
|
||||
// v2 rooms
|
||||
match room_version_id {
|
||||
| RoomVersionId::V1 | RoomVersionId::V2 => {},
|
||||
| _ => {
|
||||
join_event_stub.remove("event_id");
|
||||
},
|
||||
}
|
||||
|
||||
// In order to create a compatible ref hash (EventID) the `hashes` field needs
|
||||
// to be present
|
||||
self.services
|
||||
let event_id = self
|
||||
.services
|
||||
.server_keys
|
||||
.hash_and_sign_event(&mut join_event_stub, &room_version_id)?;
|
||||
|
||||
// Generate event id
|
||||
let event_id = gen_event_id(&join_event_stub, &room_version_id)?;
|
||||
|
||||
// Add event_id back
|
||||
join_event_stub
|
||||
.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
|
||||
.gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?;
|
||||
|
||||
// It has enough fields to be called a proper event now
|
||||
let mut join_event = join_event_stub;
|
||||
@@ -342,8 +324,8 @@ pub async fn join_remote(
|
||||
.await;
|
||||
|
||||
info!("Parsing join event");
|
||||
let parsed_join_pdu = PduEvent::from_id_val(&event_id, join_event.clone())
|
||||
.map_err(|e| err!(BadServerResponse("Invalid join event PDU: {e:?}")))?;
|
||||
let parsed_join_pdu =
|
||||
from_incoming_federation(room_id, &event_id, &mut join_event, &room_version_rules)?;
|
||||
|
||||
info!("Acquiring server signing keys for response events");
|
||||
let resp_events = &send_join_response.room_state;
|
||||
@@ -368,26 +350,15 @@ pub async fn join_remote(
|
||||
})
|
||||
.inspect_err(|e| debug_error!("Invalid send_join state event: {e:?}"))
|
||||
.ready_filter_map(Result::ok)
|
||||
.fold(HashMap::new(), async |mut state, (event_id, mut value)| {
|
||||
let pdu = if value["type"] == "m.room.create" {
|
||||
if !value.contains_key("room_id") {
|
||||
let room_id = CanonicalJsonValue::String(room_id.as_str().into());
|
||||
value.insert("room_id".into(), room_id);
|
||||
}
|
||||
|
||||
PduEvent::from_rid_val(room_id, &event_id, value.clone())
|
||||
} else {
|
||||
PduEvent::from_id_val(&event_id, value.clone())
|
||||
};
|
||||
|
||||
let pdu = match pdu {
|
||||
| Ok(pdu) => pdu,
|
||||
| Err(e) => {
|
||||
.ready_filter_map(|(event_id, mut value)| {
|
||||
from_incoming_federation(room_id, &event_id, &mut value, &room_version_rules)
|
||||
.inspect_err(|e| {
|
||||
debug_warn!("Invalid PDU in send_join response: {e:?}: {value:#?}");
|
||||
return state;
|
||||
},
|
||||
};
|
||||
|
||||
})
|
||||
.map(move |pdu| (event_id, pdu, value))
|
||||
.ok()
|
||||
})
|
||||
.fold(HashMap::new(), async |mut state, (event_id, pdu, value)| {
|
||||
self.services
|
||||
.timeline
|
||||
.add_pdu_outlier(&event_id, &value);
|
||||
@@ -423,7 +394,11 @@ pub async fn join_remote(
|
||||
.inspect_err(|e| debug_error!("Invalid send_join auth_chain event: {e:?}"))
|
||||
.ready_filter_map(Result::ok)
|
||||
.ready_for_each(|(event_id, mut value)| {
|
||||
if !value.contains_key("room_id") {
|
||||
if !room_version_rules
|
||||
.event_format
|
||||
.require_room_create_room_id
|
||||
&& value["type"] == "m.room.create"
|
||||
{
|
||||
let room_id = CanonicalJsonValue::String(room_id.as_str().into());
|
||||
value.insert("room_id".into(), room_id);
|
||||
}
|
||||
@@ -438,7 +413,7 @@ pub async fn join_remote(
|
||||
|
||||
debug!("Running send_join auth check");
|
||||
state_res::auth_check(
|
||||
&room_version::rules(&room_version_id)?,
|
||||
&room_version_rules,
|
||||
&parsed_join_pdu,
|
||||
&async |event_id| self.services.timeline.get_pdu(&event_id).await,
|
||||
&async |event_type, state_key| {
|
||||
@@ -719,27 +694,10 @@ pub async fn join_local(
|
||||
.expect("event is valid, we just created it"),
|
||||
);
|
||||
|
||||
// We keep the "event_id" in the pdu only in v1 or
|
||||
// v2 rooms
|
||||
match room_version_id {
|
||||
| RoomVersionId::V1 | RoomVersionId::V2 => {},
|
||||
| _ => {
|
||||
join_event_stub.remove("event_id");
|
||||
},
|
||||
}
|
||||
|
||||
// In order to create a compatible ref hash (EventID) the `hashes` field needs
|
||||
// to be present
|
||||
self.services
|
||||
let event_id = self
|
||||
.services
|
||||
.server_keys
|
||||
.hash_and_sign_event(&mut join_event_stub, &room_version_id)?;
|
||||
|
||||
// Generate event id
|
||||
let event_id = gen_event_id(&join_event_stub, &room_version_id)?;
|
||||
|
||||
// Add event_id back
|
||||
join_event_stub
|
||||
.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
|
||||
.gen_id_hash_and_sign_event(&mut join_event_stub, &room_version_id)?;
|
||||
|
||||
// It has enough fields to be called a proper event now
|
||||
let join_event = join_event_stub;
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashSet;
|
||||
|
||||
use futures::{FutureExt, StreamExt, TryFutureExt, pin_mut};
|
||||
use ruma::{
|
||||
CanonicalJsonObject, CanonicalJsonValue, OwnedServerName, RoomId, RoomVersionId, UserId,
|
||||
CanonicalJsonObject, CanonicalJsonValue, OwnedServerName, RoomId, UserId,
|
||||
api::federation,
|
||||
events::{
|
||||
StateEventType,
|
||||
@@ -11,7 +11,6 @@ use ruma::{
|
||||
};
|
||||
use tuwunel_core::{
|
||||
Err, Result, debug_info, debug_warn, err, implement,
|
||||
matrix::event::gen_event_id,
|
||||
pdu::PduBuilder,
|
||||
utils::{self, FutureBoolExt, future::ReadyEqExt},
|
||||
warn,
|
||||
@@ -296,26 +295,10 @@ pub async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result {
|
||||
),
|
||||
);
|
||||
|
||||
// room v3 and above removed the "event_id" field from remote PDU format
|
||||
match room_version_id {
|
||||
| RoomVersionId::V1 | RoomVersionId::V2 => {},
|
||||
| _ => {
|
||||
leave_event_stub.remove("event_id");
|
||||
},
|
||||
}
|
||||
|
||||
// In order to create a compatible ref hash (EventID) the `hashes` field needs
|
||||
// to be present
|
||||
self.services
|
||||
let event_id = self
|
||||
.services
|
||||
.server_keys
|
||||
.hash_and_sign_event(&mut leave_event_stub, &room_version_id)?;
|
||||
|
||||
// Generate event id
|
||||
let event_id = gen_event_id(&leave_event_stub, &room_version_id)?;
|
||||
|
||||
// Add event_id back
|
||||
leave_event_stub
|
||||
.insert("event_id".to_owned(), CanonicalJsonValue::String(event_id.clone().into()));
|
||||
.gen_id_hash_and_sign_event(&mut leave_event_stub, &room_version_id)?;
|
||||
|
||||
// It has enough fields to be called a proper event now
|
||||
let leave_event = leave_event_stub;
|
||||
|
||||
@@ -70,7 +70,7 @@ pub(super) async fn handle_outlier_pdu(
|
||||
|
||||
// Now that we have checked the signature and hashes we can make mutations and
|
||||
// convert to our PduEvent type.
|
||||
let event = from_incoming_federation(event_id, &mut pdu_json, &room_rules)?;
|
||||
let event = from_incoming_federation(room_id, event_id, &mut pdu_json, &room_rules)?;
|
||||
|
||||
check_room_id(room_id, &event)?;
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@ use std::cmp;
|
||||
use futures::{StreamExt, TryStreamExt};
|
||||
use ruma::{
|
||||
CanonicalJsonObject, CanonicalJsonValue, MilliSecondsSinceUnixEpoch, OwnedEventId,
|
||||
OwnedRoomId, RoomId, RoomVersionId, UserId,
|
||||
OwnedRoomId, RoomId, UserId,
|
||||
events::{StateEventType, TimelineEventType, room::create::RoomCreateEventContent},
|
||||
room_version_rules::RoomIdFormatVersion,
|
||||
uint,
|
||||
};
|
||||
use serde_json::value::to_raw_value;
|
||||
use tuwunel_core::{
|
||||
Err, Error, Result, err, implement,
|
||||
Error, Result, err, implement,
|
||||
matrix::{
|
||||
event::{Event, StateKey, TypeExt, gen_event_id},
|
||||
event::{Event, StateKey, TypeExt},
|
||||
pdu::{EventHash, PduBuilder, PduEvent},
|
||||
room_version,
|
||||
state_res::{self},
|
||||
@@ -175,36 +175,29 @@ pub async fn create_hash_and_sign_event(
|
||||
err!(Request(BadJson(warn!("Failed to convert PDU to canonical JSON: {e}"))))
|
||||
})?;
|
||||
|
||||
// room v3 and above removed the "event_id" field from remote PDU format
|
||||
if !matches!(room_version, RoomVersionId::V1 | RoomVersionId::V2) {
|
||||
pdu_json.remove("event_id");
|
||||
}
|
||||
|
||||
// room v12 and above removed the placeholder "room_id" field from m.room.create
|
||||
if matches!(version_rules.room_id_format, RoomIdFormatVersion::V2)
|
||||
if !version_rules
|
||||
.event_format
|
||||
.require_room_create_room_id
|
||||
&& pdu.kind == TimelineEventType::RoomCreate
|
||||
{
|
||||
pdu_json.remove("room_id");
|
||||
}
|
||||
|
||||
if let Err(e) = self
|
||||
pdu.event_id = self
|
||||
.services
|
||||
.server_keys
|
||||
.hash_and_sign_event(&mut pdu_json, &room_version)
|
||||
{
|
||||
use ruma::signatures::Error::PduSize;
|
||||
|
||||
return match e {
|
||||
| Error::Signatures(PduSize) => {
|
||||
Err!(Request(TooLarge("Message/PDU is too long (exceeds 65535 bytes)")))
|
||||
},
|
||||
| _ => Err!(Request(Unknown(warn!("Signing event failed: {e}")))),
|
||||
};
|
||||
}
|
||||
|
||||
// Generate event id
|
||||
pdu.event_id = gen_event_id(&pdu_json, &room_version)?;
|
||||
pdu_json.insert("event_id".into(), CanonicalJsonValue::String(pdu.event_id.clone().into()));
|
||||
.gen_id_hash_and_sign_event(&mut pdu_json, &room_version)
|
||||
.map_err(|e| {
|
||||
use Error::Signatures;
|
||||
use ruma::signatures::Error::PduSize;
|
||||
match e {
|
||||
| Signatures(PduSize) => {
|
||||
err!(Request(TooLarge("PDU exceeds 65535 bytes")))
|
||||
},
|
||||
| _ => err!(Request(Unknown(warn!("Signing event failed: {e}")))),
|
||||
}
|
||||
})?;
|
||||
|
||||
// Room id is event id for V12+
|
||||
if matches!(version_rules.room_id_format, RoomIdFormatVersion::V2)
|
||||
|
||||
Reference in New Issue
Block a user