Error handling refactor and 500 page/message templates
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
use crate::{
|
||||
routes::{AdminError, AppError},
|
||||
session_state::TypedSession,
|
||||
telemetry::spawn_blocking_with_tracing,
|
||||
routes::AdminError, session_state::TypedSession, telemetry::spawn_blocking_with_tracing,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use argon2::{
|
||||
@@ -24,8 +22,6 @@ pub enum AuthError {
|
||||
UnexpectedError(#[from] anyhow::Error),
|
||||
#[error("Invalid credentials.")]
|
||||
InvalidCredentials(#[source] anyhow::Error),
|
||||
#[error("Not authenticated.")]
|
||||
NotAuthenticated,
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Change password", skip(password, connection_pool))]
|
||||
@@ -36,7 +32,7 @@ pub async fn change_password(
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let password_hash = spawn_blocking_with_tracing(move || compute_pasword_hash(password))
|
||||
.await?
|
||||
.context("Failed to hash password")?;
|
||||
.context("Failed to hash password.")?;
|
||||
sqlx::query!(
|
||||
"UPDATE users SET password_hash = $1 WHERE user_id = $2",
|
||||
password_hash.expose_secret(),
|
||||
@@ -75,23 +71,30 @@ gZiV/M1gPc22ElAH/Jh1Hw$\
|
||||
CWOrkoo7oJBQ/iyh7uJ0LO2aLEfrHwTWllSAxT0zRno"
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
if let Some((stored_user_id, stored_expected_password_hash)) =
|
||||
get_stored_credentials(&username, connection_pool)
|
||||
.await
|
||||
.context("Failed to retrieve credentials from database.")
|
||||
.map_err(AuthError::UnexpectedError)?
|
||||
{
|
||||
user_id = Some(stored_user_id);
|
||||
expected_password_hash = stored_expected_password_hash;
|
||||
}
|
||||
|
||||
spawn_blocking_with_tracing(|| verify_password_hash(expected_password_hash, password))
|
||||
let handle =
|
||||
spawn_blocking_with_tracing(|| verify_password_hash(expected_password_hash, password));
|
||||
|
||||
let uuid = user_id
|
||||
.ok_or_else(|| anyhow::anyhow!("Unknown username."))
|
||||
.map_err(AuthError::InvalidCredentials)?;
|
||||
|
||||
handle
|
||||
.await
|
||||
.context("Failed to spawn blocking task.")
|
||||
.map_err(AuthError::UnexpectedError)??;
|
||||
|
||||
user_id
|
||||
.ok_or_else(|| anyhow::anyhow!("Unknown username."))
|
||||
.map_err(AuthError::UnexpectedError)?
|
||||
.map_err(AuthError::InvalidCredentials)
|
||||
.map(|_| uuid)
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
@@ -101,7 +104,7 @@ CWOrkoo7oJBQ/iyh7uJ0LO2aLEfrHwTWllSAxT0zRno"
|
||||
fn verify_password_hash(
|
||||
expected_password_hash: SecretString,
|
||||
password_candidate: SecretString,
|
||||
) -> Result<(), AuthError> {
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let expected_password_hash = PasswordHash::new(expected_password_hash.expose_secret())
|
||||
.context("Failed to parse hash in PHC string format.")?;
|
||||
Argon2::default()
|
||||
@@ -110,14 +113,13 @@ fn verify_password_hash(
|
||||
&expected_password_hash,
|
||||
)
|
||||
.context("Password verification failed.")
|
||||
.map_err(AuthError::InvalidCredentials)
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "Get stored credentials", skip(username, connection_pool))]
|
||||
async fn get_stored_credentials(
|
||||
username: &str,
|
||||
connection_pool: &PgPool,
|
||||
) -> Result<Option<(Uuid, SecretString)>, anyhow::Error> {
|
||||
) -> Result<Option<(Uuid, SecretString)>, sqlx::Error> {
|
||||
let row = sqlx::query!(
|
||||
r#"
|
||||
SELECT user_id, password_hash
|
||||
@@ -127,8 +129,7 @@ async fn get_stored_credentials(
|
||||
username,
|
||||
)
|
||||
.fetch_optional(connection_pool)
|
||||
.await
|
||||
.context("Failed to perform a query to retrieve stored credentials.")?
|
||||
.await?
|
||||
.map(|row| (row.user_id, SecretString::from(row.password_hash)));
|
||||
Ok(row)
|
||||
}
|
||||
@@ -137,7 +138,7 @@ pub async fn require_auth(
|
||||
session: TypedSession,
|
||||
mut request: Request,
|
||||
next: Next,
|
||||
) -> Result<Response, AppError> {
|
||||
) -> Result<Response, AdminError> {
|
||||
let user_id = session
|
||||
.get_user_id()
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user