2021-07-14 07:07:08 +00:00
use super ::{ DEVICE_ID_LENGTH , SESSION_ID_LENGTH , TOKEN_LENGTH };
2022-10-05 20:34:31 +02:00
use crate ::{ api ::client_server , services , utils , Error , Result , Ruma };
2020-07-30 18:14:47 +02:00
use ruma ::{
api ::client ::{
2022-02-18 15:33:14 +01:00
account ::{
2022-10-25 20:47:41 +00:00
change_password , deactivate , get_3pids , get_username_availability , register ,
2022-10-30 20:36:14 +01:00
request_3pid_management_token_via_email , request_3pid_management_token_via_msisdn ,
whoami , ThirdPartyIdRemovalStatus ,
2020-07-30 18:14:47 +02:00
},
2022-02-18 15:33:14 +01:00
error ::ErrorKind ,
uiaa ::{ AuthFlow , AuthType , UiaaInfo },
2020-07-30 18:14:47 +02:00
},
2022-10-08 13:03:07 +02:00
events ::{ room ::message ::RoomMessageEventContent , GlobalAccountDataEventType },
2022-02-03 20:52:41 +02:00
push , UserId ,
2020-07-30 18:14:47 +02:00
};
2023-12-22 18:31:15 -05:00
use tracing ::{ info , warn };
2020-07-30 18:14:47 +02:00
2020-08-22 21:19:14 +02:00
use register ::RegistrationKind ;
2020-07-30 18:14:47 +02:00
2022-06-18 11:13:37 +00:00
const RANDOM_USER_ID_LENGTH : usize = 10 ;
2020-07-30 18:14:47 +02:00
2020-07-31 14:40:28 +02:00
/// # `GET /_matrix/client/r0/register/available`
///
/// Checks if a username is valid and available on this server.
///
2021-08-31 19:14:37 +02:00
/// Conditions for returning true:
/// - The user id is not historical
/// - The server name of the user id matches this server
/// - No user or appservice on this server already claimed this username
///
/// Note: This will not reserve the username, so the username might become invalid when trying to register
2020-10-21 21:28:02 +02:00
pub async fn get_register_available_route (
2022-12-14 13:09:10 +01:00
body : Ruma < get_username_availability ::v3 ::Request > ,
2022-02-18 15:33:14 +01:00
) -> Result < get_username_availability ::v3 ::Response > {
2020-07-30 18:14:47 +02:00
// Validate user id
2022-10-05 20:34:31 +02:00
let user_id = UserId ::parse_with_server_name (
body . username . to_lowercase (),
services (). globals . server_name (),
)
. ok ()
. filter ( | user_id | {
! user_id . is_historical () && user_id . server_name () == services (). globals . server_name ()
})
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidUsername ,
"Username is invalid." ,
)) ? ;
2020-07-30 18:14:47 +02:00
// Check if username is creative enough
2022-09-06 23:15:09 +02:00
if services (). users . exists ( & user_id ) ? {
2020-07-30 18:14:47 +02:00
return Err ( Error ::BadRequest (
ErrorKind ::UserInUse ,
"Desired user ID is already taken." ,
));
}
// TODO add check for appservice namespaces
// If no if check is true we have an username that's available to be used.
2022-02-18 15:33:14 +01:00
Ok ( get_username_availability ::v3 ::Response { available : true })
2020-07-30 18:14:47 +02:00
}
2020-08-18 12:43:27 +02:00
/// # `POST /_matrix/client/r0/register`
2020-07-31 14:40:28 +02:00
///
/// Register an account on this homeserver.
///
2021-08-31 19:14:37 +02:00
/// You can use [`GET /_matrix/client/r0/register/available`](fn.get_register_available_route.html)
/// to check if the user id is valid and available.
///
/// - Only works if registration is enabled
/// - If type is guest: ignores all parameters except initial_device_display_name
/// - If sender is not appservice: Requires UIAA (but we only use a dummy stage)
/// - If type is not guest and no username is given: Always fails after UIAA check
/// - Creates a new account and populates it with default account data
/// - If `inhibit_login` is false: Creates a device and returns device id and access_token
2022-12-14 13:09:10 +01:00
pub async fn register_route ( body : Ruma < register ::v3 ::Request > ) -> Result < register ::v3 ::Response > {
2023-08-09 18:27:30 +02:00
if ! services (). globals . allow_registration ()
&& ! body . from_appservice
&& services (). globals . config . registration_token . is_none ()
{
2023-12-21 20:46:24 -05:00
info! ( "Registration disabled, no reg token configured, rejecting registration attempt for username {:?}" , body . username );
2020-07-30 18:14:47 +02:00
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
"Registration has been disabled." ,
));
}
2020-09-08 17:32:03 +02:00
let is_guest = body . kind == RegistrationKind ::Guest ;
2020-08-22 21:19:14 +02:00
2023-12-21 20:44:58 -05:00
if is_guest
&& ( ! services (). globals . allow_guest_registration ()
2023-12-21 21:39:49 -05:00
|| ( ! services (). globals . allow_registration ()
&& services (). globals . config . registration_token . is_some ()))
2023-12-21 20:44:58 -05:00
{
2023-12-21 21:39:49 -05:00
info! ( "Guest registration disabled / registration disabled with token configured, rejecting guest registration, initial device name: {:?}" , body . initial_device_display_name );
2023-12-21 20:44:58 -05:00
return Err ( Error ::BadRequest (
ErrorKind ::GuestAccessForbidden ,
"Guest registration is disabled." ,
));
}
2023-12-21 21:16:56 -05:00
// forbid guests from registering if there is not a real admin user yet. give generic user error.
if is_guest && services (). users . count () ? < 2 {
warn! ( "Guest account attempted to register before a real admin user has been registered, rejecting registration. Guest's initial device name: {:?}" , body . initial_device_display_name );
return Err ( Error ::BadRequest (
ErrorKind ::Forbidden ,
"Registration temporarily disabled." ,
));
}
2022-06-18 11:13:37 +00:00
let user_id = match ( & body . username , is_guest ) {
( Some ( username ), false ) => {
2022-10-05 20:34:31 +02:00
let proposed_user_id = UserId ::parse_with_server_name (
username . to_lowercase (),
services (). globals . server_name (),
)
. ok ()
. filter ( | user_id | {
! user_id . is_historical ()
&& user_id . server_name () == services (). globals . server_name ()
})
. ok_or ( Error ::BadRequest (
ErrorKind ::InvalidUsername ,
"Username is invalid." ,
)) ? ;
2022-09-06 23:15:09 +02:00
if services (). users . exists ( & proposed_user_id ) ? {
2022-06-18 11:13:37 +00:00
return Err ( Error ::BadRequest (
ErrorKind ::UserInUse ,
"Desired user ID is already taken." ,
));
}
proposed_user_id
2020-08-22 21:19:14 +02:00
}
2022-06-18 11:13:37 +00:00
_ => loop {
let proposed_user_id = UserId ::parse_with_server_name (
utils ::random_string ( RANDOM_USER_ID_LENGTH ). to_lowercase (),
2022-09-06 23:15:09 +02:00
services (). globals . server_name (),
2022-06-18 11:13:37 +00:00
)
. unwrap ();
2022-09-06 23:15:09 +02:00
if ! services (). users . exists ( & proposed_user_id ) ? {
2022-06-18 11:13:37 +00:00
break proposed_user_id ;
}
},
};
2020-07-30 18:14:47 +02:00
// UIAA
let mut uiaainfo = UiaaInfo {
flows : vec ! [ AuthFlow {
2023-08-09 18:27:30 +02:00
stages : if services (). globals . config . registration_token . is_some () {
vec! [ AuthType ::RegistrationToken ]
} else {
vec! [ AuthType ::Dummy ]
},
2020-07-30 18:14:47 +02:00
}],
completed : Vec ::new (),
params : Default ::default (),
session : None ,
auth_error : None ,
};
2023-03-07 17:58:55 +01:00
if ! body . from_appservice && ! is_guest {
2020-12-08 10:33:44 +01:00
if let Some ( auth ) = & body . auth {
2022-09-06 23:15:09 +02:00
let ( worked , uiaainfo ) = services (). uiaa . try_auth (
& UserId ::parse_with_server_name ( "" , services (). globals . server_name ())
2021-05-04 19:03:18 +02:00
. expect ( "we know this is valid" ),
"" . into (),
auth ,
& uiaainfo ,
) ? ;
2020-12-08 10:33:44 +01:00
if ! worked {
return Err ( Error ::Uiaa ( uiaainfo ));
}
// Success!
2021-07-14 12:31:38 +02:00
} else if let Some ( json ) = body . json_body {
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ));
2022-09-06 23:15:09 +02:00
services (). uiaa . create (
& UserId ::parse_with_server_name ( "" , services (). globals . server_name ())
2021-07-14 12:31:38 +02:00
. expect ( "we know this is valid" ),
"" . into (),
& uiaainfo ,
& json ,
) ? ;
return Err ( Error ::Uiaa ( uiaainfo ));
2020-12-08 10:33:44 +01:00
} else {
2021-07-14 12:31:38 +02:00
return Err ( Error ::BadRequest ( ErrorKind ::NotJson , "Not json." ));
2020-07-30 18:14:47 +02:00
}
}
2020-08-22 21:19:14 +02:00
let password = if is_guest {
None
} else {
2021-05-30 21:55:43 +02:00
body . password . as_deref ()
};
2020-07-30 18:14:47 +02:00
// Create user
2022-09-06 23:15:09 +02:00
services (). users . create ( & user_id , password ) ? ;
2020-07-30 18:14:47 +02:00
2021-08-31 19:14:37 +02:00
// Default to pretty displayname
2022-06-23 06:58:34 +00:00
let mut displayname = user_id . localpart (). to_owned ();
// If enabled append lightning bolt to display name (default true)
if services (). globals . enable_lightning_bolt () {
displayname . push_str ( " ⚡️" );
}
2022-10-05 20:34:31 +02:00
services ()
. users
2024-01-14 01:42:37 -05:00
. set_displayname ( & user_id , Some ( displayname . clone ()))
. await ? ;
2021-08-10 05:43:44 +00:00
2021-08-31 19:14:37 +02:00
// Initial account data
2022-09-06 23:15:09 +02:00
services (). account_data . update (
2020-07-30 20:49:29 +02:00
None ,
& user_id ,
2022-04-06 21:31:29 +02:00
GlobalAccountDataEventType ::PushRules . to_string (). into (),
2022-10-05 15:33:57 +02:00
& serde_json ::to_value ( ruma ::events ::push_rules ::PushRulesEvent {
2020-07-30 20:49:29 +02:00
content : ruma ::events ::push_rules ::PushRulesEventContent {
2021-04-05 21:25:10 +02:00
global : push ::Ruleset ::server_default ( & user_id ),
2020-07-30 20:49:29 +02:00
},
2022-10-05 20:34:31 +02:00
})
. expect ( "to json always works" ),
2020-07-30 20:49:29 +02:00
) ? ;
2021-08-31 19:14:37 +02:00
// Inhibit login does not work for guests
2020-08-22 21:19:14 +02:00
if ! is_guest && body . inhibit_login {
2022-02-18 15:33:14 +01:00
return Ok ( register ::v3 ::Response {
2020-07-30 20:49:29 +02:00
access_token : None ,
user_id ,
device_id : None ,
2022-10-09 17:25:06 +02:00
refresh_token : None ,
expires_in : None ,
2022-01-22 16:58:32 +01:00
});
2020-07-30 20:49:29 +02:00
}
2020-07-30 18:14:47 +02:00
// Generate new device id if the user didn't specify one
2020-08-22 21:19:14 +02:00
let device_id = if is_guest {
None
} else {
body . device_id . clone ()
}
. unwrap_or_else ( || utils ::random_string ( DEVICE_ID_LENGTH ). into ());
2020-07-30 18:14:47 +02:00
// Generate new token for the device
let token = utils ::random_string ( TOKEN_LENGTH );
2021-08-31 19:14:37 +02:00
// Create device for this account
2022-09-06 23:15:09 +02:00
services (). users . create_device (
2020-07-30 18:14:47 +02:00
& user_id ,
& device_id ,
& token ,
body . initial_device_display_name . clone (),
) ? ;
2023-12-21 20:46:24 -05:00
info! ( "New user \" {} \" registered on this server." , user_id );
// log in conduit admin channel if a non-guest user registered
2023-08-09 18:27:30 +02:00
if ! body . from_appservice && ! is_guest {
services ()
. admin
. send_message ( RoomMessageEventContent ::notice_plain ( format! (
2023-12-21 20:46:24 -05:00
"New user \" {user_id} \" registered on this server."
2023-08-09 18:27:30 +02:00
)));
}
2020-10-05 22:19:22 +02:00
2023-12-21 20:46:24 -05:00
// log in conduit admin channel if a guest registered
if ! body . from_appservice && is_guest {
services ()
. admin
. send_message ( RoomMessageEventContent ::notice_plain ( format! (
"Guest user \" {user_id} \" with device display name ` {:?} ` registered on this server." ,
body . initial_device_display_name
)));
}
// If this is the first real user, grant them admin privileges except for guest users
2022-02-03 20:52:41 +02:00
// Note: the server user, @conduit:servername, is generated first
2023-12-21 20:46:24 -05:00
if services (). users . count () ? == 2 && ! is_guest {
2022-10-05 20:34:31 +02:00
services ()
. admin
. make_user_admin ( & user_id , displayname )
. await ? ;
2020-10-23 14:35:41 +02:00
2022-02-03 20:52:41 +02:00
warn! ( "Granting {} admin privileges as the first user" , user_id );
2020-10-05 22:19:22 +02:00
}
2022-02-18 15:33:14 +01:00
Ok ( register ::v3 ::Response {
2020-07-30 18:14:47 +02:00
access_token : Some ( token ),
user_id ,
device_id : Some ( device_id ),
2022-10-09 17:25:06 +02:00
refresh_token : None ,
expires_in : None ,
2022-01-22 16:58:32 +01:00
})
2020-07-30 18:14:47 +02:00
}
2020-07-31 14:40:28 +02:00
/// # `POST /_matrix/client/r0/account/password`
///
/// Changes the password of this account.
///
2021-08-31 19:14:37 +02:00
/// - Requires UIAA to verify user password
/// - Changes the password of the sender user
/// - The password hash is calculated using argon2 with 32 character salt, the plain password is
/// not saved
///
/// If logout_devices is true it does the following for each device except the sender device:
/// - Invalidates access token
/// - Deletes device metadata (device id, device display name, last seen ip, last seen ts)
/// - Forgets to-device events
/// - Triggers device list updates
2020-10-21 21:28:02 +02:00
pub async fn change_password_route (
2022-12-14 13:09:10 +01:00
body : Ruma < change_password ::v3 ::Request > ,
2022-02-18 15:33:14 +01:00
) -> Result < change_password ::v3 ::Response > {
2020-10-18 20:33:12 +02:00
let sender_user = body . sender_user . as_ref (). expect ( "user is authenticated" );
let sender_device = body . sender_device . as_ref (). expect ( "user is authenticated" );
2020-07-30 18:14:47 +02:00
let mut uiaainfo = UiaaInfo {
flows : vec ! [ AuthFlow {
2021-10-13 10:16:45 +02:00
stages : vec ! [ AuthType ::Password ],
2020-07-30 18:14:47 +02:00
}],
completed : Vec ::new (),
params : Default ::default (),
session : None ,
auth_error : None ,
};
if let Some ( auth ) = & body . auth {
2022-10-05 20:34:31 +02:00
let ( worked , uiaainfo ) =
services ()
. uiaa
. try_auth ( sender_user , sender_device , auth , & uiaainfo ) ? ;
2020-07-30 18:14:47 +02:00
if ! worked {
return Err ( Error ::Uiaa ( uiaainfo ));
}
// Success!
2021-07-14 12:31:38 +02:00
} else if let Some ( json ) = body . json_body {
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ));
2022-10-05 20:34:31 +02:00
services ()
. uiaa
2021-09-13 19:45:56 +02:00
. create ( sender_user , sender_device , & uiaainfo , & json ) ? ;
2021-07-14 12:31:38 +02:00
return Err ( Error ::Uiaa ( uiaainfo ));
2020-07-30 18:14:47 +02:00
} else {
2021-07-14 12:31:38 +02:00
return Err ( Error ::BadRequest ( ErrorKind ::NotJson , "Not json." ));
2020-07-30 18:14:47 +02:00
}
2022-10-05 20:34:31 +02:00
services ()
. users
2021-09-13 19:45:56 +02:00
. set_password ( sender_user , Some ( & body . new_password )) ? ;
2020-07-30 18:14:47 +02:00
2021-01-16 14:48:24 -07:00
if body . logout_devices {
// Logout all devices except the current one
2022-09-06 23:15:09 +02:00
for id in services ()
2021-01-16 14:48:24 -07:00
. users
2021-09-13 19:45:56 +02:00
. all_device_ids ( sender_user )
2021-01-16 14:48:24 -07:00
. filter_map ( | id | id . ok ())
. filter ( | id | id != sender_device )
{
2022-09-06 23:15:09 +02:00
services (). users . remove_device ( sender_user , & id ) ? ;
2021-01-16 14:48:24 -07:00
}
2020-07-30 18:14:47 +02:00
}
2022-02-22 00:02:01 +01:00
info! ( "User {} changed their password." , sender_user );
2022-10-05 20:34:31 +02:00
services ()
. admin
2022-02-22 00:02:01 +01:00
. send_message ( RoomMessageEventContent ::notice_plain ( format! (
2022-12-21 10:42:12 +01:00
"User {sender_user} changed their password."
2022-02-22 00:02:01 +01:00
)));
2022-02-18 15:33:14 +01:00
Ok ( change_password ::v3 ::Response {})
2020-07-30 18:14:47 +02:00
}
2020-07-31 14:40:28 +02:00
/// # `GET _matrix/client/r0/account/whoami`
///
2021-08-31 19:14:37 +02:00
/// Get user_id of the sender user.
2020-07-31 14:40:28 +02:00
///
2021-08-31 19:14:37 +02:00
/// Note: Also works for Application Services
2022-10-05 20:34:31 +02:00
pub async fn whoami_route ( body : Ruma < whoami ::v3 ::Request > ) -> Result < whoami ::v3 ::Response > {
2020-10-18 20:33:12 +02:00
let sender_user = body . sender_user . as_ref (). expect ( "user is authenticated" );
2022-03-05 10:16:21 +08:00
let device_id = body . sender_device . as_ref (). cloned ();
2022-04-06 18:49:46 +02:00
2022-02-18 15:33:14 +01:00
Ok ( whoami ::v3 ::Response {
2020-10-18 20:33:12 +02:00
user_id : sender_user . clone (),
2022-03-05 10:16:21 +08:00
device_id ,
2022-10-15 13:17:58 +02:00
is_guest : services (). users . is_deactivated ( sender_user ) ? && ! body . from_appservice ,
2022-01-22 16:58:32 +01:00
})
2020-07-30 18:14:47 +02:00
}
2020-07-31 14:40:28 +02:00
/// # `POST /_matrix/client/r0/account/deactivate`
///
2021-08-31 19:14:37 +02:00
/// Deactivate sender user account.
2020-07-31 14:40:28 +02:00
///
/// - Leaves all rooms and rejects all invitations
/// - Invalidates all access tokens
2021-08-31 19:14:37 +02:00
/// - Deletes all device metadata (device id, device display name, last seen ip, last seen ts)
/// - Forgets all to-device events
/// - Triggers device list updates
2020-07-31 14:40:28 +02:00
/// - Removes ability to log in again
2020-09-14 20:23:19 +02:00
pub async fn deactivate_route (
2022-12-14 13:09:10 +01:00
body : Ruma < deactivate ::v3 ::Request > ,
2022-02-18 15:33:14 +01:00
) -> Result < deactivate ::v3 ::Response > {
2020-10-18 20:33:12 +02:00
let sender_user = body . sender_user . as_ref (). expect ( "user is authenticated" );
let sender_device = body . sender_device . as_ref (). expect ( "user is authenticated" );
2020-07-30 18:14:47 +02:00
let mut uiaainfo = UiaaInfo {
flows : vec ! [ AuthFlow {
2021-10-13 10:16:45 +02:00
stages : vec ! [ AuthType ::Password ],
2020-07-30 18:14:47 +02:00
}],
completed : Vec ::new (),
params : Default ::default (),
session : None ,
auth_error : None ,
};
if let Some ( auth ) = & body . auth {
2022-10-05 20:34:31 +02:00
let ( worked , uiaainfo ) =
services ()
. uiaa
. try_auth ( sender_user , sender_device , auth , & uiaainfo ) ? ;
2020-07-30 18:14:47 +02:00
if ! worked {
return Err ( Error ::Uiaa ( uiaainfo ));
}
// Success!
2021-07-14 12:31:38 +02:00
} else if let Some ( json ) = body . json_body {
uiaainfo . session = Some ( utils ::random_string ( SESSION_ID_LENGTH ));
2022-10-05 20:34:31 +02:00
services ()
. uiaa
2021-09-13 19:45:56 +02:00
. create ( sender_user , sender_device , & uiaainfo , & json ) ? ;
2021-07-14 12:31:38 +02:00
return Err ( Error ::Uiaa ( uiaainfo ));
2020-07-30 18:14:47 +02:00
} else {
2021-07-14 12:31:38 +02:00
return Err ( Error ::BadRequest ( ErrorKind ::NotJson , "Not json." ));
2020-07-30 18:14:47 +02:00
}
2022-04-02 14:00:19 +02:00
// Make the user leave all rooms before deactivation
2022-10-10 14:09:11 +02:00
client_server ::leave_all_rooms ( sender_user ). await ? ;
2020-07-30 18:14:47 +02:00
// Remove devices and mark account as deactivated
2022-09-06 23:15:09 +02:00
services (). users . deactivate_account ( sender_user ) ? ;
2020-07-30 18:14:47 +02:00
2022-02-22 00:02:01 +01:00
info! ( "User {} deactivated their account." , sender_user );
2022-10-05 20:34:31 +02:00
services ()
. admin
2022-02-22 00:02:01 +01:00
. send_message ( RoomMessageEventContent ::notice_plain ( format! (
2022-12-21 10:42:12 +01:00
"User {sender_user} deactivated their account."
2022-02-22 00:02:01 +01:00
)));
2020-11-15 12:17:21 +01:00
2022-02-18 15:33:14 +01:00
Ok ( deactivate ::v3 ::Response {
2020-07-30 18:14:47 +02:00
id_server_unbind_result : ThirdPartyIdRemovalStatus ::NoSupport ,
2022-01-22 16:58:32 +01:00
})
2020-07-30 18:14:47 +02:00
}
2021-01-26 21:54:35 -05:00
2022-10-25 20:47:41 +00:00
/// # `GET _matrix/client/v3/account/3pid`
2021-08-09 12:29:35 -07:00
///
/// Get a list of third party identifiers associated with this account.
2021-08-31 19:14:37 +02:00
///
/// - Currently always returns empty list
2022-02-18 15:33:14 +01:00
pub async fn third_party_route (
body : Ruma < get_3pids ::v3 ::Request > ,
) -> Result < get_3pids ::v3 ::Response > {
2021-08-17 16:06:09 +02:00
let _sender_user = body . sender_user . as_ref (). expect ( "user is authenticated" );
2021-01-26 21:54:35 -05:00
2022-02-18 15:33:14 +01:00
Ok ( get_3pids ::v3 ::Response ::new ( Vec ::new ()))
2021-01-26 21:54:35 -05:00
}
2022-10-25 20:47:41 +00:00
/// # `POST /_matrix/client/v3/account/3pid/email/requestToken`
///
/// "This API should be used to request validation tokens when adding an email address to an account"
///
/// - 403 signals that The homeserver does not allow the third party identifier as a contact option.
pub async fn request_3pid_management_token_via_email_route (
2022-12-14 13:09:10 +01:00
_body : Ruma < request_3pid_management_token_via_email ::v3 ::Request > ,
2022-10-25 20:47:41 +00:00
) -> Result < request_3pid_management_token_via_email ::v3 ::Response > {
Err ( Error ::BadRequest (
ErrorKind ::ThreepidDenied ,
"Third party identifier is not allowed" ,
))
}
/// # `POST /_matrix/client/v3/account/3pid/msisdn/requestToken`
///
/// "This API should be used to request validation tokens when adding an phone number to an account"
///
/// - 403 signals that The homeserver does not allow the third party identifier as a contact option.
pub async fn request_3pid_management_token_via_msisdn_route (
2022-12-14 13:09:10 +01:00
_body : Ruma < request_3pid_management_token_via_msisdn ::v3 ::Request > ,
2022-10-25 20:47:41 +00:00
) -> Result < request_3pid_management_token_via_msisdn ::v3 ::Response > {
Err ( Error ::BadRequest (
ErrorKind ::ThreepidDenied ,
"Third party identifier is not allowed" ,
))
}