feat: implement password changing (#138)
Password: Fixes Password: Implement logging out all devices except current Password: Implement password changing Co-authored-by: the0 <theo@localhost> Reviewed-on: https://git.koesters.xyz/timo/conduit/pulls/138 Reviewed-by: Timo Kösters <timo@koesters.xyz>
This commit is contained in:
		
							parent
							
								
									e809d819ac
								
							
						
					
					
						commit
						67a1f21f5d
					
				
					 3 changed files with 67 additions and 1 deletions
				
			
		|  | @ -12,7 +12,7 @@ use ruma::{ | |||
|     api::client::{ | ||||
|         error::ErrorKind, | ||||
|         r0::{ | ||||
|             account::{get_username_availability, register}, | ||||
|             account::{change_password, get_username_availability, register}, | ||||
|             alias::{create_alias, delete_alias, get_alias}, | ||||
|             backup::{ | ||||
|                 add_backup_keys, create_backup, get_backup, get_backup_keys, get_latest_backup, | ||||
|  | @ -305,6 +305,58 @@ pub fn logout_route( | |||
|     Ok(logout::Response.into()) | ||||
| } | ||||
| 
 | ||||
| #[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"); | ||||
|     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)); | ||||
|         } | ||||
|     } 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()) | ||||
| } | ||||
| 
 | ||||
| #[get("/_matrix/client/r0/capabilities")] | ||||
| pub fn get_capabilities_route() -> ConduitResult<get_capabilities::Response> { | ||||
|     let mut available = BTreeMap::new(); | ||||
|  |  | |||
|  | @ -93,6 +93,19 @@ impl Users { | |||
|             }) | ||||
|     } | ||||
| 
 | ||||
|     /// Hash and set the user's password to the Argon2 hash
 | ||||
|     pub fn set_password(&self, user_id: &UserId, password: &str) -> Result<()> { | ||||
|         if let Ok(hash) = utils::calculate_hash(&password) { | ||||
|             self.userid_password.insert(user_id.to_string(), &*hash)?; | ||||
|         } else { | ||||
|             return Err(Error::BadRequest( | ||||
|                 ErrorKind::InvalidParam, | ||||
|                 "Password does not meet the requirements.", | ||||
|             )); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the displayname of a user on this homeserver.
 | ||||
|     pub fn displayname(&self, user_id: &UserId) -> Result<Option<String>> { | ||||
|         self.userid_displayname | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ fn setup_rocket() -> rocket::Rocket { | |||
|                 client_server::get_login_route, | ||||
|                 client_server::login_route, | ||||
|                 client_server::logout_route, | ||||
|                 client_server::change_password_route, | ||||
|                 client_server::get_capabilities_route, | ||||
|                 client_server::get_pushrules_all_route, | ||||
|                 client_server::set_pushrule_route, | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue