use crate::{ authentication::{self, AuthenticatedUser, Credentials, validate_credentials}, routes::AdminError, startup::AppState, }; use axum::{ Extension, Form, extract::State, response::{IntoResponse, Redirect, Response}, }; use axum_messages::Messages; use secrecy::{ExposeSecret, SecretString}; #[derive(serde::Deserialize)] pub struct PasswordFormData { pub current_password: SecretString, pub new_password: SecretString, pub new_password_check: SecretString, } pub async fn change_password( Extension(AuthenticatedUser { user_id, username }): Extension, State(AppState { connection_pool, .. }): State, messages: Messages, Form(form): Form, ) -> Result { let credentials = Credentials { username, password: form.current_password, }; if form.new_password.expose_secret() != form.new_password_check.expose_secret() { messages.error("You entered two different passwords - the field values must match."); Err(AdminError::ChangePassword) } else if validate_credentials(credentials, &connection_pool) .await .is_err() { messages.error("The current password is incorrect."); Err(AdminError::ChangePassword) } else if let Err(e) = verify_password(form.new_password.expose_secret()) { messages.error(e); Err(AdminError::ChangePassword) } else { authentication::change_password(user_id, form.new_password, &connection_pool) .await .map_err(|_| AdminError::ChangePassword)?; messages.success("Your password has been changed."); Ok(Redirect::to("/admin/password").into_response()) } } fn verify_password(password: &str) -> Result<(), String> { if password.len() < 12 || password.len() > 128 { return Err("The password must contain between 12 and 128 characters.".into()); } Ok(()) }