@@ -103,6 +103,14 @@ pub struct RequestBody {
103103
104104 #[ serde( default ) ]
105105 refresh_token : bool ,
106+
107+ /// ID of the client device.
108+ /// If this does not correspond to a known client device, a new device will
109+ /// be created. The given device ID must not be the same as a
110+ /// cross-signing key ID. The server will auto-generate a device_id if
111+ /// this is not specified.
112+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
113+ device_id : Option < String > ,
106114}
107115
108116#[ derive( Debug , Serialize , Deserialize ) ]
@@ -310,6 +318,7 @@ pub(crate) async fn post(
310318 & homeserver,
311319 user,
312320 password,
321+ input. device_id , // TODO check for validity
313322 )
314323 . await ?
315324 }
@@ -446,6 +455,7 @@ async fn user_password_login(
446455 homeserver : & dyn HomeserverConnection ,
447456 username : String ,
448457 password : String ,
458+ requested_device_id : Option < String > ,
449459) -> Result < ( CompatSession , User ) , RouteError > {
450460 // Try getting the localpart out of the MXID
451461 let username = homeserver. localpart ( & username) . unwrap_or ( & username) ;
@@ -498,9 +508,14 @@ async fn user_password_login(
498508 // Lock the user sync to make sure we don't get into a race condition
499509 repo. user ( ) . acquire_lock_for_sync ( & user) . await ?;
500510
501- // Now that the user credentials have been verified, start a new compat session
502- let device = Device :: generate ( & mut rng) ;
503511 let mxid = homeserver. mxid ( & user. username ) ;
512+
513+ // Now that the user credentials have been verified, start a new compat session
514+ let device = if let Some ( requested_device_id) = requested_device_id {
515+ Device :: from ( requested_device_id)
516+ } else {
517+ Device :: generate ( & mut rng)
518+ } ;
504519 homeserver
505520 . create_device ( & mxid, device. as_str ( ) )
506521 . await
0 commit comments