@ -59,7 +59,7 @@ pub async fn join_room_by_id_route(
. iter ( )
. filter_map ( | event | serde_json ::from_str ( event . json ( ) . get ( ) ) . ok ( ) )
. filter_map ( | event : serde_json ::Value | event . get ( "sender" ) . cloned ( ) )
. filter_map ( | sender | sender . as_str ( ) . map ( | s | s . to_owned ( ) ) )
. filter_map ( | sender | sender . as_str ( ) . map ( ToOwned ::to_owned ) )
. filter_map ( | sender | UserId ::parse ( sender ) . ok ( ) )
. map ( | user | user . server_name ( ) . to_owned ( ) ) ,
) ;
@ -105,7 +105,7 @@ pub async fn join_room_by_id_or_alias_route(
. iter ( )
. filter_map ( | event | serde_json ::from_str ( event . json ( ) . get ( ) ) . ok ( ) )
. filter_map ( | event : serde_json ::Value | event . get ( "sender" ) . cloned ( ) )
. filter_map ( | sender | sender . as_str ( ) . map ( | s | s . to_owned ( ) ) )
. filter_map ( | sender | sender . as_str ( ) . map ( ToOwned ::to_owned ) )
. filter_map ( | sender | UserId ::parse ( sender ) . ok ( ) )
. map ( | user | user . server_name ( ) . to_owned ( ) ) ,
) ;
@ -543,313 +543,11 @@ async fn join_room_by_id_helper(
let state_lock = mutex_state . lock ( ) . await ;
// Ask a remote server if we are not participating in this room
if ! services ( )
if services ( )
. rooms
. state_cache
. server_in_room ( services ( ) . globals . server_name ( ) , room_id ) ?
{
info ! ( "Joining {room_id} over federation." ) ;
let ( make_join_response , remote_server ) =
make_join_request ( sender_user , room_id , servers ) . await ? ;
info ! ( "make_join finished" ) ;
let room_version_id = match make_join_response . room_version {
Some ( room_version )
if services ( )
. globals
. supported_room_versions ( )
. contains ( & room_version ) = >
{
room_version
}
_ = > return Err ( Error ::BadServerResponse ( "Room version is not supported" ) ) ,
} ;
let mut join_event_stub : CanonicalJsonObject =
serde_json ::from_str ( make_join_response . event . get ( ) ) . map_err ( | _ | {
Error ::BadServerResponse ( "Invalid make_join event json received from server." )
} ) ? ;
let join_authorized_via_users_server = join_event_stub
. get ( "content" )
. map ( | s | {
s . as_object ( ) ?
. get ( "join_authorised_via_users_server" ) ?
. as_str ( )
} )
. and_then ( | s | OwnedUserId ::try_from ( s . unwrap_or_default ( ) ) . ok ( ) ) ;
// TODO: Is origin needed?
join_event_stub . insert (
"origin" . to_owned ( ) ,
CanonicalJsonValue ::String ( services ( ) . globals . server_name ( ) . as_str ( ) . to_owned ( ) ) ,
) ;
join_event_stub . insert (
"origin_server_ts" . to_owned ( ) ,
CanonicalJsonValue ::Integer (
utils ::millis_since_unix_epoch ( )
. try_into ( )
. expect ( "Timestamp is valid js_int value" ) ,
) ,
) ;
join_event_stub . insert (
"content" . to_owned ( ) ,
to_canonical_value ( RoomMemberEventContent {
membership : MembershipState ::Join ,
displayname : services ( ) . users . displayname ( sender_user ) ? ,
avatar_url : services ( ) . users . avatar_url ( sender_user ) ? ,
is_direct : None ,
third_party_invite : None ,
blurhash : services ( ) . users . blurhash ( sender_user ) ? ,
reason ,
join_authorized_via_users_server ,
} )
. expect ( "event is valid, we just created it" ) ,
) ;
// We don't leave the event id in the pdu because that's only allowed in v1 or v2 rooms
join_event_stub . remove ( "event_id" ) ;
// In order to create a compatible ref hash (EventID) the `hashes` field needs to be present
ruma ::signatures ::hash_and_sign_event (
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
& mut join_event_stub ,
& room_version_id ,
)
. expect ( "event is valid, we just created it" ) ;
// Generate event id
let event_id = format! (
"${}" ,
ruma ::signatures ::reference_hash ( & join_event_stub , & room_version_id )
. expect ( "ruma can calculate reference hashes" )
) ;
let event_id = < & EventId > ::try_from ( event_id . as_str ( ) )
. expect ( "ruma's reference hashes are valid event ids" ) ;
// Add event_id back
join_event_stub . insert (
"event_id" . to_owned ( ) ,
CanonicalJsonValue ::String ( event_id . as_str ( ) . to_owned ( ) ) ,
) ;
// It has enough fields to be called a proper event now
let mut join_event = join_event_stub ;
info ! ( "Asking {remote_server} for send_join" ) ;
let send_join_response = services ( )
. sending
. send_federation_request (
& remote_server ,
federation ::membership ::create_join_event ::v2 ::Request {
room_id : room_id . to_owned ( ) ,
event_id : event_id . to_owned ( ) ,
pdu : PduEvent ::convert_to_outgoing_federation_event ( join_event . clone ( ) ) ,
omit_members : false ,
} ,
)
. await ? ;
info ! ( "send_join finished" ) ;
if let Some ( signed_raw ) = & send_join_response . room_state . event {
info ! ( "There is a signed event. This room is probably using restricted joins. Adding signature to our event" ) ;
let ( signed_event_id , signed_value ) =
match gen_event_id_canonical_json ( signed_raw , & room_version_id ) {
Ok ( t ) = > t ,
Err ( _ ) = > {
// Event could not be converted to canonical json
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Could not convert event to canonical json." ,
) ) ;
}
} ;
if signed_event_id ! = event_id {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server sent event with wrong event id" ,
) ) ;
}
match signed_value [ "signatures" ]
. as_object ( )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server sent invalid signatures type" ,
) )
. and_then ( | e | {
e . get ( remote_server . as_str ( ) ) . ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server did not send its signature" ,
) )
} ) {
Ok ( signature ) = > {
join_event
. get_mut ( "signatures" )
. expect ( "we created a valid pdu" )
. as_object_mut ( )
. expect ( "we created a valid pdu" )
. insert ( remote_server . to_string ( ) , signature . clone ( ) ) ;
}
Err ( e ) = > {
warn ! (
"Server {remote_server} sent invalid signature in sendjoin signatures for event {signed_value:?}: {e:?}" ,
) ;
}
}
}
services ( ) . rooms . short . get_or_create_shortroomid ( room_id ) ? ;
info ! ( "Parsing join event" ) ;
let parsed_join_pdu = PduEvent ::from_id_val ( event_id , join_event . clone ( ) )
. map_err ( | _ | Error ::BadServerResponse ( "Invalid join event PDU." ) ) ? ;
let mut state = HashMap ::new ( ) ;
let pub_key_map = RwLock ::new ( BTreeMap ::new ( ) ) ;
info ! ( "Fetching join signing keys" ) ;
services ( )
. rooms
. event_handler
. fetch_join_signing_keys ( & send_join_response , & room_version_id , & pub_key_map )
. await ? ;
info ! ( "Going through send_join response room_state" ) ;
for result in send_join_response
. room_state
. state
. iter ( )
. map ( | pdu | validate_and_add_event_id ( pdu , & room_version_id , & pub_key_map ) )
{
let ( event_id , value ) = match result . await {
Ok ( t ) = > t ,
Err ( _ ) = > continue ,
} ;
let pdu = PduEvent ::from_id_val ( & event_id , value . clone ( ) ) . map_err ( | e | {
warn ! ( "Invalid PDU in send_join response: {} {:?}" , e , value ) ;
Error ::BadServerResponse ( "Invalid PDU in send_join response." )
} ) ? ;
services ( )
. rooms
. outlier
. add_pdu_outlier ( & event_id , & value ) ? ;
if let Some ( state_key ) = & pdu . state_key {
let shortstatekey = services ( )
. rooms
. short
. get_or_create_shortstatekey ( & pdu . kind . to_string ( ) . into ( ) , state_key ) ? ;
state . insert ( shortstatekey , pdu . event_id . clone ( ) ) ;
}
}
info ! ( "Going through send_join response auth_chain" ) ;
for result in send_join_response
. room_state
. auth_chain
. iter ( )
. map ( | pdu | validate_and_add_event_id ( pdu , & room_version_id , & pub_key_map ) )
{
let ( event_id , value ) = match result . await {
Ok ( t ) = > t ,
Err ( _ ) = > continue ,
} ;
services ( )
. rooms
. outlier
. add_pdu_outlier ( & event_id , & value ) ? ;
}
info ! ( "Running send_join auth check" ) ;
let authenticated = state_res ::event_auth ::auth_check (
& state_res ::RoomVersion ::new ( & room_version_id ) . expect ( "room version is supported" ) ,
& parsed_join_pdu ,
None ::< PduEvent > , // TODO: third party invite
| k , s | {
services ( )
. rooms
. timeline
. get_pdu (
state . get (
& services ( )
. rooms
. short
. get_or_create_shortstatekey ( & k . to_string ( ) . into ( ) , s )
. ok ( ) ? ,
) ? ,
)
. ok ( ) ?
} ,
)
. map_err ( | e | {
warn ! ( "Auth check failed: {e}" ) ;
Error ::BadRequest ( ErrorKind ::InvalidParam , "Auth check failed" )
} ) ? ;
if ! authenticated {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Auth check failed" ,
) ) ;
}
info ! ( "Saving state from send_join" ) ;
let ( statehash_before_join , new , removed ) = services ( ) . rooms . state_compressor . save_state (
room_id ,
Arc ::new (
state
. into_iter ( )
. map ( | ( k , id ) | {
services ( )
. rooms
. state_compressor
. compress_state_event ( k , & id )
} )
. collect ::< Result < _ > > ( ) ? ,
) ,
) ? ;
services ( )
. rooms
. state
. force_state ( room_id , statehash_before_join , new , removed , & state_lock )
. await ? ;
info ! ( "Updating joined counts for new room" ) ;
services ( ) . rooms . state_cache . update_joined_count ( room_id ) ? ;
// We append to state before appending the pdu, so we don't have a moment in time with the
// pdu without it's state. This is okay because append_pdu can't fail.
let statehash_after_join = services ( ) . rooms . state . append_to_state ( & parsed_join_pdu ) ? ;
info ! ( "Appending new room join event" ) ;
services ( )
. rooms
. timeline
. append_pdu (
& parsed_join_pdu ,
join_event ,
vec! [ ( * parsed_join_pdu . event_id ) . to_owned ( ) ] ,
& state_lock ,
)
. await ? ;
info ! ( "Setting final room state for new room" ) ;
// We set the room state after inserting the pdu, so that we never have a moment in time
// where events in the current room state do not exist
services ( )
. rooms
. state
. set_room_state ( room_id , statehash_after_join , & state_lock ) ? ;
} else {
info ! ( "We can join locally" ) ;
let join_rules_event = services ( ) . rooms . state_accessor . room_state_get (
@ -870,10 +568,7 @@ async fn join_room_by_id_helper(
let restriction_rooms = match join_rules_event_content {
Some ( RoomJoinRulesEventContent {
join_rule : JoinRule ::Restricted ( restricted ) ,
} )
| Some ( RoomJoinRulesEventContent {
join_rule : JoinRule ::KnockRestricted ( restricted ) ,
join_rule : JoinRule ::Restricted ( restricted ) | JoinRule ::KnockRestricted ( restricted ) ,
} ) = > restricted
. allow
. into_iter ( )
@ -901,12 +596,12 @@ async fn join_room_by_id_helper(
. collect ::< Vec < _ > > ( )
{
if user . server_name ( ) = = services ( ) . globals . server_name ( )
& & services ( )
. rooms
. state_accessor
. user_can_invite ( room_id , & user , sender_user , & state_lock )
. await
. unwrap_or ( false )
& & services ( ) . rooms . state_accessor . user_can_invite (
room_id ,
& user ,
sender_user ,
& state_lock ,
)
{
auth_user = Some ( user ) ;
break ;
@ -1012,89 +707,385 @@ async fn join_room_by_id_helper(
. expect ( "event is valid, we just created it" ) ,
) ;
// We don't leave the event id in the pdu because that's only allowed in v1 or v2 rooms
join_event_stub . remove ( "event_id" ) ;
// We don't leave the event id in the pdu because that's only allowed in v1 or v2 rooms
join_event_stub . remove ( "event_id" ) ;
// In order to create a compatible ref hash (EventID) the `hashes` field needs to be present
ruma ::signatures ::hash_and_sign_event (
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
& mut join_event_stub ,
& room_version_id ,
)
. expect ( "event is valid, we just created it" ) ;
// Generate event id
let event_id = format! (
"${}" ,
ruma ::signatures ::reference_hash ( & join_event_stub , & room_version_id )
. expect ( "ruma can calculate reference hashes" )
) ;
let event_id = < & EventId > ::try_from ( event_id . as_str ( ) )
. expect ( "ruma's reference hashes are valid event ids" ) ;
// Add event_id back
join_event_stub . insert (
"event_id" . to_owned ( ) ,
CanonicalJsonValue ::String ( event_id . as_str ( ) . to_owned ( ) ) ,
) ;
// It has enough fields to be called a proper event now
let join_event = join_event_stub ;
let send_join_response = services ( )
. sending
. send_federation_request (
& remote_server ,
federation ::membership ::create_join_event ::v2 ::Request {
room_id : room_id . to_owned ( ) ,
event_id : event_id . to_owned ( ) ,
pdu : PduEvent ::convert_to_outgoing_federation_event ( join_event . clone ( ) ) ,
omit_members : false ,
} ,
)
. await ? ;
if let Some ( signed_raw ) = send_join_response . room_state . event {
let Ok ( ( signed_event_id , signed_value ) ) =
gen_event_id_canonical_json ( & signed_raw , & room_version_id )
else {
// Event could not be converted to canonical json
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Could not convert event to canonical json." ,
) ) ;
} ;
if signed_event_id ! = event_id {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server sent event with wrong event id" ,
) ) ;
}
drop ( state_lock ) ;
let pub_key_map = RwLock ::new ( BTreeMap ::new ( ) ) ;
services ( )
. rooms
. event_handler
. handle_incoming_pdu (
& remote_server ,
& signed_event_id ,
room_id ,
signed_value ,
true ,
& pub_key_map ,
)
. await ? ;
} else {
return Err ( error ) ;
}
} else {
return Err ( error ) ;
}
} else {
info ! ( "Joining {room_id} over federation." ) ;
let ( make_join_response , remote_server ) =
make_join_request ( sender_user , room_id , servers ) . await ? ;
info ! ( "make_join finished" ) ;
let room_version_id = match make_join_response . room_version {
Some ( room_version )
if services ( )
. globals
. supported_room_versions ( )
. contains ( & room_version ) = >
{
room_version
}
_ = > return Err ( Error ::BadServerResponse ( "Room version is not supported" ) ) ,
} ;
let mut join_event_stub : CanonicalJsonObject =
serde_json ::from_str ( make_join_response . event . get ( ) ) . map_err ( | _ | {
Error ::BadServerResponse ( "Invalid make_join event json received from server." )
} ) ? ;
let join_authorized_via_users_server = join_event_stub
. get ( "content" )
. map ( | s | {
s . as_object ( ) ?
. get ( "join_authorised_via_users_server" ) ?
. as_str ( )
} )
. and_then ( | s | OwnedUserId ::try_from ( s . unwrap_or_default ( ) ) . ok ( ) ) ;
// TODO: Is origin needed?
join_event_stub . insert (
"origin" . to_owned ( ) ,
CanonicalJsonValue ::String ( services ( ) . globals . server_name ( ) . as_str ( ) . to_owned ( ) ) ,
) ;
join_event_stub . insert (
"origin_server_ts" . to_owned ( ) ,
CanonicalJsonValue ::Integer (
utils ::millis_since_unix_epoch ( )
. try_into ( )
. expect ( "Timestamp is valid js_int value" ) ,
) ,
) ;
join_event_stub . insert (
"content" . to_owned ( ) ,
to_canonical_value ( RoomMemberEventContent {
membership : MembershipState ::Join ,
displayname : services ( ) . users . displayname ( sender_user ) ? ,
avatar_url : services ( ) . users . avatar_url ( sender_user ) ? ,
is_direct : None ,
third_party_invite : None ,
blurhash : services ( ) . users . blurhash ( sender_user ) ? ,
reason ,
join_authorized_via_users_server ,
} )
. expect ( "event is valid, we just created it" ) ,
) ;
// We don't leave the event id in the pdu because that's only allowed in v1 or v2 rooms
join_event_stub . remove ( "event_id" ) ;
// In order to create a compatible ref hash (EventID) the `hashes` field needs to be present
ruma ::signatures ::hash_and_sign_event (
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
& mut join_event_stub ,
& room_version_id ,
)
. expect ( "event is valid, we just created it" ) ;
// Generate event id
let event_id = format! (
"${}" ,
ruma ::signatures ::reference_hash ( & join_event_stub , & room_version_id )
. expect ( "ruma can calculate reference hashes" )
) ;
let event_id = < & EventId > ::try_from ( event_id . as_str ( ) )
. expect ( "ruma's reference hashes are valid event ids" ) ;
// Add event_id back
join_event_stub . insert (
"event_id" . to_owned ( ) ,
CanonicalJsonValue ::String ( event_id . as_str ( ) . to_owned ( ) ) ,
) ;
// It has enough fields to be called a proper event now
let mut join_event = join_event_stub ;
info ! ( "Asking {remote_server} for send_join" ) ;
let send_join_response = services ( )
. sending
. send_federation_request (
& remote_server ,
federation ::membership ::create_join_event ::v2 ::Request {
room_id : room_id . to_owned ( ) ,
event_id : event_id . to_owned ( ) ,
pdu : PduEvent ::convert_to_outgoing_federation_event ( join_event . clone ( ) ) ,
omit_members : false ,
} ,
)
. await ? ;
info ! ( "send_join finished" ) ;
if let Some ( signed_raw ) = & send_join_response . room_state . event {
info ! ( "There is a signed event. This room is probably using restricted joins. Adding signature to our event" ) ;
let Ok ( ( signed_event_id , signed_value ) ) =
gen_event_id_canonical_json ( signed_raw , & room_version_id )
else {
// Event could not be converted to canonical json
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Could not convert event to canonical json." ,
) ) ;
} ;
if signed_event_id ! = event_id {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server sent event with wrong event id" ,
) ) ;
}
match signed_value [ "signatures" ]
. as_object ( )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server sent invalid signatures type" ,
) )
. and_then ( | e | {
e . get ( remote_server . as_str ( ) ) . ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server did not send its signature" ,
) )
} ) {
Ok ( signature ) = > {
join_event
. get_mut ( "signatures" )
. expect ( "we created a valid pdu" )
. as_object_mut ( )
. expect ( "we created a valid pdu" )
. insert ( remote_server . to_string ( ) , signature . clone ( ) ) ;
}
Err ( e ) = > {
warn ! (
"Server {remote_server} sent invalid signature in sendjoin signatures for event {signed_value:?}: {e:?}" ,
) ;
}
}
}
services ( ) . rooms . short . get_or_create_shortroomid ( room_id ) ? ;
// In order to create a compatible ref hash (EventID) the `hashes` field needs to be present
ruma ::signatures ::hash_and_sign_event (
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
& mut join_event_stub ,
& room_version_id ,
)
. expect ( "event is valid, we just created it" ) ;
info ! ( "Parsing join event" ) ;
let parsed_join_pdu = PduEvent ::from_id_val ( event_id , join_event . clone ( ) )
. map_err ( | _ | Error ::BadServerResponse ( "Invalid join event PDU." ) ) ? ;
// Generate event id
let event_id = format! (
"${}" ,
ruma ::signatures ::reference_hash ( & join_event_stub , & room_version_id )
. expect ( "ruma can calculate reference hashes" )
) ;
let event_id = < & EventId > ::try_from ( event_id . as_str ( ) )
. expect ( "ruma's reference hashes are valid event ids" ) ;
let mut state = HashMap ::new ( ) ;
let pub_key_map = RwLock ::new ( BTreeMap ::new ( ) ) ;
// Add event_id back
join_event_stub . insert (
"event_id" . to_owned ( ) ,
CanonicalJsonValue ::String ( event_id . as_str ( ) . to_owned ( ) ) ,
) ;
info ! ( "Fetching join signing keys" ) ;
services ( )
. rooms
. event_handler
. fetch_join_signing_keys ( & send_join_response , & room_version_id , & pub_key_map )
. await ? ;
// It has enough fields to be called a proper event now
let join_event = join_event_stub ;
info ! ( "Going through send_join response room_state" ) ;
for result in send_join_response
. room_state
. state
. iter ( )
. map ( | pdu | validate_and_add_event_id ( pdu , & room_version_id , & pub_key_map ) )
{
let Ok ( ( event_id , value ) ) = result . await else {
continue ;
} ;
let send_join_response = services ( )
. sending
. send_federation_request (
& remote_server ,
federation ::membership ::create_join_event ::v2 ::Request {
room_id : room_id . to_owned ( ) ,
event_id : event_id . to_owned ( ) ,
pdu : PduEvent ::convert_to_outgoing_federation_event ( join_event . clone ( ) ) ,
omit_members : false ,
} ,
)
. await ? ;
let pdu = PduEvent ::from_id_val ( & event_id , value . clone ( ) ) . map_err ( | e | {
warn ! ( "Invalid PDU in send_join response: {} {:?}" , e , value ) ;
Error ::BadServerResponse ( "Invalid PDU in send_join response." )
} ) ? ;
if let Some ( signed_raw ) = send_join_response . room_state . event {
let ( signed_event_id , signed_value ) =
match gen_event_id_canonical_json ( & signed_raw , & room_version_id ) {
Ok ( t ) = > t ,
Err ( _ ) = > {
// Event could not be converted to canonical json
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Could not convert event to canonical json." ,
) ) ;
}
} ;
services ( )
. rooms
. outlier
. add_pdu_outlier ( & event_id , & value ) ? ;
if let Some ( state_key ) = & pdu . state_key {
let shortstatekey = services ( )
. rooms
. short
. get_or_create_shortstatekey ( & pdu . kind . to_string ( ) . into ( ) , state_key ) ? ;
state . insert ( shortstatekey , pdu . event_id . clone ( ) ) ;
}
}
if signed_event_id ! = event_id {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Server sent event with wrong event id" ,
) ) ;
}
info ! ( "Going through send_join response auth_chain" ) ;
for result in send_join_response
. room_state
. auth_chain
. iter ( )
. map ( | pdu | validate_and_add_event_id ( pdu , & room_version_id , & pub_key_map ) )
{
let Ok ( ( event_id , value ) ) = result . await else {
continue ;
} ;
drop ( state_lock ) ;
let pub_key_map = RwLock ::new ( BTreeMap ::new ( ) ) ;
services ( )
. rooms
. outlier
. add_pdu_outlier ( & event_id , & value ) ? ;
}
info ! ( "Running send_join auth check" ) ;
let authenticated = state_res ::event_auth ::auth_check (
& state_res ::RoomVersion ::new ( & room_version_id ) . expect ( "room version is supported" ) ,
& parsed_join_pdu ,
None ::< PduEvent > , // TODO: third party invite
| k , s | {
services ( )
. rooms
. event_handler
. handle_incoming_pdu (
& remote_server ,
& signed_event_id ,
room_id ,
signed_value ,
true ,
& pub_key_map ,
. timeline
. get_pdu (
state . get (
& services ( )
. rooms
. short
. get_or_create_shortstatekey ( & k . to_string ( ) . into ( ) , s )
. ok ( ) ? ,
) ? ,
)
. await ? ;
} else {
return Err ( error ) ;
}
} else {
return Err ( error ) ;
. ok ( ) ?
} ,
)
. map_err ( | e | {
warn ! ( "Auth check failed: {e}" ) ;
Error ::BadRequest ( ErrorKind ::InvalidParam , "Auth check failed" )
} ) ? ;
if ! authenticated {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Auth check failed" ,
) ) ;
}
info ! ( "Saving state from send_join" ) ;
let ( statehash_before_join , new , removed ) = services ( ) . rooms . state_compressor . save_state (
room_id ,
Arc ::new (
state
. into_iter ( )
. map ( | ( k , id ) | {
services ( )
. rooms
. state_compressor
. compress_state_event ( k , & id )
} )
. collect ::< Result < _ > > ( ) ? ,
) ,
) ? ;
services ( )
. rooms
. state
. force_state ( room_id , statehash_before_join , new , removed , & state_lock )
. await ? ;
info ! ( "Updating joined counts for new room" ) ;
services ( ) . rooms . state_cache . update_joined_count ( room_id ) ? ;
// We append to state before appending the pdu, so we don't have a moment in time with the
// pdu without it's state. This is okay because append_pdu can't fail.
let statehash_after_join = services ( ) . rooms . state . append_to_state ( & parsed_join_pdu ) ? ;
info ! ( "Appending new room join event" ) ;
services ( )
. rooms
. timeline
. append_pdu (
& parsed_join_pdu ,
join_event ,
vec! [ ( * parsed_join_pdu . event_id ) . to_owned ( ) ] ,
& state_lock ,
)
. await ? ;
info ! ( "Setting final room state for new room" ) ;
// We set the room state after inserting the pdu, so that we never have a moment in time
// where events in the current room state do not exist
services ( )
. rooms
. state
. set_room_state ( room_id , statehash_after_join , & state_lock ) ? ;
}
Ok ( join_room_by_id ::v3 ::Response ::new ( room_id . to_owned ( ) ) )
@ -1275,16 +1266,13 @@ pub(crate) async fn invite_helper<'a>(
let pub_key_map = RwLock ::new ( BTreeMap ::new ( ) ) ;
// We do not add the event_id field to the pdu here because of signature and hashes checks
let ( event_id , value ) = match gen_event_id_canonical_json ( & response . event , & room_version_id )
{
Ok ( t ) = > t ,
Err ( _ ) = > {
// Event could not be converted to canonical json
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Could not convert event to canonical json." ,
) ) ;
}
let Ok ( ( event_id , value ) ) = gen_event_id_canonical_json ( & response . event , & room_version_id )
else {
// Event could not be converted to canonical json
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
"Could not convert event to canonical json." ,
) ) ;
} ;
if * pdu . event_id ! = * event_id {
@ -1393,10 +1381,7 @@ pub async fn leave_all_rooms(user_id: &UserId) -> Result<()> {
. collect ::< Vec < _ > > ( ) ;
for room_id in all_rooms {
let room_id = match room_id {
Ok ( room_id ) = > room_id ,
Err ( _ ) = > continue ,
} ;
let Ok ( room_id ) = room_id else { continue } ;
let _ = leave_room ( user_id , & room_id , None ) . await ;
}
@ -1406,35 +1391,11 @@ pub async fn leave_all_rooms(user_id: &UserId) -> Result<()> {
pub async fn leave_room ( user_id : & UserId , room_id : & RoomId , reason : Option < String > ) -> Result < ( ) > {
// Ask a remote server if we don't have this room
if ! services ( )
if services ( )
. rooms
. state_cache
. server_in_room ( services ( ) . globals . server_name ( ) , room_id ) ?
{
if let Err ( e ) = remote_leave_room ( user_id , room_id ) . await {
warn ! ( "Failed to leave room {} remotely: {}" , user_id , e ) ;
// Don't tell the client about this error
}
let last_state = services ( )
. rooms
. state_cache
. invite_state ( user_id , room_id ) ?
. map_or_else (
| | services ( ) . rooms . state_cache . left_state ( user_id , room_id ) ,
| s | Ok ( Some ( s ) ) ,
) ? ;
// We always drop the invite, we can't rely on other servers
services ( ) . rooms . state_cache . update_membership (
room_id ,
user_id ,
MembershipState ::Leave ,
user_id ,
last_state ,
true ,
) ? ;
} else {
let mutex_state = Arc ::clone (
services ( )
. globals
@ -1493,6 +1454,30 @@ pub async fn leave_room(user_id: &UserId, room_id: &RoomId, reason: Option<Strin
& state_lock ,
)
. await ? ;
} else {
if let Err ( e ) = remote_leave_room ( user_id , room_id ) . await {
warn ! ( "Failed to leave room {} remotely: {}" , user_id , e ) ;
// Don't tell the client about this error
}
let last_state = services ( )
. rooms
. state_cache
. invite_state ( user_id , room_id ) ?
. map_or_else (
| | services ( ) . rooms . state_cache . left_state ( user_id , room_id ) ,
| s | Ok ( Some ( s ) ) ,
) ? ;
// We always drop the invite, we can't rely on other servers
services ( ) . rooms . state_cache . update_membership (
room_id ,
user_id ,
MembershipState ::Leave ,
user_id ,
last_state ,
true ,
) ? ;
}
Ok ( ( ) )
@ -1516,7 +1501,7 @@ async fn remote_leave_room(user_id: &UserId, room_id: &RoomId) -> Result<()> {
. iter ( )
. filter_map ( | event | serde_json ::from_str ( event . json ( ) . get ( ) ) . ok ( ) )
. filter_map ( | event : serde_json ::Value | event . get ( "sender" ) . cloned ( ) )
. filter_map ( | sender | sender . as_str ( ) . map ( | s | s . to_owned ( ) ) )
. filter_map ( | sender | sender . as_str ( ) . map ( ToOwned ::to_owned ) )
. filter_map ( | sender | UserId ::parse ( sender ) . ok ( ) )
. map ( | user | user . server_name ( ) . to_owned ( ) )
. collect ( ) ;