@@ -3,6 +3,7 @@ use actix_web::http::header::{HeaderMap, HeaderValue};
3
3
use actix_web:: http:: { header, StatusCode } ;
4
4
use actix_web:: { web, HttpRequest , HttpResponse , ResponseError } ;
5
5
use anyhow:: Context ;
6
+ use argon2:: { Algorithm , Argon2 , Params , PasswordHash , PasswordVerifier , Version } ;
6
7
use secrecy:: { ExposeSecret , Secret } ;
7
8
use sha3:: Digest ;
8
9
use sqlx:: PgPool ;
@@ -152,21 +153,40 @@ async fn validate_credentials(
152
153
credentials : Credentials ,
153
154
pool : & PgPool ,
154
155
) -> Result < uuid:: Uuid , PublishError > {
155
- let password_hash = sha3:: Sha3_256 :: digest ( credentials. password . expose_secret ( ) . as_bytes ( ) ) ;
156
- let password_hash = format ! ( "{:x}" , password_hash) ;
157
-
158
- let user_id: Option < _ > = sqlx:: query!(
159
- r#"SELECT user_id FROM users WHERE username = $1 AND password_hash = $2"# ,
156
+ let hasher = Argon2 :: new (
157
+ Algorithm :: Argon2id ,
158
+ Version :: V0x13 ,
159
+ Params :: new ( 15000 , 2 , 1 , None )
160
+ . context ( "Failed to build Argon2 params" )
161
+ . map_err ( PublishError :: UnexpectedError ) ?,
162
+ ) ;
163
+
164
+ let row: Option < _ > = sqlx:: query!(
165
+ r#"SELECT user_id, password_hash, salt FROM users WHERE username = $1"# ,
160
166
credentials. username,
161
- password_hash,
162
167
)
163
168
. fetch_optional ( pool)
164
169
. await
165
170
. context ( "Failed to perform the query to validate auth credentials" )
166
171
. map_err ( PublishError :: UnexpectedError ) ?;
167
172
168
- user_id
169
- . map ( |row| row. user_id )
170
- . ok_or_else ( || anyhow:: anyhow!( "Invalid username or password" ) )
171
- . map_err ( PublishError :: AuthError )
173
+ let ( expected_password_hash, user_id, salt) = match row {
174
+ Some ( row) => ( row. password_hash , row. user_id , row. salt ) ,
175
+ None => {
176
+ return Err ( PublishError :: AuthError ( anyhow:: anyhow!(
177
+ "Invalid username or password"
178
+ ) ) )
179
+ }
180
+ } ;
181
+
182
+ let expected_password_hash = PasswordHash :: new ( & expected_password_hash)
183
+ . context ( "Failed to parse hash in PHC string format" )
184
+ . map_err ( PublishError :: UnexpectedError ) ?;
185
+
186
+ Argon2 :: default ( ) . verify_password (
187
+ credentials. password . expose_secret ( ) . as_bytes ( ) ,
188
+ & expected_password_hash,
189
+ ) . context ( "Failed to verify password" ) . map_err ( PublishError :: UnexpectedError ) ?;
190
+
191
+ Ok ( user_id)
172
192
}
0 commit comments