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>next
parent
e809d819ac
commit
67a1f21f5d
|
@ -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 New Issue