diff --git a/src/controllers/users_controller.rs b/src/controllers/users_controller.rs index 513f5720..46843092 100644 --- a/src/controllers/users_controller.rs +++ b/src/controllers/users_controller.rs @@ -318,9 +318,10 @@ pub async fn reset_password_post<'r, 'o: 'r>( if let Some(user) = User::find_by_password_token(form.token.to_owned(), &db).await? { - let changed = user - .change_password(&form.new_password, conf.bcrypt_cost, &db) - .await; + let change = ChangePassword { + password: form.new_password, + }; + let changed = user.change_password(change, conf, &db).await; match changed { Ok(user) => { let body = template!( diff --git a/src/models/user.rs b/src/models/user.rs index 5675d923..4ee6e8fe 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -106,7 +106,7 @@ lazy_static! { pub struct NewUser { #[validate(regex = "NEW_USER_REGEX")] pub username: String, - #[validate(length(min = 8, message = "Password to short"))] + #[validate(length(min = 8, message = "Password too short"))] pub password: String, #[validate(length(min = 3, max = 254))] pub full_name: String, @@ -145,6 +145,12 @@ pub struct ChangeAdmin { pub admin: bool, } +#[derive(Validate, FromForm, Deserialize, Debug, Clone)] +pub struct ChangePassword { + #[validate(length(min = 8, message = "Password too short"))] + pub password: String, +} + impl User { pub async fn all(db: &DbConn) -> Result> { let all_users = @@ -374,11 +380,12 @@ impl User { pub async fn change_password( mut self, - new_password: &str, - bcrypt_cost: u32, + change: ChangePassword, + conf: &Config, db: &DbConn, ) -> Result { - self.hashed_password = hash(new_password, bcrypt_cost)?; + change.validate()?; + self.hashed_password = hash(&change.password, conf.bcrypt_cost)?; self.password_reset_token = None; self.password_reset_expiry = None; self.update(db).await diff --git a/tests/users.rs b/tests/users.rs index 5754fd50..a0a6a801 100644 --- a/tests/users.rs +++ b/tests/users.rs @@ -386,6 +386,28 @@ async fn forgot_password() { "should get reset password page" ); + let short_password = "pw"; + + common::dont_expect_mail(async || { + let response = http_client + .post(format!("/users/reset_password/")) + .header(ContentType::Form) + .header(Accept::HTML) + .body(format!( + "token={}&new_password={}", + &token, &short_password + )) + .dispatch() + .await; + + assert_eq!( + response.status(), + Status::UnprocessableEntity, + "should not accept short password" + ); + }) + .await; + let old_password_hash = user.hashed_password.clone(); let new_password = "passw0rd";