Fix missing validations of federation member event stubs.
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
@@ -168,6 +168,7 @@ pub async fn join_remote(
|
|||||||
let room_version_rules = room_version::rules(&room_version_id)?;
|
let room_version_rules = room_version::rules(&room_version_id)?;
|
||||||
let (mut join_event, event_id, join_authorized_via_users_server) = self
|
let (mut join_event, event_id, join_authorized_via_users_server) = self
|
||||||
.create_join_event(
|
.create_join_event(
|
||||||
|
room_id,
|
||||||
sender_user,
|
sender_user,
|
||||||
&make_join_response.event,
|
&make_join_response.event,
|
||||||
&room_version_id,
|
&room_version_id,
|
||||||
@@ -636,6 +637,7 @@ pub async fn join_local(
|
|||||||
let room_version_rules = room_version::rules(&room_version_id)?;
|
let room_version_rules = room_version::rules(&room_version_id)?;
|
||||||
let (join_event, event_id, _) = self
|
let (join_event, event_id, _) = self
|
||||||
.create_join_event(
|
.create_join_event(
|
||||||
|
room_id,
|
||||||
sender_user,
|
sender_user,
|
||||||
&make_join_response.event,
|
&make_join_response.event,
|
||||||
&room_version_id,
|
&room_version_id,
|
||||||
@@ -689,6 +691,7 @@ pub async fn join_local(
|
|||||||
#[tracing::instrument(name = "make_join", level = "debug", skip_all)]
|
#[tracing::instrument(name = "make_join", level = "debug", skip_all)]
|
||||||
async fn create_join_event(
|
async fn create_join_event(
|
||||||
&self,
|
&self,
|
||||||
|
room_id: &RoomId,
|
||||||
sender_user: &UserId,
|
sender_user: &UserId,
|
||||||
join_event_stub: &RawJsonValue,
|
join_event_stub: &RawJsonValue,
|
||||||
room_version_id: &RoomVersionId,
|
room_version_id: &RoomVersionId,
|
||||||
@@ -711,22 +714,6 @@ async fn create_join_event(
|
|||||||
})
|
})
|
||||||
.and_then(|s| OwnedUserId::try_from(s.as_str().unwrap_or_default()).ok());
|
.and_then(|s| OwnedUserId::try_from(s.as_str().unwrap_or_default()).ok());
|
||||||
|
|
||||||
event.insert(
|
|
||||||
"origin".into(),
|
|
||||||
CanonicalJsonValue::String(
|
|
||||||
self.services
|
|
||||||
.globals
|
|
||||||
.server_name()
|
|
||||||
.as_str()
|
|
||||||
.to_owned(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
event.insert(
|
|
||||||
"origin_server_ts".into(),
|
|
||||||
CanonicalJsonValue::Integer(utils::millis_since_unix_epoch().try_into()?),
|
|
||||||
);
|
|
||||||
|
|
||||||
let displayname = self.services.users.displayname(sender_user).ok();
|
let displayname = self.services.users.displayname(sender_user).ok();
|
||||||
|
|
||||||
let avatar_url = self.services.users.avatar_url(sender_user).ok();
|
let avatar_url = self.services.users.avatar_url(sender_user).ok();
|
||||||
@@ -747,6 +734,30 @@ async fn create_join_event(
|
|||||||
})?,
|
})?,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
event.insert(
|
||||||
|
"origin".into(),
|
||||||
|
CanonicalJsonValue::String(
|
||||||
|
self.services
|
||||||
|
.globals
|
||||||
|
.server_name()
|
||||||
|
.as_str()
|
||||||
|
.to_owned(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
event.insert(
|
||||||
|
"origin_server_ts".into(),
|
||||||
|
CanonicalJsonValue::Integer(utils::millis_since_unix_epoch().try_into()?),
|
||||||
|
);
|
||||||
|
|
||||||
|
event.insert("room_id".into(), CanonicalJsonValue::String(room_id.as_str().into()));
|
||||||
|
|
||||||
|
event.insert("sender".into(), CanonicalJsonValue::String(sender_user.as_str().into()));
|
||||||
|
|
||||||
|
event.insert("state_key".into(), CanonicalJsonValue::String(sender_user.as_str().into()));
|
||||||
|
|
||||||
|
event.insert("type".into(), CanonicalJsonValue::String("m.room.member".into()));
|
||||||
|
|
||||||
let event_id = self
|
let event_id = self
|
||||||
.services
|
.services
|
||||||
.server_keys
|
.server_keys
|
||||||
|
|||||||
@@ -257,6 +257,17 @@ async fn knock_room_helper_local(
|
|||||||
.expect("event is valid, we just created it"),
|
.expect("event is valid, we just created it"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
knock_event_stub
|
||||||
|
.insert("room_id".into(), CanonicalJsonValue::String(room_id.as_str().into()));
|
||||||
|
|
||||||
|
knock_event_stub
|
||||||
|
.insert("state_key".into(), CanonicalJsonValue::String(sender_user.as_str().into()));
|
||||||
|
|
||||||
|
knock_event_stub
|
||||||
|
.insert("sender".into(), CanonicalJsonValue::String(sender_user.as_str().into()));
|
||||||
|
|
||||||
|
knock_event_stub.insert("type".into(), CanonicalJsonValue::String("m.room.member".into()));
|
||||||
|
|
||||||
// In order to create a compatible ref hash (EventID) the `hashes` field needs
|
// In order to create a compatible ref hash (EventID) the `hashes` field needs
|
||||||
// to be present
|
// to be present
|
||||||
self.services
|
self.services
|
||||||
@@ -419,6 +430,17 @@ async fn knock_room_helper_remote(
|
|||||||
.expect("event is valid, we just created it"),
|
.expect("event is valid, we just created it"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
knock_event_stub
|
||||||
|
.insert("room_id".into(), CanonicalJsonValue::String(room_id.as_str().into()));
|
||||||
|
|
||||||
|
knock_event_stub
|
||||||
|
.insert("state_key".into(), CanonicalJsonValue::String(sender_user.as_str().into()));
|
||||||
|
|
||||||
|
knock_event_stub
|
||||||
|
.insert("sender".into(), CanonicalJsonValue::String(sender_user.as_str().into()));
|
||||||
|
|
||||||
|
knock_event_stub.insert("type".into(), CanonicalJsonValue::String("m.room.member".into()));
|
||||||
|
|
||||||
// In order to create a compatible ref hash (EventID) the `hashes` field needs
|
// In order to create a compatible ref hash (EventID) the `hashes` field needs
|
||||||
// to be present
|
// to be present
|
||||||
self.services
|
self.services
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use futures::{FutureExt, StreamExt, TryFutureExt, future::ready, pin_mut};
|
use futures::{
|
||||||
|
FutureExt, StreamExt, TryFutureExt,
|
||||||
|
future::{join3, ready},
|
||||||
|
pin_mut,
|
||||||
|
};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
CanonicalJsonObject, CanonicalJsonValue, OwnedServerName, RoomId, UserId,
|
CanonicalJsonObject, CanonicalJsonValue, OwnedServerName, RoomId, UserId,
|
||||||
api::federation,
|
api::federation,
|
||||||
|
canonical_json::to_canonical_value,
|
||||||
events::{
|
events::{
|
||||||
StateEventType,
|
StateEventType,
|
||||||
room::member::{MembershipState, RoomMemberEventContent},
|
room::member::{MembershipState, RoomMemberEventContent},
|
||||||
@@ -14,7 +19,10 @@ use tuwunel_core::{
|
|||||||
matrix::{PduCount, room_version},
|
matrix::{PduCount, room_version},
|
||||||
pdu::PduBuilder,
|
pdu::PduBuilder,
|
||||||
state_res,
|
state_res,
|
||||||
utils::{self, FutureBoolExt, future::ReadyBoolExt},
|
utils::{
|
||||||
|
self, FutureBoolExt,
|
||||||
|
future::{ReadyBoolExt, TryExtExt},
|
||||||
|
},
|
||||||
warn,
|
warn,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,7 +104,11 @@ pub async fn leave(
|
|||||||
|
|
||||||
// Ask a remote server if we don't have this room and are not knocking on it
|
// Ask a remote server if we don't have this room and are not knocking on it
|
||||||
if remote_leave_now || dont_have_room.and(not_knocked).await {
|
if remote_leave_now || dont_have_room.and(not_knocked).await {
|
||||||
if let Err(e) = self.remote_leave(user_id, room_id).boxed().await {
|
if let Err(e) = self
|
||||||
|
.remote_leave(user_id, room_id, reason)
|
||||||
|
.boxed()
|
||||||
|
.await
|
||||||
|
{
|
||||||
warn!(%user_id, "Failed to leave room {room_id} remotely: {e}");
|
warn!(%user_id, "Failed to leave room {room_id} remotely: {e}");
|
||||||
// Don't tell the client about this error
|
// Don't tell the client about this error
|
||||||
}
|
}
|
||||||
@@ -178,7 +190,12 @@ pub async fn leave(
|
|||||||
|
|
||||||
#[implement(Service)]
|
#[implement(Service)]
|
||||||
#[tracing::instrument(name = "remote", level = "debug", skip_all)]
|
#[tracing::instrument(name = "remote", level = "debug", skip_all)]
|
||||||
async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result {
|
async fn remote_leave(
|
||||||
|
&self,
|
||||||
|
user_id: &UserId,
|
||||||
|
room_id: &RoomId,
|
||||||
|
reason: Option<String>,
|
||||||
|
) -> Result {
|
||||||
let mut make_leave_response_and_server =
|
let mut make_leave_response_and_server =
|
||||||
Err!(BadServerResponse("No remote server available to assist in leaving {room_id}."));
|
Err!(BadServerResponse("No remote server available to assist in leaving {room_id}."));
|
||||||
|
|
||||||
@@ -281,17 +298,34 @@ async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result {
|
|||||||
|
|
||||||
let room_version_rules = room_version::rules(&room_version_id)?;
|
let room_version_rules = room_version::rules(&room_version_id)?;
|
||||||
|
|
||||||
let mut leave_event_stub = serde_json::from_str::<CanonicalJsonObject>(
|
let mut event = serde_json::from_str::<CanonicalJsonObject>(make_leave_response.event.get())
|
||||||
make_leave_response.event.get(),
|
.map_err(|e| {
|
||||||
)
|
err!(BadServerResponse(warn!(
|
||||||
.map_err(|e| {
|
"Invalid make_leave event json received from {remote_server} for {room_id}: \
|
||||||
err!(BadServerResponse(warn!(
|
{e:?}"
|
||||||
"Invalid make_leave event json received from {remote_server} for {room_id}: {e:?}"
|
)))
|
||||||
)))
|
})?;
|
||||||
})?;
|
|
||||||
|
|
||||||
// TODO: Is origin needed?
|
let displayname = self.services.users.displayname(user_id).ok();
|
||||||
leave_event_stub.insert(
|
|
||||||
|
let avatar_url = self.services.users.avatar_url(user_id).ok();
|
||||||
|
|
||||||
|
let blurhash = self.services.users.blurhash(user_id).ok();
|
||||||
|
|
||||||
|
let (displayname, avatar_url, blurhash) = join3(displayname, avatar_url, blurhash).await;
|
||||||
|
|
||||||
|
event.insert(
|
||||||
|
"content".into(),
|
||||||
|
to_canonical_value(RoomMemberEventContent {
|
||||||
|
displayname,
|
||||||
|
avatar_url,
|
||||||
|
blurhash,
|
||||||
|
reason,
|
||||||
|
..RoomMemberEventContent::new(MembershipState::Leave)
|
||||||
|
})?,
|
||||||
|
);
|
||||||
|
|
||||||
|
event.insert(
|
||||||
"origin".into(),
|
"origin".into(),
|
||||||
CanonicalJsonValue::String(
|
CanonicalJsonValue::String(
|
||||||
self.services
|
self.services
|
||||||
@@ -301,24 +335,26 @@ async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result {
|
|||||||
.to_owned(),
|
.to_owned(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
leave_event_stub.insert(
|
|
||||||
|
event.insert(
|
||||||
"origin_server_ts".into(),
|
"origin_server_ts".into(),
|
||||||
CanonicalJsonValue::Integer(
|
CanonicalJsonValue::Integer(utils::millis_since_unix_epoch().try_into()?),
|
||||||
utils::millis_since_unix_epoch()
|
|
||||||
.try_into()
|
|
||||||
.expect("Timestamp is valid js_int value"),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
event.insert("room_id".into(), CanonicalJsonValue::String(room_id.as_str().into()));
|
||||||
|
|
||||||
|
event.insert("state_key".into(), CanonicalJsonValue::String(user_id.as_str().into()));
|
||||||
|
|
||||||
|
event.insert("sender".into(), CanonicalJsonValue::String(user_id.as_str().into()));
|
||||||
|
|
||||||
|
event.insert("type".into(), CanonicalJsonValue::String("m.room.member".into()));
|
||||||
|
|
||||||
let event_id = self
|
let event_id = self
|
||||||
.services
|
.services
|
||||||
.server_keys
|
.server_keys
|
||||||
.gen_id_hash_and_sign_event(&mut leave_event_stub, &room_version_id)?;
|
.gen_id_hash_and_sign_event(&mut event, &room_version_id)?;
|
||||||
|
|
||||||
state_res::check_pdu_format(&leave_event_stub, &room_version_rules.event_format)?;
|
state_res::check_pdu_format(&event, &room_version_rules.event_format)?;
|
||||||
|
|
||||||
// It has enough fields to be called a proper event now
|
|
||||||
let leave_event = leave_event_stub;
|
|
||||||
|
|
||||||
self.services
|
self.services
|
||||||
.federation
|
.federation
|
||||||
@@ -328,7 +364,7 @@ async fn remote_leave(&self, user_id: &UserId, room_id: &RoomId) -> Result {
|
|||||||
pdu: self
|
pdu: self
|
||||||
.services
|
.services
|
||||||
.federation
|
.federation
|
||||||
.format_pdu_into(leave_event.clone(), Some(&room_version_id))
|
.format_pdu_into(event.clone(), Some(&room_version_id))
|
||||||
.await,
|
.await,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user