Skip to content

Commit fd2a74f

Browse files
committed
chore: Redefined error message upon failed login
1 parent d1330ea commit fd2a74f

File tree

8 files changed

+187
-183
lines changed

8 files changed

+187
-183
lines changed

Diff for: Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ reqwest = { version = "0.11.18", default-features = false, features = ["json", "
3333
rand = { version = "0.8", features = ["std_rng"] }
3434
thiserror = "1"
3535
anyhow = "1"
36-
base64 = "0.13.0"
3736
argon2 = { version = "0.3", features = ["std"] }
3837
urlencoding = "2"
3938
htmlescape = "0.3"
4039
hmac = { version = "0.12", features = ["std"] }
4140
sha2 = "0.10"
4241
hex = "0.4"
42+
base64 = "0.21.0"
4343

4444
[dev-dependencies]
4545
once_cell = "1"

Diff for: src/authentication.rs

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use anyhow::Context;
2+
use argon2::{Argon2, PasswordHash, PasswordVerifier};
3+
use secrecy::{ExposeSecret, Secret};
4+
use sqlx::PgPool;
5+
6+
use crate::telemetry::spawn_blocking_with_tracing;
7+
8+
#[derive(thiserror::Error, Debug)]
9+
pub enum AuthError {
10+
#[error("Invalid credentials.")]
11+
InvalidCredentials(#[source] anyhow::Error),
12+
#[error(transparent)]
13+
UnexpectedError(#[from] anyhow::Error),
14+
}
15+
16+
pub struct Credentials {
17+
pub username: String,
18+
pub password: Secret<String>,
19+
}
20+
21+
#[tracing::instrument(name = "Get stored credentials", skip(username, pool))]
22+
async fn get_stored_credentials(
23+
username: &str,
24+
pool: &PgPool,
25+
) -> Result<Option<(uuid::Uuid, Secret<String>)>, anyhow::Error> {
26+
let row = sqlx::query!(
27+
r#"
28+
SELECT user_id, password_hash
29+
FROM users
30+
WHERE username = $1
31+
"#,
32+
username,
33+
)
34+
.fetch_optional(pool)
35+
.await
36+
.context("Failed to performed a query to retrieve stored credentials.")?
37+
.map(|row| (row.user_id, Secret::new(row.password_hash)));
38+
Ok(row)
39+
}
40+
41+
#[tracing::instrument(name = "Validate credentials", skip(credentials, pool))]
42+
pub async fn validate_credentials(
43+
credentials: Credentials,
44+
pool: &PgPool,
45+
) -> Result<uuid::Uuid, AuthError> {
46+
let mut user_id = None;
47+
let mut expected_password_hash = Secret::new(
48+
"$argon2id$v=19$m=15000,t=2,p=1$\
49+
gZiV/M1gPc22ElAH/Jh1Hw$\
50+
CWOrkoo7oJBQ/iyh7uJ0LO2aLEfrHwTWllSAxT0zRno"
51+
.to_string(),
52+
);
53+
54+
if let Some((stored_user_id, stored_password_hash)) =
55+
get_stored_credentials(&credentials.username, pool).await?
56+
{
57+
user_id = Some(stored_user_id);
58+
expected_password_hash = stored_password_hash;
59+
}
60+
61+
spawn_blocking_with_tracing(move || {
62+
verify_password_hash(expected_password_hash, credentials.password)
63+
})
64+
.await
65+
.context("Failed to spawn blocking task.")??;
66+
67+
user_id
68+
.ok_or_else(|| anyhow::anyhow!("Unknown username."))
69+
.map_err(AuthError::InvalidCredentials)
70+
}
71+
72+
#[tracing::instrument(
73+
name = "Validate credentials",
74+
skip(expected_password_hash, password_candidate)
75+
)]
76+
fn verify_password_hash(
77+
expected_password_hash: Secret<String>,
78+
password_candidate: Secret<String>,
79+
) -> Result<(), AuthError> {
80+
let expected_password_hash = PasswordHash::new(expected_password_hash.expose_secret())
81+
.context("Failed to parse hash in PHC string format.")?;
82+
83+
Argon2::default()
84+
.verify_password(
85+
password_candidate.expose_secret().as_bytes(),
86+
&expected_password_hash,
87+
)
88+
.context("Invalid password.")
89+
.map_err(AuthError::InvalidCredentials)
90+
}

Diff for: src/configuration.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct ApplicationSettings {
1919
pub port: u16,
2020
pub host: String,
2121
pub base_url: String,
22+
pub hmac_secret: Secret<String>,
2223
}
2324

2425
#[derive(serde::Deserialize, Clone)]

Diff for: src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ pub mod configuration;
33
pub mod domain;
44
pub mod email_client;
55
pub mod routes;
6-
pub mod session_state;
76
pub mod startup;
87
pub mod telemetry;
98
pub mod utils;

0 commit comments

Comments
 (0)