Skip to main content

tuwunel_api/client/account/
change_password.rs

1use axum::extract::State;
2use futures::StreamExt;
3use ruma::api::client::account::change_password;
4use tuwunel_core::{Result, info, utils::ReadyExt};
5
6use crate::{ClientIp, Ruma, router::auth_uiaa};
7
8/// # `POST /_matrix/client/r0/account/password`
9///
10/// Changes the password of this account.
11///
12/// - Requires UIAA to verify user password
13/// - Changes the password of the sender user
14/// - The password hash is calculated using argon2 with 32 character salt, the
15///   plain password is
16/// not saved
17///
18/// If logout_devices is true it does the following for each device except the
19/// sender device:
20/// - Invalidates access token
21/// - Deletes device metadata (device id, device display name, last seen ip,
22///   last seen ts)
23/// - Forgets to-device events
24/// - Triggers device list updates
25#[tracing::instrument(skip_all, fields(%client), name = "change_password")]
26pub(crate) async fn change_password_route(
27	State(services): State<crate::State>,
28	ClientIp(client): ClientIp,
29	body: Ruma<change_password::v3::Request>,
30) -> Result<change_password::v3::Response> {
31	let ref sender_user = auth_uiaa(&services, &body).await?;
32
33	services
34		.users
35		.set_password(sender_user, Some(&body.new_password))
36		.await?;
37
38	if body.logout_devices {
39		// Logout all devices except the current one
40		services
41			.users
42			.all_device_ids(sender_user)
43			.ready_filter(|&id| Some(id) != body.sender_device.as_deref())
44			.for_each(|id| services.users.remove_device(sender_user, id))
45			.await;
46	}
47
48	info!("User {sender_user} changed their password.");
49
50	if services.server.config.admin_room_notices {
51		services
52			.admin
53			.notice(&format!("User {sender_user} changed their password."))
54			.await;
55	}
56
57	Ok(change_password::v3::Response {})
58}