2020-05-01 23:17:25 +02:00
use std ::{
collections ::BTreeMap ,
convert ::{ TryFrom , TryInto } ,
time ::{ Duration , SystemTime } ,
} ;
2020-04-11 09:30:11 +02:00
2020-06-09 15:13:17 +02:00
use crate ::{ utils , ConduitResult , Database , Error , Ruma } ;
2020-06-16 12:11:38 +02:00
use keys ::{ upload_signatures , upload_signing_keys } ;
2020-06-11 21:06:43 +02:00
use log ::warn ;
2020-05-25 23:24:13 +02:00
use rocket ::{ delete , get , options , post , put , State } ;
2020-06-05 18:19:26 +02:00
use ruma ::{
api ::client ::{
2020-06-09 15:13:17 +02:00
error ::ErrorKind ,
2020-06-05 18:19:26 +02:00
r0 ::{
2020-07-05 07:48:19 +02:00
account ::{
change_password , deactivate , get_username_availability , register ,
ThirdPartyIdRemovalStatus ,
} ,
2020-06-05 18:19:26 +02:00
alias ::{ create_alias , delete_alias , get_alias } ,
2020-06-16 12:11:38 +02:00
backup ::{
add_backup_keys , create_backup , get_backup , get_backup_keys , get_latest_backup ,
update_backup ,
} ,
2020-06-05 18:19:26 +02:00
capabilities ::get_capabilities ,
config ::{ get_global_account_data , set_global_account_data } ,
context ::get_context ,
device ::{ self , delete_device , delete_devices , get_device , get_devices , update_device } ,
directory ::{
self , get_public_rooms , get_public_rooms_filtered , get_room_visibility ,
set_room_visibility ,
} ,
filter ::{ self , create_filter , get_filter } ,
keys ::{ self , claim_keys , get_keys , upload_keys } ,
media ::{ create_content , get_content , get_content_thumbnail , get_media_config } ,
membership ::{
ban_user , forget_room , get_member_events , invite_user , join_room_by_id ,
2020-07-25 18:35:22 +02:00
join_room_by_id_or_alias , joined_rooms , kick_user , leave_room , unban_user ,
2020-06-05 18:19:26 +02:00
} ,
message ::{ create_message_event , get_message_events } ,
presence ::set_presence ,
profile ::{
get_avatar_url , get_display_name , get_profile , set_avatar_url , set_display_name ,
} ,
2020-06-16 12:11:38 +02:00
push ::{ get_pushers , get_pushrules_all , set_pushrule , set_pushrule_enabled } ,
2020-06-05 18:19:26 +02:00
read_marker ::set_read_marker ,
redact ::redact_event ,
2020-07-11 14:08:37 +02:00
room ::{ self , create_room , get_room_event } ,
2020-07-04 16:41:05 -04:00
session ::{ get_login_types , login , logout , logout_all } ,
2020-06-05 18:19:26 +02:00
state ::{
create_state_event_for_empty_key , create_state_event_for_key , get_state_events ,
get_state_events_for_empty_key , get_state_events_for_key ,
} ,
sync ::sync_events ,
2020-07-26 22:33:20 +02:00
tag ::{ create_tag , delete_tag , get_tags } ,
2020-06-05 18:19:26 +02:00
thirdparty ::get_protocols ,
to_device ::{ self , send_event_to_device } ,
typing ::create_typing_event ,
2020-06-11 21:06:43 +02:00
uiaa ::{ AuthFlow , UiaaInfo } ,
2020-06-05 18:19:26 +02:00
user_directory ::search_users ,
2020-05-18 09:22:07 +02:00
} ,
2020-06-05 18:19:26 +02:00
unversioned ::get_supported_versions ,
2020-04-11 09:30:11 +02:00
} ,
2020-06-05 18:19:26 +02:00
events ::{
2020-06-09 15:13:17 +02:00
room ::{
canonical_alias , guest_access , history_visibility , join_rules , member , name , redaction ,
topic ,
} ,
2020-07-26 22:33:20 +02:00
AnyEphemeralRoomEvent , AnyEvent , AnySyncEphemeralRoomEvent , EventType ,
2020-06-05 18:19:26 +02:00
} ,
2020-07-26 15:41:28 +02:00
Raw , RoomAliasId , RoomId , RoomVersionId , UserId ,
2020-05-23 11:20:00 +02:00
} ;
2020-04-11 09:30:11 +02:00
const GUEST_NAME_LENGTH : usize = 10 ;
const DEVICE_ID_LENGTH : usize = 10 ;
const TOKEN_LENGTH : usize = 256 ;
2020-05-18 17:53:34 +02:00
const MXC_LENGTH : usize = 256 ;
2020-06-06 18:44:50 +02:00
const SESSION_ID_LENGTH : usize = 256 ;
2020-04-11 09:30:11 +02:00
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/versions " ) ]
2020-06-09 15:13:17 +02:00
pub fn get_supported_versions_route ( ) -> ConduitResult < get_supported_versions ::Response > {
2020-06-16 12:11:38 +02:00
let mut unstable_features = BTreeMap ::new ( ) ;
unstable_features . insert ( " org.matrix.e2e_cross_signing " . to_owned ( ) , true ) ;
2020-06-09 15:13:17 +02:00
Ok ( get_supported_versions ::Response {
2020-04-19 14:14:47 +02:00
versions : vec ! [ " r0.5.0 " . to_owned ( ) , " r0.6.0 " . to_owned ( ) ] ,
2020-06-16 12:11:38 +02:00
unstable_features ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/register/available " , data = " <body> " ) ]
2020-05-01 23:17:25 +02:00
pub fn get_register_available_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-05-01 23:17:25 +02:00
body : Ruma < get_username_availability ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_username_availability ::Response > {
2020-05-01 23:17:25 +02:00
// Validate user id
2020-06-09 15:13:17 +02:00
let user_id = UserId ::parse_with_server_name ( body . username . clone ( ) , db . globals . server_name ( ) )
. ok ( )
. filter ( | user_id | {
! user_id . is_historical ( ) & & user_id . server_name ( ) = = db . globals . server_name ( )
} )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidUsername ,
" Username is invalid. " ,
) ) ? ;
2020-05-01 23:17:25 +02:00
// Check if username is creative enough
2020-06-09 15:13:17 +02:00
if db . users . exists ( & user_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::UserInUse ,
" Desired user ID is already taken. " ,
) ) ;
2020-05-01 23:17:25 +02:00
}
// TODO add check for appservice namespaces
// If no if check is true we have an username that's available to be used.
2020-06-09 15:13:17 +02:00
Ok ( get_username_availability ::Response { available : true } . into ( ) )
2020-05-01 23:17:25 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/register " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn register_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < register ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < register ::Response > {
2020-06-06 19:02:31 +02:00
if db . globals . registration_disabled ( ) {
2020-06-09 15:13:17 +02:00
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" Registration has been disabled. " ,
) ) ;
2020-06-06 19:02:31 +02:00
}
2020-04-11 09:30:11 +02:00
// Validate user id
2020-06-09 15:13:17 +02:00
let user_id = UserId ::parse_with_server_name (
2020-04-11 09:30:11 +02:00
body . username
. clone ( )
2020-05-27 07:09:23 +02:00
. unwrap_or_else ( | | utils ::random_string ( GUEST_NAME_LENGTH ) )
. to_lowercase ( ) ,
2020-05-13 10:41:51 +02:00
db . globals . server_name ( ) ,
)
. ok ( )
2020-06-09 15:13:17 +02:00
. filter ( | user_id | ! user_id . is_historical ( ) & & user_id . server_name ( ) = = db . globals . server_name ( ) )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidUsername ,
" Username is invalid. " ,
) ) ? ;
2020-04-11 09:30:11 +02:00
// Check if username is creative enough
2020-06-09 15:13:17 +02:00
if db . users . exists ( & user_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::UserInUse ,
" Desired user ID is already taken. " ,
) ) ;
2020-04-11 09:30:11 +02:00
}
2020-06-06 18:44:50 +02:00
// UIAA
2020-06-09 15:13:17 +02:00
let mut uiaainfo = UiaaInfo {
2020-06-06 18:44:50 +02:00
flows : vec ! [ AuthFlow {
stages : vec ! [ " m.login.dummy " . to_owned ( ) ] ,
} ] ,
completed : Vec ::new ( ) ,
params : Default ::default ( ) ,
2020-06-09 15:13:17 +02:00
session : None ,
2020-06-06 18:44:50 +02:00
auth_error : None ,
} ;
if let Some ( auth ) = & body . auth {
2020-06-09 15:13:17 +02:00
let ( worked , uiaainfo ) =
db . uiaa
2020-07-25 14:25:24 -04:00
. try_auth ( & user_id , " " . into ( ) , auth , & uiaainfo , & db . users , & db . globals ) ? ;
2020-06-06 18:44:50 +02:00
if ! worked {
2020-06-09 15:13:17 +02:00
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
2020-06-06 18:44:50 +02:00
}
2020-06-08 11:45:22 +02:00
// Success!
2020-06-06 18:44:50 +02:00
} else {
2020-06-09 15:13:17 +02:00
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ) ) ;
2020-07-25 14:25:24 -04:00
db . uiaa . create ( & user_id , " " . into ( ) , & uiaainfo ) ? ;
2020-06-09 15:13:17 +02:00
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
2020-06-06 18:44:50 +02:00
}
2020-04-14 22:25:44 +02:00
let password = body . password . clone ( ) . unwrap_or_default ( ) ;
2020-07-05 07:48:19 +02:00
// Create user
db . users . create ( & user_id , & password ) ? ;
2020-04-11 09:30:11 +02:00
// Generate new device id if the user didn't specify one
let device_id = body
2020-06-03 20:55:11 +02:00
. device_id
. clone ( )
2020-07-25 14:25:24 -04:00
. unwrap_or_else ( | | utils ::random_string ( DEVICE_ID_LENGTH ) . into ( ) ) ;
2020-04-11 09:30:11 +02:00
// Generate new token for the device
let token = utils ::random_string ( TOKEN_LENGTH ) ;
2020-05-03 17:25:31 +02:00
// Add device
2020-06-09 15:13:17 +02:00
db . users . create_device (
& user_id ,
& device_id ,
& token ,
body . initial_device_display_name . clone ( ) ,
) ? ;
2020-04-11 09:30:11 +02:00
2020-05-02 09:24:09 +02:00
// Initial data
2020-06-09 15:13:17 +02:00
db . account_data . update (
None ,
& user_id ,
2020-07-26 22:33:20 +02:00
EventType ::PushRules ,
& ruma ::events ::push_rules ::PushRulesEvent {
2020-06-09 15:13:17 +02:00
content : ruma ::events ::push_rules ::PushRulesEventContent {
2020-06-12 13:18:25 +02:00
global : crate ::push_rules ::default_pushrules ( & user_id ) ,
2020-06-09 15:13:17 +02:00
} ,
2020-07-26 22:33:20 +02:00
} ,
2020-06-09 15:13:17 +02:00
& db . globals ,
) ? ;
2020-05-02 09:24:09 +02:00
2020-06-09 15:13:17 +02:00
Ok ( register ::Response {
2020-04-11 09:30:11 +02:00
access_token : Some ( token ) ,
user_id ,
2020-07-17 19:52:04 -04:00
device_id : Some ( device_id . into ( ) ) ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/login " ) ]
2020-06-09 15:13:17 +02:00
pub fn get_login_route ( ) -> ConduitResult < get_login_types ::Response > {
Ok ( get_login_types ::Response {
2020-04-11 09:30:11 +02:00
flows : vec ! [ get_login_types ::LoginType ::Password ] ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/login " , data = " <body> " ) ]
2020-05-09 21:47:09 +02:00
pub fn login_route (
db : State < '_ , Database > ,
body : Ruma < login ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < login ::Response > {
2020-04-11 09:30:11 +02:00
// Validate login method
let user_id =
2020-05-24 18:25:52 +02:00
// TODO: Other login methods
if let ( login ::UserInfo ::MatrixId ( username ) , login ::LoginInfo ::Password { password } ) =
2020-04-11 09:30:11 +02:00
( body . user . clone ( ) , body . login_info . clone ( ) )
{
2020-06-09 15:13:17 +02:00
let user_id = UserId ::parse_with_server_name ( username , db . globals . server_name ( ) ) . map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidUsername , " Username is invalid. " ) ) ? ;
let hash = db . users . password_hash ( & user_id ) ? . ok_or ( Error ::BadRequest ( ErrorKind ::Forbidden , " Wrong username or password. " ) ) ? ;
2020-07-05 07:48:19 +02:00
if hash . is_empty ( ) {
return Err ( Error ::BadRequest ( ErrorKind ::UserDeactivated , " The user has been deactivated " ) ) ;
}
2020-06-09 15:13:17 +02:00
let hash_matches =
argon2 ::verify_encoded ( & hash , password . as_bytes ( ) ) . unwrap_or ( false ) ;
if ! hash_matches {
return Err ( Error ::BadRequest ( ErrorKind ::Forbidden , " Wrong username or password. " ) ) ;
2020-04-11 09:30:11 +02:00
}
2020-06-09 15:13:17 +02:00
user_id
2020-04-11 09:30:11 +02:00
} else {
2020-06-09 15:13:17 +02:00
return Err ( Error ::BadRequest ( ErrorKind ::Forbidden , " Bad login type. " ) ) ;
2020-04-11 09:30:11 +02:00
} ;
// Generate new device id if the user didn't specify one
let device_id = body
2020-05-26 21:06:54 +02:00
. body
2020-04-11 09:30:11 +02:00
. device_id
2020-06-03 13:41:30 +02:00
. clone ( )
2020-07-17 19:52:04 -04:00
. unwrap_or_else ( | | utils ::random_string ( DEVICE_ID_LENGTH ) . into ( ) ) ;
2020-04-11 09:30:11 +02:00
// Generate a new token for the device
let token = utils ::random_string ( TOKEN_LENGTH ) ;
2020-05-03 17:25:31 +02:00
// Add device
2020-06-09 15:13:17 +02:00
db . users . create_device (
& user_id ,
& device_id ,
& token ,
body . initial_device_display_name . clone ( ) ,
) ? ;
Ok ( login ::Response {
2020-04-11 09:30:11 +02:00
user_id ,
access_token : token ,
2020-07-21 14:04:39 -04:00
home_server : Some ( db . globals . server_name ( ) . to_owned ( ) ) ,
2020-07-18 08:21:25 -04:00
device_id : device_id . into ( ) ,
2020-04-11 09:30:11 +02:00
well_known : None ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/logout " , data = " <body> " ) ]
2020-05-24 22:10:09 +02:00
pub fn logout_route (
db : State < '_ , Database > ,
body : Ruma < logout ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < logout ::Response > {
2020-05-24 22:10:09 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-07-25 14:25:24 -04:00
db . users . remove_device ( & user_id , device_id ) ? ;
2020-05-24 22:10:09 +02:00
2020-06-09 15:13:17 +02:00
Ok ( logout ::Response . into ( ) )
2020-05-24 22:10:09 +02:00
}
2020-07-04 16:41:05 -04:00
#[ post( " /_matrix/client/r0/logout/all " , data = " <body> " ) ]
pub fn logout_all_route (
db : State < '_ , Database > ,
body : Ruma < logout_all ::Request > ,
) -> ConduitResult < logout_all ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
for device_id in db . users . all_device_ids ( user_id ) {
if let Ok ( device_id ) = device_id {
db . users . remove_device ( & user_id , & device_id ) ? ;
}
}
Ok ( logout_all ::Response . into ( ) )
}
2020-07-02 20:38:25 +02:00
#[ post( " /_matrix/client/r0/account/password " , data = " <body> " ) ]
pub fn change_password_route (
db : State < '_ , Database > ,
body : Ruma < change_password ::Request > ,
) -> ConduitResult < change_password ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-07-05 07:48:19 +02:00
2020-07-02 20:38:25 +02:00
let mut uiaainfo = UiaaInfo {
flows : vec ! [ AuthFlow {
stages : vec ! [ " m.login.password " . to_owned ( ) ] ,
} ] ,
completed : Vec ::new ( ) ,
params : Default ::default ( ) ,
session : None ,
auth_error : None ,
} ;
if let Some ( auth ) = & body . auth {
2020-07-25 14:25:24 -04:00
let ( worked , uiaainfo ) =
db . uiaa
. try_auth ( & user_id , device_id , auth , & uiaainfo , & db . users , & db . globals ) ? ;
2020-07-02 20:38:25 +02:00
if ! worked {
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
}
2020-07-05 07:48:19 +02:00
// Success!
2020-07-02 20:38:25 +02:00
} else {
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ) ) ;
db . uiaa . create ( & user_id , & device_id , & uiaainfo ) ? ;
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
}
db . users . set_password ( & user_id , & body . new_password ) ? ;
// TODO: Read logout_devices field when it's available and respect that, currently not supported in Ruma
// See: https://github.com/ruma/ruma/issues/107
// Logout all devices except the current one
for id in db
. users
. all_device_ids ( & user_id )
. filter_map ( | id | id . ok ( ) )
. filter ( | id | id ! = device_id )
{
db . users . remove_device ( & user_id , & id ) ? ;
}
Ok ( change_password ::Response . into ( ) )
}
2020-07-05 07:48:19 +02:00
#[ post( " /_matrix/client/r0/account/deactivate " , data = " <body> " ) ]
pub fn deactivate_route (
db : State < '_ , Database > ,
body : Ruma < deactivate ::Request > ,
) -> ConduitResult < deactivate ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let mut uiaainfo = UiaaInfo {
flows : vec ! [ AuthFlow {
stages : vec ! [ " m.login.password " . to_owned ( ) ] ,
} ] ,
completed : Vec ::new ( ) ,
params : Default ::default ( ) ,
session : None ,
auth_error : None ,
} ;
if let Some ( auth ) = & body . auth {
let ( worked , uiaainfo ) = db . uiaa . try_auth (
& user_id ,
& device_id ,
auth ,
& uiaainfo ,
& db . users ,
& db . globals ,
) ? ;
if ! worked {
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
}
// Success!
} else {
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ) ) ;
db . uiaa . create ( & user_id , & device_id , & uiaainfo ) ? ;
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
}
// Leave all joined rooms and reject all invitations
for room_id in db
. rooms
. rooms_joined ( & user_id )
. chain ( db . rooms . rooms_invited ( & user_id ) )
{
let room_id = room_id ? ;
let event = member ::MemberEventContent {
membership : member ::MembershipState ::Leave ,
displayname : None ,
avatar_url : None ,
is_direct : None ,
third_party_invite : None ,
} ;
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomMember ,
serde_json ::to_value ( event ) . expect ( " event is valid, we just created it " ) ,
None ,
Some ( user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
}
// Remove devices and mark account as deactivated
db . users . deactivate_account ( & user_id ) ? ;
Ok ( deactivate ::Response {
id_server_unbind_result : ThirdPartyIdRemovalStatus ::NoSupport ,
}
. into ( ) )
}
2020-05-03 17:25:31 +02:00
#[ get( " /_matrix/client/r0/capabilities " ) ]
2020-06-09 15:13:17 +02:00
pub fn get_capabilities_route ( ) -> ConduitResult < get_capabilities ::Response > {
2020-06-02 19:32:18 +02:00
let mut available = BTreeMap ::new ( ) ;
available . insert (
2020-07-25 14:25:24 -04:00
RoomVersionId ::Version5 ,
2020-06-02 19:32:18 +02:00
get_capabilities ::RoomVersionStability ::Stable ,
) ;
available . insert (
2020-07-25 14:25:24 -04:00
RoomVersionId ::Version6 ,
2020-06-02 19:32:18 +02:00
get_capabilities ::RoomVersionStability ::Stable ,
) ;
2020-04-28 19:56:34 +02:00
2020-06-09 15:13:17 +02:00
Ok ( get_capabilities ::Response {
2020-04-19 14:14:47 +02:00
capabilities : get_capabilities ::Capabilities {
2020-06-02 19:32:18 +02:00
change_password : None , // None means it is possible
room_versions : Some ( get_capabilities ::RoomVersionsCapability {
default : " 6 " . to_owned ( ) ,
available ,
} ) ,
2020-04-19 14:14:47 +02:00
custom_capabilities : BTreeMap ::new ( ) ,
} ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-19 14:14:47 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/pushrules " , data = " <body> " ) ]
2020-05-23 19:17:08 +02:00
pub fn get_pushrules_all_route (
db : State < '_ , Database > ,
body : Ruma < get_pushrules_all ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_pushrules_all ::Response > {
2020-05-23 19:17:08 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-24 18:25:52 +02:00
2020-07-26 22:33:20 +02:00
let event = db
2020-05-23 19:17:08 +02:00
. account_data
2020-07-26 22:33:20 +02:00
. get ::< ruma ::events ::push_rules ::PushRulesEvent > ( None , & user_id , EventType ::PushRules ) ?
2020-06-09 15:13:17 +02:00
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" PushRules event not found. " ,
2020-07-26 22:33:20 +02:00
) ) ? ;
Ok ( get_pushrules_all ::Response {
global : event . content . global ,
2020-05-23 19:17:08 +02:00
}
2020-07-26 22:33:20 +02:00
. into ( ) )
2020-05-01 20:26:57 +02:00
}
#[ put(
" /_matrix/client/r0/pushrules/<_scope>/<_kind>/<_rule_id> " ,
2020-06-16 12:11:38 +02:00
//data = "<body>"
2020-05-01 20:26:57 +02:00
) ]
pub fn set_pushrule_route (
2020-06-16 12:11:38 +02:00
//db: State<'_, Database>,
//body: Ruma<set_pushrule::Request>,
2020-05-01 20:26:57 +02:00
_scope : String ,
_kind : String ,
_rule_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_pushrule ::Response > {
2020-05-01 20:26:57 +02:00
// TODO
2020-05-23 19:17:08 +02:00
warn! ( " TODO: set_pushrule_route " ) ;
2020-06-09 15:13:17 +02:00
Ok ( set_pushrule ::Response . into ( ) )
2020-05-01 20:26:57 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put( " /_matrix/client/r0/pushrules/<_scope>/<_kind>/<_rule_id>/enabled " ) ]
2020-05-01 20:26:57 +02:00
pub fn set_pushrule_enabled_route (
_scope : String ,
_kind : String ,
_rule_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_pushrule_enabled ::Response > {
2020-05-01 20:26:57 +02:00
// TODO
2020-05-23 19:17:08 +02:00
warn! ( " TODO: set_pushrule_enabled_route " ) ;
2020-06-09 15:13:17 +02:00
Ok ( set_pushrule_enabled ::Response . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/user/<_user_id>/filter/<_filter_id> " ) ]
2020-04-11 09:30:11 +02:00
pub fn get_filter_route (
_user_id : String ,
_filter_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_filter ::Response > {
2020-04-11 09:30:11 +02:00
// TODO
2020-06-09 15:13:17 +02:00
Ok ( get_filter ::Response {
2020-04-11 09:30:11 +02:00
filter : filter ::FilterDefinition {
event_fields : None ,
event_format : None ,
account_data : None ,
room : None ,
presence : None ,
} ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/user/<_user_id>/filter " ) ]
2020-06-09 15:13:17 +02:00
pub fn create_filter_route ( _user_id : String ) -> ConduitResult < create_filter ::Response > {
2020-04-11 09:30:11 +02:00
// TODO
2020-06-09 15:13:17 +02:00
Ok ( create_filter ::Response {
2020-04-11 09:30:11 +02:00
filter_id : utils ::random_string ( 10 ) ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put(
" /_matrix/client/r0/user/<_user_id>/account_data/<_type> " ,
data = " <body> "
) ]
2020-04-11 09:30:11 +02:00
pub fn set_global_account_data_route (
2020-05-17 19:56:40 +02:00
db : State < '_ , Database > ,
body : Ruma < set_global_account_data ::Request > ,
2020-04-11 09:30:11 +02:00
_user_id : String ,
_type : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_global_account_data ::Response > {
2020-05-17 19:56:40 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-07-26 22:33:20 +02:00
let content = serde_json ::from_str ::< serde_json ::Value > ( body . data . get ( ) )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::BadJson , " Data is invalid. " ) ) ? ;
let event_type = body . event_type . to_string ( ) ;
2020-06-09 15:13:17 +02:00
db . account_data . update (
None ,
user_id ,
2020-07-26 22:33:20 +02:00
EventType ::Custom ( event_type ) ,
& content ,
2020-06-09 15:13:17 +02:00
& db . globals ,
) ? ;
2020-05-17 19:56:40 +02:00
2020-06-09 15:13:17 +02:00
Ok ( set_global_account_data ::Response . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get(
" /_matrix/client/r0/user/<_user_id>/account_data/<_type> " ,
data = " <body> "
) ]
2020-04-11 09:30:11 +02:00
pub fn get_global_account_data_route (
2020-05-17 19:56:40 +02:00
db : State < '_ , Database > ,
body : Ruma < get_global_account_data ::Request > ,
2020-04-11 09:30:11 +02:00
_user_id : String ,
_type : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_global_account_data ::Response > {
2020-05-17 19:56:40 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-07-26 22:33:20 +02:00
let data = db
2020-07-25 15:48:12 -04:00
. account_data
2020-07-26 22:33:20 +02:00
. get ::< ruma ::events ::AnyBasicEvent > (
2020-05-17 21:28:36 +02:00
None ,
user_id ,
2020-07-26 22:33:20 +02:00
EventType ::try_from ( & body . event_type ) . expect ( " EventType::try_from can never fail " ) ,
2020-06-09 15:13:17 +02:00
) ?
2020-07-25 15:48:12 -04:00
. ok_or ( Error ::BadRequest ( ErrorKind ::NotFound , " Data not found. " ) ) ? ;
2020-07-26 22:33:20 +02:00
Ok ( get_global_account_data ::Response {
account_data : Raw ::from ( data ) ,
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put( " /_matrix/client/r0/profile/<_user_id>/displayname " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn set_displayname_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < set_display_name ::Request > ,
_user_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_display_name ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-04-11 09:30:11 +02:00
2020-05-24 18:25:52 +02:00
db . users
2020-06-09 15:13:17 +02:00
. set_displayname ( & user_id , body . displayname . clone ( ) ) ? ;
2020-05-09 21:47:09 +02:00
2020-05-24 18:25:52 +02:00
// Send a new membership event into all joined rooms
for room_id in db . rooms . rooms_joined ( & user_id ) {
2020-06-09 15:13:17 +02:00
let room_id = room_id ? ;
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomMember ,
serde_json ::to_value ( ruma ::events ::room ::member ::MemberEventContent {
displayname : body . displayname . clone ( ) ,
2020-07-26 15:41:28 +02:00
.. serde_json ::from_value ::< Raw < _ > > (
2020-06-09 15:13:17 +02:00
db . rooms
2020-06-12 13:18:25 +02:00
. room_state_get ( & room_id , & EventType ::RoomMember , & user_id . to_string ( ) ) ?
2020-06-11 10:03:08 +02:00
. ok_or_else ( | | {
Error ::bad_database (
" Tried to send displayname update for user not in the room. " ,
)
} ) ?
2020-06-09 15:13:17 +02:00
. content
. clone ( ) ,
)
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Database contains invalid PDU. " ) ) ?
2020-06-09 15:13:17 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Database contains invalid PDU. " ) ) ?
2020-06-09 15:13:17 +02:00
} )
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-04-11 09:30:11 +02:00
}
2020-05-24 18:25:52 +02:00
// Presence update
2020-06-09 15:13:17 +02:00
db . global_edus . update_presence (
ruma ::events ::presence ::PresenceEvent {
content : ruma ::events ::presence ::PresenceEventContent {
avatar_url : db . users . avatar_url ( & user_id ) ? ,
currently_active : None ,
displayname : db . users . displayname ( & user_id ) ? ,
last_active_ago : Some (
utils ::millis_since_unix_epoch ( )
. try_into ( )
. expect ( " time is valid " ) ,
) ,
2020-07-26 15:41:28 +02:00
presence : ruma ::presence ::PresenceState ::Online ,
2020-06-09 15:13:17 +02:00
status_msg : None ,
2020-06-04 22:36:48 +02:00
} ,
2020-06-09 15:13:17 +02:00
sender : user_id . clone ( ) ,
} ,
& db . globals ,
) ? ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
Ok ( set_display_name ::Response . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/profile/<_user_id>/displayname " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn get_displayname_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < get_display_name ::Request > ,
2020-05-03 17:25:31 +02:00
_user_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_display_name ::Response > {
2020-06-08 12:28:30 +02:00
let user_id = body . body . user_id . clone ( ) ;
2020-06-09 15:13:17 +02:00
Ok ( get_display_name ::Response {
displayname : db . users . displayname ( & user_id ) ? ,
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put( " /_matrix/client/r0/profile/<_user_id>/avatar_url " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn set_avatar_url_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < set_avatar_url ::Request > ,
_user_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_avatar_url ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-04-11 09:30:11 +02:00
2020-05-26 10:27:51 +02:00
if let Some ( avatar_url ) = & body . avatar_url {
2020-05-24 18:25:52 +02:00
if ! avatar_url . starts_with ( " mxc:// " ) {
2020-06-09 15:13:17 +02:00
return Err ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" avatar_url has to start with mxc://. " ,
) ) ;
2020-05-24 18:25:52 +02:00
}
2020-04-11 09:30:11 +02:00
2020-05-24 18:25:52 +02:00
// TODO in the future when we can handle media uploads make sure that this url is our own server
// TODO also make sure this is valid mxc:// format (not only starting with it)
}
2020-05-19 23:47:30 +02:00
2020-06-09 15:13:17 +02:00
db . users . set_avatar_url ( & user_id , body . avatar_url . clone ( ) ) ? ;
2020-05-19 23:47:30 +02:00
2020-05-24 18:25:52 +02:00
// Send a new membership event into all joined rooms
for room_id in db . rooms . rooms_joined ( & user_id ) {
2020-06-09 15:13:17 +02:00
let room_id = room_id ? ;
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomMember ,
serde_json ::to_value ( ruma ::events ::room ::member ::MemberEventContent {
avatar_url : body . avatar_url . clone ( ) ,
2020-07-26 15:41:28 +02:00
.. serde_json ::from_value ::< Raw < _ > > (
2020-06-09 15:13:17 +02:00
db . rooms
2020-06-12 13:18:25 +02:00
. room_state_get ( & room_id , & EventType ::RoomMember , & user_id . to_string ( ) ) ?
2020-06-11 10:03:08 +02:00
. ok_or_else ( | | {
Error ::bad_database (
" Tried to send avatar url update for user not in the room. " ,
)
} ) ?
2020-06-09 15:13:17 +02:00
. content
. clone ( ) ,
)
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Database contains invalid PDU. " ) ) ?
2020-06-09 15:13:17 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Database contains invalid PDU. " ) ) ?
2020-06-09 15:13:17 +02:00
} )
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-04-11 09:30:11 +02:00
}
2020-05-24 18:25:52 +02:00
// Presence update
2020-06-09 15:13:17 +02:00
db . global_edus . update_presence (
ruma ::events ::presence ::PresenceEvent {
content : ruma ::events ::presence ::PresenceEventContent {
avatar_url : db . users . avatar_url ( & user_id ) ? ,
currently_active : None ,
displayname : db . users . displayname ( & user_id ) ? ,
last_active_ago : Some (
utils ::millis_since_unix_epoch ( )
. try_into ( )
. expect ( " time is valid " ) ,
) ,
2020-07-26 15:41:28 +02:00
presence : ruma ::presence ::PresenceState ::Online ,
2020-06-09 15:13:17 +02:00
status_msg : None ,
2020-06-04 22:36:48 +02:00
} ,
2020-06-09 15:13:17 +02:00
sender : user_id . clone ( ) ,
} ,
& db . globals ,
) ? ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
Ok ( set_avatar_url ::Response . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/profile/<_user_id>/avatar_url " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn get_avatar_url_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < get_avatar_url ::Request > ,
2020-05-03 17:25:31 +02:00
_user_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_avatar_url ::Response > {
2020-06-08 12:28:30 +02:00
let user_id = body . body . user_id . clone ( ) ;
2020-06-09 15:13:17 +02:00
Ok ( get_avatar_url ::Response {
avatar_url : db . users . avatar_url ( & user_id ) ? ,
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/profile/<_user_id> " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn get_profile_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < get_profile ::Request > ,
2020-05-03 17:25:31 +02:00
_user_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_profile ::Response > {
2020-06-08 12:28:30 +02:00
let user_id = body . body . user_id . clone ( ) ;
2020-06-09 15:13:17 +02:00
let avatar_url = db . users . avatar_url ( & user_id ) ? ;
let displayname = db . users . displayname ( & user_id ) ? ;
if avatar_url . is_none ( ) & & displayname . is_none ( ) {
// Return 404 if we don't have a profile for this id
return Err ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Profile was not found. " ,
) ) ;
2020-04-11 09:30:11 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( get_profile ::Response {
avatar_url ,
displayname ,
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put( " /_matrix/client/r0/presence/<_user_id>/status " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn set_presence_route (
2020-05-09 21:47:09 +02:00
db : State < '_ , Database > ,
body : Ruma < set_presence ::Request > ,
2020-04-11 09:30:11 +02:00
_user_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_presence ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-09 21:47:09 +02:00
2020-06-09 15:13:17 +02:00
db . global_edus . update_presence (
ruma ::events ::presence ::PresenceEvent {
content : ruma ::events ::presence ::PresenceEventContent {
avatar_url : db . users . avatar_url ( & user_id ) ? ,
currently_active : None ,
displayname : db . users . displayname ( & user_id ) ? ,
last_active_ago : Some (
utils ::millis_since_unix_epoch ( )
. try_into ( )
. expect ( " time is valid " ) ,
) ,
presence : body . presence ,
status_msg : body . status_msg . clone ( ) ,
2020-06-04 22:36:48 +02:00
} ,
2020-06-09 15:13:17 +02:00
sender : user_id . clone ( ) ,
} ,
& db . globals ,
) ? ;
2020-05-09 21:47:09 +02:00
2020-06-09 15:13:17 +02:00
Ok ( set_presence ::Response . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/keys/upload " , data = " <body> " ) ]
2020-05-17 19:56:40 +02:00
pub fn upload_keys_route (
db : State < '_ , Database > ,
body : Ruma < upload_keys ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < upload_keys ::Response > {
2020-05-17 19:56:40 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
if let Some ( one_time_keys ) = & body . one_time_keys {
for ( key_key , key_value ) in one_time_keys {
db . users
2020-06-09 15:13:17 +02:00
. add_one_time_key ( user_id , device_id , key_key , key_value ) ? ;
2020-05-17 19:56:40 +02:00
}
}
if let Some ( device_keys ) = & body . device_keys {
2020-06-16 12:11:38 +02:00
// This check is needed to assure that signatures are kept
if db . users . get_device_keys ( user_id , device_id ) ? . is_none ( ) {
db . users
. add_device_keys ( user_id , device_id , device_keys , & db . globals ) ? ;
}
2020-05-17 19:56:40 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( upload_keys ::Response {
one_time_key_counts : db . users . count_one_time_keys ( user_id , device_id ) ? ,
}
. into ( ) )
2020-05-17 19:56:40 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/keys/query " , data = " <body> " ) ]
2020-05-17 19:56:40 +02:00
pub fn get_keys_route (
db : State < '_ , Database > ,
body : Ruma < get_keys ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_keys ::Response > {
2020-06-16 12:11:38 +02:00
let sender_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let mut master_keys = BTreeMap ::new ( ) ;
let mut self_signing_keys = BTreeMap ::new ( ) ;
let mut user_signing_keys = BTreeMap ::new ( ) ;
2020-05-17 19:56:40 +02:00
let mut device_keys = BTreeMap ::new ( ) ;
for ( user_id , device_ids ) in & body . device_keys {
if device_ids . is_empty ( ) {
let mut container = BTreeMap ::new ( ) ;
2020-06-16 12:11:38 +02:00
for device_id in db . users . all_device_ids ( user_id ) {
let device_id = device_id ? ;
if let Some ( mut keys ) = db . users . get_device_keys ( user_id , & device_id ) ? {
let metadata = db
. users
. get_device_metadata ( user_id , & device_id ) ?
. ok_or_else ( | | {
Error ::bad_database ( " all_device_keys contained nonexistent device. " )
} ) ? ;
2020-06-03 20:55:11 +02:00
2020-06-16 12:11:38 +02:00
keys . unsigned = Some ( keys ::UnsignedDeviceInfo {
device_display_name : metadata . display_name ,
} ) ;
2020-06-03 20:55:11 +02:00
2020-07-25 14:25:24 -04:00
container . insert ( device_id , keys ) ;
2020-06-16 12:11:38 +02:00
}
2020-05-17 19:56:40 +02:00
}
device_keys . insert ( user_id . clone ( ) , container ) ;
} else {
for device_id in device_ids {
let mut container = BTreeMap ::new ( ) ;
2020-06-16 12:11:38 +02:00
if let Some ( mut keys ) = db . users . get_device_keys ( & user_id . clone ( ) , & device_id ) ? {
2020-06-09 15:13:17 +02:00
let metadata = db . users . get_device_metadata ( user_id , & device_id ) ? . ok_or (
Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Tried to get keys for nonexistent device. " ,
) ,
) ? ;
2020-06-03 20:55:11 +02:00
keys . unsigned = Some ( keys ::UnsignedDeviceInfo {
device_display_name : metadata . display_name ,
} ) ;
2020-07-25 14:25:24 -04:00
container . insert ( device_id . clone ( ) , keys ) ;
2020-05-17 19:56:40 +02:00
}
device_keys . insert ( user_id . clone ( ) , container ) ;
}
}
2020-06-16 12:11:38 +02:00
if let Some ( master_key ) = db . users . get_master_key ( user_id , sender_id ) ? {
master_keys . insert ( user_id . clone ( ) , master_key ) ;
}
if let Some ( self_signing_key ) = db . users . get_self_signing_key ( user_id , sender_id ) ? {
self_signing_keys . insert ( user_id . clone ( ) , self_signing_key ) ;
}
if user_id = = sender_id {
if let Some ( user_signing_key ) = db . users . get_user_signing_key ( sender_id ) ? {
user_signing_keys . insert ( user_id . clone ( ) , user_signing_key ) ;
}
}
2020-05-17 19:56:40 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( get_keys ::Response {
2020-06-16 12:11:38 +02:00
master_keys ,
self_signing_keys ,
user_signing_keys ,
2020-05-17 19:56:40 +02:00
device_keys ,
2020-06-16 12:11:38 +02:00
failures : BTreeMap ::new ( ) ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/keys/claim " , data = " <body> " ) ]
2020-05-17 19:56:40 +02:00
pub fn claim_keys_route (
db : State < '_ , Database > ,
body : Ruma < claim_keys ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < claim_keys ::Response > {
2020-05-17 19:56:40 +02:00
let mut one_time_keys = BTreeMap ::new ( ) ;
for ( user_id , map ) in & body . one_time_keys {
let mut container = BTreeMap ::new ( ) ;
for ( device_id , key_algorithm ) in map {
2020-06-09 15:13:17 +02:00
if let Some ( one_time_keys ) =
db . users
. take_one_time_key ( user_id , device_id , key_algorithm ) ?
2020-05-17 19:56:40 +02:00
{
let mut c = BTreeMap ::new ( ) ;
c . insert ( one_time_keys . 0 , one_time_keys . 1 ) ;
container . insert ( device_id . clone ( ) , c ) ;
}
}
one_time_keys . insert ( user_id . clone ( ) , container ) ;
}
2020-06-09 15:13:17 +02:00
Ok ( claim_keys ::Response {
2020-05-17 19:56:40 +02:00
failures : BTreeMap ::new ( ) ,
one_time_keys ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-16 12:11:38 +02:00
#[ post( " /_matrix/client/unstable/room_keys/version " , data = " <body> " ) ]
pub fn create_backup_route (
db : State < '_ , Database > ,
body : Ruma < create_backup ::Request > ,
) -> ConduitResult < create_backup ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let version = db
. key_backups
. create_backup ( & user_id , & body . algorithm , & db . globals ) ? ;
Ok ( create_backup ::Response { version } . into ( ) )
}
#[ put(
" /_matrix/client/unstable/room_keys/version/<_version> " ,
data = " <body> "
) ]
pub fn update_backup_route (
db : State < '_ , Database > ,
body : Ruma < update_backup ::Request > ,
_version : String ,
) -> ConduitResult < update_backup ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
db . key_backups
. update_backup ( & user_id , & body . version , & body . algorithm , & db . globals ) ? ;
Ok ( update_backup ::Response . into ( ) )
}
#[ get( " /_matrix/client/unstable/room_keys/version " , data = " <body> " ) ]
pub fn get_latest_backup_route (
db : State < '_ , Database > ,
body : Ruma < get_latest_backup ::Request > ,
) -> ConduitResult < get_latest_backup ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let ( version , algorithm ) =
db . key_backups
. get_latest_backup ( & user_id ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Key backup does not exist. " ,
) ) ? ;
Ok ( get_latest_backup ::Response {
algorithm ,
count : ( db . key_backups . count_keys ( user_id , & version ) ? as u32 ) . into ( ) ,
etag : db . key_backups . get_etag ( user_id , & version ) ? ,
version ,
}
. into ( ) )
}
#[ get(
" /_matrix/client/unstable/room_keys/version/<_version> " ,
data = " <body> "
) ]
pub fn get_backup_route (
db : State < '_ , Database > ,
body : Ruma < get_backup ::Request > ,
_version : String ,
) -> ConduitResult < get_backup ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let algorithm =
db . key_backups
. get_backup ( & user_id , & body . version ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Key backup does not exist. " ,
) ) ? ;
Ok ( get_backup ::Response {
algorithm ,
count : ( db . key_backups . count_keys ( user_id , & body . version ) ? as u32 ) . into ( ) ,
etag : db . key_backups . get_etag ( user_id , & body . version ) ? ,
version : body . version . clone ( ) ,
}
. into ( ) )
}
#[ put( " /_matrix/client/unstable/room_keys/keys " , data = " <body> " ) ]
pub fn add_backup_keys_route (
db : State < '_ , Database > ,
body : Ruma < add_backup_keys ::Request > ,
) -> ConduitResult < add_backup_keys ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
for ( room_id , room ) in & body . rooms {
for ( session_id , key_data ) in & room . sessions {
db . key_backups . add_key (
& user_id ,
& body . version ,
& room_id ,
& session_id ,
& key_data ,
& db . globals ,
) ?
}
}
Ok ( add_backup_keys ::Response {
count : ( db . key_backups . count_keys ( user_id , & body . version ) ? as u32 ) . into ( ) ,
etag : db . key_backups . get_etag ( user_id , & body . version ) ? ,
}
. into ( ) )
}
#[ get( " /_matrix/client/unstable/room_keys/keys " , data = " <body> " ) ]
pub fn get_backup_keys_route (
db : State < '_ , Database > ,
body : Ruma < get_backup_keys ::Request > ,
) -> ConduitResult < get_backup_keys ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let rooms = db . key_backups . get_all ( & user_id , & body . version ) ? ;
Ok ( get_backup_keys ::Response { rooms } . into ( ) )
}
2020-04-11 09:30:11 +02:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/read_markers " , data = " <body> " ) ]
pub fn set_read_marker_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < set_read_marker ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_read_marker ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-17 19:56:40 +02:00
2020-07-26 22:33:20 +02:00
let fully_read_event = ruma ::events ::fully_read ::FullyReadEvent {
content : ruma ::events ::fully_read ::FullyReadEventContent {
event_id : body . fully_read . clone ( ) ,
} ,
room_id : body . room_id . clone ( ) ,
} ;
2020-06-09 15:13:17 +02:00
db . account_data . update (
Some ( & body . room_id ) ,
& user_id ,
2020-07-26 22:33:20 +02:00
EventType ::FullyRead ,
& fully_read_event ,
2020-06-09 15:13:17 +02:00
& db . globals ,
) ? ;
2020-05-01 20:26:57 +02:00
2020-04-11 20:03:22 +02:00
if let Some ( event ) = & body . read_receipt {
2020-06-09 15:13:17 +02:00
db . rooms . edus . room_read_set (
& body . room_id ,
& user_id ,
db . rooms . get_pdu_count ( event ) ? . ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Event does not exist. " ,
) ) ? ,
) ? ;
2020-05-01 20:26:57 +02:00
2020-04-19 14:14:47 +02:00
let mut user_receipts = BTreeMap ::new ( ) ;
2020-04-11 20:03:22 +02:00
user_receipts . insert (
user_id . clone ( ) ,
2020-06-05 18:19:26 +02:00
ruma ::events ::receipt ::Receipt {
2020-04-19 14:14:47 +02:00
ts : Some ( SystemTime ::now ( ) ) ,
2020-04-11 20:03:22 +02:00
} ,
) ;
2020-04-19 14:14:47 +02:00
let mut receipt_content = BTreeMap ::new ( ) ;
2020-04-11 20:03:22 +02:00
receipt_content . insert (
event . clone ( ) ,
2020-06-05 18:19:26 +02:00
ruma ::events ::receipt ::Receipts {
2020-04-11 20:03:22 +02:00
read : Some ( user_receipts ) ,
} ,
) ;
2020-06-09 15:13:17 +02:00
db . rooms . edus . roomlatest_update (
& user_id ,
& body . room_id ,
2020-07-18 08:21:25 -04:00
AnyEvent ::Ephemeral ( AnyEphemeralRoomEvent ::Receipt (
2020-06-21 15:58:42 -04:00
ruma ::events ::receipt ::ReceiptEvent {
content : ruma ::events ::receipt ::ReceiptEventContent ( receipt_content ) ,
room_id : body . room_id . clone ( ) ,
} ,
) ) ,
2020-06-09 15:13:17 +02:00
& db . globals ,
) ? ;
2020-04-11 20:03:22 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( set_read_marker ::Response . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put(
" /_matrix/client/r0/rooms/<_room_id>/typing/<_user_id> " ,
data = " <body> "
) ]
2020-04-12 21:12:50 +02:00
pub fn create_typing_event_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-12 21:12:50 +02:00
body : Ruma < create_typing_event ::Request > ,
_room_id : String ,
_user_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < create_typing_event ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-04-12 21:12:50 +02:00
if body . typing {
2020-06-09 15:13:17 +02:00
db . rooms . edus . roomactive_add (
& user_id ,
& body . room_id ,
body . timeout . map ( | d | d . as_millis ( ) as u64 ) . unwrap_or ( 30000 )
+ utils ::millis_since_unix_epoch ( ) ,
& db . globals ,
) ? ;
2020-04-12 21:12:50 +02:00
} else {
2020-06-04 11:17:36 +02:00
db . rooms
. edus
2020-06-09 15:13:17 +02:00
. roomactive_remove ( & user_id , & body . room_id , & db . globals ) ? ;
2020-04-12 21:12:50 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( create_typing_event ::Response . into ( ) )
2020-04-12 21:12:50 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/createRoom " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn create_room_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < create_room ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < create_room ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-04-11 09:30:11 +02:00
2020-06-21 15:58:42 -04:00
let room_id = RoomId ::new ( db . globals . server_name ( ) ) ;
2020-06-09 15:13:17 +02:00
let alias = body
. room_alias_name
. as_ref ( )
. map_or ( Ok ( None ) , | localpart | {
// TODO: Check for invalid characters and maximum length
let alias =
RoomAliasId ::try_from ( format! ( " # {} : {} " , localpart , db . globals . server_name ( ) ) )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Invalid alias. " ) ) ? ;
if db . rooms . id_from_alias ( & alias ) ? . is_some ( ) {
Err ( Error ::BadRequest (
ErrorKind ::RoomInUse ,
" Room alias already exists. " ,
) )
} else {
Ok ( Some ( alias ) )
2020-05-25 23:24:13 +02:00
}
2020-06-09 15:13:17 +02:00
} ) ? ;
2020-05-25 23:24:13 +02:00
2020-07-17 16:00:39 -04:00
let mut content = ruma ::events ::room ::create ::CreateEventContent ::new ( user_id . clone ( ) ) ;
content . federate = body . creation_content . as_ref ( ) . map_or ( true , | c | c . federate ) ;
content . predecessor = body
. creation_content
. as_ref ( )
. and_then ( | c | c . predecessor . clone ( ) ) ;
2020-07-25 14:25:24 -04:00
content . room_version = RoomVersionId ::Version6 ;
2020-07-18 08:21:25 -04:00
2020-05-25 23:24:13 +02:00
// 1. The room create event
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomCreate ,
2020-07-17 16:00:39 -04:00
serde_json ::to_value ( content ) . expect ( " event is valid, we just created it " ) ,
2020-06-09 15:13:17 +02:00
None ,
Some ( " " . to_owned ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-04-11 09:30:11 +02:00
2020-05-25 23:24:13 +02:00
// 2. Let the room creator join
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomMember ,
serde_json ::to_value ( member ::MemberEventContent {
membership : member ::MembershipState ::Join ,
displayname : db . users . displayname ( & user_id ) ? ,
avatar_url : db . users . avatar_url ( & user_id ) ? ,
is_direct : body . is_direct ,
third_party_invite : None ,
} )
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-03 17:25:31 +02:00
2020-05-23 11:20:00 +02:00
// Figure out preset. We need it for power levels and preset specific events
let visibility = body . visibility . unwrap_or ( room ::Visibility ::Private ) ;
let preset = body . preset . unwrap_or_else ( | | match visibility {
room ::Visibility ::Private = > create_room ::RoomPreset ::PrivateChat ,
room ::Visibility ::Public = > create_room ::RoomPreset ::PublicChat ,
} ) ;
2020-05-25 23:24:13 +02:00
// 3. Power levels
2020-05-23 11:20:00 +02:00
let mut users = BTreeMap ::new ( ) ;
users . insert ( user_id . clone ( ) , 100. into ( ) ) ;
for invite_user_id in & body . invite {
users . insert ( invite_user_id . clone ( ) , 100. into ( ) ) ;
}
let power_levels_content = if let Some ( power_levels ) = & body . power_level_content_override {
2020-06-09 15:13:17 +02:00
serde_json ::from_str ( power_levels . json ( ) . get ( ) ) . map_err ( | _ | {
Error ::BadRequest ( ErrorKind ::BadJson , " Invalid power_level_content_override. " )
} ) ?
2020-05-23 11:20:00 +02:00
} else {
2020-06-05 18:19:26 +02:00
serde_json ::to_value ( ruma ::events ::room ::power_levels ::PowerLevelsEventContent {
2020-05-25 23:24:13 +02:00
ban : 50. into ( ) ,
events : BTreeMap ::new ( ) ,
events_default : 0. into ( ) ,
invite : 50. into ( ) ,
kick : 50. into ( ) ,
redact : 50. into ( ) ,
state_default : 50. into ( ) ,
2020-05-23 11:20:00 +02:00
users ,
2020-05-25 23:24:13 +02:00
users_default : 0. into ( ) ,
2020-06-05 18:19:26 +02:00
notifications : ruma ::events ::room ::power_levels ::NotificationPowerLevels {
2020-05-25 23:24:13 +02:00
room : 50. into ( ) ,
} ,
2020-05-23 11:20:00 +02:00
} )
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " )
2020-05-23 11:20:00 +02:00
} ;
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomPowerLevels ,
power_levels_content ,
None ,
Some ( " " . to_owned ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-23 11:20:00 +02:00
2020-05-25 23:24:13 +02:00
// 4. Events set by preset
// 4.1 Join Rules
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomJoinRules ,
match preset {
2020-07-25 14:25:24 -04:00
create_room ::RoomPreset ::PublicChat = > serde_json ::to_value (
join_rules ::JoinRulesEventContent ::new ( join_rules ::JoinRule ::Public ) ,
)
. expect ( " event is valid, we just created it " ) ,
// according to spec "invite" is the default
_ = > serde_json ::to_value ( join_rules ::JoinRulesEventContent ::new (
join_rules ::JoinRule ::Invite ,
) )
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
} ,
None ,
Some ( " " . to_owned ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-23 11:20:00 +02:00
2020-05-25 23:24:13 +02:00
// 4.2 History Visibility
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomHistoryVisibility ,
2020-07-17 16:00:39 -04:00
serde_json ::to_value ( history_visibility ::HistoryVisibilityEventContent ::new (
history_visibility ::HistoryVisibility ::Shared ,
) )
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( " " . to_owned ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-03 17:25:31 +02:00
2020-05-25 23:24:13 +02:00
// 4.3 Guest Access
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomGuestAccess ,
match preset {
2020-07-17 16:00:39 -04:00
create_room ::RoomPreset ::PublicChat = > serde_json ::to_value (
guest_access ::GuestAccessEventContent ::new ( guest_access ::GuestAccess ::Forbidden ) ,
)
. expect ( " event is valid, we just created it " ) ,
_ = > serde_json ::to_value ( guest_access ::GuestAccessEventContent ::new (
guest_access ::GuestAccess ::CanJoin ,
) )
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
} ,
None ,
Some ( " " . to_owned ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-23 11:20:00 +02:00
2020-05-25 23:24:13 +02:00
// 5. Events listed in initial_state
2020-05-23 11:20:00 +02:00
for create_room ::InitialStateEvent {
event_type ,
state_key ,
content ,
} in & body . initial_state
{
2020-07-26 20:41:10 +02:00
// Silently skip encryption events if they are not allowed
if event_type = = & EventType ::RoomEncryption & & db . globals . encryption_disabled ( ) {
2020-07-26 22:45:10 +02:00
continue ;
2020-07-26 20:41:10 +02:00
}
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
event_type . clone ( ) ,
serde_json ::from_str ( content . get ( ) ) . map_err ( | _ | {
Error ::BadRequest ( ErrorKind ::BadJson , " Invalid initial_state content. " )
} ) ? ,
None ,
state_key . clone ( ) ,
None ,
& db . globals ,
) ? ;
2020-05-23 11:20:00 +02:00
}
2020-05-25 23:24:13 +02:00
// 6. Events implied by name and topic
2020-05-03 17:25:31 +02:00
if let Some ( name ) = & body . name {
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomName ,
serde_json ::to_value (
name ::NameEventContent ::new ( name . clone ( ) )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Name is invalid. " ) ) ? ,
2020-05-03 17:25:31 +02:00
)
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( " " . to_owned ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-03 17:25:31 +02:00
}
if let Some ( topic ) = & body . topic {
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomTopic ,
serde_json ::to_value ( topic ::TopicEventContent {
topic : topic . clone ( ) ,
} )
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( " " . to_owned ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-04-11 09:30:11 +02:00
}
2020-05-25 23:24:13 +02:00
// 7. Events implied by invite (and TODO: invite_3pid)
2020-04-14 13:54:32 +02:00
for user in & body . invite {
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomMember ,
serde_json ::to_value ( member ::MemberEventContent {
membership : member ::MembershipState ::Invite ,
displayname : db . users . displayname ( & user ) ? ,
avatar_url : db . users . avatar_url ( & user ) ? ,
is_direct : body . is_direct ,
third_party_invite : None ,
} )
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( user . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-04-14 13:54:32 +02:00
}
2020-05-25 23:24:13 +02:00
// Homeserver specific stuff
if let Some ( alias ) = alias {
2020-06-09 15:13:17 +02:00
db . rooms . set_alias ( & alias , Some ( & room_id ) , & db . globals ) ? ;
2020-05-25 23:24:13 +02:00
}
if let Some ( room ::Visibility ::Public ) = body . visibility {
2020-06-09 15:13:17 +02:00
db . rooms . set_public ( & room_id , true ) ? ;
2020-05-25 23:24:13 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( create_room ::Response { room_id } . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-07-25 18:35:22 +02:00
#[ get( " /_matrix/client/r0/joined_rooms " , data = " <body> " ) ]
pub fn joined_rooms_route (
db : State < '_ , Database > ,
body : Ruma < joined_rooms ::Request > ,
) -> ConduitResult < joined_rooms ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
Ok ( joined_rooms ::Response {
joined_rooms : db
. rooms
. rooms_joined ( & user_id )
. filter_map ( | r | r . ok ( ) )
. collect ( ) ,
}
. into ( ) )
}
2020-06-22 07:26:09 -04:00
#[ put(
" /_matrix/client/r0/rooms/<_room_id>/redact/<_event_id>/<_txn_id> " ,
data = " <body> "
) ]
2020-05-26 10:27:51 +02:00
pub fn redact_event_route (
db : State < '_ , Database > ,
body : Ruma < redact_event ::Request > ,
_room_id : String ,
_event_id : String ,
_txn_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < redact_event ::Response > {
2020-05-26 10:27:51 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
let event_id = db . rooms . append_pdu (
2020-05-26 10:27:51 +02:00
body . room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomRedaction ,
serde_json ::to_value ( redaction ::RedactionEventContent {
reason : body . reason . clone ( ) ,
2020-05-25 23:24:13 +02:00
} )
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
2020-05-26 10:27:51 +02:00
None ,
None ,
Some ( body . event_id . clone ( ) ) ,
& db . globals ,
2020-06-09 15:13:17 +02:00
) ? ;
Ok ( redact_event ::Response { event_id } . into ( ) )
2020-05-26 10:27:51 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put( " /_matrix/client/r0/directory/room/<_room_alias> " , data = " <body> " ) ]
2020-05-25 23:24:13 +02:00
pub fn create_alias_route (
db : State < '_ , Database > ,
body : Ruma < create_alias ::Request > ,
_room_alias : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < create_alias ::Response > {
if db . rooms . id_from_alias ( & body . room_alias ) ? . is_some ( ) {
return Err ( Error ::Conflict ( " Alias already exists. " ) ) ;
2020-05-25 23:24:13 +02:00
}
db . rooms
2020-06-09 15:13:17 +02:00
. set_alias ( & body . room_alias , Some ( & body . room_id ) , & db . globals ) ? ;
2020-05-25 23:24:13 +02:00
2020-06-09 15:13:17 +02:00
Ok ( create_alias ::Response . into ( ) )
2020-05-25 23:24:13 +02:00
}
2020-06-22 07:26:09 -04:00
#[ delete( " /_matrix/client/r0/directory/room/<_room_alias> " , data = " <body> " ) ]
2020-05-25 23:24:13 +02:00
pub fn delete_alias_route (
db : State < '_ , Database > ,
body : Ruma < delete_alias ::Request > ,
_room_alias : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < delete_alias ::Response > {
db . rooms . set_alias ( & body . room_alias , None , & db . globals ) ? ;
2020-05-25 23:24:13 +02:00
2020-06-09 15:13:17 +02:00
Ok ( delete_alias ::Response . into ( ) )
2020-05-25 23:24:13 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/directory/room/<_room_alias> " , data = " <body> " ) ]
2020-04-26 22:39:15 +02:00
pub fn get_alias_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-26 22:39:15 +02:00
body : Ruma < get_alias ::Request > ,
_room_alias : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_alias ::Response > {
if body . room_alias . server_name ( ) ! = db . globals . server_name ( ) {
2020-04-26 22:39:15 +02:00
todo! ( " ask remote server " ) ;
2020-04-11 09:30:11 +02:00
}
2020-06-09 15:13:17 +02:00
let room_id = db
. rooms
. id_from_alias ( & body . room_alias ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Room with alias not found. " ,
) ) ? ;
Ok ( get_alias ::Response {
room_id ,
2020-06-21 15:58:42 -04:00
servers : vec ! [ db . globals . server_name ( ) . to_string ( ) ] ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/join " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn join_room_by_id_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < join_room_by_id ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < join_room_by_id ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-03 17:25:31 +02:00
2020-05-24 18:25:52 +02:00
// TODO: Ask a remote server if we don't have this room
2020-06-19 12:19:07 +02:00
let event = member ::MemberEventContent {
membership : member ::MembershipState ::Join ,
displayname : db . users . displayname ( & user_id ) ? ,
avatar_url : db . users . avatar_url ( & user_id ) ? ,
is_direct : None ,
third_party_invite : None ,
} ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
body . room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomMember ,
serde_json ::to_value ( event ) . expect ( " event is valid, we just created it " ) ,
None ,
Some ( user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
Ok ( join_room_by_id ::Response {
2020-05-24 18:25:52 +02:00
room_id : body . room_id . clone ( ) ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/join/<_room_id_or_alias> " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn join_room_by_id_or_alias_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < join_room_by_id_or_alias ::Request > ,
_room_id_or_alias : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < join_room_by_id_or_alias ::Response > {
let room_id = RoomId ::try_from ( body . room_id_or_alias . clone ( ) ) . or_else ( | alias | {
Ok ::< _ , Error > ( db . rooms . id_from_alias ( & alias ) ? . ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Room not found (TODO: Federation). " ,
) ) ? )
} ) ? ;
2020-04-11 09:30:11 +02:00
2020-05-23 11:20:00 +02:00
let body = Ruma {
user_id : body . user_id . clone ( ) ,
device_id : body . device_id . clone ( ) ,
json_body : None ,
body : join_room_by_id ::Request {
room_id ,
third_party_signed : body . third_party_signed . clone ( ) ,
} ,
} ;
2020-06-09 15:13:17 +02:00
Ok ( join_room_by_id_or_alias ::Response {
room_id : join_room_by_id_route ( db , body , " " . to_owned ( ) ) ? . 0. room_id ,
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/leave " , data = " <body> " ) ]
2020-04-19 14:14:47 +02:00
pub fn leave_room_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-19 14:14:47 +02:00
body : Ruma < leave_room ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < leave_room ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
2020-07-26 15:41:28 +02:00
let mut event = serde_json ::from_value ::< Raw < member ::MemberEventContent > > (
2020-06-12 13:18:25 +02:00
db . rooms
. room_state_get ( & body . room_id , & EventType ::RoomMember , & user_id . to_string ( ) ) ?
2020-06-09 15:13:17 +02:00
. ok_or ( Error ::BadRequest (
ErrorKind ::BadState ,
" Cannot leave a room you are not a member of. " ,
) ) ?
. content
. clone ( ) ,
)
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ? ;
2020-06-04 15:02:27 +02:00
2020-06-09 15:13:17 +02:00
event . membership = member ::MembershipState ::Leave ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
body . room_id . clone ( ) ,
user_id . clone ( ) ,
EventType ::RoomMember ,
serde_json ::to_value ( event ) . expect ( " event is valid, we just created it " ) ,
None ,
Some ( user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
Ok ( leave_room ::Response . into ( ) )
2020-04-19 14:14:47 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/kick " , data = " <body> " ) ]
2020-06-04 15:02:27 +02:00
pub fn kick_user_route (
db : State < '_ , Database > ,
body : Ruma < kick_user ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < kick_user ::Response > {
2020-06-04 15:02:27 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-07-26 15:41:28 +02:00
let mut event = serde_json ::from_value ::< Raw < ruma ::events ::room ::member ::MemberEventContent > > (
db . rooms
. room_state_get ( & body . room_id , & EventType ::RoomMember , & user_id . to_string ( ) ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::BadState ,
" Cannot kick member that's not in the room. " ,
) ) ?
. content
. clone ( ) ,
)
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ?
. deserialize ( )
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ? ;
2020-06-04 15:02:27 +02:00
2020-06-05 18:19:26 +02:00
event . membership = ruma ::events ::room ::member ::MembershipState ::Leave ;
2020-06-04 15:02:27 +02:00
// TODO: reason
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
body . room_id . clone ( ) ,
user_id . clone ( ) , // Sender
EventType ::RoomMember ,
serde_json ::to_value ( event ) . expect ( " event is valid, we just created it " ) ,
None ,
Some ( body . body . user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-06-04 15:02:27 +02:00
2020-06-09 15:13:17 +02:00
Ok ( kick_user ::Response . into ( ) )
2020-06-04 15:02:27 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/ban " , data = " <body> " ) ]
2020-06-04 15:02:27 +02:00
pub fn ban_user_route (
db : State < '_ , Database > ,
body : Ruma < ban_user ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < ban_user ::Response > {
2020-06-04 15:02:27 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
// TODO: reason
2020-06-12 13:18:25 +02:00
let event = db
. rooms
. room_state_get ( & body . room_id , & EventType ::RoomMember , & user_id . to_string ( ) ) ?
2020-06-09 15:13:17 +02:00
. map_or (
Ok ::< _ , Error > ( member ::MemberEventContent {
membership : member ::MembershipState ::Ban ,
displayname : db . users . displayname ( & user_id ) ? ,
avatar_url : db . users . avatar_url ( & user_id ) ? ,
is_direct : None ,
third_party_invite : None ,
} ) ,
| event | {
2020-07-26 15:41:28 +02:00
let mut event = serde_json ::from_value ::< Raw < member ::MemberEventContent > > (
2020-06-09 15:13:17 +02:00
event . content . clone ( ) ,
)
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ? ;
2020-06-09 15:13:17 +02:00
event . membership = ruma ::events ::room ::member ::MembershipState ::Ban ;
Ok ( event )
} ,
) ? ;
db . rooms . append_pdu (
body . room_id . clone ( ) ,
user_id . clone ( ) , // Sender
EventType ::RoomMember ,
serde_json ::to_value ( event ) . expect ( " event is valid, we just created it " ) ,
None ,
Some ( body . body . user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-06-04 15:02:27 +02:00
2020-06-09 15:13:17 +02:00
Ok ( ban_user ::Response . into ( ) )
2020-06-04 15:02:27 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/unban " , data = " <body> " ) ]
2020-06-04 15:02:27 +02:00
pub fn unban_user_route (
db : State < '_ , Database > ,
body : Ruma < unban_user ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < unban_user ::Response > {
2020-06-04 15:02:27 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-07-26 15:41:28 +02:00
let mut event = serde_json ::from_value ::< Raw < ruma ::events ::room ::member ::MemberEventContent > > (
db . rooms
. room_state_get ( & body . room_id , & EventType ::RoomMember , & user_id . to_string ( ) ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::BadState ,
" Cannot unban a user who is not banned. " ,
) ) ?
. content
. clone ( ) ,
)
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ?
. deserialize ( )
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ? ;
2020-06-04 15:02:27 +02:00
2020-06-05 18:19:26 +02:00
event . membership = ruma ::events ::room ::member ::MembershipState ::Leave ;
2020-06-04 15:02:27 +02:00
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
body . room_id . clone ( ) ,
user_id . clone ( ) , // Sender
EventType ::RoomMember ,
serde_json ::to_value ( event ) . expect ( " event is valid, we just created it " ) ,
None ,
Some ( body . body . user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-06-04 15:02:27 +02:00
2020-06-09 15:13:17 +02:00
Ok ( unban_user ::Response . into ( ) )
2020-06-04 15:02:27 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/forget " , data = " <body> " ) ]
2020-04-28 19:56:34 +02:00
pub fn forget_room_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-28 19:56:34 +02:00
body : Ruma < forget_room ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < forget_room ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
db . rooms . forget ( & body . room_id , & user_id ) ? ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
Ok ( forget_room ::Response . into ( ) )
2020-04-28 19:56:34 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/rooms/<_room_id>/invite " , data = " <body> " ) ]
2020-04-14 13:54:32 +02:00
pub fn invite_user_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-14 13:54:32 +02:00
body : Ruma < invite_user ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < invite_user ::Response > {
2020-04-14 13:54:32 +02:00
if let invite_user ::InvitationRecipient ::UserId { user_id } = & body . recipient {
2020-06-09 15:13:17 +02:00
db . rooms . append_pdu (
body . room_id . clone ( ) ,
body . user_id . clone ( ) . expect ( " user is authenticated " ) ,
EventType ::RoomMember ,
serde_json ::to_value ( member ::MemberEventContent {
membership : member ::MembershipState ::Invite ,
displayname : db . users . displayname ( & user_id ) ? ,
avatar_url : db . users . avatar_url ( & user_id ) ? ,
is_direct : None ,
third_party_invite : None ,
} )
. expect ( " event is valid, we just created it " ) ,
None ,
Some ( user_id . to_string ( ) ) ,
None ,
& db . globals ,
) ? ;
2020-05-24 18:25:52 +02:00
2020-06-09 15:13:17 +02:00
Ok ( invite_user ::Response . into ( ) )
2020-04-14 13:54:32 +02:00
} else {
2020-06-09 15:13:17 +02:00
Err ( Error ::BadRequest ( ErrorKind ::NotFound , " User not found. " ) )
2020-04-14 13:54:32 +02:00
}
}
2020-06-22 07:26:09 -04:00
#[ put( " /_matrix/client/r0/directory/list/room/<_room_id> " , data = " <body> " ) ]
2020-05-25 23:24:13 +02:00
pub async fn set_room_visibility_route (
db : State < '_ , Database > ,
body : Ruma < set_room_visibility ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < set_room_visibility ::Response > {
2020-05-25 23:24:13 +02:00
match body . visibility {
2020-06-09 15:13:17 +02:00
room ::Visibility ::Public = > db . rooms . set_public ( & body . room_id , true ) ? ,
room ::Visibility ::Private = > db . rooms . set_public ( & body . room_id , false ) ? ,
2020-05-25 23:24:13 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( set_room_visibility ::Response . into ( ) )
2020-05-25 23:24:13 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/directory/list/room/<_room_id> " , data = " <body> " ) ]
2020-05-25 23:24:13 +02:00
pub async fn get_room_visibility_route (
db : State < '_ , Database > ,
body : Ruma < get_room_visibility ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_room_visibility ::Response > {
Ok ( get_room_visibility ::Response {
visibility : if db . rooms . is_public_room ( & body . room_id ) ? {
2020-05-25 23:24:13 +02:00
room ::Visibility ::Public
} else {
room ::Visibility ::Private
} ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-05-25 23:24:13 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/publicRooms " , data = " <body> " ) ]
2020-05-19 16:28:03 +02:00
pub async fn get_public_rooms_route (
db : State < '_ , Database > ,
2020-05-23 11:20:00 +02:00
body : Ruma < get_public_rooms ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_public_rooms ::Response > {
2020-05-23 11:20:00 +02:00
let Ruma {
body :
get_public_rooms ::Request {
limit ,
server ,
since ,
} ,
user_id ,
device_id ,
json_body ,
} = body ;
2020-06-09 15:13:17 +02:00
let get_public_rooms_filtered ::Response {
chunk ,
prev_batch ,
next_batch ,
total_room_count_estimate ,
} = get_public_rooms_filtered_route (
2020-05-23 11:20:00 +02:00
db ,
Ruma {
body : get_public_rooms_filtered ::Request {
filter : None ,
limit ,
room_network : get_public_rooms_filtered ::RoomNetwork ::Matrix ,
server ,
since ,
} ,
user_id ,
device_id ,
json_body ,
} ,
)
2020-06-09 15:13:17 +02:00
. await ?
. 0 ;
Ok ( get_public_rooms ::Response {
chunk ,
prev_batch ,
next_batch ,
total_room_count_estimate ,
}
. into ( ) )
2020-05-19 16:28:03 +02:00
}
2020-07-22 21:57:14 +02:00
#[ post( " /_matrix/client/r0/publicRooms " , data = " <_body> " ) ]
2020-04-22 11:53:06 +02:00
pub async fn get_public_rooms_filtered_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-07-22 21:57:14 +02:00
_body : Ruma < get_public_rooms_filtered ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_public_rooms_filtered ::Response > {
2020-05-03 17:25:31 +02:00
let mut chunk = db
. rooms
2020-05-25 23:24:13 +02:00
. public_rooms ( )
2020-04-14 13:54:32 +02:00
. map ( | room_id | {
2020-06-09 15:13:17 +02:00
let room_id = room_id ? ;
2020-05-25 23:24:13 +02:00
2020-06-12 13:18:25 +02:00
// TODO: Do not load full state?
let state = db . rooms . room_state_full ( & room_id ) ? ;
2020-05-23 11:20:00 +02:00
2020-06-09 15:13:17 +02:00
let chunk = directory ::PublicRoomsChunk {
2020-04-19 14:14:47 +02:00
aliases : Vec ::new ( ) ,
2020-06-09 15:13:17 +02:00
canonical_alias : state . get ( & ( EventType ::RoomCanonicalAlias , " " . to_owned ( ) ) ) . map_or ( Ok ::< _ , Error > ( None ) , | s | {
Ok ( serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::canonical_alias ::CanonicalAliasEventContent > ,
2020-05-25 20:10:46 +02:00
> ( s . content . clone ( ) )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid canonical alias event in database. " ) ) ?
2020-05-25 20:10:46 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid canonical alias event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. alias )
} ) ? ,
name : state . get ( & ( EventType ::RoomName , " " . to_owned ( ) ) ) . map_or ( Ok ::< _ , Error > ( None ) , | s | {
2020-07-26 15:41:28 +02:00
Ok ( serde_json ::from_value ::< Raw < ruma ::events ::room ::name ::NameEventContent > > (
2020-05-23 11:20:00 +02:00
s . content . clone ( ) ,
)
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room name event in database. " ) ) ?
2020-05-23 11:20:00 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room name event in database. " ) ) ?
2020-05-23 11:20:00 +02:00
. name ( )
2020-06-09 15:13:17 +02:00
. map ( | n | n . to_owned ( ) ) )
} ) ? ,
2020-05-03 17:25:31 +02:00
num_joined_members : ( db . rooms . room_members ( & room_id ) . count ( ) as u32 ) . into ( ) ,
2020-04-14 13:54:32 +02:00
room_id ,
2020-06-09 15:13:17 +02:00
topic : state . get ( & ( EventType ::RoomTopic , " " . to_owned ( ) ) ) . map_or ( Ok ::< _ , Error > ( None ) , | s | {
Ok ( Some ( serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::topic ::TopicEventContent > ,
2020-05-23 11:20:00 +02:00
> ( s . content . clone ( ) )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room topic event in database. " ) ) ?
2020-05-23 11:20:00 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room topic event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. topic ) )
} ) ? ,
world_readable : state . get ( & ( EventType ::RoomHistoryVisibility , " " . to_owned ( ) ) ) . map_or ( Ok ::< _ , Error > ( false ) , | s | {
Ok ( serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::history_visibility ::HistoryVisibilityEventContent > ,
2020-05-25 20:10:46 +02:00
> ( s . content . clone ( ) )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room history visibility event in database. " ) ) ?
2020-05-25 20:10:46 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room history visibility event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. history_visibility = = history_visibility ::HistoryVisibility ::WorldReadable )
} ) ? ,
guest_can_join : state . get ( & ( EventType ::RoomGuestAccess , " " . to_owned ( ) ) ) . map_or ( Ok ::< _ , Error > ( false ) , | s | {
Ok ( serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::guest_access ::GuestAccessEventContent > ,
2020-05-25 20:10:46 +02:00
> ( s . content . clone ( ) )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room guest access event in database. " ) ) ?
2020-05-25 20:10:46 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room guest access event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. guest_access = = guest_access ::GuestAccess ::CanJoin )
} ) ? ,
avatar_url : state . get ( & ( EventType ::RoomAvatar , " " . to_owned ( ) ) ) . map_or ( Ok ::< _ , Error > ( None ) , | s | {
Ok ( Some ( serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::avatar ::AvatarEventContent > ,
2020-05-25 20:10:46 +02:00
> ( s . content . clone ( ) )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room avatar event in database. " ) ) ?
2020-05-25 20:10:46 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid room avatar event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. url ) )
} ) ? ,
} ;
Ok ::< _ , Error > ( chunk )
2020-04-11 09:30:11 +02:00
} )
2020-06-09 15:13:17 +02:00
. filter_map ( | r | r . ok ( ) ) // Filter out buggy rooms
2020-04-11 09:30:11 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-04-25 11:47:32 +02:00
chunk . sort_by ( | l , r | r . num_joined_members . cmp ( & l . num_joined_members ) ) ;
2020-05-14 09:10:15 +02:00
/*
2020-04-22 11:53:06 +02:00
chunk . extend_from_slice (
& server_server ::send_request (
2020-05-03 17:25:31 +02:00
& db ,
2020-04-26 22:39:15 +02:00
" privacytools.io " . to_owned ( ) ,
2020-06-05 18:19:26 +02:00
ruma ::api ::federation ::v1 ::get_public_rooms ::Request {
2020-04-26 22:39:15 +02:00
limit : Some ( 20_ u32 . into ( ) ) ,
2020-04-22 11:53:06 +02:00
since : None ,
2020-06-05 18:19:26 +02:00
room_network : ruma ::api ::federation ::v1 ::get_public_rooms ::RoomNetwork ::Matrix ,
2020-04-22 11:53:06 +02:00
} ,
)
. await
2020-06-09 15:13:17 +02:00
?
2020-04-22 11:53:06 +02:00
. chunk
. into_iter ( )
2020-06-09 15:13:17 +02:00
. map ( | c | serde_json ::from_str ( & serde_json ::to_string ( & c ) ? ) ? )
2020-04-22 11:53:06 +02:00
. collect ::< Vec < _ > > ( ) ,
) ;
2020-05-14 09:10:15 +02:00
* /
2020-04-22 11:53:06 +02:00
2020-04-11 09:30:11 +02:00
let total_room_count_estimate = ( chunk . len ( ) as u32 ) . into ( ) ;
2020-06-09 15:13:17 +02:00
Ok ( get_public_rooms_filtered ::Response {
2020-04-11 09:30:11 +02:00
chunk ,
prev_batch : None ,
next_batch : None ,
total_room_count_estimate : Some ( total_room_count_estimate ) ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/user_directory/search " , data = " <body> " ) ]
2020-04-14 13:54:32 +02:00
pub fn search_users_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-14 13:54:32 +02:00
body : Ruma < search_users ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < search_users ::Response > {
Ok ( search_users ::Response {
2020-05-03 17:25:31 +02:00
results : db
. users
. iter ( )
2020-06-09 15:13:17 +02:00
. filter_map ( | user_id | {
// Filter out buggy users (they should not exist, but you never know...)
let user_id = user_id . ok ( ) ? ;
2020-07-05 07:48:19 +02:00
if db . users . is_deactivated ( & user_id ) . ok ( ) ? {
return None ;
}
let user = search_users ::User {
2020-06-09 15:13:17 +02:00
user_id : user_id . clone ( ) ,
display_name : db . users . displayname ( & user_id ) . ok ( ) ? ,
avatar_url : db . users . avatar_url ( & user_id ) . ok ( ) ? ,
2020-07-05 07:48:19 +02:00
} ;
if ! user . user_id . to_string ( ) . contains ( & body . search_term )
& & user
2020-05-18 10:29:45 +02:00
. display_name
. as_ref ( )
. filter ( | name | name . contains ( & body . search_term ) )
2020-07-05 07:48:19 +02:00
. is_none ( )
{
return None ;
}
Some ( user )
2020-04-14 13:54:32 +02:00
} )
. collect ( ) ,
limited : false ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-14 13:54:32 +02:00
}
2020-06-14 08:57:47 +02:00
#[ get( " /_matrix/client/r0/rooms/<_room_id>/members " , data = " <body> " ) ]
2020-06-12 13:18:25 +02:00
pub fn get_member_events_route (
db : State < '_ , Database > ,
2020-06-14 08:57:47 +02:00
body : Ruma < get_member_events ::Request > ,
2020-06-12 13:18:25 +02:00
_room_id : String ,
) -> ConduitResult < get_member_events ::Response > {
2020-06-14 08:57:47 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-12 13:18:25 +02:00
2020-06-14 08:57:47 +02:00
if ! db . rooms . is_joined ( user_id , & body . room_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" You don't have permission to view this room. " ,
) ) ;
}
2020-06-12 13:18:25 +02:00
Ok ( get_member_events ::Response {
2020-06-14 08:57:47 +02:00
chunk : db
2020-06-12 13:18:25 +02:00
. rooms
. room_state_type ( & body . room_id , & EventType ::RoomMember ) ?
. values ( )
. map ( | pdu | pdu . to_member_event ( ) )
2020-06-14 08:57:47 +02:00
. collect ( ) ,
2020-06-12 13:18:25 +02:00
}
. into ( ) )
2020-04-19 14:14:47 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/thirdparty/protocols " ) ]
2020-06-09 15:13:17 +02:00
pub fn get_protocols_route ( ) -> ConduitResult < get_protocols ::Response > {
2020-05-17 19:56:40 +02:00
warn! ( " TODO: get_protocols_route " ) ;
2020-06-09 15:13:17 +02:00
Ok ( get_protocols ::Response {
2020-04-19 14:14:47 +02:00
protocols : BTreeMap ::new ( ) ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-07-11 14:08:37 +02:00
#[ get(
" /_matrix/client/r0/rooms/<_room_id>/event/<_event_id> " ,
data = " <body> "
) ]
pub fn get_room_event_route (
db : State < '_ , Database > ,
body : Ruma < get_room_event ::Request > ,
_room_id : String ,
_event_id : String ,
) -> ConduitResult < get_room_event ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
if ! db . rooms . is_joined ( user_id , & body . room_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" You don't have permission to view this room. " ,
) ) ;
}
Ok ( get_room_event ::Response {
event : db
. rooms
. get_pdu ( & body . event_id ) ?
. ok_or ( Error ::BadRequest ( ErrorKind ::NotFound , " Event not found. " ) ) ?
. to_room_event ( ) ,
}
. into ( ) )
}
2020-04-11 09:30:11 +02:00
#[ put(
" /_matrix/client/r0/rooms/<_room_id>/send/<_event_type>/<_txn_id> " ,
data = " <body> "
) ]
pub fn create_message_event_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-05-18 09:22:07 +02:00
body : Ruma < create_message_event ::Request > ,
2020-04-11 09:30:11 +02:00
_room_id : String ,
_event_type : String ,
_txn_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < create_message_event ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-01 20:26:57 +02:00
2020-04-11 09:30:11 +02:00
let mut unsigned = serde_json ::Map ::new ( ) ;
unsigned . insert ( " transaction_id " . to_owned ( ) , body . txn_id . clone ( ) . into ( ) ) ;
2020-06-09 15:13:17 +02:00
let event_id = db . rooms . append_pdu (
2020-05-24 18:25:52 +02:00
body . room_id . clone ( ) ,
user_id . clone ( ) ,
body . event_type . clone ( ) ,
2020-06-09 15:13:17 +02:00
serde_json ::from_str (
body . json_body
. ok_or ( Error ::BadRequest ( ErrorKind ::BadJson , " Invalid JSON body. " ) ) ?
. get ( ) ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::BadJson , " Invalid JSON body. " ) ) ? ,
2020-05-24 18:25:52 +02:00
Some ( unsigned ) ,
None ,
2020-05-26 10:27:51 +02:00
None ,
2020-05-24 18:25:52 +02:00
& db . globals ,
2020-06-09 15:13:17 +02:00
) ? ;
Ok ( create_message_event ::Response { event_id } . into ( ) )
2020-04-11 09:30:11 +02:00
}
#[ put(
2020-06-22 07:26:09 -04:00
" /_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key> " ,
2020-04-11 09:30:11 +02:00
data = " <body> "
) ]
pub fn create_state_event_for_key_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-05-18 09:22:07 +02:00
body : Ruma < create_state_event_for_key ::Request > ,
2020-04-11 09:30:11 +02:00
_room_id : String ,
_event_type : String ,
_state_key : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < create_state_event_for_key ::Response > {
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-01 20:26:57 +02:00
2020-06-09 15:13:17 +02:00
let content = serde_json ::from_str ::< serde_json ::Value > (
body . json_body
. as_ref ( )
. ok_or ( Error ::BadRequest ( ErrorKind ::BadJson , " Invalid JSON body. " ) ) ?
. get ( ) ,
)
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::BadJson , " Invalid JSON body. " ) ) ? ;
2020-05-25 23:24:13 +02:00
if body . event_type = = EventType ::RoomCanonicalAlias {
let canonical_alias = serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < canonical_alias ::CanonicalAliasEventContent > ,
2020-05-25 23:24:13 +02:00
> ( content . clone ( ) )
2020-06-09 15:13:17 +02:00
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Invalid canonical alias. " ) ) ?
2020-05-25 23:24:13 +02:00
. deserialize ( )
2020-06-09 15:13:17 +02:00
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Invalid canonical alias. " ) ) ? ;
2020-05-25 23:24:13 +02:00
let mut aliases = canonical_alias . alt_aliases ;
if let Some ( alias ) = canonical_alias . alias {
aliases . push ( alias ) ;
}
for alias in aliases {
if alias . server_name ( ) ! = db . globals . server_name ( )
| | db
. rooms
2020-06-09 15:13:17 +02:00
. id_from_alias ( & alias ) ?
2020-05-25 23:24:13 +02:00
. filter ( | room | room = = & body . room_id ) // Make sure it's the right room
. is_none ( )
{
2020-06-09 15:13:17 +02:00
return Err ( Error ::BadRequest ( ErrorKind ::Forbidden , " You are only allowed to send canonical_alias events when it's aliases already exists " ) ) ;
2020-05-25 23:24:13 +02:00
}
}
}
2020-06-09 15:13:17 +02:00
let event_id = db . rooms . append_pdu (
2020-05-24 18:25:52 +02:00
body . room_id . clone ( ) ,
user_id . clone ( ) ,
body . event_type . clone ( ) ,
2020-05-25 23:24:13 +02:00
content ,
2020-05-24 18:25:52 +02:00
None ,
Some ( body . state_key . clone ( ) ) ,
2020-05-26 10:27:51 +02:00
None ,
2020-05-24 18:25:52 +02:00
& db . globals ,
2020-06-09 15:13:17 +02:00
) ? ;
Ok ( create_state_event_for_key ::Response { event_id } . into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put(
" /_matrix/client/r0/rooms/<_room_id>/state/<_event_type> " ,
data = " <body> "
) ]
2020-04-11 09:30:11 +02:00
pub fn create_state_event_for_empty_key_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-05-18 09:22:07 +02:00
body : Ruma < create_state_event_for_empty_key ::Request > ,
2020-04-11 09:30:11 +02:00
_room_id : String ,
_event_type : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < create_state_event_for_empty_key ::Response > {
2020-05-25 23:24:13 +02:00
// This just calls create_state_event_for_key_route
let Ruma {
body :
create_state_event_for_empty_key ::Request {
room_id ,
event_type ,
data ,
} ,
user_id ,
device_id ,
json_body ,
} = body ;
2020-05-01 20:26:57 +02:00
2020-06-09 15:13:17 +02:00
Ok ( create_state_event_for_empty_key ::Response {
event_id : create_state_event_for_key_route (
db ,
Ruma {
body : create_state_event_for_key ::Request {
room_id ,
event_type ,
data ,
state_key : " " . to_owned ( ) ,
} ,
user_id ,
device_id ,
json_body ,
2020-05-25 23:24:13 +02:00
} ,
2020-06-09 15:13:17 +02:00
_room_id ,
_event_type ,
" " . to_owned ( ) ,
) ?
. 0
. event_id ,
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/rooms/<_room_id>/state " , data = " <body> " ) ]
2020-05-18 09:22:07 +02:00
pub fn get_state_events_route (
db : State < '_ , Database > ,
body : Ruma < get_state_events ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_state_events ::Response > {
2020-05-24 18:25:52 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
if ! db . rooms . is_joined ( user_id , & body . room_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" You don't have permission to view the room state. " ,
) ) ;
2020-05-24 18:25:52 +02:00
}
2020-06-03 16:24:00 +02:00
2020-06-09 15:13:17 +02:00
Ok ( get_state_events ::Response {
2020-06-03 16:24:00 +02:00
room_state : db
. rooms
2020-06-12 13:18:25 +02:00
. room_state_full ( & body . room_id ) ?
2020-06-03 16:24:00 +02:00
. values ( )
. map ( | pdu | pdu . to_state_event ( ) )
. collect ( ) ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-05-18 09:22:07 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get(
" /_matrix/client/r0/rooms/<_room_id>/state/<_event_type>/<_state_key> " ,
data = " <body> "
) ]
2020-05-18 09:22:07 +02:00
pub fn get_state_events_for_key_route (
db : State < '_ , Database > ,
body : Ruma < get_state_events_for_key ::Request > ,
_room_id : String ,
_event_type : String ,
_state_key : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_state_events_for_key ::Response > {
2020-05-24 18:25:52 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
if ! db . rooms . is_joined ( user_id , & body . room_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" You don't have permission to view the room state. " ,
) ) ;
2020-06-03 16:24:00 +02:00
}
2020-06-12 13:18:25 +02:00
let event = db
. rooms
. room_state_get ( & body . room_id , & body . event_type , & body . state_key ) ?
2020-06-09 15:13:17 +02:00
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" State event not found. " ,
) ) ? ;
Ok ( get_state_events_for_key ::Response {
content : serde_json ::value ::to_raw_value ( & event . content )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid event content in database " ) ) ? ,
2020-05-18 09:22:07 +02:00
}
2020-06-09 15:13:17 +02:00
. into ( ) )
2020-05-18 09:22:07 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get(
" /_matrix/client/r0/rooms/<_room_id>/state/<_event_type> " ,
data = " <body> "
) ]
2020-05-18 09:22:07 +02:00
pub fn get_state_events_for_empty_key_route (
db : State < '_ , Database > ,
body : Ruma < get_state_events_for_empty_key ::Request > ,
_room_id : String ,
_event_type : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_state_events_for_empty_key ::Response > {
2020-05-24 18:25:52 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
if ! db . rooms . is_joined ( user_id , & body . room_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" You don't have permission to view the room state. " ,
) ) ;
2020-06-03 16:24:00 +02:00
}
2020-06-12 13:18:25 +02:00
let event = db
. rooms
. room_state_get ( & body . room_id , & body . event_type , " " ) ?
2020-06-09 15:13:17 +02:00
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" State event not found. " ,
) ) ? ;
Ok ( get_state_events_for_empty_key ::Response {
2020-06-12 13:18:25 +02:00
content : serde_json ::value ::to_raw_value ( & event )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid event content in database " ) ) ? ,
2020-05-18 09:22:07 +02:00
}
2020-06-09 15:13:17 +02:00
. into ( ) )
2020-05-18 09:22:07 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/sync " , data = " <body> " ) ]
2020-04-11 09:30:11 +02:00
pub fn sync_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-04-11 09:30:11 +02:00
body : Ruma < sync_events ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < sync_events ::Response > {
2020-05-17 21:28:36 +02:00
std ::thread ::sleep ( Duration ::from_millis ( 1000 ) ) ;
2020-05-11 12:33:25 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-05-17 19:56:40 +02:00
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
let next_batch = db . globals . current_count ( ) ? . to_string ( ) ;
2020-04-11 09:30:11 +02:00
2020-04-19 14:14:47 +02:00
let mut joined_rooms = BTreeMap ::new ( ) ;
2020-04-11 20:03:22 +02:00
let since = body
. since
. clone ( )
. and_then ( | string | string . parse ( ) . ok ( ) )
. unwrap_or ( 0 ) ;
2020-04-29 12:18:45 +02:00
2020-05-03 17:25:31 +02:00
for room_id in db . rooms . rooms_joined ( & user_id ) {
2020-06-09 15:13:17 +02:00
let room_id = room_id ? ;
2020-05-03 17:25:31 +02:00
let mut pdus = db
. rooms
2020-06-16 12:11:38 +02:00
. pdus_since ( & user_id , & room_id , since ) ?
2020-06-09 15:13:17 +02:00
. filter_map ( | r | r . ok ( ) ) // Filter out buggy events
2020-05-03 17:25:31 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-04-29 12:18:45 +02:00
let mut send_member_count = false ;
2020-06-06 17:23:14 +02:00
let mut joined_since_last_sync = false ;
2020-06-04 18:27:57 +02:00
let mut send_notification_counts = false ;
2020-04-29 12:18:45 +02:00
for pdu in & pdus {
2020-06-04 18:27:57 +02:00
send_notification_counts = true ;
2020-04-29 12:18:45 +02:00
if pdu . kind = = EventType ::RoomMember {
send_member_count = true ;
2020-06-06 17:23:14 +02:00
if ! joined_since_last_sync & & pdu . state_key = = Some ( user_id . to_string ( ) ) {
2020-05-23 11:20:00 +02:00
let content = serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::member ::MemberEventContent > ,
2020-05-23 11:20:00 +02:00
> ( pdu . content . clone ( ) )
2020-07-26 15:41:28 +02:00
. expect ( " Raw::from_value always works " )
2020-05-23 11:20:00 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid PDU in database. " ) ) ? ;
2020-06-05 18:19:26 +02:00
if content . membership = = ruma ::events ::room ::member ::MembershipState ::Join {
2020-06-06 17:23:14 +02:00
joined_since_last_sync = true ;
// Both send_member_count and joined_since_last_sync are set. There's nothing more
2020-05-23 11:20:00 +02:00
// to do
break ;
}
}
2020-04-29 12:18:45 +02:00
}
}
2020-06-12 13:18:25 +02:00
let members = db . rooms . room_state_type ( & room_id , & EventType ::RoomMember ) ? ;
2020-06-04 18:27:57 +02:00
let ( joined_member_count , invited_member_count , heroes ) = if send_member_count {
let joined_member_count = db . rooms . room_members ( & room_id ) . count ( ) ;
let invited_member_count = db . rooms . room_members_invited ( & room_id ) . count ( ) ;
// Recalculate heroes (first 5 members)
let mut heroes = Vec ::new ( ) ;
if joined_member_count + invited_member_count < = 5 {
// Go through all PDUs and for each member event, check if the user is still joined or
// invited until we have 5 or we reach the end
for hero in db
. rooms
2020-06-16 12:11:38 +02:00
. all_pdus ( & user_id , & room_id ) ?
2020-06-04 18:27:57 +02:00
. filter_map ( | pdu | pdu . ok ( ) ) // Ignore all broken pdus
. filter ( | pdu | pdu . kind = = EventType ::RoomMember )
2020-06-09 15:13:17 +02:00
. map ( | pdu | {
2020-06-04 18:27:57 +02:00
let content = serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::member ::MemberEventContent > ,
2020-06-04 18:27:57 +02:00
> ( pdu . content . clone ( ) )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ?
2020-06-04 18:27:57 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ? ;
2020-06-09 15:13:17 +02:00
if let Some ( state_key ) = & pdu . state_key {
let current_content = serde_json ::from_value ::<
2020-07-26 15:41:28 +02:00
Raw < ruma ::events ::room ::member ::MemberEventContent > ,
2020-06-09 15:13:17 +02:00
> (
2020-06-12 13:18:25 +02:00
members
. get ( state_key )
2020-06-11 10:03:08 +02:00
. ok_or_else ( | | {
Error ::bad_database (
" A user that joined once has no member event anymore. " ,
)
} ) ?
2020-06-09 15:13:17 +02:00
. content
. clone ( ) ,
)
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " Invalid member event in database. " ) ) ?
2020-06-09 15:13:17 +02:00
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | {
Error ::bad_database ( " Invalid member event in database. " )
} ) ? ;
2020-06-09 15:13:17 +02:00
// The membership was and still is invite or join
if matches! (
content . membership ,
ruma ::events ::room ::member ::MembershipState ::Join
| ruma ::events ::room ::member ::MembershipState ::Invite
) & & matches! (
current_content . membership ,
ruma ::events ::room ::member ::MembershipState ::Join
| ruma ::events ::room ::member ::MembershipState ::Invite
) {
Ok ::< _ , Error > ( Some ( state_key . clone ( ) ) )
} else {
Ok ( None )
}
2020-06-04 18:27:57 +02:00
} else {
2020-06-09 15:13:17 +02:00
Ok ( None )
2020-06-04 18:27:57 +02:00
}
} )
2020-06-09 15:13:17 +02:00
. filter_map ( | u | u . ok ( ) ) // Filter out buggy users
// Filter for possible heroes
. filter_map ( | u | u )
2020-06-04 18:27:57 +02:00
{
if heroes . contains ( & hero ) | | hero = = user_id . to_string ( ) {
continue ;
}
heroes . push ( hero ) ;
}
}
(
Some ( joined_member_count ) ,
Some ( invited_member_count ) ,
heroes ,
)
} else {
( None , None , Vec ::new ( ) )
} ;
let notification_count = if send_notification_counts {
2020-06-09 15:13:17 +02:00
if let Some ( last_read ) = db . rooms . edus . room_read_get ( & room_id , & user_id ) ? {
2020-05-31 19:40:01 +02:00
Some (
( db . rooms
2020-06-16 12:11:38 +02:00
. pdus_since ( & user_id , & room_id , last_read ) ?
2020-06-09 15:13:17 +02:00
. filter_map ( | pdu | pdu . ok ( ) ) // Filter out buggy events
2020-06-02 19:32:18 +02:00
. filter ( | pdu | {
matches! (
2020-06-09 15:13:17 +02:00
pdu . kind . clone ( ) ,
2020-06-02 19:32:18 +02:00
EventType ::RoomMessage | EventType ::RoomEncrypted
)
} )
2020-05-31 19:40:01 +02:00
. count ( ) as u32 )
. into ( ) ,
)
2020-05-09 21:47:09 +02:00
} else {
None
2020-06-04 18:27:57 +02:00
}
} else {
None
} ;
2020-05-01 20:26:57 +02:00
// They /sync response doesn't always return all messages, so we say the output is
// limited unless there are enough events
let mut limited = true ;
pdus = pdus . split_off ( pdus . len ( ) . checked_sub ( 10 ) . unwrap_or_else ( | | {
limited = false ;
0
} ) ) ;
2020-06-09 15:13:17 +02:00
let prev_batch = pdus . first ( ) . map_or ( Ok ::< _ , Error > ( None ) , | e | {
Ok ( Some (
db . rooms
. get_pdu_count ( & e . event_id ) ?
2020-06-11 10:03:08 +02:00
. ok_or_else ( | | Error ::bad_database ( " Can't find count from event in db. " ) ) ?
2020-06-09 15:13:17 +02:00
. to_string ( ) ,
) )
} ) ? ;
2020-05-01 20:26:57 +02:00
2020-04-29 12:18:45 +02:00
let room_events = pdus
. into_iter ( )
2020-07-18 08:21:25 -04:00
. map ( | pdu | pdu . to_sync_room_event ( ) )
2020-04-29 12:18:45 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-05-03 17:25:31 +02:00
let mut edus = db
. rooms
. edus
2020-06-09 15:13:17 +02:00
. roomlatests_since ( & room_id , since ) ?
. filter_map ( | r | r . ok ( ) ) // Filter out buggy events
2020-05-03 17:25:31 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-06-04 11:17:36 +02:00
if db
. rooms
. edus
2020-06-09 15:13:17 +02:00
. last_roomactive_update ( & room_id , & db . globals ) ?
2020-06-04 11:17:36 +02:00
> since
{
2020-06-04 13:58:55 +02:00
edus . push (
serde_json ::from_str (
2020-07-21 14:04:39 -04:00
& serde_json ::to_string ( & AnySyncEphemeralRoomEvent ::Typing (
2020-06-09 15:13:17 +02:00
db . rooms . edus . roomactives_all ( & room_id ) ? ,
2020-07-21 14:04:39 -04:00
) )
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
2020-06-04 13:58:55 +02:00
)
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
2020-06-04 13:58:55 +02:00
) ;
2020-05-03 17:25:31 +02:00
}
2020-06-06 22:34:08 +02:00
let joined_room = sync_events ::JoinedRoom {
account_data : sync_events ::AccountData {
events : db
. account_data
2020-06-09 15:13:17 +02:00
. changes_since ( Some ( & room_id ) , & user_id , since ) ?
2020-06-06 22:34:08 +02:00
. into_iter ( )
2020-07-21 16:26:01 -04:00
. filter_map ( | ( _ , v ) | {
serde_json ::from_str ( v . json ( ) . get ( ) )
. map_err ( | _ | Error ::bad_database ( " Invalid account event in database. " ) )
. ok ( )
2020-06-21 15:58:42 -04:00
} )
2020-07-21 16:26:01 -04:00
. collect ::< Vec < _ > > ( ) ,
2020-06-06 22:34:08 +02:00
} ,
summary : sync_events ::RoomSummary {
heroes ,
joined_member_count : joined_member_count . map ( | n | ( n as u32 ) . into ( ) ) ,
invited_member_count : invited_member_count . map ( | n | ( n as u32 ) . into ( ) ) ,
} ,
unread_notifications : sync_events ::UnreadNotificationsCount {
highlight_count : None ,
notification_count ,
} ,
timeline : sync_events ::Timeline {
2020-07-17 16:00:39 -04:00
limited : limited | | joined_since_last_sync ,
2020-06-06 22:34:08 +02:00
prev_batch ,
events : room_events ,
} ,
// TODO: state before timeline
state : sync_events ::State {
events : if joined_since_last_sync {
2020-06-12 13:18:25 +02:00
db . rooms
. room_state_full ( & room_id ) ?
2020-06-06 22:34:08 +02:00
. into_iter ( )
2020-07-18 08:21:25 -04:00
. map ( | ( _ , pdu ) | pdu . to_sync_state_event ( ) )
2020-06-06 22:34:08 +02:00
. collect ( )
} else {
Vec ::new ( )
2020-04-29 12:18:45 +02:00
} ,
2020-04-11 09:30:11 +02:00
} ,
2020-06-06 22:34:08 +02:00
ephemeral : sync_events ::Ephemeral { events : edus } ,
} ;
if ! joined_room . is_empty ( ) {
2020-06-09 15:13:17 +02:00
joined_rooms . insert ( room_id . clone ( ) , joined_room ) ;
2020-06-06 22:34:08 +02:00
}
2020-04-11 09:30:11 +02:00
}
2020-04-19 14:14:47 +02:00
let mut left_rooms = BTreeMap ::new ( ) ;
2020-05-03 17:25:31 +02:00
for room_id in db . rooms . rooms_left ( & user_id ) {
2020-06-09 15:13:17 +02:00
let room_id = room_id ? ;
2020-06-16 12:11:38 +02:00
let pdus = db . rooms . pdus_since ( & user_id , & room_id , since ) ? ;
2020-06-09 15:13:17 +02:00
let room_events = pdus
. filter_map ( | pdu | pdu . ok ( ) ) // Filter out buggy events
2020-07-18 08:21:25 -04:00
. map ( | pdu | pdu . to_sync_room_event ( ) )
2020-06-09 15:13:17 +02:00
. collect ( ) ;
2020-05-03 17:25:31 +02:00
2020-06-06 22:34:08 +02:00
// TODO: Only until leave point
2020-05-03 17:25:31 +02:00
let mut edus = db
. rooms
. edus
2020-06-09 15:13:17 +02:00
. roomlatests_since ( & room_id , since ) ?
. filter_map ( | r | r . ok ( ) ) // Filter out buggy events
2020-05-03 17:25:31 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-06-04 11:17:36 +02:00
if db
. rooms
. edus
2020-06-09 15:13:17 +02:00
. last_roomactive_update ( & room_id , & db . globals ) ?
2020-06-04 11:17:36 +02:00
> since
{
2020-06-04 13:58:55 +02:00
edus . push (
serde_json ::from_str (
2020-07-21 14:04:39 -04:00
& serde_json ::to_string ( & AnySyncEphemeralRoomEvent ::Typing (
2020-06-09 15:13:17 +02:00
db . rooms . edus . roomactives_all ( & room_id ) ? ,
2020-06-26 18:34:11 -04:00
) )
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
2020-06-04 13:58:55 +02:00
)
2020-06-09 15:13:17 +02:00
. expect ( " event is valid, we just created it " ) ,
2020-06-04 13:58:55 +02:00
) ;
2020-06-04 11:17:36 +02:00
}
2020-04-19 14:14:47 +02:00
2020-06-06 22:34:08 +02:00
let left_room = sync_events ::LeftRoom {
account_data : sync_events ::AccountData { events : Vec ::new ( ) } ,
timeline : sync_events ::Timeline {
2020-07-17 16:00:39 -04:00
limited : false ,
2020-06-06 22:34:08 +02:00
prev_batch : Some ( next_batch . clone ( ) ) ,
events : room_events ,
2020-04-19 14:14:47 +02:00
} ,
2020-06-06 22:34:08 +02:00
state : sync_events ::State { events : Vec ::new ( ) } ,
} ;
if ! left_room . is_empty ( ) {
2020-06-09 15:13:17 +02:00
left_rooms . insert ( room_id . clone ( ) , left_room ) ;
2020-06-06 22:34:08 +02:00
}
2020-04-19 14:14:47 +02:00
}
let mut invited_rooms = BTreeMap ::new ( ) ;
2020-05-03 17:25:31 +02:00
for room_id in db . rooms . rooms_invited ( & user_id ) {
2020-06-09 15:13:17 +02:00
let room_id = room_id ? ;
2020-04-14 13:54:32 +02:00
2020-06-06 22:34:08 +02:00
let invited_room = sync_events ::InvitedRoom {
invite_state : sync_events ::InviteState {
events : db
. rooms
2020-06-12 13:18:25 +02:00
. room_state_full ( & room_id ) ?
2020-06-06 22:34:08 +02:00
. into_iter ( )
. map ( | ( _ , pdu ) | pdu . to_stripped_state_event ( ) )
. collect ( ) ,
2020-04-14 13:54:32 +02:00
} ,
2020-06-06 22:34:08 +02:00
} ;
if ! invited_room . is_empty ( ) {
invited_rooms . insert ( room_id . clone ( ) , invited_room ) ;
}
2020-04-14 13:54:32 +02:00
}
2020-07-03 11:24:23 +02:00
// Remove all to-device events the device received *last time*
2020-07-26 15:41:28 +02:00
db . users
. remove_to_device_events ( user_id , device_id , since ) ? ;
2020-07-03 11:24:23 +02:00
2020-06-09 15:13:17 +02:00
Ok ( sync_events ::Response {
2020-04-11 09:30:11 +02:00
next_batch ,
rooms : sync_events ::Rooms {
2020-04-19 14:14:47 +02:00
leave : left_rooms ,
2020-04-11 09:30:11 +02:00
join : joined_rooms ,
2020-04-14 13:54:32 +02:00
invite : invited_rooms ,
2020-04-11 09:30:11 +02:00
} ,
2020-05-09 21:47:09 +02:00
presence : sync_events ::Presence {
events : db
. global_edus
2020-06-09 15:13:17 +02:00
. presence_since ( since ) ?
2020-06-04 22:36:48 +02:00
. map ( | edu | {
2020-06-09 15:13:17 +02:00
let mut edu = edu ?
. deserialize ( )
2020-06-11 10:03:08 +02:00
. map_err ( | _ | Error ::bad_database ( " EDU in database is invalid. " ) ) ? ;
2020-06-09 15:13:17 +02:00
if let Some ( timestamp ) = edu . content . last_active_ago {
let last_active_ago =
js_int ::UInt ::try_from ( utils ::millis_since_unix_epoch ( ) )
. expect ( " time is valid " )
- timestamp ;
edu . content . last_active_ago = Some ( last_active_ago ) ;
}
Ok ::< _ , Error > ( edu . into ( ) )
2020-05-09 21:47:09 +02:00
} )
2020-06-09 15:13:17 +02:00
. filter_map ( | edu | edu . ok ( ) ) // Filter out buggy events
2020-05-09 21:47:09 +02:00
. collect ( ) ,
} ,
2020-05-01 20:26:57 +02:00
account_data : sync_events ::AccountData {
2020-05-09 21:47:09 +02:00
events : db
. account_data
2020-06-09 15:13:17 +02:00
. changes_since ( None , & user_id , since ) ?
2020-05-01 20:26:57 +02:00
. into_iter ( )
2020-07-21 16:26:01 -04:00
. filter_map ( | ( _ , v ) | {
serde_json ::from_str ( v . json ( ) . get ( ) )
. map_err ( | _ | Error ::bad_database ( " Invalid account event in database. " ) )
. ok ( )
2020-06-22 07:26:09 -04:00
} )
2020-07-21 16:26:01 -04:00
. collect ::< Vec < _ > > ( ) ,
2020-05-01 20:26:57 +02:00
} ,
2020-06-06 22:34:08 +02:00
device_lists : sync_events ::DeviceLists {
changed : if since ! = 0 {
db . users
2020-06-16 12:11:38 +02:00
. keys_changed ( since )
2020-06-09 15:13:17 +02:00
. filter_map ( | u | u . ok ( ) )
. collect ( ) // Filter out buggy events
2020-06-06 22:34:08 +02:00
} else {
Vec ::new ( )
} ,
left : Vec ::new ( ) , // TODO
2020-05-18 11:36:32 +02:00
} ,
2020-06-02 19:32:18 +02:00
device_one_time_keys_count : Default ::default ( ) , // TODO
2020-05-17 19:56:40 +02:00
to_device : sync_events ::ToDevice {
2020-07-03 11:24:23 +02:00
events : db . users . get_to_device_events ( user_id , device_id ) ? ,
2020-05-17 19:56:40 +02:00
} ,
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-04-11 09:30:11 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get(
" /_matrix/client/r0/rooms/<_room_id>/context/<_event_id> " ,
data = " <body> "
) ]
2020-06-04 13:58:55 +02:00
pub fn get_context_route (
2020-05-03 17:25:31 +02:00
db : State < '_ , Database > ,
2020-06-04 13:58:55 +02:00
body : Ruma < get_context ::Request > ,
2020-04-29 12:18:45 +02:00
_room_id : String ,
2020-06-04 13:58:55 +02:00
_event_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_context ::Response > {
2020-05-24 18:25:52 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
if ! db . rooms . is_joined ( user_id , & body . room_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" You don't have permission to view this room. " ,
) ) ;
2020-05-24 18:25:52 +02:00
}
2020-06-09 15:13:17 +02:00
let base_event = db
. rooms
. get_pdu ( & body . event_id ) ?
. ok_or ( Error ::BadRequest (
ErrorKind ::NotFound ,
" Base event not found. " ,
) ) ?
. to_room_event ( ) ;
let base_token = db
. rooms
. get_pdu_count ( & body . event_id ) ?
. expect ( " event still exists " ) ;
2020-06-04 13:58:55 +02:00
2020-06-09 15:13:17 +02:00
let events_before = db
. rooms
2020-06-16 12:11:38 +02:00
. pdus_until ( & user_id , & body . room_id , base_token )
2020-06-09 15:13:17 +02:00
. take (
u32 ::try_from ( body . limit ) . map_err ( | _ | {
Error ::BadRequest ( ErrorKind ::InvalidParam , " Limit value is invalid. " )
} ) ? as usize
/ 2 ,
)
. filter_map ( | r | r . ok ( ) ) // Remove buggy events
. collect ::< Vec < _ > > ( ) ;
2020-06-04 13:58:55 +02:00
2020-07-26 17:34:12 +02:00
let start_token = events_before . last ( ) . map_or ( Ok ( None ) , | ( _ , e ) | {
2020-06-09 15:13:17 +02:00
Ok ::< _ , Error > ( Some (
db . rooms
. get_pdu_count ( & e . event_id ) ?
2020-06-11 10:03:08 +02:00
. ok_or_else ( | | Error ::bad_database ( " Can't find count from event in db. " ) ) ?
2020-06-09 15:13:17 +02:00
. to_string ( ) ,
) )
} ) ? ;
2020-06-04 13:58:55 +02:00
2020-06-09 15:13:17 +02:00
let events_before = events_before
. into_iter ( )
2020-07-26 17:34:12 +02:00
. map ( | ( _ , pdu ) | pdu . to_room_event ( ) )
2020-06-09 15:13:17 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-05-01 20:26:57 +02:00
2020-06-09 15:13:17 +02:00
let events_after = db
. rooms
2020-06-16 12:11:38 +02:00
. pdus_after ( & user_id , & body . room_id , base_token )
2020-06-09 15:13:17 +02:00
. take (
u32 ::try_from ( body . limit ) . map_err ( | _ | {
Error ::BadRequest ( ErrorKind ::InvalidParam , " Limit value is invalid. " )
} ) ? as usize
/ 2 ,
)
. filter_map ( | r | r . ok ( ) ) // Remove buggy events
. collect ::< Vec < _ > > ( ) ;
2020-06-04 13:58:55 +02:00
2020-07-26 17:34:12 +02:00
let end_token = if let Some ( last_event ) = events_after . last ( ) {
Some (
utils ::u64_from_bytes ( & last_event . 0 )
. map_err ( | _ | Error ::bad_database ( " Invalid pdu id in db. " ) ) ?
2020-06-09 15:13:17 +02:00
. to_string ( ) ,
2020-07-26 17:34:12 +02:00
)
} else {
None
} ;
2020-06-04 13:58:55 +02:00
2020-06-09 15:13:17 +02:00
let events_after = events_after
. into_iter ( )
2020-07-26 17:34:12 +02:00
. map ( | ( _ , pdu ) | pdu . to_room_event ( ) )
2020-06-09 15:13:17 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-06-04 13:58:55 +02:00
2020-06-09 15:13:17 +02:00
Ok ( get_context ::Response {
start : start_token ,
end : end_token ,
events_before ,
event : Some ( base_event ) ,
events_after ,
state : db // TODO: State at event
. rooms
2020-06-12 13:18:25 +02:00
. room_state_full ( & body . room_id ) ?
2020-06-09 15:13:17 +02:00
. values ( )
. map ( | pdu | pdu . to_state_event ( ) )
. collect ( ) ,
2020-04-28 19:56:34 +02:00
}
2020-06-09 15:13:17 +02:00
. into ( ) )
2020-04-28 19:56:34 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/rooms/<_room_id>/messages " , data = " <body> " ) ]
2020-06-04 13:58:55 +02:00
pub fn get_message_events_route (
db : State < '_ , Database > ,
body : Ruma < get_message_events ::Request > ,
_room_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_message_events ::Response > {
2020-06-04 13:58:55 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-09 15:13:17 +02:00
if ! db . rooms . is_joined ( user_id , & body . room_id ) ? {
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
" You don't have permission to view this room. " ,
) ) ;
2020-06-04 13:58:55 +02:00
}
2020-06-09 15:13:17 +02:00
let from = body
. from
. clone ( )
. parse ( )
. map_err ( | _ | Error ::BadRequest ( ErrorKind ::InvalidParam , " Invalid `from` value. " ) ) ? ;
2020-07-26 17:34:12 +02:00
let to = body . to . as_ref ( ) . map ( | t | t . as_bytes ( ) ) ;
// Use limit or else 10
2020-06-24 17:03:33 -04:00
let limit = body
. limit
. try_into ( )
. map_or ( Ok ::< _ , Error > ( 10_ usize ) , | l : u32 | Ok ( l as usize ) ) ? ;
2020-07-26 17:34:12 +02:00
2020-06-09 15:13:17 +02:00
match body . dir {
get_message_events ::Direction ::Forward = > {
let events_after = db
. rooms
2020-06-16 12:11:38 +02:00
. pdus_after ( & user_id , & body . room_id , from )
2020-06-21 15:58:42 -04:00
. take ( limit )
2020-06-09 15:13:17 +02:00
. filter_map ( | r | r . ok ( ) ) // Filter out buggy events
2020-07-26 17:34:12 +02:00
. take_while ( | ( k , _ ) | Some ( & * * k ) ! = to ) // Stop at `to`
2020-06-09 15:13:17 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-07-26 17:34:12 +02:00
let end_token = if let Some ( last_event ) = events_after . last ( ) {
Some (
utils ::u64_from_bytes ( & last_event . 0 )
. map_err ( | _ | Error ::bad_database ( " Invalid pdu id in db. " ) ) ?
2020-06-09 15:13:17 +02:00
. to_string ( ) ,
2020-07-26 17:34:12 +02:00
)
} else {
None
} ;
2020-06-09 15:13:17 +02:00
let events_after = events_after
. into_iter ( )
2020-07-26 17:34:12 +02:00
. map ( | ( _ , pdu ) | pdu . to_room_event ( ) )
2020-06-09 15:13:17 +02:00
. collect ::< Vec < _ > > ( ) ;
Ok ( get_message_events ::Response {
start : Some ( body . from . clone ( ) ) ,
end : end_token ,
chunk : events_after ,
state : Vec ::new ( ) ,
2020-06-04 13:58:55 +02:00
}
2020-06-09 15:13:17 +02:00
. into ( ) )
}
get_message_events ::Direction ::Backward = > {
let events_before = db
. rooms
2020-06-16 12:11:38 +02:00
. pdus_until ( & user_id , & body . room_id , from )
2020-06-21 15:58:42 -04:00
. take ( limit )
2020-06-09 15:13:17 +02:00
. filter_map ( | r | r . ok ( ) ) // Filter out buggy events
2020-07-26 17:34:12 +02:00
. take_while ( | ( k , _ ) | Some ( & * * k ) ! = to ) // Stop at `to`
2020-06-09 15:13:17 +02:00
. collect ::< Vec < _ > > ( ) ;
2020-07-26 17:34:12 +02:00
let start_token = if let Some ( last_event ) = events_before . last ( ) {
Some (
utils ::u64_from_bytes ( & last_event . 0 )
. map_err ( | _ | Error ::bad_database ( " Invalid pdu id in db. " ) ) ?
2020-06-09 15:13:17 +02:00
. to_string ( ) ,
2020-07-26 17:34:12 +02:00
)
} else {
None
} ;
2020-06-09 15:13:17 +02:00
let events_before = events_before
. into_iter ( )
2020-07-26 17:34:12 +02:00
. map ( | ( _ , pdu ) | pdu . to_room_event ( ) )
2020-06-09 15:13:17 +02:00
. collect ::< Vec < _ > > ( ) ;
Ok ( get_message_events ::Response {
start : Some ( body . from . clone ( ) ) ,
end : start_token ,
chunk : events_before ,
state : Vec ::new ( ) ,
2020-06-04 13:58:55 +02:00
}
2020-06-09 15:13:17 +02:00
. into ( ) )
2020-06-04 13:58:55 +02:00
}
}
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/voip/turnServer " ) ]
2020-06-09 15:13:17 +02:00
pub fn turn_server_route ( ) -> ConduitResult < create_message_event ::Response > {
Err ( Error ::BadRequest (
ErrorKind ::NotFound ,
" There is no turn server yet. " ,
) )
2020-04-14 13:54:32 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/publicised_groups " ) ]
2020-06-09 15:13:17 +02:00
pub fn publicised_groups_route ( ) -> ConduitResult < create_message_event ::Response > {
Err ( Error ::BadRequest (
ErrorKind ::NotFound ,
" There are not publicised groups yet. " ,
) )
2020-04-14 13:54:32 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put(
" /_matrix/client/r0/sendToDevice/<_event_type>/<_txn_id> " ,
data = " <body> "
) ]
2020-05-01 20:26:57 +02:00
pub fn send_event_to_device_route (
2020-05-17 19:56:40 +02:00
db : State < '_ , Database > ,
body : Ruma < send_event_to_device ::Request > ,
2020-05-01 20:26:57 +02:00
_event_type : String ,
_txn_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < send_event_to_device ::Response > {
2020-05-17 19:56:40 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
for ( target_user_id , map ) in & body . messages {
for ( target_device_id_maybe , event ) in map {
match target_device_id_maybe {
2020-06-09 15:13:17 +02:00
to_device ::DeviceIdOrAllDevices ::DeviceId ( target_device_id ) = > {
db . users . add_to_device_event (
2020-05-17 19:56:40 +02:00
user_id ,
& target_user_id ,
& target_device_id ,
& body . event_type ,
2020-06-09 15:13:17 +02:00
serde_json ::from_str ( event . get ( ) ) . map_err ( | _ | {
Error ::BadRequest ( ErrorKind ::InvalidParam , " Event is invalid " )
} ) ? ,
2020-05-17 19:56:40 +02:00
& db . globals ,
2020-06-09 15:13:17 +02:00
) ?
}
2020-05-17 19:56:40 +02:00
to_device ::DeviceIdOrAllDevices ::AllDevices = > {
for target_device_id in db . users . all_device_ids ( & target_user_id ) {
2020-06-09 15:13:17 +02:00
db . users . add_to_device_event (
user_id ,
& target_user_id ,
& target_device_id ? ,
& body . event_type ,
serde_json ::from_str ( event . get ( ) ) . map_err ( | _ | {
Error ::BadRequest ( ErrorKind ::InvalidParam , " Event is invalid " )
} ) ? ,
& db . globals ,
) ? ;
2020-05-17 19:56:40 +02:00
}
}
}
}
}
2020-06-09 15:13:17 +02:00
Ok ( send_event_to_device ::Response . into ( ) )
2020-05-01 20:26:57 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/media/r0/config " ) ]
2020-07-23 23:03:24 -04:00
pub fn get_media_config_route (
db : State < '_ , Database > ,
) -> ConduitResult < get_media_config ::Response > {
2020-07-24 16:04:01 -04:00
Ok ( get_media_config ::Response {
upload_size : db . globals . max_request_size ( ) . into ( ) ,
}
. into ( ) )
2020-05-01 20:26:57 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/media/r0/upload " , data = " <body> " ) ]
2020-05-18 17:53:34 +02:00
pub fn create_content_route (
db : State < '_ , Database > ,
body : Ruma < create_content ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < create_content ::Response > {
2020-05-19 18:31:34 +02:00
let mxc = format! (
" mxc://{}/{} " ,
db . globals . server_name ( ) ,
utils ::random_string ( MXC_LENGTH )
) ;
2020-06-09 15:13:17 +02:00
db . media . create (
mxc . clone ( ) ,
body . filename . as_ref ( ) ,
& body . content_type ,
& body . file ,
) ? ;
2020-05-18 17:53:34 +02:00
2020-06-09 15:13:17 +02:00
Ok ( create_content ::Response { content_uri : mxc } . into ( ) )
2020-05-18 17:53:34 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get(
" /_matrix/media/r0/download/<_server_name>/<_media_id> " ,
data = " <body> "
) ]
2020-05-18 17:53:34 +02:00
pub fn get_content_route (
db : State < '_ , Database > ,
body : Ruma < get_content ::Request > ,
_server_name : String ,
_media_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_content ::Response > {
2020-05-19 18:31:34 +02:00
if let Some ( ( filename , content_type , file ) ) = db
. media
2020-06-09 15:13:17 +02:00
. get ( format! ( " mxc:// {} / {} " , body . server_name , body . media_id ) ) ?
2020-05-19 18:31:34 +02:00
{
2020-06-09 15:13:17 +02:00
Ok ( get_content ::Response {
2020-05-18 17:53:34 +02:00
file ,
content_type ,
content_disposition : filename . unwrap_or_default ( ) , // TODO: Spec says this should be optional
2020-06-09 15:13:17 +02:00
}
. into ( ) )
2020-05-18 17:53:34 +02:00
} else {
2020-06-09 15:13:17 +02:00
Err ( Error ::BadRequest ( ErrorKind ::NotFound , " Media not found. " ) )
2020-05-18 17:53:34 +02:00
}
}
2020-06-22 07:26:09 -04:00
#[ get(
" /_matrix/media/r0/thumbnail/<_server_name>/<_media_id> " ,
data = " <body> "
) ]
2020-05-18 17:53:34 +02:00
pub fn get_content_thumbnail_route (
db : State < '_ , Database > ,
body : Ruma < get_content_thumbnail ::Request > ,
_server_name : String ,
_media_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_content_thumbnail ::Response > {
if let Some ( ( _ , content_type , file ) ) = db . media . get_thumbnail (
format! ( " mxc:// {} / {} " , body . server_name , body . media_id ) ,
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. " ) ) ? ,
) ? {
Ok ( get_content_thumbnail ::Response { file , content_type } . into ( ) )
2020-05-18 17:53:34 +02:00
} else {
2020-06-09 15:13:17 +02:00
Err ( Error ::BadRequest ( ErrorKind ::NotFound , " Media not found. " ) )
2020-05-18 17:53:34 +02:00
}
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/devices " , data = " <body> " ) ]
2020-06-03 13:41:30 +02:00
pub fn get_devices_route (
db : State < '_ , Database > ,
body : Ruma < get_devices ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_devices ::Response > {
2020-06-03 13:41:30 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let devices = db
. users
. all_devices_metadata ( user_id )
2020-06-09 15:13:17 +02:00
. filter_map ( | r | r . ok ( ) ) // Filter out buggy devices
2020-06-03 13:41:30 +02:00
. collect ::< Vec < device ::Device > > ( ) ;
2020-06-09 15:13:17 +02:00
Ok ( get_devices ::Response { devices } . into ( ) )
2020-06-03 13:41:30 +02:00
}
2020-06-22 07:26:09 -04:00
#[ get( " /_matrix/client/r0/devices/<_device_id> " , data = " <body> " ) ]
2020-06-03 13:41:30 +02:00
pub fn get_device_route (
db : State < '_ , Database > ,
body : Ruma < get_device ::Request > ,
2020-06-07 18:38:00 +02:00
_device_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < get_device ::Response > {
2020-06-03 13:41:30 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-07 18:38:00 +02:00
2020-06-08 12:28:30 +02:00
let device = db
. users
2020-06-09 15:13:17 +02:00
. get_device_metadata ( & user_id , & body . body . device_id ) ?
. ok_or ( Error ::BadRequest ( ErrorKind ::NotFound , " Device not found. " ) ) ? ;
2020-06-03 13:41:30 +02:00
2020-06-09 15:13:17 +02:00
Ok ( get_device ::Response { device } . into ( ) )
2020-06-03 13:41:30 +02:00
}
2020-06-22 07:26:09 -04:00
#[ put( " /_matrix/client/r0/devices/<_device_id> " , data = " <body> " ) ]
2020-06-03 13:41:30 +02:00
pub fn update_device_route (
db : State < '_ , Database > ,
body : Ruma < update_device ::Request > ,
2020-06-07 18:38:00 +02:00
_device_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < update_device ::Response > {
2020-06-03 13:41:30 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-07 18:38:00 +02:00
2020-06-09 15:13:17 +02:00
let mut device = db
2020-06-08 12:28:30 +02:00
. users
2020-06-09 15:13:17 +02:00
. get_device_metadata ( & user_id , & body . body . device_id ) ?
. ok_or ( Error ::BadRequest ( ErrorKind ::NotFound , " Device not found. " ) ) ? ;
2020-06-03 13:41:30 +02:00
2020-06-09 15:13:17 +02:00
device . display_name = body . display_name . clone ( ) ;
2020-06-03 13:41:30 +02:00
2020-06-09 15:13:17 +02:00
db . users
. update_device_metadata ( & user_id , & body . body . device_id , & device ) ? ;
Ok ( update_device ::Response . into ( ) )
2020-06-03 13:41:30 +02:00
}
2020-06-22 07:26:09 -04:00
#[ delete( " /_matrix/client/r0/devices/<_device_id> " , data = " <body> " ) ]
2020-06-03 13:41:30 +02:00
pub fn delete_device_route (
db : State < '_ , Database > ,
body : Ruma < delete_device ::Request > ,
2020-06-07 18:38:00 +02:00
_device_id : String ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < delete_device ::Response > {
2020-06-03 13:41:30 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-07 18:38:00 +02:00
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-06 18:44:50 +02:00
// UIAA
2020-06-08 15:17:58 +02:00
let mut uiaainfo = UiaaInfo {
2020-06-06 18:44:50 +02:00
flows : vec ! [ AuthFlow {
stages : vec ! [ " m.login.password " . to_owned ( ) ] ,
} ] ,
completed : Vec ::new ( ) ,
params : Default ::default ( ) ,
2020-06-08 15:17:58 +02:00
session : None ,
2020-06-06 18:44:50 +02:00
auth_error : None ,
} ;
if let Some ( auth ) = & body . auth {
2020-06-09 15:13:17 +02:00
let ( worked , uiaainfo ) = db . uiaa . try_auth (
& user_id ,
& device_id ,
auth ,
& uiaainfo ,
& db . users ,
& db . globals ,
) ? ;
2020-06-06 18:44:50 +02:00
if ! worked {
2020-06-09 15:13:17 +02:00
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
2020-06-06 18:44:50 +02:00
}
2020-06-08 11:45:22 +02:00
// Success!
2020-06-06 18:44:50 +02:00
} else {
2020-06-08 15:17:58 +02:00
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ) ) ;
2020-06-09 15:13:17 +02:00
db . uiaa . create ( & user_id , & device_id , & uiaainfo ) ? ;
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
2020-06-06 18:44:50 +02:00
}
2020-06-09 15:13:17 +02:00
db . users . remove_device ( & user_id , & body . body . device_id ) ? ;
2020-06-03 13:41:30 +02:00
2020-06-09 15:13:17 +02:00
Ok ( delete_device ::Response . into ( ) )
2020-06-03 13:41:30 +02:00
}
2020-06-22 07:26:09 -04:00
#[ post( " /_matrix/client/r0/delete_devices " , data = " <body> " ) ]
2020-06-03 13:41:30 +02:00
pub fn delete_devices_route (
db : State < '_ , Database > ,
body : Ruma < delete_devices ::Request > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < delete_devices ::Response > {
2020-06-03 13:41:30 +02:00
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-08 12:28:30 +02:00
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
2020-06-06 18:44:50 +02:00
// UIAA
2020-06-09 15:13:17 +02:00
let mut uiaainfo = UiaaInfo {
2020-06-06 18:44:50 +02:00
flows : vec ! [ AuthFlow {
stages : vec ! [ " m.login.password " . to_owned ( ) ] ,
} ] ,
completed : Vec ::new ( ) ,
params : Default ::default ( ) ,
2020-06-09 15:13:17 +02:00
session : None ,
2020-06-06 18:44:50 +02:00
auth_error : None ,
} ;
if let Some ( auth ) = & body . auth {
2020-06-09 15:13:17 +02:00
let ( worked , uiaainfo ) = db . uiaa . try_auth (
& user_id ,
& device_id ,
auth ,
& uiaainfo ,
& db . users ,
& db . globals ,
) ? ;
2020-06-06 18:44:50 +02:00
if ! worked {
2020-06-09 15:13:17 +02:00
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
2020-06-06 18:44:50 +02:00
}
2020-06-08 11:45:22 +02:00
// Success!
2020-06-06 18:44:50 +02:00
} else {
2020-06-09 15:13:17 +02:00
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ) ) ;
db . uiaa . create ( & user_id , & device_id , & uiaainfo ) ? ;
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
2020-06-06 18:44:50 +02:00
}
2020-06-03 13:41:30 +02:00
for device_id in & body . devices {
2020-06-09 15:13:17 +02:00
db . users . remove_device ( & user_id , & device_id ) ?
2020-06-03 13:41:30 +02:00
}
2020-06-09 15:13:17 +02:00
Ok ( delete_devices ::Response . into ( ) )
2020-06-03 13:41:30 +02:00
}
2020-06-16 12:11:38 +02:00
#[ post( " /_matrix/client/unstable/keys/device_signing/upload " , data = " <body> " ) ]
pub fn upload_signing_keys_route (
db : State < '_ , Database > ,
body : Ruma < upload_signing_keys ::Request > ,
) -> ConduitResult < upload_signing_keys ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let device_id = body . device_id . as_ref ( ) . expect ( " user is authenticated " ) ;
// UIAA
let mut uiaainfo = UiaaInfo {
flows : vec ! [ AuthFlow {
stages : vec ! [ " m.login.password " . to_owned ( ) ] ,
} ] ,
completed : Vec ::new ( ) ,
params : Default ::default ( ) ,
session : None ,
auth_error : None ,
} ;
if let Some ( auth ) = & body . auth {
let ( worked , uiaainfo ) = db . uiaa . try_auth (
& user_id ,
& device_id ,
auth ,
& uiaainfo ,
& db . users ,
& db . globals ,
) ? ;
if ! worked {
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
}
// Success!
} else {
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ) ) ;
db . uiaa . create ( & user_id , & device_id , & uiaainfo ) ? ;
return Err ( Error ::Uiaa ( uiaainfo ) ) ;
}
if let Some ( master_key ) = & body . master_key {
db . users . add_cross_signing_keys (
user_id ,
& master_key ,
& body . self_signing_key ,
& body . user_signing_key ,
& db . globals ,
) ? ;
}
Ok ( upload_signing_keys ::Response . into ( ) )
}
#[ post( " /_matrix/client/unstable/keys/signatures/upload " , data = " <body> " ) ]
pub fn upload_signatures_route (
db : State < '_ , Database > ,
body : Ruma < upload_signatures ::Request > ,
) -> ConduitResult < upload_signatures ::Response > {
let sender_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
for ( user_id , signed_keys ) in & body . signed_keys {
for ( key_id , signed_key ) in signed_keys {
for signature in signed_key
. get ( " signatures " )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Missing signatures field. " ,
) ) ?
. get ( sender_id . to_string ( ) )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Invalid user in signatures field. " ,
) ) ?
. as_object ( )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Invalid signature. " ,
) ) ?
. clone ( )
. into_iter ( )
{
// Signature validation?
let signature = (
signature . 0 ,
signature
. 1
. as_str ( )
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidParam ,
" Invalid signature value. " ,
) ) ?
. to_owned ( ) ,
) ;
db . users
. sign_key ( & user_id , & key_id , signature , & sender_id , & db . globals ) ? ;
}
}
}
Ok ( upload_signatures ::Response . into ( ) )
}
#[ get( " /_matrix/client/r0/pushers " ) ]
pub fn pushers_route ( ) -> ConduitResult < get_pushers ::Response > {
Ok ( get_pushers ::Response {
pushers : Vec ::new ( ) ,
}
. into ( ) )
}
#[ post( " /_matrix/client/r0/pushers/set " ) ]
pub fn set_pushers_route ( ) -> ConduitResult < get_pushers ::Response > {
Ok ( get_pushers ::Response {
pushers : Vec ::new ( ) ,
}
. into ( ) )
}
2020-07-26 22:33:20 +02:00
#[ put(
" /_matrix/client/r0/user/<_user_id>/rooms/<_room_id>/tags/<_tag> " ,
data = " <body> "
) ]
pub fn update_tag_route (
db : State < '_ , Database > ,
_user_id : String ,
_room_id : String ,
_tag : String ,
body : Ruma < create_tag ::Request > ,
) -> ConduitResult < create_tag ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let mut tags_event = db
. account_data
. get ::< ruma ::events ::tag ::TagEvent > ( Some ( & body . room_id ) , user_id , EventType ::Tag ) ?
. unwrap_or_else ( | | ruma ::events ::tag ::TagEvent {
content : ruma ::events ::tag ::TagEventContent {
tags : BTreeMap ::new ( ) ,
} ,
} ) ;
tags_event
. content
. tags
. insert ( body . tag . to_string ( ) , body . tag_info . clone ( ) ) ;
db . account_data . update (
Some ( & body . room_id ) ,
user_id ,
EventType ::Tag ,
& tags_event ,
& db . globals ,
) ? ;
Ok ( create_tag ::Response . into ( ) )
}
#[ delete(
" /_matrix/client/r0/user/<_user_id>/rooms/<_room_id>/tags/<_tag> " ,
data = " <body> "
) ]
pub fn delete_tag_route (
db : State < '_ , Database > ,
_user_id : String ,
_room_id : String ,
_tag : String ,
body : Ruma < delete_tag ::Request > ,
) -> ConduitResult < delete_tag ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
let mut tags_event = db
. account_data
. get ::< ruma ::events ::tag ::TagEvent > ( Some ( & body . room_id ) , user_id , EventType ::Tag ) ?
. unwrap_or_else ( | | ruma ::events ::tag ::TagEvent {
content : ruma ::events ::tag ::TagEventContent {
tags : BTreeMap ::new ( ) ,
} ,
} ) ;
tags_event . content . tags . remove ( & body . tag ) ;
db . account_data . update (
Some ( & body . room_id ) ,
user_id ,
EventType ::Tag ,
& tags_event ,
& db . globals ,
) ? ;
Ok ( delete_tag ::Response . into ( ) )
}
#[ get(
" /_matrix/client/r0/user/<_user_id>/rooms/<_room_id>/tags " ,
data = " <body> "
) ]
pub fn get_tags_route (
db : State < '_ , Database > ,
_user_id : String ,
_room_id : String ,
body : Ruma < get_tags ::Request > ,
) -> ConduitResult < get_tags ::Response > {
let user_id = body . user_id . as_ref ( ) . expect ( " user is authenticated " ) ;
Ok ( get_tags ::Response {
tags : db
. account_data
. get ::< ruma ::events ::tag ::TagEvent > ( Some ( & body . room_id ) , user_id , EventType ::Tag ) ?
. unwrap_or_else ( | | ruma ::events ::tag ::TagEvent {
content : ruma ::events ::tag ::TagEventContent {
tags : BTreeMap ::new ( ) ,
} ,
} )
. content
. tags ,
}
. into ( ) )
}
2020-04-11 09:30:11 +02:00
#[ options( " /<_segments..> " ) ]
2020-04-29 12:18:45 +02:00
pub fn options_route (
2020-05-03 17:25:31 +02:00
_segments : rocket ::http ::uri ::Segments < '_ > ,
2020-06-09 15:13:17 +02:00
) -> ConduitResult < send_event_to_device ::Response > {
Ok ( send_event_to_device ::Response . into ( ) )
2020-04-19 14:14:47 +02:00
}