2023-06-26 08:33:31 +02:00
#![ allow(deprecated) ]
2021-05-20 23:46:52 +02:00
use crate ::{
2022-09-06 23:15:09 +02:00
api ::client_server ::{ self , claim_keys_helper , get_keys_helper } ,
2024-07-06 22:56:08 +01:00
service ::{
globals ::SigningKeys ,
2024-08-24 10:27:03 +01:00
media ::FileMeta ,
2024-07-06 22:56:08 +01:00
pdu ::{ gen_event_id_canonical_json , PduBuilder } ,
} ,
2022-10-05 20:34:31 +02:00
services , utils , Error , PduEvent , Result , Ruma ,
2021-05-20 23:46:52 +02:00
} ;
2022-01-20 11:51:31 +01:00
use axum ::{ response ::IntoResponse , Json } ;
2024-09-24 18:48:48 +02:00
use axum_extra ::headers ::{ CacheControl , Header } ;
2020-10-05 22:19:22 +02:00
use get_profile_information ::v1 ::ProfileField ;
2024-06-25 09:39:06 +01:00
use http ::header ::AUTHORIZATION ;
2022-10-05 20:41:05 +02:00
2020-09-12 22:41:33 +02:00
use ruma ::{
api ::{
2021-06-17 20:12:36 +02:00
client ::error ::{ Error as RumaError , ErrorKind } ,
2020-09-12 22:41:33 +02:00
federation ::{
2024-08-24 10:27:03 +01:00
authenticated_media ::{
get_content , get_content_thumbnail , Content , ContentMetadata , FileOrLocation ,
} ,
2021-06-14 11:36:18 +02:00
authorization ::get_event_authorization ,
2023-02-18 13:20:20 +01:00
backfill ::get_backfill ,
2021-04-21 10:51:34 +02:00
device ::get_devices ::{ self , v1 ::UserDevice } ,
2020-09-25 12:26:29 +02:00
directory ::{ get_public_rooms , get_public_rooms_filtered } ,
2024-05-02 09:26:43 +01:00
discovery ::{
discover_homeserver , get_server_keys , get_server_version , ServerSigningKeys ,
VerifyKey ,
} ,
2021-06-14 10:52:27 +02:00
event ::{ get_event , get_missing_events , get_room_state , get_room_state_ids } ,
2021-05-28 13:44:40 +02:00
keys ::{ claim_keys , get_keys } ,
2025-02-28 14:09:33 +00:00
membership ::{
create_invite , create_join_event , create_leave_event , prepare_join_event ,
prepare_leave_event ,
} ,
2024-05-28 00:22:11 +02:00
openid ::get_openid_userinfo ,
2021-04-16 18:18:29 +02:00
query ::{ get_profile_information , get_room_information } ,
2024-03-02 11:12:22 +00:00
space ::get_hierarchy ,
2021-05-28 13:44:40 +02:00
transactions ::{
2022-03-05 10:16:21 +08:00
edu ::{ DeviceListUpdateContent , DirectDeviceContent , Edu , SigningKeyUpdateContent } ,
2021-05-28 13:44:40 +02:00
send_transaction_message ,
} ,
2020-08-06 08:29:59 -04:00
} ,
2022-02-12 21:04:38 +01:00
EndpointError , IncomingResponse , MatrixVersion , OutgoingRequest , OutgoingResponse ,
SendAccessToken ,
2020-08-14 11:29:32 +02:00
} ,
2022-12-14 13:09:10 +01:00
directory ::{ Filter , RoomNetwork } ,
2021-04-11 21:01:27 +02:00
events ::{
2022-10-09 17:25:06 +02:00
receipt ::{ ReceiptEvent , ReceiptEventContent , ReceiptType } ,
2021-04-16 18:18:29 +02:00
room ::{
2024-04-09 14:36:50 +01:00
join_rules ::{ AllowRule , JoinRule , RoomJoinRulesEventContent } ,
2021-10-13 10:16:45 +02:00
member ::{ MembershipState , RoomMemberEventContent } ,
2021-04-16 18:18:29 +02:00
} ,
2023-02-26 16:29:06 +01:00
StateEventType , TimelineEventType ,
2021-04-11 21:01:27 +02:00
} ,
2022-02-18 15:33:14 +01:00
serde ::{ Base64 , JsonObject , Raw } ,
2022-10-08 13:03:07 +02:00
to_device ::DeviceIdOrAllDevices ,
2023-02-18 13:20:20 +01:00
uint , user_id , CanonicalJsonObject , CanonicalJsonValue , EventId , MilliSecondsSinceUnixEpoch ,
OwnedEventId , OwnedRoomId , OwnedServerName , OwnedServerSigningKeyId , OwnedUserId , RoomId ,
2024-04-09 14:36:50 +01:00
RoomVersionId , ServerName , Signatures , UserId ,
2020-05-26 10:27:51 +02:00
} ;
2021-10-13 10:16:45 +02:00
use serde_json ::value ::{ to_raw_value , RawValue as RawJsonValue } ;
2020-04-22 20:55:11 +02:00
use std ::{
2022-10-08 13:03:07 +02:00
collections ::BTreeMap ,
2020-08-14 11:31:31 +02:00
fmt ::Debug ,
2021-04-29 20:58:05 +02:00
mem ,
2020-12-08 12:34:46 +01:00
net ::{ IpAddr , SocketAddr } ,
2024-03-05 14:22:54 +00:00
sync ::Arc ,
2021-05-20 23:46:52 +02:00
time ::{ Duration , Instant , SystemTime } ,
2020-04-22 20:55:11 +02:00
} ;
2024-10-31 16:23:54 +00:00
use tokio ::sync ::{ Mutex , RwLock } ;
2022-10-05 20:41:05 +02:00
2023-12-23 19:34:27 -08:00
use tracing ::{ debug , error , warn } ;
2020-04-19 14:14:47 +02:00
2021-04-21 00:35:44 -03:00
/// Wraps either an literal IP address plus port, or a hostname plus complement
/// (colon-plus-port if it was specified).
///
/// Note: A `FedDest::Named` might contain an IP address in string form if there
/// was no port specified to construct a SocketAddr with.
///
/// # Examples:
2022-04-14 16:42:08 +02:00
/// ```rust
2022-10-12 14:39:58 -07:00
/// # use conduit::api::server_server::FedDest;
2022-04-14 16:42:08 +02:00
/// # fn main() -> Result<(), std::net::AddrParseError> {
2021-04-21 00:35:44 -03:00
/// FedDest::Literal("198.51.100.3:8448".parse()?);
/// FedDest::Literal("[2001:db8::4:5]:443".parse()?);
/// FedDest::Named("matrix.example.org".to_owned(), "".to_owned());
/// FedDest::Named("matrix.example.org".to_owned(), ":8448".to_owned());
/// FedDest::Named("198.51.100.5".to_owned(), "".to_owned());
2022-04-14 16:42:08 +02:00
/// # Ok(())
/// # }
2021-04-21 00:35:44 -03:00
/// ```
2022-10-10 14:09:11 +02:00
#[ derive(Clone, Debug, PartialEq, Eq) ]
2021-08-26 23:11:13 +02:00
pub enum FedDest {
2021-04-16 00:27:26 -03:00
Literal ( SocketAddr ) ,
Named ( String , String ) ,
}
2021-04-16 12:18:22 -03:00
impl FedDest {
2021-04-21 00:35:44 -03:00
fn into_https_string ( self ) -> String {
2021-04-16 00:27:26 -03:00
match self {
2022-12-21 10:42:12 +01:00
Self ::Literal ( addr ) = > format! ( " https:// {addr} " ) ,
Self ::Named ( host , port ) = > format! ( " https:// {host} {port} " ) ,
2021-04-16 00:27:26 -03:00
}
}
2021-04-21 00:35:44 -03:00
fn hostname ( & self ) -> String {
2021-04-16 00:27:26 -03:00
match & self {
Self ::Literal ( addr ) = > addr . ip ( ) . to_string ( ) ,
2021-04-16 12:18:22 -03:00
Self ::Named ( host , _ ) = > host . clone ( ) ,
2021-04-16 00:27:26 -03:00
}
}
2021-08-26 23:11:13 +02:00
fn port ( & self ) -> Option < u16 > {
match & self {
Self ::Literal ( addr ) = > Some ( addr . port ( ) ) ,
Self ::Named ( _ , port ) = > port [ 1 .. ] . parse ( ) . ok ( ) ,
}
}
2021-04-16 00:27:26 -03:00
}
2022-09-06 23:15:09 +02:00
#[ tracing::instrument(skip(request)) ]
2024-05-05 13:11:44 +01:00
pub ( crate ) async fn send_request < T > (
2021-01-14 14:39:56 -05:00
destination : & ServerName ,
2020-04-19 14:14:47 +02:00
request : T ,
2020-08-14 11:31:31 +02:00
) -> Result < T ::IncomingResponse >
where
2024-05-05 13:11:44 +01:00
T : OutgoingRequest + Debug ,
2020-08-14 11:31:31 +02:00
{
2022-09-06 23:15:09 +02:00
if ! services ( ) . globals . allow_federation ( ) {
2020-11-14 23:13:06 +01:00
return Err ( Error ::bad_config ( " Federation is disabled. " ) ) ;
2020-10-06 21:04:51 +02:00
}
2023-07-10 16:26:36 +02:00
if destination = = services ( ) . globals . server_name ( ) {
return Err ( Error ::bad_config (
" Won't send federation request to ourselves " ,
) ) ;
}
2023-03-13 08:27:59 +01:00
debug! ( " Preparing to send request to {destination} " ) ;
2023-02-23 11:20:40 +01:00
2022-10-05 20:34:31 +02:00
let cached_result = services ( )
. globals
2020-12-06 11:05:51 +01:00
. actual_destination_cache
. read ( )
2024-03-05 14:22:54 +00:00
. await
2021-01-14 14:39:56 -05:00
. get ( destination )
2020-12-06 11:05:51 +01:00
. cloned ( ) ;
2020-09-23 12:03:08 +02:00
2024-06-24 22:12:54 +01:00
let actual_destination = if let Some ( DestinationResponse {
actual_destination ,
dest_type ,
} ) = cached_result
{
match dest_type {
DestType ::IsIpOrHasPort = > actual_destination ,
DestType ::LookupFailed {
well_known_retry ,
well_known_backoff_mins ,
} = > {
if well_known_retry < Instant ::now ( ) {
find_actual_destination ( destination , None , false , Some ( well_known_backoff_mins ) )
. await
} else {
actual_destination
}
}
2021-08-26 23:11:13 +02:00
2024-06-24 22:12:54 +01:00
DestType ::WellKnown { expires } = > {
if expires < Instant ::now ( ) {
find_actual_destination ( destination , None , false , None ) . await
} else {
actual_destination
}
}
DestType ::WellKnownSrv {
srv_expires ,
well_known_expires ,
well_known_host ,
} = > {
if well_known_expires < Instant ::now ( ) {
find_actual_destination ( destination , None , false , None ) . await
} else if srv_expires < Instant ::now ( ) {
find_actual_destination ( destination , Some ( well_known_host ) , true , None ) . await
} else {
actual_destination
}
}
DestType ::Srv {
well_known_retry ,
well_known_backoff_mins ,
srv_expires ,
} = > {
if well_known_retry < Instant ::now ( ) {
find_actual_destination ( destination , None , false , Some ( well_known_backoff_mins ) )
. await
} else if srv_expires < Instant ::now ( ) {
find_actual_destination ( destination , None , true , Some ( well_known_backoff_mins ) )
. await
} else {
actual_destination
}
}
}
} else {
find_actual_destination ( destination , None , false , None ) . await
2020-12-06 11:05:51 +01:00
} ;
2020-08-14 11:31:31 +02:00
2021-08-26 23:11:13 +02:00
let actual_destination_str = actual_destination . clone ( ) . into_https_string ( ) ;
2020-08-14 11:31:31 +02:00
let mut http_request = request
2022-02-12 21:04:38 +01:00
. try_into_http_request ::< Vec < u8 > > (
& actual_destination_str ,
SendAccessToken ::IfRequired ( " " ) ,
2024-08-28 11:24:51 +01:00
& [ MatrixVersion ::V1_11 ] ,
2022-02-12 21:04:38 +01:00
)
2020-09-15 08:55:02 +02:00
. map_err ( | e | {
2021-08-26 23:11:13 +02:00
warn! (
" Failed to find destination {}: {} " ,
actual_destination_str , e
) ;
2020-09-15 08:55:02 +02:00
Error ::BadServerResponse ( " Invalid destination " )
} ) ? ;
2020-04-22 11:53:06 +02:00
2020-04-22 21:14:40 +02:00
let mut request_map = serde_json ::Map ::new ( ) ;
2020-04-19 14:14:47 +02:00
2020-04-22 21:14:40 +02:00
if ! http_request . body ( ) . is_empty ( ) {
2020-04-25 11:47:32 +02:00
request_map . insert (
" content " . to_owned ( ) ,
2020-09-15 08:55:02 +02:00
serde_json ::from_slice ( http_request . body ( ) )
. expect ( " body is valid json, we just created it " ) ,
2020-04-25 11:47:32 +02:00
) ;
2020-04-22 21:14:40 +02:00
} ;
2020-04-19 14:14:47 +02:00
2020-04-22 11:53:06 +02:00
request_map . insert ( " method " . to_owned ( ) , T ::METADATA . method . to_string ( ) . into ( ) ) ;
2020-08-14 11:31:31 +02:00
request_map . insert (
" uri " . to_owned ( ) ,
http_request
. uri ( )
. path_and_query ( )
. expect ( " all requests have a path " )
. to_string ( )
. into ( ) ,
) ;
2022-10-05 20:34:31 +02:00
request_map . insert (
" origin " . to_owned ( ) ,
services ( ) . globals . server_name ( ) . as_str ( ) . into ( ) ,
) ;
2020-09-14 11:00:31 +02:00
request_map . insert ( " destination " . to_owned ( ) , destination . as_str ( ) . into ( ) ) ;
2020-04-22 21:14:40 +02:00
2020-10-27 19:10:09 -04:00
let mut request_json =
serde_json ::from_value ( request_map . into ( ) ) . expect ( " valid JSON is valid BTreeMap " ) ;
2020-06-05 18:19:26 +02:00
ruma ::signatures ::sign_json (
2022-09-06 23:15:09 +02:00
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
2020-12-31 21:07:05 +01:00
& mut request_json ,
2020-05-09 21:47:09 +02:00
)
2020-09-15 08:55:02 +02:00
. expect ( " our request json is what ruma expects " ) ;
2020-04-19 14:14:47 +02:00
2020-10-27 19:10:09 -04:00
let request_json : serde_json ::Map < String , serde_json ::Value > =
serde_json ::from_slice ( & serde_json ::to_vec ( & request_json ) . unwrap ( ) ) . unwrap ( ) ;
2020-04-22 11:53:06 +02:00
let signatures = request_json [ " signatures " ]
. as_object ( )
. unwrap ( )
. values ( )
2020-08-14 11:31:31 +02:00
. map ( | v | {
v . as_object ( )
. unwrap ( )
. iter ( )
. map ( | ( k , v ) | ( k , v . as_str ( ) . unwrap ( ) ) )
} ) ;
for signature_server in signatures {
for s in signature_server {
http_request . headers_mut ( ) . insert (
AUTHORIZATION ,
2024-09-24 18:48:48 +02:00
format! (
2024-04-30 09:31:44 +01:00
" X-Matrix origin= \" {} \" ,destination= \" {} \" ,key= \" {} \" ,sig= \" {} \" " ,
2022-09-06 23:15:09 +02:00
services ( ) . globals . server_name ( ) ,
2024-04-30 09:31:44 +01:00
destination ,
2020-08-14 11:31:31 +02:00
s . 0 ,
s . 1
2024-09-24 18:48:48 +02:00
)
. try_into ( )
. unwrap ( ) ,
2020-08-14 11:31:31 +02:00
) ;
}
2020-04-22 11:53:06 +02:00
}
2024-03-31 21:30:26 +01:00
let reqwest_request = reqwest ::Request ::try_from ( http_request ) ? ;
2020-08-14 11:31:31 +02:00
2020-09-23 15:23:29 +02:00
let url = reqwest_request . url ( ) . clone ( ) ;
2021-08-26 23:11:13 +02:00
2023-03-13 08:27:59 +01:00
debug! ( " Sending request to {destination} at {url} " ) ;
2022-10-05 20:34:31 +02:00
let response = services ( )
. globals
. federation_client ( )
. execute ( reqwest_request )
. await ;
2023-03-13 08:27:59 +01:00
debug! ( " Received response from {destination} at {url} " ) ;
2020-04-22 11:53:06 +02:00
2021-04-29 20:58:05 +02:00
match response {
Ok ( mut response ) = > {
// reqwest::Response -> http::Response conversion
let status = response . status ( ) ;
let mut http_response_builder = http ::Response ::builder ( )
. status ( status )
. version ( response . version ( ) ) ;
mem ::swap (
response . headers_mut ( ) ,
http_response_builder
. headers_mut ( )
. expect ( " http::response::Builder is usable " ) ,
) ;
2020-12-05 21:03:43 +01:00
2023-03-13 08:27:59 +01:00
debug! ( " Getting response bytes from {destination} " ) ;
2021-04-29 20:58:05 +02:00
let body = response . bytes ( ) . await . unwrap_or_else ( | e | {
2021-04-13 15:00:45 +02:00
warn! ( " server error {} " , e ) ;
Vec ::new ( ) . into ( )
} ) ; // TODO: handle timeout
2023-03-13 08:27:59 +01:00
debug! ( " Got response bytes from {destination} " ) ;
2020-12-05 21:03:43 +01:00
if status ! = 200 {
2021-08-21 14:22:21 +02:00
warn! (
2021-03-26 11:10:45 +01:00
" {} {}: {} " ,
url ,
status ,
2021-03-26 13:41:05 +01:00
String ::from_utf8_lossy ( & body )
. lines ( )
. collect ::< Vec < _ > > ( )
. join ( " " )
2021-03-26 11:10:45 +01:00
) ;
2020-12-05 21:03:43 +01:00
}
2020-09-12 21:30:07 +02:00
2021-05-23 16:45:32 +02:00
let http_response = http_response_builder
. body ( body )
. expect ( " reqwest body is valid http body " ) ;
if status = = 200 {
2023-03-13 08:27:59 +01:00
debug! ( " Parsing response bytes from {destination} " ) ;
2021-05-23 16:45:32 +02:00
let response = T ::IncomingResponse ::try_from_http_response ( http_response ) ;
2021-08-26 23:11:13 +02:00
2021-08-04 22:55:03 +02:00
response . map_err ( | e | {
2021-08-17 16:06:09 +02:00
warn! (
2024-09-24 18:48:48 +02:00
" Invalid 200 response from {} on: {} {:?} " ,
2021-08-17 16:06:09 +02:00
& destination , url , e
) ;
2021-08-04 22:55:03 +02:00
Error ::BadServerResponse ( " Server returned bad 200 response. " )
} )
2021-05-23 16:45:32 +02:00
} else {
2023-03-13 08:27:59 +01:00
debug! ( " Returning error from {destination} " ) ;
2021-05-23 16:45:32 +02:00
Err ( Error ::FederationError (
destination . to_owned ( ) ,
2022-12-14 13:09:10 +01:00
RumaError ::from_http_response ( http_response ) ,
2021-05-23 16:45:32 +02:00
) )
}
2020-04-22 11:53:06 +02:00
}
2022-10-13 10:14:52 +02:00
Err ( e ) = > {
2022-10-15 00:28:43 +02:00
warn! (
" Could not send request to {} at {}: {} " ,
destination , actual_destination_str , e
) ;
2022-10-13 10:14:52 +02:00
Err ( e . into ( ) )
2022-10-15 00:28:43 +02:00
}
2020-04-22 11:53:06 +02:00
}
2020-04-19 14:14:47 +02:00
}
2020-04-22 20:55:11 +02:00
2021-04-16 12:18:22 -03:00
fn get_ip_with_port ( destination_str : & str ) -> Option < FedDest > {
2021-04-16 00:27:26 -03:00
if let Ok ( destination ) = destination_str . parse ::< SocketAddr > ( ) {
2021-04-16 12:18:22 -03:00
Some ( FedDest ::Literal ( destination ) )
2020-12-08 12:34:46 +01:00
} else if let Ok ( ip_addr ) = destination_str . parse ::< IpAddr > ( ) {
2021-04-16 12:18:22 -03:00
Some ( FedDest ::Literal ( SocketAddr ::new ( ip_addr , 8448 ) ) )
2020-12-08 12:34:46 +01:00
} else {
None
}
}
2021-04-16 12:18:22 -03:00
fn add_port_to_hostname ( destination_str : & str ) -> FedDest {
2021-04-16 00:27:26 -03:00
let ( host , port ) = match destination_str . find ( ':' ) {
None = > ( destination_str , " :8448 " ) ,
Some ( pos ) = > destination_str . split_at ( pos ) ,
} ;
2021-10-13 10:24:39 +02:00
FedDest ::Named ( host . to_owned ( ) , port . to_owned ( ) )
2020-12-08 12:34:46 +01:00
}
2024-06-24 22:12:54 +01:00
#[ derive(Clone) ]
pub struct DestinationResponse {
pub actual_destination : FedDest ,
pub dest_type : DestType ,
}
#[ derive(Clone) ]
pub enum DestType {
WellKnownSrv {
srv_expires : Instant ,
well_known_expires : Instant ,
well_known_host : String ,
} ,
WellKnown {
expires : Instant ,
} ,
Srv {
srv_expires : Instant ,
well_known_retry : Instant ,
well_known_backoff_mins : u16 ,
} ,
IsIpOrHasPort ,
LookupFailed {
well_known_retry : Instant ,
well_known_backoff_mins : u16 ,
} ,
}
/// Implemented according to the specification at <https://spec.matrix.org/v1.11/server-server-api/#resolving-server-names>
2020-12-08 12:34:46 +01:00
/// Numbers in comments below refer to bullet points in linked section of specification
2024-06-24 22:12:54 +01:00
async fn find_actual_destination (
destination : & '_ ServerName ,
// The host used to potentially lookup SRV records against, only used when only_request_srv is true
well_known_dest : Option < String > ,
// Should be used when only the SRV lookup has expired
only_request_srv : bool ,
// The backoff time for the last well known failure, if any
well_known_backoff_mins : Option < u16 > ,
) -> FedDest {
2023-03-13 08:27:59 +01:00
debug! ( " Finding actual destination for {destination} " ) ;
2024-06-24 22:12:54 +01:00
let destination_str = destination . to_string ( ) ;
let next_backoff_mins = well_known_backoff_mins
// Errors are recommended to be cached for up to an hour
. map ( | mins | ( mins * 2 ) . min ( 60 ) )
. unwrap_or ( 1 ) ;
let ( actual_destination , dest_type ) = if only_request_srv {
let destination_str = well_known_dest . unwrap_or ( destination_str ) ;
let ( dest , expires ) = get_srv_destination ( destination_str ) . await ;
let well_known_retry =
Instant ::now ( ) + Duration ::from_secs ( ( 60 * next_backoff_mins ) . into ( ) ) ;
(
dest ,
if let Some ( expires ) = expires {
DestType ::Srv {
well_known_backoff_mins : next_backoff_mins ,
srv_expires : expires ,
well_known_retry ,
}
2021-04-16 12:18:22 -03:00
} else {
2024-06-24 22:12:54 +01:00
DestType ::LookupFailed {
well_known_retry ,
well_known_backoff_mins : next_backoff_mins ,
}
} ,
)
} else {
match get_ip_with_port ( & destination_str ) {
Some ( host_port ) = > {
debug! ( " 1: IP literal with provided or default port " ) ;
( host_port , DestType ::IsIpOrHasPort )
}
None = > {
if let Some ( pos ) = destination_str . find ( ':' ) {
debug! ( " 2: Hostname with included port " ) ;
let ( host , port ) = destination_str . split_at ( pos ) ;
(
FedDest ::Named ( host . to_owned ( ) , port . to_owned ( ) ) ,
DestType ::IsIpOrHasPort ,
)
} else {
debug! ( " Requesting well known for {destination_str} " ) ;
match request_well_known ( destination_str . as_str ( ) ) . await {
Some ( ( delegated_hostname , timestamp ) ) = > {
debug! ( " 3: A .well-known file is available " ) ;
match get_ip_with_port ( & delegated_hostname ) {
// 3.1: IP literal in .well-known file
Some ( host_and_port ) = > {
( host_and_port , DestType ::WellKnown { expires : timestamp } )
}
None = > {
if let Some ( pos ) = delegated_hostname . find ( ':' ) {
debug! ( " 3.2: Hostname with port in .well-known file " ) ;
let ( host , port ) = delegated_hostname . split_at ( pos ) ;
(
FedDest ::Named ( host . to_owned ( ) , port . to_owned ( ) ) ,
DestType ::WellKnown { expires : timestamp } ,
)
2021-08-26 23:11:13 +02:00
} else {
2024-06-24 22:12:54 +01:00
debug! ( " Delegated hostname has no port in this branch " ) ;
let ( dest , srv_expires ) =
get_srv_destination ( delegated_hostname . clone ( ) ) . await ;
(
dest ,
if let Some ( srv_expires ) = srv_expires {
DestType ::WellKnownSrv {
srv_expires ,
well_known_expires : timestamp ,
well_known_host : delegated_hostname ,
}
} else {
DestType ::WellKnown { expires : timestamp }
} ,
)
2020-12-08 12:34:46 +01:00
}
}
}
}
2024-06-24 22:12:54 +01:00
None = > {
debug! ( " 4: No .well-known or an error occured " ) ;
let ( dest , expires ) = get_srv_destination ( destination_str ) . await ;
let well_known_retry = Instant ::now ( )
+ Duration ::from_secs ( ( 60 * next_backoff_mins ) . into ( ) ) ;
(
dest ,
if let Some ( expires ) = expires {
DestType ::Srv {
srv_expires : expires ,
well_known_retry ,
well_known_backoff_mins : next_backoff_mins ,
}
2021-08-26 23:11:13 +02:00
} else {
2024-06-24 22:12:54 +01:00
DestType ::LookupFailed {
well_known_retry ,
well_known_backoff_mins : next_backoff_mins ,
}
} ,
)
2020-12-08 12:34:46 +01:00
}
}
}
2020-12-06 11:05:51 +01:00
}
2021-04-16 00:27:26 -03:00
}
2021-04-16 12:18:22 -03:00
} ;
2024-06-24 22:12:54 +01:00
2023-03-13 08:27:59 +01:00
debug! ( " Actual destination: {actual_destination:?} " ) ;
2020-12-06 11:05:51 +01:00
2024-06-24 22:12:54 +01:00
let response = DestinationResponse {
actual_destination ,
dest_type ,
2021-04-16 12:18:22 -03:00
} ;
2024-06-24 22:12:54 +01:00
services ( )
. globals
. actual_destination_cache
. write ( )
. await
. insert ( destination . to_owned ( ) , response . clone ( ) ) ;
response . actual_destination
}
/// Looks up the SRV records for federation usage
///
/// If no timestamp is returned, that means no SRV record was found
async fn get_srv_destination ( delegated_hostname : String ) -> ( FedDest , Option < Instant > ) {
if let Some ( ( hostname_override , timestamp ) ) = query_srv_record ( & delegated_hostname ) . await {
debug! ( " SRV lookup successful " ) ;
let force_port = hostname_override . port ( ) ;
if let Ok ( override_ip ) = services ( )
. globals
. dns_resolver ( )
. lookup_ip ( hostname_override . hostname ( ) )
. await
{
services ( )
. globals
. tls_name_override
. write ( )
. unwrap ( )
. insert (
delegated_hostname . clone ( ) ,
( override_ip . iter ( ) . collect ( ) , force_port . unwrap_or ( 8448 ) ) ,
) ;
} else {
2024-07-06 17:06:11 +01:00
// Removing in case there was previously a SRV record
services ( )
. globals
. tls_name_override
. write ( )
. unwrap ( )
. remove ( & delegated_hostname ) ;
2024-06-24 22:12:54 +01:00
warn! ( " Using SRV record, but could not resolve to IP " ) ;
}
if let Some ( port ) = force_port {
(
FedDest ::Named ( delegated_hostname , format! ( " : {port} " ) ) ,
Some ( timestamp ) ,
)
} else {
( add_port_to_hostname ( & delegated_hostname ) , Some ( timestamp ) )
}
} else {
2024-07-06 17:31:31 +01:00
// Removing in case there was previously a SRV record
services ( )
. globals
. tls_name_override
. write ( )
. unwrap ( )
. remove ( & delegated_hostname ) ;
2024-06-24 22:12:54 +01:00
debug! ( " No SRV records found " ) ;
( add_port_to_hostname ( & delegated_hostname ) , None )
}
2020-12-06 11:05:51 +01:00
}
2024-06-24 22:12:54 +01:00
async fn query_given_srv_record ( record : & str ) -> Option < ( FedDest , Instant ) > {
2024-04-01 20:55:13 +01:00
services ( )
2022-10-05 20:34:31 +02:00
. globals
2020-12-08 12:34:46 +01:00
. dns_resolver ( )
2024-04-01 20:55:13 +01:00
. srv_lookup ( record )
2020-12-08 12:34:46 +01:00
. await
. map ( | srv | {
srv . iter ( ) . next ( ) . map ( | result | {
2024-06-24 22:12:54 +01:00
(
FedDest ::Named (
result . target ( ) . to_string ( ) . trim_end_matches ( '.' ) . to_owned ( ) ,
format! ( " : {} " , result . port ( ) ) ,
) ,
srv . as_lookup ( ) . valid_until ( ) ,
2020-12-08 12:34:46 +01:00
)
} )
} )
2024-04-01 20:55:13 +01:00
. unwrap_or ( None )
}
2024-06-24 22:12:54 +01:00
async fn query_srv_record ( hostname : & '_ str ) -> Option < ( FedDest , Instant ) > {
2024-04-01 20:55:13 +01:00
let hostname = hostname . trim_end_matches ( '.' ) ;
if let Some ( host_port ) = query_given_srv_record ( & format! ( " _matrix-fed._tcp. {hostname} . " ) ) . await
2020-12-08 12:34:46 +01:00
{
Some ( host_port )
} else {
2024-04-01 20:55:13 +01:00
query_given_srv_record ( & format! ( " _matrix._tcp. {hostname} . " ) ) . await
2020-12-08 12:34:46 +01:00
}
}
2024-06-24 22:12:54 +01:00
async fn request_well_known ( destination : & str ) -> Option < ( String , Instant ) > {
2023-02-23 12:28:15 +01:00
let response = services ( )
. globals
. default_client ( )
. get ( & format! ( " https:// {destination} /.well-known/matrix/server " ) )
. send ( )
. await ;
2023-03-13 08:27:59 +01:00
debug! ( " Got well known response " ) ;
2024-06-24 22:12:54 +01:00
let response = match response {
Err ( e ) = > {
debug! ( " Well known error: {e:?} " ) ;
return None ;
}
Ok ( r ) = > r ,
} ;
let mut headers = response . headers ( ) . values ( ) ;
let cache_for = CacheControl ::decode ( & mut headers )
. ok ( )
. and_then ( | cc | {
// Servers should respect the cache control headers present on the response, or use a sensible default when headers are not present.
if cc . no_store ( ) | | cc . no_cache ( ) {
Some ( Duration ::ZERO )
} else {
cc . max_age ( )
// Servers should additionally impose a maximum cache time for responses: 48 hours is recommended.
. map ( | age | age . min ( Duration ::from_secs ( 60 * 60 * 48 ) ) )
}
} )
// The recommended sensible default is 24 hours.
. unwrap_or_else ( | | Duration ::from_secs ( 60 * 60 * 24 ) ) ;
let text = response . text ( ) . await ;
2023-03-13 08:27:59 +01:00
debug! ( " Got well known response text " ) ;
2024-06-24 22:12:54 +01:00
let host = | | {
let body : serde_json ::Value = serde_json ::from_str ( & text . ok ( ) ? ) . ok ( ) ? ;
body . get ( " m.server " ) ? . as_str ( ) . map ( ToOwned ::to_owned )
} ;
host ( ) . map ( | host | ( host , Instant ::now ( ) + cache_for ) )
2020-12-08 12:34:46 +01:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/version`
///
/// Get version information on this server.
2022-01-20 11:51:31 +01:00
pub async fn get_server_version_route (
_body : Ruma < get_server_version ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_server_version ::v1 ::Response > {
2021-04-11 21:01:27 +02:00
Ok ( get_server_version ::v1 ::Response {
server : Some ( get_server_version ::v1 ::Server {
2020-04-22 20:55:11 +02:00
name : Some ( " Conduit " . to_owned ( ) ) ,
version : Some ( env! ( " CARGO_PKG_VERSION " ) . to_owned ( ) ) ,
2020-04-28 20:03:14 +02:00
} ) ,
2022-01-22 16:58:32 +01:00
} )
2020-04-22 20:55:11 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/key/v2/server`
///
/// Gets the public signing keys of this server.
///
/// - Matrix does not support invalidating public keys, so the key returned by this will be valid
2025-02-23 13:50:02 +00:00
/// forever.
2021-04-13 15:00:45 +02:00
// Response type for this endpoint is Json because we need to calculate a signature for the response
2022-09-06 23:15:09 +02:00
pub async fn get_server_keys_route ( ) -> Result < impl IntoResponse > {
2022-10-09 17:25:06 +02:00
let mut verify_keys : BTreeMap < OwnedServerSigningKeyId , VerifyKey > = BTreeMap ::new ( ) ;
2020-04-22 20:55:11 +02:00
verify_keys . insert (
2022-09-06 23:15:09 +02:00
format! ( " ed25519: {} " , services ( ) . globals . keypair ( ) . version ( ) )
2021-11-27 00:30:28 +01:00
. try_into ( )
. expect ( " found invalid server signing keys in DB " ) ,
2020-08-14 11:31:31 +02:00
VerifyKey {
2022-09-06 23:15:09 +02:00
key : Base64 ::new ( services ( ) . globals . keypair ( ) . public_key ( ) . to_vec ( ) ) ,
2020-04-22 20:55:11 +02:00
} ,
) ;
let mut response = serde_json ::from_slice (
2021-04-13 15:00:45 +02:00
get_server_keys ::v2 ::Response {
2022-02-18 15:33:14 +01:00
server_key : Raw ::new ( & ServerSigningKeys {
2022-09-06 23:15:09 +02:00
server_name : services ( ) . globals . server_name ( ) . to_owned ( ) ,
2020-08-14 11:31:31 +02:00
verify_keys ,
old_verify_keys : BTreeMap ::new ( ) ,
2025-02-23 05:35:28 +00:00
signatures : Signatures ::new ( ) ,
2021-05-20 23:46:52 +02:00
valid_until_ts : MilliSecondsSinceUnixEpoch ::from_system_time (
2021-08-25 16:06:35 +02:00
SystemTime ::now ( ) + Duration ::from_secs ( 86400 * 7 ) ,
2021-05-20 23:46:52 +02:00
)
. expect ( " time is valid " ) ,
2022-02-18 15:33:14 +01:00
} )
. expect ( " static conversion, no errors " ) ,
2021-04-13 15:00:45 +02:00
}
2021-04-23 18:45:06 +02:00
. try_into_http_response ::< Vec < u8 > > ( )
2020-04-22 20:55:11 +02:00
. unwrap ( )
. body ( ) ,
)
. unwrap ( ) ;
2020-11-15 16:48:43 -05:00
2020-06-05 18:19:26 +02:00
ruma ::signatures ::sign_json (
2022-09-06 23:15:09 +02:00
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
2020-05-17 19:56:40 +02:00
& mut response ,
)
. unwrap ( ) ;
2020-11-15 16:48:43 -05:00
2022-01-22 13:32:21 +01:00
Ok ( Json ( response ) )
2020-04-22 20:55:11 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/key/v2/server/{keyId}`
///
/// Gets the public signing keys of this server.
///
/// - Matrix does not support invalidating public keys, so the key returned by this will be valid
2025-02-23 13:50:02 +00:00
/// forever.
2022-09-06 23:15:09 +02:00
pub async fn get_server_keys_deprecated_route ( ) -> impl IntoResponse {
get_server_keys_route ( ) . await
2020-04-22 20:55:11 +02:00
}
2020-08-14 11:29:32 +02:00
2021-08-31 19:14:37 +02:00
/// # `POST /_matrix/federation/v1/publicRooms`
///
/// Lists the public rooms on this server.
2020-09-14 11:42:16 +02:00
pub async fn get_public_rooms_filtered_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_public_rooms_filtered ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_public_rooms_filtered ::v1 ::Response > {
2020-09-14 11:42:16 +02:00
let response = client_server ::get_public_rooms_filtered_helper (
None ,
body . limit ,
body . since . as_deref ( ) ,
& body . filter ,
& body . room_network ,
)
2022-01-22 16:58:32 +01:00
. await ? ;
2020-09-14 11:42:16 +02:00
Ok ( get_public_rooms_filtered ::v1 ::Response {
2022-02-18 11:52:00 +01:00
chunk : response . chunk ,
2020-09-14 11:42:16 +02:00
prev_batch : response . prev_batch ,
next_batch : response . next_batch ,
total_room_count_estimate : response . total_room_count_estimate ,
2022-01-22 16:58:32 +01:00
} )
2020-09-14 11:42:16 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/publicRooms`
///
/// Lists the public rooms on this server.
2020-08-14 11:29:32 +02:00
pub async fn get_public_rooms_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_public_rooms ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_public_rooms ::v1 ::Response > {
2020-09-14 11:42:16 +02:00
let response = client_server ::get_public_rooms_filtered_helper (
2020-08-23 08:32:43 -04:00
None ,
2020-09-14 11:42:16 +02:00
body . limit ,
body . since . as_deref ( ) ,
2022-12-14 13:09:10 +01:00
& Filter ::default ( ) ,
& RoomNetwork ::Matrix ,
2020-08-14 11:29:32 +02:00
)
2022-01-22 16:58:32 +01:00
. await ? ;
2020-08-14 11:29:32 +02:00
Ok ( get_public_rooms ::v1 ::Response {
2022-02-18 11:52:00 +01:00
chunk : response . chunk ,
2020-09-14 11:42:16 +02:00
prev_batch : response . prev_batch ,
next_batch : response . next_batch ,
total_room_count_estimate : response . total_room_count_estimate ,
2022-01-22 16:58:32 +01:00
} )
2020-08-14 11:29:32 +02:00
}
2023-02-20 22:59:45 +01:00
pub fn parse_incoming_pdu (
pdu : & RawJsonValue ,
) -> Result < ( OwnedEventId , CanonicalJsonObject , OwnedRoomId ) > {
let value : CanonicalJsonObject = serde_json ::from_str ( pdu . get ( ) ) . map_err ( | e | {
warn! ( " Error parsing incoming event {:?}: {:?} " , pdu , e ) ;
Error ::BadServerResponse ( " Invalid PDU in server response " )
} ) ? ;
let room_id : OwnedRoomId = value
. get ( " room_id " )
. and_then ( | id | RoomId ::parse ( id . as_str ( ) ? ) . ok ( ) )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Invalid room id in pdu " ,
) ) ? ;
let room_version_id = services ( ) . rooms . state . get_room_version ( & room_id ) ? ;
2023-12-23 19:48:14 -08:00
let ( event_id , value ) = match gen_event_id_canonical_json ( pdu , & room_version_id ) {
2023-02-20 22:59:45 +01:00
Ok ( t ) = > t ,
2024-07-06 22:56:08 +01:00
Err ( e ) = > {
2023-02-20 22:59:45 +01:00
// Event could not be converted to canonical json
2024-07-06 22:56:08 +01:00
return Err ( e ) ;
2023-02-20 22:59:45 +01:00
}
} ;
Ok ( ( event_id , value , room_id ) )
}
2024-07-06 22:56:08 +01:00
/// Attempts to parse and append PDU to timeline.
/// If no event ID is returned, then the PDU was failed to be parsed.
/// If the Ok(()) is returned, then the PDU was successfully appended to the timeline.
async fn handle_pdu_in_transaction (
origin : & ServerName ,
pub_key_map : & RwLock < BTreeMap < String , SigningKeys > > ,
pdu : & RawJsonValue ,
) -> ( Option < OwnedEventId > , Result < ( ) > ) {
let ( event_id , value , room_id ) = match parse_incoming_pdu ( pdu ) {
Ok ( t ) = > t ,
Err ( e ) = > {
warn! ( " Could not parse PDU: {e} " ) ;
warn! ( " Full PDU: {:?} " , & pdu ) ;
return ( None , Err ( Error ::BadServerResponse ( " Could not parse PDU " ) ) ) ;
}
} ;
// Makes use of the m.room.create event. If we cannot fetch this event,
// we must have never been in that room.
if services ( ) . rooms . state . get_room_version ( & room_id ) . is_err ( ) {
debug! ( " Room {room_id} is not known to this server " ) ;
return (
Some ( event_id ) ,
Err ( Error ::BadServerResponse ( " Room is not known to this server " ) ) ,
) ;
}
// We do not add the event_id field to the pdu here because of signature and hashes checks
let mutex = Arc ::clone (
services ( )
. globals
. roomid_mutex_federation
. write ( )
. await
. entry ( room_id . to_owned ( ) )
. or_default ( ) ,
) ;
let mutex_lock = mutex . lock ( ) . await ;
let start_time = Instant ::now ( ) ;
if let Err ( e ) = services ( )
. rooms
. event_handler
. handle_incoming_pdu ( origin , & event_id , & room_id , value , true , pub_key_map )
. await
{
warn! ( " Error appending PDU to timeline: {}: {:?} " , e , pdu ) ;
return ( Some ( event_id ) , Err ( e ) ) ;
}
drop ( mutex_lock ) ;
let elapsed = start_time . elapsed ( ) ;
debug! (
" Handling transaction of event {} took {}m{}s " ,
event_id ,
elapsed . as_secs ( ) / 60 ,
elapsed . as_secs ( ) % 60
) ;
( Some ( event_id ) , Ok ( ( ) ) )
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/federation/v1/send/{txnId}`
///
/// Push EDUs and PDUs to this server.
2021-06-08 18:10:00 +02:00
pub async fn send_transaction_message_route (
2022-12-14 13:09:10 +01:00
body : Ruma < send_transaction_message ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < send_transaction_message ::v1 ::Response > {
2022-04-06 19:08:23 +02:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2021-02-01 17:02:56 -05:00
let mut resolved_map = BTreeMap ::new ( ) ;
2021-04-13 21:34:31 +02:00
let pub_key_map = RwLock ::new ( BTreeMap ::new ( ) ) ;
2021-03-26 11:10:45 +01:00
// This is all the auth_events that have been recursively fetched so they don't have to be
// deserialized over and over again.
// TODO: make this persist across requests but not in a DB Tree (in globals?)
// TODO: This could potentially also be some sort of trie (suffix tree) like structure so
// that once an auth event is known it would know (using indexes maybe) all of the auth
// events that it references.
2021-06-29 20:18:52 -04:00
// let mut auth_cache = EventMap::new();
2021-03-26 11:10:45 +01:00
2021-04-05 21:46:10 +02:00
for pdu in & body . pdus {
2024-07-06 22:56:08 +01:00
let ( event_id , result ) =
handle_pdu_in_transaction ( sender_servername , & pub_key_map , pdu ) . await ;
2023-08-11 10:48:48 +02:00
2024-07-06 22:56:08 +01:00
if let Some ( event_id ) = event_id {
resolved_map . insert ( event_id . clone ( ) , result . map_err ( | e | e . sanitized_error ( ) ) ) ;
2021-03-26 11:10:45 +01:00
}
2021-03-25 23:55:40 +01:00
}
2021-05-12 20:04:28 +02:00
for edu in body
. edus
. iter ( )
2021-06-11 15:47:53 -04:00
. filter_map ( | edu | serde_json ::from_str ::< Edu > ( edu . json ( ) . get ( ) ) . ok ( ) )
2021-05-12 20:04:28 +02:00
{
match edu {
Edu ::Presence ( _ ) = > { }
Edu ::Receipt ( receipt ) = > {
for ( room_id , room_updates ) in receipt . receipts {
for ( user_id , user_updates ) in room_updates . read {
2024-06-11 16:06:30 +02:00
if user_id . server_name ( ) = = sender_servername {
if let Some ( ( event_id , _ ) ) = user_updates
. event_ids
. iter ( )
. filter_map ( | id | {
services ( )
. rooms
. timeline
. get_pdu_count ( id )
. ok ( )
. flatten ( )
. map ( | r | ( id , r ) )
} )
. max_by_key ( | ( _ , count ) | * count )
{
let mut user_receipts = BTreeMap ::new ( ) ;
user_receipts . insert ( user_id . clone ( ) , user_updates . data ) ;
let mut receipts = BTreeMap ::new ( ) ;
receipts . insert ( ReceiptType ::Read , user_receipts ) ;
let mut receipt_content = BTreeMap ::new ( ) ;
receipt_content . insert ( event_id . to_owned ( ) , receipts ) ;
let event = ReceiptEvent {
content : ReceiptEventContent ( receipt_content ) ,
room_id : room_id . clone ( ) ,
} ;
2022-10-05 20:34:31 +02:00
services ( )
. rooms
2024-06-11 16:06:30 +02:00
. edus
. read_receipt
. readreceipt_update ( & user_id , & room_id , event ) ? ;
} else {
// TODO fetch missing events
debug! ( " No known event ids in read receipt: {:?} " , user_updates ) ;
}
2021-05-12 20:04:28 +02:00
}
}
}
}
Edu ::Typing ( typing ) = > {
2024-06-11 16:06:30 +02:00
if typing . user_id . server_name ( ) = = sender_servername
& & services ( )
. rooms
. state_cache
. is_joined ( & typing . user_id , & typing . room_id ) ?
2022-10-05 20:34:31 +02:00
{
2022-03-23 11:05:41 +01:00
if typing . typing {
2024-03-22 08:22:15 +01:00
services ( )
. rooms
. edus
. typing
. typing_add (
& typing . user_id ,
& typing . room_id ,
3000 + utils ::millis_since_unix_epoch ( ) ,
)
. await ? ;
2022-03-23 11:05:41 +01:00
} else {
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. edus
. typing
2024-03-22 08:22:15 +01:00
. typing_remove ( & typing . user_id , & typing . room_id )
. await ? ;
2022-03-23 11:05:41 +01:00
}
2021-05-12 20:04:28 +02:00
}
}
2021-08-24 19:10:31 +02:00
Edu ::DeviceListUpdate ( DeviceListUpdateContent { user_id , .. } ) = > {
2024-06-11 16:06:30 +02:00
if user_id . server_name ( ) = = sender_servername {
services ( ) . users . mark_device_key_update ( & user_id ) ? ;
}
2021-05-28 13:44:40 +02:00
}
Edu ::DirectToDevice ( DirectDeviceContent {
sender ,
ev_type ,
message_id ,
messages ,
} ) = > {
2024-06-11 16:06:30 +02:00
if sender . server_name ( ) = = sender_servername
// Check if this is a new transaction id
& & services ( )
. transaction_ids
. existing_txnid ( & sender , None , & message_id ) ?
. is_none ( )
2021-05-28 13:44:40 +02:00
{
2024-06-11 16:06:30 +02:00
for ( target_user_id , map ) in & messages {
for ( target_device_id_maybe , event ) in map {
match target_device_id_maybe {
DeviceIdOrAllDevices ::DeviceId ( target_device_id ) = > {
2022-09-06 23:15:09 +02:00
services ( ) . users . add_to_device_event (
2021-05-28 13:44:40 +02:00
& sender ,
2021-09-13 19:45:56 +02:00
target_user_id ,
2024-06-11 16:06:30 +02:00
target_device_id ,
2021-06-17 20:12:36 +02:00
& ev_type . to_string ( ) ,
2024-06-11 16:06:30 +02:00
event . deserialize_as ( ) . map_err ( | e | {
warn! ( " To-Device event is invalid: {event:?} {e} " ) ;
2021-05-28 13:44:40 +02:00
Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Event is invalid " ,
)
} ) ? ,
2024-06-11 16:06:30 +02:00
) ?
}
DeviceIdOrAllDevices ::AllDevices = > {
for target_device_id in
services ( ) . users . all_device_ids ( target_user_id )
{
services ( ) . users . add_to_device_event (
& sender ,
target_user_id ,
& target_device_id ? ,
& ev_type . to_string ( ) ,
event . deserialize_as ( ) . map_err ( | _ | {
Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Event is invalid " ,
)
} ) ? ,
) ? ;
}
2021-05-28 13:44:40 +02:00
}
}
}
}
2024-06-11 16:06:30 +02:00
// Save transaction id with empty data
services ( )
. transaction_ids
. add_txnid ( & sender , None , & message_id , & [ ] ) ? ;
}
2021-05-28 13:44:40 +02:00
}
2022-03-05 10:16:21 +08:00
Edu ::SigningKeyUpdate ( SigningKeyUpdateContent {
user_id ,
master_key ,
self_signing_key ,
} ) = > {
2024-06-11 16:06:30 +02:00
if user_id . server_name ( ) = = sender_servername {
if let Some ( master_key ) = master_key {
services ( ) . users . add_cross_signing_keys (
& user_id ,
& master_key ,
& self_signing_key ,
& None ,
true ,
) ? ;
}
2022-03-05 10:16:21 +08:00
}
}
2021-05-12 20:04:28 +02:00
Edu ::_Custom ( _ ) = > { }
}
}
2024-07-06 22:56:08 +01:00
Ok ( send_transaction_message ::v1 ::Response { pdus : resolved_map } )
2021-01-03 17:26:17 -05:00
}
2021-01-15 15:46:47 -05:00
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/event/{eventId}`
///
/// Retrieves a single event from the server.
///
/// - Only works if a user of this server is currently invited or joined the room
2022-01-20 11:51:31 +01:00
pub async fn get_event_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_event ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_event ::v1 ::Response > {
2021-08-31 19:14:37 +02:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2022-09-06 23:15:09 +02:00
let event = services ( )
2022-10-05 20:34:31 +02:00
. rooms
. timeline
2021-08-31 19:14:37 +02:00
. get_pdu_json ( & body . event_id ) ?
2023-07-29 19:17:12 +00:00
. ok_or_else ( | | {
2023-07-28 23:40:10 +00:00
warn! ( " Event not found, event ID: {:?} " , & body . event_id ) ;
2023-07-29 14:30:48 +00:00
Error ::BadRequest ( ErrorKind ::NotFound , " Event not found. " )
} ) ? ;
2021-08-31 19:14:37 +02:00
let room_id_str = event
. get ( " room_id " )
. and_then ( | val | val . as_str ( ) )
. ok_or_else ( | | Error ::bad_database ( " Invalid event in database " ) ) ? ;
2021-11-27 00:30:28 +01:00
let room_id = < & RoomId > ::try_from ( room_id_str )
2021-08-31 19:14:37 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room id field in event in database " ) ) ? ;
2022-10-05 20:34:31 +02:00
if ! services ( )
. rooms
. state_cache
. server_in_room ( sender_servername , room_id ) ?
{
2022-01-17 14:35:38 +01:00
return Err ( Error ::BadRequest (
2024-04-07 20:46:18 +01:00
ErrorKind ::forbidden ( ) ,
2022-01-17 14:35:38 +01:00
" Server is not in room " ,
) ) ;
2021-08-31 19:14:37 +02:00
}
2023-02-22 15:49:55 +01:00
if ! services ( ) . rooms . state_accessor . server_can_see_event (
sender_servername ,
2023-12-23 19:48:14 -08:00
room_id ,
2023-02-22 15:49:55 +01:00
& body . event_id ,
) ? {
return Err ( Error ::BadRequest (
2024-04-07 20:46:18 +01:00
ErrorKind ::forbidden ( ) ,
2023-02-22 15:49:55 +01:00
" Server is not allowed to see event. " ,
) ) ;
}
2021-04-07 15:56:57 +02:00
Ok ( get_event ::v1 ::Response {
2022-09-06 23:15:09 +02:00
origin : services ( ) . globals . server_name ( ) . to_owned ( ) ,
2021-05-20 23:46:52 +02:00
origin_server_ts : MilliSecondsSinceUnixEpoch ::now ( ) ,
2021-08-31 19:14:37 +02:00
pdu : PduEvent ::convert_to_outgoing_federation_event ( event ) ,
2022-01-22 16:58:32 +01:00
} )
2021-04-07 15:56:57 +02:00
}
2023-02-18 13:20:20 +01:00
/// # `GET /_matrix/federation/v1/backfill/<room_id>`
///
/// Retrieves events from before the sender joined the room, if the room's
/// history visibility allows.
pub async fn get_backfill_route (
body : Ruma < get_backfill ::v1 ::Request > ,
) -> Result < get_backfill ::v1 ::Response > {
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2023-07-31 16:18:23 +02:00
debug! ( " Got backfill request from: {} " , sender_servername ) ;
2023-02-18 13:20:20 +01:00
if ! services ( )
. rooms
. state_cache
. server_in_room ( sender_servername , & body . room_id ) ?
{
return Err ( Error ::BadRequest (
2024-04-07 20:46:18 +01:00
ErrorKind ::forbidden ( ) ,
2023-02-18 13:20:20 +01:00
" Server is not in room. " ,
) ) ;
}
services ( )
. rooms
. event_handler
. acl_check ( sender_servername , & body . room_id ) ? ;
let until = body
. v
. iter ( )
. map ( | eventid | services ( ) . rooms . timeline . get_pdu_count ( eventid ) )
. filter_map ( | r | r . ok ( ) . flatten ( ) )
. max ( )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" No known eventid in v " ,
) ) ? ;
let limit = body . limit . min ( uint! ( 100 ) ) ;
let all_events = services ( )
. rooms
. timeline
2023-12-23 19:48:14 -08:00
. pdus_until ( user_id! ( " @doesntmatter:conduit.rs " ) , & body . room_id , until ) ?
2023-02-18 13:20:20 +01:00
. take ( limit . try_into ( ) . unwrap ( ) ) ;
let events = all_events
. filter_map ( | r | r . ok ( ) )
. filter ( | ( _ , e ) | {
matches! (
services ( ) . rooms . state_accessor . server_can_see_event (
sender_servername ,
& e . room_id ,
& e . event_id ,
) ,
Ok ( true ) ,
)
} )
2023-02-20 22:59:45 +01:00
. map ( | ( _ , pdu ) | services ( ) . rooms . timeline . get_pdu_json ( & pdu . event_id ) )
2023-02-18 13:20:20 +01:00
. filter_map ( | r | r . ok ( ) . flatten ( ) )
2023-12-23 19:48:14 -08:00
. map ( PduEvent ::convert_to_outgoing_federation_event )
2023-02-18 13:20:20 +01:00
. collect ( ) ;
Ok ( get_backfill ::v1 ::Response {
origin : services ( ) . globals . server_name ( ) . to_owned ( ) ,
origin_server_ts : MilliSecondsSinceUnixEpoch ::now ( ) ,
pdus : events ,
} )
}
2021-08-31 19:14:37 +02:00
/// # `POST /_matrix/federation/v1/get_missing_events/{roomId}`
///
/// Retrieves events that the sender is missing.
2022-01-20 11:51:31 +01:00
pub async fn get_missing_events_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_missing_events ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_missing_events ::v1 ::Response > {
2021-08-31 19:14:37 +02:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2022-10-05 20:34:31 +02:00
if ! services ( )
. rooms
. state_cache
. server_in_room ( sender_servername , & body . room_id ) ?
{
2021-08-31 19:14:37 +02:00
return Err ( Error ::BadRequest (
2024-04-07 20:46:18 +01:00
ErrorKind ::forbidden ( ) ,
2021-08-31 19:14:37 +02:00
" Server is not in room " ,
) ) ;
}
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. event_handler
2022-10-10 14:09:11 +02:00
. acl_check ( sender_servername , & body . room_id ) ? ;
2022-01-17 14:35:38 +01:00
2020-09-25 12:26:29 +02:00
let mut queued_events = body . latest_events . clone ( ) ;
let mut events = Vec ::new ( ) ;
let mut i = 0 ;
while i < queued_events . len ( ) & & events . len ( ) < u64 ::from ( body . limit ) as usize {
2022-10-05 09:34:25 +02:00
if let Some ( pdu ) = services ( ) . rooms . timeline . get_pdu_json ( & queued_events [ i ] ) ? {
2021-08-31 19:14:37 +02:00
let room_id_str = pdu
. get ( " room_id " )
. and_then ( | val | val . as_str ( ) )
. ok_or_else ( | | Error ::bad_database ( " Invalid event in database " ) ) ? ;
2021-11-27 00:30:28 +01:00
let event_room_id = < & RoomId > ::try_from ( room_id_str )
2021-08-31 19:14:37 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room id field in event in database " ) ) ? ;
if event_room_id ! = body . room_id {
warn! (
" Evil event detected: Event {} found while searching in room {} " ,
queued_events [ i ] , body . room_id
) ;
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Evil event detected " ,
) ) ;
}
2021-04-14 10:43:31 +02:00
2021-08-31 19:14:37 +02:00
if body . earliest_events . contains ( & queued_events [ i ] ) {
2020-09-25 12:26:29 +02:00
i + = 1 ;
continue ;
}
2023-02-22 15:49:55 +01:00
if ! services ( ) . rooms . state_accessor . server_can_see_event (
sender_servername ,
& body . room_id ,
& queued_events [ i ] ,
) ? {
i + = 1 ;
continue ;
}
2020-09-25 12:26:29 +02:00
queued_events . extend_from_slice (
2022-10-09 17:25:06 +02:00
& serde_json ::from_value ::< Vec < OwnedEventId > > (
2021-04-11 21:01:27 +02:00
serde_json ::to_value ( pdu . get ( " prev_events " ) . cloned ( ) . ok_or_else ( | | {
Error ::bad_database ( " Event in db has no prev_events field. " )
} ) ? )
. expect ( " canonical json is valid json value " ) ,
2020-09-25 12:26:29 +02:00
)
. map_err ( | _ | Error ::bad_database ( " Invalid prev_events content in pdu in db. " ) ) ? ,
) ;
2021-04-11 21:01:27 +02:00
events . push ( PduEvent ::convert_to_outgoing_federation_event ( pdu ) ) ;
2020-09-25 12:26:29 +02:00
}
i + = 1 ;
}
2022-01-22 16:58:32 +01:00
Ok ( get_missing_events ::v1 ::Response { events } )
2020-09-25 12:26:29 +02:00
}
2020-10-05 22:19:22 +02:00
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/event_auth/{roomId}/{eventId}`
///
/// Retrieves the auth chain for a given event.
///
/// - This does not include the event itself
2022-01-20 11:51:31 +01:00
pub async fn get_event_authorization_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_event_authorization ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_event_authorization ::v1 ::Response > {
2021-08-31 19:14:37 +02:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2022-10-05 20:34:31 +02:00
if ! services ( )
. rooms
. state_cache
. server_in_room ( sender_servername , & body . room_id ) ?
{
2022-01-17 14:35:38 +01:00
return Err ( Error ::BadRequest (
2024-04-07 20:46:18 +01:00
ErrorKind ::forbidden ( ) ,
2022-01-17 14:35:38 +01:00
" Server is not in room. " ,
) ) ;
}
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. event_handler
2022-10-10 14:09:11 +02:00
. acl_check ( sender_servername , & body . room_id ) ? ;
2022-01-17 14:35:38 +01:00
2022-09-06 23:15:09 +02:00
let event = services ( )
2022-10-05 20:34:31 +02:00
. rooms
. timeline
2021-08-31 19:14:37 +02:00
. get_pdu_json ( & body . event_id ) ?
2023-07-29 19:17:12 +00:00
. ok_or_else ( | | {
2023-07-28 23:40:10 +00:00
warn! ( " Event not found, event ID: {:?} " , & body . event_id ) ;
2023-07-29 14:30:48 +00:00
Error ::BadRequest ( ErrorKind ::NotFound , " Event not found. " )
} ) ? ;
2021-08-31 19:14:37 +02:00
let room_id_str = event
. get ( " room_id " )
. and_then ( | val | val . as_str ( ) )
. ok_or_else ( | | Error ::bad_database ( " Invalid event in database " ) ) ? ;
2021-11-27 00:30:28 +01:00
let room_id = < & RoomId > ::try_from ( room_id_str )
2021-08-31 19:14:37 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room id field in event in database " ) ) ? ;
2022-10-05 20:34:31 +02:00
let auth_chain_ids = services ( )
. rooms
. auth_chain
. get_auth_chain ( room_id , vec! [ Arc ::from ( & * body . event_id ) ] )
. await ? ;
2021-06-14 11:36:18 +02:00
2021-07-18 20:43:39 +02:00
Ok ( get_event_authorization ::v1 ::Response {
auth_chain : auth_chain_ids
2022-10-05 09:34:25 +02:00
. filter_map ( | id | services ( ) . rooms . timeline . get_pdu_json ( & id ) . ok ( ) ? )
2021-08-26 17:58:32 -04:00
. map ( PduEvent ::convert_to_outgoing_federation_event )
2021-07-18 20:43:39 +02:00
. collect ( ) ,
2022-01-22 16:58:32 +01:00
} )
2021-06-14 11:36:18 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/state/{roomId}`
///
/// Retrieves the current state of the room.
2022-01-20 11:51:31 +01:00
pub async fn get_room_state_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_room_state ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_room_state ::v1 ::Response > {
2021-08-31 19:14:37 +02:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2022-10-05 20:34:31 +02:00
if ! services ( )
. rooms
. state_cache
. server_in_room ( sender_servername , & body . room_id ) ?
{
2021-08-31 19:14:37 +02:00
return Err ( Error ::BadRequest (
2024-04-07 20:46:18 +01:00
ErrorKind ::forbidden ( ) ,
2021-08-31 19:14:37 +02:00
" Server is not in room. " ,
) ) ;
}
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. event_handler
2022-10-10 14:09:11 +02:00
. acl_check ( sender_servername , & body . room_id ) ? ;
2022-01-17 14:35:38 +01:00
2022-09-06 23:15:09 +02:00
let shortstatehash = services ( )
2022-10-05 20:34:31 +02:00
. rooms
. state_accessor
2021-06-14 10:52:27 +02:00
. pdu_shortstatehash ( & body . event_id ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Pdu state not found. " ,
) ) ? ;
2022-09-06 23:15:09 +02:00
let pdus = services ( )
2022-10-05 20:34:31 +02:00
. rooms
. state_accessor
2022-06-18 16:38:41 +02:00
. state_full_ids ( shortstatehash )
. await ?
2022-10-10 14:09:11 +02:00
. into_values ( )
. map ( | id | {
2021-06-14 10:52:27 +02:00
PduEvent ::convert_to_outgoing_federation_event (
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. timeline
. get_pdu_json ( & id )
. unwrap ( )
. unwrap ( ) ,
2021-06-14 10:52:27 +02:00
)
} )
. collect ( ) ;
2022-10-05 20:34:31 +02:00
let auth_chain_ids = services ( )
. rooms
. auth_chain
. get_auth_chain ( & body . room_id , vec! [ Arc ::from ( & * body . event_id ) ] )
. await ? ;
2021-06-14 10:52:27 +02:00
2021-07-18 20:43:39 +02:00
Ok ( get_room_state ::v1 ::Response {
auth_chain : auth_chain_ids
2022-10-11 18:10:51 +02:00
. filter_map (
| id | match services ( ) . rooms . timeline . get_pdu_json ( & id ) . ok ( ) ? {
Some ( json ) = > Some ( PduEvent ::convert_to_outgoing_federation_event ( json ) ) ,
None = > {
error! ( " Could not find event json for {id} in db. " ) ;
None
2022-10-11 17:59:49 +02:00
}
2022-10-11 18:10:51 +02:00
} ,
)
2021-07-18 20:43:39 +02:00
. collect ( ) ,
pdus ,
2022-01-22 16:58:32 +01:00
} )
2021-06-14 10:52:27 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/state_ids/{roomId}`
///
/// Retrieves the current state of the room.
2022-01-20 11:51:31 +01:00
pub async fn get_room_state_ids_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_room_state_ids ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_room_state_ids ::v1 ::Response > {
2021-08-31 19:14:37 +02:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2022-10-05 20:34:31 +02:00
if ! services ( )
. rooms
. state_cache
. server_in_room ( sender_servername , & body . room_id ) ?
{
2021-08-31 19:14:37 +02:00
return Err ( Error ::BadRequest (
2024-04-07 20:46:18 +01:00
ErrorKind ::forbidden ( ) ,
2021-08-31 19:14:37 +02:00
" Server is not in room. " ,
) ) ;
}
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. event_handler
2022-10-10 14:09:11 +02:00
. acl_check ( sender_servername , & body . room_id ) ? ;
2022-01-17 14:35:38 +01:00
2022-09-06 23:15:09 +02:00
let shortstatehash = services ( )
2022-10-05 20:34:31 +02:00
. rooms
. state_accessor
2021-03-18 00:09:57 +01:00
. pdu_shortstatehash ( & body . event_id ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Pdu state not found. " ,
) ) ? ;
2022-09-06 23:15:09 +02:00
let pdu_ids = services ( )
2022-10-05 20:34:31 +02:00
. rooms
. state_accessor
2022-06-18 16:38:41 +02:00
. state_full_ids ( shortstatehash )
. await ?
2022-10-10 14:09:11 +02:00
. into_values ( )
. map ( | id | ( * id ) . to_owned ( ) )
2021-07-01 19:55:26 +02:00
. collect ( ) ;
2021-03-18 00:09:57 +01:00
2022-10-05 20:34:31 +02:00
let auth_chain_ids = services ( )
. rooms
. auth_chain
. get_auth_chain ( & body . room_id , vec! [ Arc ::from ( & * body . event_id ) ] )
. await ? ;
2021-03-18 00:09:57 +01:00
Ok ( get_room_state_ids ::v1 ::Response {
2021-11-26 20:36:40 +01:00
auth_chain_ids : auth_chain_ids . map ( | id | ( * id ) . to_owned ( ) ) . collect ( ) ,
2021-03-18 00:09:57 +01:00
pdu_ids ,
2022-01-22 16:58:32 +01:00
} )
2021-03-18 00:09:57 +01:00
}
2025-02-28 14:09:33 +00:00
/// # `GET /_matrix/federation/v1/make_leave/{roomId}/{userId}`
///
/// Creates a leave template.
pub async fn create_leave_event_template_route (
body : Ruma < prepare_leave_event ::v1 ::Request > ,
) -> Result < prepare_leave_event ::v1 ::Response > {
let ( mutex_state , room_version_id ) =
member_shake_preamble ( & body . sender_servername , & body . room_id ) . await ? ;
let state_lock = mutex_state . lock ( ) . await ;
Ok ( prepare_leave_event ::v1 ::Response {
room_version : Some ( room_version_id ) ,
event : create_membership_template (
& body . user_id ,
& body . room_id ,
None ,
MembershipState ::Leave ,
state_lock ,
) ? ,
} )
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/make_join/{roomId}/{userId}`
///
/// Creates a join template.
2022-01-20 11:51:31 +01:00
pub async fn create_join_event_template_route (
2022-12-14 13:09:10 +01:00
body : Ruma < prepare_join_event ::v1 ::Request > ,
2022-02-18 15:33:14 +01:00
) -> Result < prepare_join_event ::v1 ::Response > {
2024-10-31 16:23:54 +00:00
let ( mutex_state , room_version_id ) =
member_shake_preamble ( & body . sender_servername , & body . room_id ) . await ? ;
2022-09-06 23:15:09 +02:00
let state_lock = mutex_state . lock ( ) . await ;
2022-01-17 14:35:38 +01:00
2024-04-09 14:36:50 +01:00
let join_authorized_via_users_server = if
// The following two functions check whether the user can "join" without performing a restricted join
! services ( )
. rooms
. state_cache
. is_joined ( & body . user_id , & body . room_id )
. unwrap_or ( false )
& & ! services ( )
. rooms
. state_cache
. is_invited ( & body . user_id , & body . room_id )
. unwrap_or ( false )
// This function also checks whether the room is restricted in the first place, meaning a restricted join will not happen if the room is public for example
& & user_can_perform_restricted_join ( & body . user_id , & body . room_id , & room_version_id ) ?
{
let auth_user = services ( )
. rooms
. state_cache
. room_members ( & body . room_id )
. filter_map ( Result ::ok )
. filter ( | user | user . server_name ( ) = = services ( ) . globals . server_name ( ) )
. find ( | user | {
services ( )
. rooms
. state_accessor
. user_can_invite ( & body . room_id , user , & body . user_id , & state_lock )
. unwrap_or ( false )
} ) ;
2022-01-18 16:53:25 +01:00
2024-04-09 14:36:50 +01:00
if auth_user . is_some ( ) {
auth_user
} else {
2022-01-18 16:53:25 +01:00
return Err ( Error ::BadRequest (
2024-04-09 14:36:50 +01:00
ErrorKind ::UnableToGrantJoin ,
" No user on this server is able to assist in joining. " ,
2022-01-18 16:53:25 +01:00
) ) ;
}
2024-04-09 14:36:50 +01:00
} else {
None
} ;
2022-01-18 16:53:25 +01:00
2022-10-05 09:34:25 +02:00
if ! body . ver . contains ( & room_version_id ) {
2021-07-21 11:29:13 +02:00
return Err ( Error ::BadRequest (
ErrorKind ::IncompatibleRoomVersion {
room_version : room_version_id ,
} ,
" Room version not supported. " ,
) ) ;
}
2021-04-16 18:18:29 +02:00
2024-10-31 16:23:54 +00:00
Ok ( prepare_join_event ::v1 ::Response {
room_version : Some ( room_version_id ) ,
event : create_membership_template (
& body . user_id ,
& body . room_id ,
join_authorized_via_users_server ,
MembershipState ::Join ,
state_lock ,
) ? ,
} )
}
/// Creates a template for the given membership state, to return on the `/make_<membership>` endpoints
fn create_membership_template (
user_id : & UserId ,
room_id : & RoomId ,
join_authorized_via_users_server : Option < OwnedUserId > ,
membership : MembershipState ,
state_lock : tokio ::sync ::MutexGuard < '_ , ( ) > ,
) -> Result < Box < RawJsonValue > , Error > {
2021-10-13 10:16:45 +02:00
let content = to_raw_value ( & RoomMemberEventContent {
2021-04-16 18:18:29 +02:00
avatar_url : None ,
2021-07-15 23:17:58 +02:00
blurhash : None ,
2021-04-16 18:18:29 +02:00
displayname : None ,
is_direct : None ,
2024-10-31 16:23:54 +00:00
membership ,
2021-04-16 18:18:29 +02:00
third_party_invite : None ,
2021-08-19 11:01:18 +02:00
reason : None ,
2024-04-09 14:36:50 +01:00
join_authorized_via_users_server ,
2021-04-16 18:18:29 +02:00
} )
. expect ( " member event is valid value " ) ;
2022-10-12 10:57:54 +02:00
let ( _pdu , mut pdu_json ) = services ( ) . rooms . timeline . create_hash_and_sign_event (
2022-10-05 20:34:31 +02:00
PduBuilder {
2023-02-26 16:29:06 +01:00
event_type : TimelineEventType ::RoomMember ,
2022-10-05 20:34:31 +02:00
content ,
unsigned : None ,
2024-10-31 16:23:54 +00:00
state_key : Some ( user_id . to_string ( ) ) ,
2022-10-05 20:34:31 +02:00
redacts : None ,
2024-06-22 11:50:39 +01:00
timestamp : None ,
2022-10-05 20:34:31 +02:00
} ,
2024-10-31 16:23:54 +00:00
user_id ,
room_id ,
2022-10-05 20:34:31 +02:00
& state_lock ,
) ? ;
2021-04-16 18:18:29 +02:00
2022-09-06 23:15:09 +02:00
drop ( state_lock ) ;
2021-04-16 18:18:29 +02:00
2022-10-12 10:57:54 +02:00
pdu_json . remove ( " event_id " ) ;
2024-10-31 16:23:54 +00:00
let raw_event = to_raw_value ( & pdu_json ) . expect ( " CanonicalJson can be serialized to JSON " ) ;
Ok ( raw_event )
2021-04-16 18:18:29 +02:00
}
2024-10-31 16:23:54 +00:00
/// checks whether the given room exists, and checks whether the specified server is allowed to send events according to the ACL
fn room_and_acl_check ( room_id : & RoomId , sender_servername : & OwnedServerName ) -> Result < ( ) , Error > {
2022-10-05 09:34:25 +02:00
if ! services ( ) . rooms . metadata . exists ( room_id ) ? {
2022-01-17 14:35:38 +01:00
return Err ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Room is unknown to this server. " ,
) ) ;
}
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. event_handler
2022-10-10 14:09:11 +02:00
. acl_check ( sender_servername , room_id ) ? ;
2024-10-31 16:23:54 +00:00
Ok ( ( ) )
}
/// Takes care of common boilerpalte for room membership handshake endpoints.
/// The returned mutex must be locked by the caller.
async fn member_shake_preamble (
sender_servername : & Option < OwnedServerName > ,
room_id : & RoomId ,
) -> Result < ( Arc < Mutex < ( ) > > , RoomVersionId ) , Error > {
let sender_servername = sender_servername . as_ref ( ) . expect ( " server is authenticated " ) ;
room_and_acl_check ( room_id , sender_servername ) ? ;
let mutex_state = Arc ::clone (
services ( )
. globals
. roomid_mutex_state
. write ( )
. await
. entry ( room_id . to_owned ( ) )
. or_default ( ) ,
) ;
let room_version_id = services ( ) . rooms . state . get_room_version ( room_id ) ? ;
Ok ( ( mutex_state , room_version_id ) )
}
async fn create_join_event (
sender_servername : & Option < OwnedServerName > ,
room_id : & RoomId ,
pdu : & RawJsonValue ,
) -> Result < create_join_event ::v1 ::RoomState > {
let sender_servername = sender_servername . as_ref ( ) . expect ( " server is authenticated " ) ;
room_and_acl_check ( room_id , sender_servername ) ? ;
2022-01-17 14:35:38 +01:00
2021-04-16 18:18:29 +02:00
// We need to return the state prior to joining, let's keep a reference to that here
2022-09-06 23:15:09 +02:00
let shortstatehash = services ( )
2022-10-05 20:34:31 +02:00
. rooms
. state
2022-10-05 09:34:25 +02:00
. get_room_shortstatehash ( room_id ) ?
2021-07-25 19:28:54 +02:00
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Pdu state not found. " ,
) ) ? ;
2021-04-16 18:18:29 +02:00
2024-10-31 16:23:54 +00:00
let pdu = append_member_pdu ( MembershipState ::Join , sender_servername , room_id , pdu ) . await ? ;
let state_ids = services ( )
. rooms
. state_accessor
. state_full_ids ( shortstatehash )
. await ? ;
let auth_chain_ids = services ( )
. rooms
. auth_chain
. get_auth_chain ( room_id , state_ids . values ( ) . cloned ( ) . collect ( ) )
. await ? ;
Ok ( create_join_event ::v1 ::RoomState {
auth_chain : auth_chain_ids
. filter_map ( | id | services ( ) . rooms . timeline . get_pdu_json ( & id ) . ok ( ) . flatten ( ) )
. map ( PduEvent ::convert_to_outgoing_federation_event )
. collect ( ) ,
state : state_ids
. iter ( )
. filter_map ( | ( _ , id ) | services ( ) . rooms . timeline . get_pdu_json ( id ) . ok ( ) . flatten ( ) )
. map ( PduEvent ::convert_to_outgoing_federation_event )
. collect ( ) ,
event : pdu . map ( | pdu | {
to_raw_value ( & CanonicalJsonValue ::Object ( pdu ) )
. expect ( " To raw json should not fail since only change was adding signature " )
} ) ,
} )
}
/// Takes the given membership PDU and attempts to append it to the timeline
async fn append_member_pdu (
membership : MembershipState ,
sender_servername : & OwnedServerName ,
room_id : & RoomId ,
pdu : & RawJsonValue ,
) -> Result < Option < BTreeMap < String , CanonicalJsonValue > > , Error > {
2021-04-16 18:18:29 +02:00
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
2022-11-27 23:25:42 +01:00
let room_version_id = services ( ) . rooms . state . get_room_version ( room_id ) ? ;
2024-04-09 14:36:50 +01:00
let ( event_id , mut value ) = match gen_event_id_canonical_json ( pdu , & room_version_id ) {
2021-04-16 18:18:29 +02:00
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. " ,
) ) ;
}
} ;
2024-04-09 14:36:50 +01:00
let state_key : OwnedUserId = serde_json ::from_value (
value
. get ( " state_key " )
. ok_or_else ( | | Error ::BadRequest ( ErrorKind ::BadJson , " State key is missing " ) ) ?
. clone ( )
. into ( ) ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::BadJson , " State key is not a valid user ID " ) ) ? ;
let sender : OwnedUserId = serde_json ::from_value (
value
. get ( " sender " )
. ok_or_else ( | | Error ::BadRequest ( ErrorKind ::BadJson , " Sender is missing " ) ) ?
. clone ( )
. into ( ) ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::BadJson , " Sender is not a valid user ID " ) ) ? ;
if state_key ! = sender {
return Err ( Error ::BadRequest (
ErrorKind ::BadJson ,
" Sender and state key don't match " ,
) ) ;
}
// Security-wise, we only really need to check the event is not from us, cause otherwise it must be signed by that server,
// but we might as well check this since this event shouldn't really be sent on behalf of another server
if state_key . server_name ( ) ! = sender_servername {
return Err ( Error ::BadRequest (
ErrorKind ::forbidden ( ) ,
" User's server and origin don't match " ,
) ) ;
}
let event_type : StateEventType = serde_json ::from_value (
value
. get ( " type " )
. ok_or_else ( | | Error ::BadRequest ( ErrorKind ::BadJson , " Missing event type " ) ) ?
. clone ( )
. into ( ) ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::BadJson , " Invalid event type " ) ) ? ;
if event_type ! = StateEventType ::RoomMember {
return Err ( Error ::BadRequest (
ErrorKind ::BadJson ,
" Event type is not membership " ,
) ) ;
}
let event_content : RoomMemberEventContent = serde_json ::from_value (
value
. get ( " content " )
. ok_or_else ( | | Error ::BadRequest ( ErrorKind ::BadJson , " Missing event content " ) ) ?
. clone ( )
. into ( ) ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::BadJson , " Invalid event content " ) ) ? ;
2024-10-31 16:23:54 +00:00
if event_content . membership ! = membership {
2024-04-09 14:36:50 +01:00
return Err ( Error ::BadRequest (
ErrorKind ::BadJson ,
" Membership of sent event does not match that of the endpoint " ,
) ) ;
}
2024-10-31 16:23:54 +00:00
let sign_join_event = membership = = MembershipState ::Join
& & event_content
. join_authorized_via_users_server
. map ( | user | user . server_name ( ) = = services ( ) . globals . server_name ( ) )
. unwrap_or_default ( )
2024-04-09 14:36:50 +01:00
& & user_can_perform_restricted_join ( & sender , room_id , & room_version_id ) . unwrap_or_default ( ) ;
if sign_join_event {
ruma ::signatures ::hash_and_sign_event (
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
& mut value ,
& room_version_id ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Failed to sign event. " ) ) ? ;
}
2022-10-09 17:25:06 +02:00
let origin : OwnedServerName = serde_json ::from_value (
2021-04-16 18:18:29 +02:00
serde_json ::to_value ( value . get ( " origin " ) . ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Event needs an origin field. " ,
) ) ? )
. expect ( " CanonicalJson is valid json value " ) ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Origin field is invalid. " ) ) ? ;
2021-07-01 19:55:26 +02:00
let mutex = Arc ::clone (
2022-10-05 20:34:31 +02:00
services ( )
. globals
2021-07-13 15:44:25 +02:00
. roomid_mutex_federation
2021-07-01 19:55:26 +02:00
. write ( )
2024-03-05 14:22:54 +00:00
. await
2021-11-26 20:36:40 +01:00
. entry ( room_id . to_owned ( ) )
2021-07-01 19:55:26 +02:00
. or_default ( ) ,
) ;
let mutex_lock = mutex . lock ( ) . await ;
2022-10-05 20:34:31 +02:00
let pdu_id : Vec < u8 > = services ( )
. rooms
. event_handler
2024-04-09 14:36:50 +01:00
. handle_incoming_pdu (
& origin ,
& event_id ,
room_id ,
value . clone ( ) ,
true ,
& pub_key_map ,
)
2022-10-05 09:34:25 +02:00
. await ?
2021-07-25 19:28:54 +02:00
. ok_or ( Error ::BadRequest (
2021-04-16 18:18:29 +02:00
ErrorKind ::InvalidParam ,
2021-07-25 19:28:54 +02:00
" Could not accept incoming PDU as timeline event. " ,
) ) ? ;
2021-07-01 19:55:26 +02:00
drop ( mutex_lock ) ;
2021-04-16 18:18:29 +02:00
2022-09-06 23:15:09 +02:00
let servers = services ( )
2021-04-16 18:18:29 +02:00
. rooms
2022-10-05 09:34:25 +02:00
. state_cache
2021-09-13 19:45:56 +02:00
. room_servers ( room_id )
2021-04-16 18:18:29 +02:00
. filter_map ( | r | r . ok ( ) )
2022-09-06 23:15:09 +02:00
. filter ( | server | & * * server ! = services ( ) . globals . server_name ( ) ) ;
2021-04-16 18:18:29 +02:00
2022-09-06 23:15:09 +02:00
services ( ) . sending . send_pdu ( servers , & pdu_id ) ? ;
2021-07-14 07:07:08 +00:00
2024-10-31 16:23:54 +00:00
Ok ( if sign_join_event { Some ( value ) } else { None } )
2021-07-25 19:28:54 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/federation/v1/send_join/{roomId}/{eventId}`
///
/// Submits a signed join event.
2021-07-25 19:28:54 +02:00
pub async fn create_join_event_v1_route (
2022-12-14 13:09:10 +01:00
body : Ruma < create_join_event ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < create_join_event ::v1 ::Response > {
2024-10-31 16:23:54 +00:00
let room_state = create_join_event ( & body . sender_servername , & body . room_id , & body . pdu ) . await ? ;
2021-07-25 19:28:54 +02:00
2022-01-22 16:58:32 +01:00
Ok ( create_join_event ::v1 ::Response { room_state } )
2021-07-25 19:28:54 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/federation/v2/send_join/{roomId}/{eventId}`
///
/// Submits a signed join event.
2021-07-25 19:28:54 +02:00
pub async fn create_join_event_v2_route (
2022-12-14 13:09:10 +01:00
body : Ruma < create_join_event ::v2 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < create_join_event ::v2 ::Response > {
2023-02-26 16:29:06 +01:00
let create_join_event ::v1 ::RoomState {
auth_chain ,
state ,
event ,
2024-10-31 16:23:54 +00:00
} = create_join_event ( & body . sender_servername , & body . room_id , & body . pdu ) . await ? ;
2023-02-26 16:29:06 +01:00
let room_state = create_join_event ::v2 ::RoomState {
members_omitted : false ,
auth_chain ,
state ,
event ,
servers_in_room : None ,
} ;
2021-07-25 19:28:54 +02:00
2022-01-22 16:58:32 +01:00
Ok ( create_join_event ::v2 ::Response { room_state } )
2021-04-16 18:18:29 +02:00
}
2025-02-28 14:09:33 +00:00
/// # `PUT /_matrix/federation/v2/send_leave/{roomId}/{eventId}`
///
/// Submits a signed leave event.
pub async fn create_leave_event_route (
body : Ruma < create_leave_event ::v2 ::Request > ,
) -> Result < create_leave_event ::v2 ::Response > {
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
room_and_acl_check ( & body . room_id , sender_servername ) ? ;
append_member_pdu (
MembershipState ::Leave ,
sender_servername ,
& body . room_id ,
& body . pdu ,
)
. await ? ;
Ok ( create_leave_event ::v2 ::Response { } )
}
2024-04-09 14:36:50 +01:00
/// Checks whether the given user can join the given room via a restricted join.
/// This doesn't check the current user's membership. This should be done externally,
/// either by using the state cache or attempting to authorize the event.
fn user_can_perform_restricted_join (
user_id : & UserId ,
room_id : & RoomId ,
room_version_id : & RoomVersionId ,
) -> Result < bool > {
let join_rules_event = services ( ) . rooms . state_accessor . room_state_get (
room_id ,
& StateEventType ::RoomJoinRules ,
" " ,
) ? ;
let Some ( join_rules_event_content ) = join_rules_event
. as_ref ( )
. map ( | join_rules_event | {
serde_json ::from_str ::< RoomJoinRulesEventContent > ( join_rules_event . content . get ( ) )
. map_err ( | e | {
warn! ( " Invalid join rules event: {} " , e ) ;
Error ::bad_database ( " Invalid join rules event in db. " )
} )
} )
. transpose ( ) ?
else {
return Ok ( false ) ;
} ;
if matches! (
room_version_id ,
RoomVersionId ::V1
| RoomVersionId ::V2
| RoomVersionId ::V3
| RoomVersionId ::V4
| RoomVersionId ::V5
| RoomVersionId ::V6
| RoomVersionId ::V7
) {
return Ok ( false ) ;
}
let ( JoinRule ::Restricted ( r ) | JoinRule ::KnockRestricted ( r ) ) =
join_rules_event_content . join_rule
else {
return Ok ( false ) ;
} ;
if r . allow
. iter ( )
. filter_map ( | rule | {
if let AllowRule ::RoomMembership ( membership ) = rule {
Some ( membership )
} else {
None
}
} )
. any ( | m | {
services ( )
. rooms
. state_cache
. is_joined ( user_id , & m . room_id )
. unwrap_or ( false )
} )
{
Ok ( true )
} else {
Err ( Error ::BadRequest (
ErrorKind ::UnableToAuthorizeJoin ,
" User is not known to be in any required room. " ,
) )
}
}
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/federation/v2/invite/{roomId}/{eventId}`
///
/// Invites a remote user to a room.
2021-06-08 18:10:00 +02:00
pub async fn create_invite_route (
2022-12-14 13:09:10 +01:00
body : Ruma < create_invite ::v2 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < create_invite ::v2 ::Response > {
2022-01-17 14:35:38 +01:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2022-10-05 20:34:31 +02:00
services ( )
. rooms
. event_handler
2022-10-10 14:09:11 +02:00
. acl_check ( sender_servername , & body . room_id ) ? ;
2022-01-17 14:35:38 +01:00
2022-10-05 20:34:31 +02:00
if ! services ( )
. globals
. supported_room_versions ( )
. contains ( & body . room_version )
{
2021-04-11 21:01:27 +02:00
return Err ( Error ::BadRequest (
ErrorKind ::IncompatibleRoomVersion {
room_version : body . room_version . clone ( ) ,
} ,
" Server does not support this room version. " ,
) ) ;
}
let mut signed_event = utils ::to_canonical_object ( & body . event )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Invite event is invalid. " ) ) ? ;
ruma ::signatures ::hash_and_sign_event (
2022-09-06 23:15:09 +02:00
services ( ) . globals . server_name ( ) . as_str ( ) ,
services ( ) . globals . keypair ( ) ,
2021-04-11 21:01:27 +02:00
& mut signed_event ,
& body . room_version ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Failed to sign event. " ) ) ? ;
2021-04-13 21:34:31 +02:00
// Generate event id
2021-11-27 00:30:28 +01:00
let event_id = EventId ::parse ( format! (
2021-04-13 21:34:31 +02:00
" ${} " ,
ruma ::signatures ::reference_hash ( & signed_event , & body . room_version )
2024-07-07 13:30:53 +01:00
. expect ( " Event format validated when event was hashed " )
2021-04-13 21:34:31 +02:00
) )
. expect ( " ruma's reference hashes are valid event ids " ) ;
// Add event_id back
signed_event . insert (
" event_id " . to_owned ( ) ,
2022-10-09 17:25:06 +02:00
CanonicalJsonValue ::String ( event_id . to_string ( ) ) ,
2021-04-13 21:34:31 +02:00
) ;
2022-10-09 17:25:06 +02:00
let sender : OwnedUserId = serde_json ::from_value (
2021-04-26 18:20:20 +02:00
signed_event
. get ( " sender " )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Event had no sender field. " ,
) ) ?
. clone ( )
. into ( ) ,
2021-04-11 21:01:27 +02:00
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " sender is not a user id. " ) ) ? ;
2021-04-26 18:20:20 +02:00
2021-11-26 20:36:40 +01:00
let invited_user : Box < _ > = serde_json ::from_value (
2021-04-26 18:20:20 +02:00
signed_event
. get ( " state_key " )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Event had no state_key field. " ,
) ) ?
. clone ( )
. into ( ) ,
2021-04-11 21:01:27 +02:00
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " state_key is not a user id. " ) ) ? ;
let mut invite_state = body . invite_room_state . clone ( ) ;
2021-10-13 11:51:30 +02:00
let mut event : JsonObject = serde_json ::from_str ( body . event . get ( ) )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Invalid invite event bytes. " ) ) ? ;
2021-04-11 21:01:27 +02:00
event . insert ( " event_id " . to_owned ( ) , " $dummy " . into ( ) ) ;
2021-10-13 11:51:30 +02:00
let pdu : PduEvent = serde_json ::from_value ( event . into ( ) ) . map_err ( | e | {
2021-04-13 21:34:31 +02:00
warn! ( " Invalid invite event: {} " , e ) ;
Error ::BadRequest ( ErrorKind ::InvalidParam , " Invalid invite event. " )
} ) ? ;
invite_state . push ( pdu . to_stripped_state_event ( ) ) ;
2022-11-27 23:25:42 +01:00
// If we are active in the room, the remote server will notify us about the join via /send
if ! services ( )
. rooms
. state_cache
. server_in_room ( services ( ) . globals . server_name ( ) , & body . room_id ) ?
{
2022-10-05 09:34:25 +02:00
services ( ) . rooms . state_cache . update_membership (
2021-04-13 21:34:31 +02:00
& body . room_id ,
& invited_user ,
MembershipState ::Invite ,
& sender ,
Some ( invite_state ) ,
2021-08-17 00:22:52 +02:00
true ,
2021-04-13 21:34:31 +02:00
) ? ;
}
2021-04-11 21:01:27 +02:00
Ok ( create_invite ::v2 ::Response {
event : PduEvent ::convert_to_outgoing_federation_event ( signed_event ) ,
2022-01-22 16:58:32 +01:00
} )
2021-04-11 21:01:27 +02:00
}
2024-08-24 10:27:03 +01:00
/// # `GET /_matrix/federation/v1/media/download/{serverName}/{mediaId}`
///
/// Load media from our server.
pub async fn get_content_route (
body : Ruma < get_content ::v1 ::Request > ,
) -> Result < get_content ::v1 ::Response > {
let mxc = format! (
" mxc://{}/{} " ,
services ( ) . globals . server_name ( ) ,
body . media_id
) ;
if let Some ( FileMeta {
content_disposition ,
content_type ,
file ,
} ) = services ( ) . media . get ( mxc . clone ( ) ) . await ?
{
Ok ( get_content ::v1 ::Response ::new (
ContentMetadata ::new ( ) ,
FileOrLocation ::File ( Content {
file ,
content_type ,
content_disposition : Some ( content_disposition ) ,
} ) ,
) )
} else {
Err ( Error ::BadRequest ( ErrorKind ::NotFound , " Media not found. " ) )
}
}
/// # `GET /_matrix/federation/v1/media/thumbnail/{serverName}/{mediaId}`
///
/// Load media thumbnail from our server or over federation.
pub async fn get_content_thumbnail_route (
body : Ruma < get_content_thumbnail ::v1 ::Request > ,
) -> Result < get_content_thumbnail ::v1 ::Response > {
let mxc = format! (
" mxc://{}/{} " ,
services ( ) . globals . server_name ( ) ,
body . media_id
) ;
let Some ( FileMeta {
file ,
content_type ,
content_disposition ,
} ) = services ( )
. media
. get_thumbnail (
mxc . clone ( ) ,
body . width
. try_into ( )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Width is invalid. " ) ) ? ,
body . height
. try_into ( )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Width is invalid. " ) ) ? ,
)
. await ?
else {
return Err ( Error ::BadRequest ( ErrorKind ::NotFound , " Media not found. " ) ) ;
} ;
services ( )
. media
. upload_thumbnail (
mxc ,
content_type . as_deref ( ) ,
body . width . try_into ( ) . expect ( " all UInts are valid u32s " ) ,
body . height . try_into ( ) . expect ( " all UInts are valid u32s " ) ,
& file ,
)
. await ? ;
Ok ( get_content_thumbnail ::v1 ::Response ::new (
ContentMetadata ::new ( ) ,
FileOrLocation ::File ( Content {
file ,
content_type ,
content_disposition : Some ( content_disposition ) ,
} ) ,
) )
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/user/devices/{userId}`
///
/// Gets information on all devices of the user.
2022-01-20 11:51:31 +01:00
pub async fn get_devices_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_devices ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_devices ::v1 ::Response > {
2024-02-01 12:05:59 +01:00
if body . user_id . server_name ( ) ! = services ( ) . globals . server_name ( ) {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Tried to access user from other server. " ,
) ) ;
}
2022-04-06 18:49:46 +02:00
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
2021-04-21 10:51:34 +02:00
Ok ( get_devices ::v1 ::Response {
user_id : body . user_id . clone ( ) ,
2022-09-06 23:15:09 +02:00
stream_id : services ( )
2021-04-21 10:51:34 +02:00
. users
. get_devicelist_version ( & body . user_id ) ?
. unwrap_or ( 0 )
. try_into ( )
. expect ( " version will not grow that large " ) ,
2022-09-06 23:15:09 +02:00
devices : services ( )
2021-04-21 10:51:34 +02:00
. users
. all_devices_metadata ( & body . user_id )
. filter_map ( | r | r . ok ( ) )
. filter_map ( | metadata | {
Some ( UserDevice {
2022-09-06 23:15:09 +02:00
keys : services ( )
2021-04-21 10:51:34 +02:00
. users
. get_device_keys ( & body . user_id , & metadata . device_id )
. ok ( ) ? ? ,
device_id : metadata . device_id ,
device_display_name : metadata . display_name ,
} )
} )
. collect ( ) ,
2023-07-16 16:50:03 +02:00
master_key : services ( ) . users . get_master_key ( None , & body . user_id , & | u | {
u . server_name ( ) = = sender_servername
} ) ? ,
2022-09-06 23:15:09 +02:00
self_signing_key : services ( )
2022-03-05 10:16:21 +08:00
. users
2023-07-16 16:50:03 +02:00
. get_self_signing_key ( None , & body . user_id , & | u | {
u . server_name ( ) = = sender_servername
} ) ? ,
2022-01-22 16:58:32 +01:00
} )
2021-04-21 10:51:34 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/query/directory`
///
/// Resolve a room alias to a room id.
2022-01-20 11:51:31 +01:00
pub async fn get_room_information_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_room_information ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_room_information ::v1 ::Response > {
2022-09-06 23:15:09 +02:00
let room_id = services ( )
2021-04-16 18:18:29 +02:00
. rooms
2022-10-05 20:34:31 +02:00
. alias
. resolve_local_alias ( & body . room_alias ) ?
2021-04-21 14:06:39 +02:00
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Room alias not found. " ,
) ) ? ;
2021-04-16 18:18:29 +02:00
Ok ( get_room_information ::v1 ::Response {
room_id ,
2022-09-06 23:15:09 +02:00
servers : vec ! [ services ( ) . globals . server_name ( ) . to_owned ( ) ] ,
2022-01-22 16:58:32 +01:00
} )
2021-04-16 18:18:29 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/federation/v1/query/profile`
///
/// Gets information on a profile.
2022-01-20 11:51:31 +01:00
pub async fn get_profile_information_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_profile_information ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < get_profile_information ::v1 ::Response > {
2024-02-01 12:05:59 +01:00
if body . user_id . server_name ( ) ! = services ( ) . globals . server_name ( ) {
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Tried to access user from other server. " ,
) ) ;
}
2020-10-05 22:19:22 +02:00
let mut displayname = None ;
let mut avatar_url = None ;
2021-07-15 23:17:58 +02:00
let mut blurhash = None ;
2020-10-05 22:19:22 +02:00
2020-12-04 18:16:17 -05:00
match & body . field {
2022-10-05 20:34:31 +02:00
Some ( ProfileField ::DisplayName ) = > {
displayname = services ( ) . users . displayname ( & body . user_id ) ?
}
2021-07-15 23:17:58 +02:00
Some ( ProfileField ::AvatarUrl ) = > {
2022-09-06 23:15:09 +02:00
avatar_url = services ( ) . users . avatar_url ( & body . user_id ) ? ;
blurhash = services ( ) . users . blurhash ( & body . user_id ) ?
2021-07-15 23:17:58 +02:00
}
2021-07-15 19:54:04 +02:00
// TODO: what to do with custom
Some ( _ ) = > { }
2020-10-05 22:19:22 +02:00
None = > {
2022-09-06 23:15:09 +02:00
displayname = services ( ) . users . displayname ( & body . user_id ) ? ;
avatar_url = services ( ) . users . avatar_url ( & body . user_id ) ? ;
blurhash = services ( ) . users . blurhash ( & body . user_id ) ? ;
2020-10-05 22:19:22 +02:00
}
}
Ok ( get_profile_information ::v1 ::Response {
2021-07-15 23:17:58 +02:00
blurhash ,
2020-10-05 22:19:22 +02:00
displayname ,
avatar_url ,
2022-01-22 16:58:32 +01:00
} )
2020-10-05 22:19:22 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `POST /_matrix/federation/v1/user/keys/query`
///
/// Gets devices and identity keys for the given users.
2022-10-05 20:34:31 +02:00
pub async fn get_keys_route ( body : Ruma < get_keys ::v1 ::Request > ) -> Result < get_keys ::v1 ::Response > {
2024-02-01 12:05:59 +01:00
if body
. device_keys
. iter ( )
. any ( | ( u , _ ) | u . server_name ( ) ! = services ( ) . globals . server_name ( ) )
{
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Tried to access user from other server. " ,
) ) ;
}
2022-10-05 20:34:31 +02:00
let result = get_keys_helper ( None , & body . device_keys , | u | {
Some ( u . server_name ( ) ) = = body . sender_servername . as_deref ( )
} )
2021-07-20 19:40:25 +02:00
. await ? ;
2021-05-20 23:46:52 +02:00
Ok ( get_keys ::v1 ::Response {
device_keys : result . device_keys ,
master_keys : result . master_keys ,
self_signing_keys : result . self_signing_keys ,
2022-01-22 16:58:32 +01:00
} )
2021-05-20 23:46:52 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `POST /_matrix/federation/v1/user/keys/claim`
///
/// Claims one-time keys.
2021-06-08 18:10:00 +02:00
pub async fn claim_keys_route (
2021-05-28 13:44:40 +02:00
body : Ruma < claim_keys ::v1 ::Request > ,
2022-01-22 16:58:32 +01:00
) -> Result < claim_keys ::v1 ::Response > {
2024-02-01 12:05:59 +01:00
if body
. one_time_keys
. iter ( )
. any ( | ( u , _ ) | u . server_name ( ) ! = services ( ) . globals . server_name ( ) )
{
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Tried to access user from other server. " ,
) ) ;
}
2022-09-06 23:15:09 +02:00
let result = claim_keys_helper ( & body . one_time_keys ) . await ? ;
2021-05-28 13:44:40 +02:00
Ok ( claim_keys ::v1 ::Response {
one_time_keys : result . one_time_keys ,
2022-01-22 16:58:32 +01:00
} )
2021-05-28 13:44:40 +02:00
}
2024-05-28 00:22:11 +02:00
/// # `GET /_matrix/federation/v1/openid/userinfo`
///
/// Get information about the user that generated the OpenID token.
pub async fn get_openid_userinfo_route (
body : Ruma < get_openid_userinfo ::v1 ::Request > ,
) -> Result < get_openid_userinfo ::v1 ::Response > {
Ok ( get_openid_userinfo ::v1 ::Response ::new (
services ( )
. users
. find_from_openid_token ( & body . access_token ) ?
. ok_or_else ( | | {
Error ::BadRequest (
ErrorKind ::Unauthorized ,
" OpenID token has expired or does not exist. " ,
)
} ) ? ,
) )
}
2024-03-02 11:12:22 +00:00
/// # `GET /_matrix/federation/v1/hierarchy/{roomId}`
///
/// Gets the space tree in a depth-first manner to locate child rooms of a given space.
pub async fn get_hierarchy_route (
body : Ruma < get_hierarchy ::v1 ::Request > ,
) -> Result < get_hierarchy ::v1 ::Response > {
let sender_servername = body
. sender_servername
. as_ref ( )
. expect ( " server is authenticated " ) ;
if services ( ) . rooms . metadata . exists ( & body . room_id ) ? {
services ( )
. rooms
. spaces
. get_federation_hierarchy ( & body . room_id , sender_servername , body . suggested_only )
. await
} else {
Err ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Room does not exist. " ,
) )
}
}
2024-05-02 09:26:43 +01:00
/// # `GET /.well-known/matrix/server`
///
/// Returns the federation server discovery information.
pub async fn well_known_server (
_body : Ruma < discover_homeserver ::Request > ,
) -> Result < discover_homeserver ::Response > {
Ok ( discover_homeserver ::Response {
server : services ( ) . globals . well_known_server ( ) ,
} )
}
2020-12-08 12:34:46 +01:00
#[ cfg(test) ]
mod tests {
2021-04-24 12:27:46 +02:00
use super ::{ add_port_to_hostname , get_ip_with_port , FedDest } ;
2020-12-08 12:34:46 +01:00
#[ test ]
fn ips_get_default_ports ( ) {
assert_eq! (
2021-04-21 00:35:44 -03:00
get_ip_with_port ( " 1.1.1.1 " ) ,
Some ( FedDest ::Literal ( " 1.1.1.1:8448 " . parse ( ) . unwrap ( ) ) )
2020-12-08 12:34:46 +01:00
) ;
assert_eq! (
2021-04-21 00:35:44 -03:00
get_ip_with_port ( " dead:beef:: " ) ,
Some ( FedDest ::Literal ( " [dead:beef::]:8448 " . parse ( ) . unwrap ( ) ) )
2020-12-08 12:34:46 +01:00
) ;
}
#[ test ]
fn ips_keep_custom_ports ( ) {
assert_eq! (
2021-04-21 00:35:44 -03:00
get_ip_with_port ( " 1.1.1.1:1234 " ) ,
Some ( FedDest ::Literal ( " 1.1.1.1:1234 " . parse ( ) . unwrap ( ) ) )
2020-12-08 12:34:46 +01:00
) ;
assert_eq! (
2021-04-21 00:35:44 -03:00
get_ip_with_port ( " [dead::beef]:8933 " ) ,
Some ( FedDest ::Literal ( " [dead::beef]:8933 " . parse ( ) . unwrap ( ) ) )
2020-12-08 12:34:46 +01:00
) ;
}
#[ test ]
fn hostnames_get_default_ports ( ) {
assert_eq! (
2021-04-21 00:35:44 -03:00
add_port_to_hostname ( " example.com " ) ,
FedDest ::Named ( String ::from ( " example.com " ) , String ::from ( " :8448 " ) )
2020-12-08 12:34:46 +01:00
)
}
#[ test ]
fn hostnames_keep_custom_ports ( ) {
assert_eq! (
2021-04-21 00:35:44 -03:00
add_port_to_hostname ( " example.com:1337 " ) ,
FedDest ::Named ( String ::from ( " example.com " ) , String ::from ( " :1337 " ) )
2020-12-08 12:34:46 +01:00
)
}
}