settings/security: change password

This commit is contained in:
Philippe Loctaux 2023-04-10 18:58:57 +02:00
parent a67c7559b9
commit b05361510a
7 changed files with 121 additions and 1 deletions

View file

@ -0,0 +1,5 @@
update users
set password = ?
where id is ?

View file

@ -558,6 +558,16 @@
},
"query": "update refresh_tokens\n\nset revoked_at = CURRENT_TIMESTAMP\n\nwhere app is ?\n and revoked_at is null"
},
"9784afe2dcff4db86908175d4e3145baf72b3361f43e4127350a14a183ef63f7": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "update users\n\nset password = ?\n\nwhere id is ?"
},
"9f1885c4786f73335b4d614f562bb7cad49c91bfe7f084d8c25c6c571673ab90": {
"describe": {
"columns": [],

View file

@ -149,4 +149,18 @@ impl Users {
Ok((query.rows_affected() == 1).then_some(()))
}
pub async fn set_password(
conn: impl SqliteExecutor<'_>,
id: &str,
password: Option<&str>,
) -> Result<Option<()>, Error> {
let query: SqliteQueryResult =
sqlx::query_file!("queries/users/set_password.sql", password, id)
.execute(conn)
.await
.map_err(handle_error)?;
Ok((query.rows_affected() == 1).then_some(()))
}
}

View file

@ -14,6 +14,7 @@ pub fn routes() -> Vec<Route> {
user_settings_security,
user_settings_security_logout_everywhere,
user_settings_security_paper_key,
user_settings_security_password,
]
}

View file

@ -176,3 +176,43 @@ pub async fn user_settings_security_paper_key(
flash_message,
))
}
#[derive(Debug, FromForm)]
pub struct PasswordForm<'r> {
pub password: &'r str,
}
#[post("/settings/security/password", data = "<form>")]
pub async fn user_settings_security_password(
mut db: Connection<Database>,
jwt_user: JwtUser,
form: Form<PasswordForm<'_>>,
) -> Result<Flash<Redirect>> {
let (flash_kind, flash_message) = if !form.password.is_empty() {
// Hash password
let password = form.password.to_string();
let password = task::spawn_blocking(move || Password::new(&password)).await??;
let mut transaction = db.begin().await?;
// Get user info
let user = User::get_by_login(&mut transaction, &jwt_user.0.subject)
.await?
.ok_or_else(|| Error::not_found("Could not find user"))?;
// Set password
user.set_password(&mut transaction, Some(&password)).await?;
transaction.commit().await?;
(FlashKind::Success, "Your new password has been saved.")
} else {
(FlashKind::Warning, "Nothing to do.")
};
Ok(Flash::new(
Redirect::to(uri!(user_settings_security)),
flash_kind,
flash_message,
))
}

View file

@ -43,7 +43,7 @@
<div class="mb-4">
<h3 class="card-title">Password</h3>
<div>
<a href="#" class="btn">
<a class="btn" data-bs-toggle="modal" data-bs-target="#modal-password">
Set new password
</a>
</div>
@ -79,6 +79,44 @@
</div>
</div>
<!-- Password modal -->
<div class="modal modal-blur" tabindex="-1" id="modal-password">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-status bg-info"></div>
<div class="modal-header">
<h5 class="modal-title">Set new password</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="./security/password" method="post">
<div class="modal-body py-4">
<div class="mb-2">
<label class="form-label required" for="password">Password</label>
<div class="input-group input-group-flat">
<input id="password" name="password" type="password" class="form-control"
placeholder="Your password"
autocomplete="off" required>
</div>
</div>
</div>
<div class="modal-footer">
<a href="#" class="btn btn-link link-secondary" data-bs-dismiss="modal">
Cancel
</a>
<button type="submit" class="btn btn-primary ms-auto">
Save password
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Paper key modal -->
<div class="modal modal-blur" tabindex="-1" id="modal-paper-key">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">

View file

@ -167,4 +167,16 @@ impl User {
Ok(())
}
pub async fn set_password(
&self,
conn: impl SqliteExecutor<'_>,
password: Option<&Password>,
) -> Result<(), Error> {
let password = password.map(|password| password.hash());
DatabaseUsers::set_password(conn, self.id.as_ref(), password).await?;
Ok(())
}
}