Added hashing
All checks were successful
Rust Build / Check (pull_request) Successful in 1m24s
Rust Build / Test Suite (pull_request) Successful in 1m38s
Rust Build / Rustfmt (pull_request) Successful in 26s
Rust Build / Clippy (pull_request) Successful in 1m21s
Rust Build / build (pull_request) Successful in 2m40s

This commit is contained in:
2025-04-05 11:55:12 -04:00
parent 7644d7c2d8
commit b45a0475ed
3 changed files with 59 additions and 9 deletions

View File

@@ -1,5 +1,6 @@
use axum::{Json, http::StatusCode}; use axum::{Json, http::StatusCode};
use crate::hashing;
use crate::repo; use crate::repo;
pub mod request { pub mod request {
@@ -48,6 +49,7 @@ pub async fn register_user(
email_verified: true, email_verified: true,
date_created: String::from("2025-01-01 12:00:00"), date_created: String::from("2025-01-01 12:00:00"),
last_login: String::from("nil"), last_login: String::from("nil"),
salt_id: uuid::Uuid::nil(),
}; };
match repo::user::exists(&pool, &user.username).await { match repo::user::exists(&pool, &user.username).await {
@@ -61,6 +63,12 @@ pub async fn register_user(
}), }),
) )
} else { } else {
let salt_string = hashing::generate_salt().unwrap();
let mut salt = icarus_models::user::salt::Salt::default();
salt.salt = salt_string.as_str().to_string();
salt.id = repo::salt::insert(&pool, &salt).await.unwrap();
user.salt_id = salt.id;
match repo::user::insert(&pool, &user).await { match repo::user::insert(&pool, &user).await {
Ok(id) => { Ok(id) => {
user.id = id; user.id = id;

View File

@@ -9,17 +9,18 @@ use argon2::{
}; };
pub fn generate_salt() -> Result<SaltString, argon2::Error> { pub fn generate_salt() -> Result<SaltString, argon2::Error> {
// Generate a random salt
// SaltString::generate uses OsRng internally for cryptographic security
let salt = SaltString::generate(&mut OsRng); let salt = SaltString::generate(&mut OsRng);
Ok(salt) Ok(salt)
} }
pub fn hash_password(password: &String) -> Result<String, argon2::password_hash::Error> { pub fn hash_password(
password: &String,
salt: &SaltString,
) -> Result<String, argon2::password_hash::Error> {
let password_bytes = password.as_bytes(); let password_bytes = password.as_bytes();
// Generate a random salt
// SaltString::generate uses OsRng internally for cryptographic security
let salt = generate_salt().unwrap();
// Create an Argon2 instance with default parameters (recommended) // Create an Argon2 instance with default parameters (recommended)
// You could customize parameters here if needed, but defaults are strong // You could customize parameters here if needed, but defaults are strong
let argon2 = Argon2::default(); let argon2 = Argon2::default();
@@ -27,7 +28,7 @@ pub fn hash_password(password: &String) -> Result<String, argon2::password_hash:
// Hash the password with the salt // Hash the password with the salt
// The output is a PasswordHash string format that includes algorithm, version, // The output is a PasswordHash string format that includes algorithm, version,
// parameters, salt, and the hash itself. // parameters, salt, and the hash itself.
let password_hash = argon2.hash_password(password_bytes, &salt)?.to_string(); let password_hash = argon2.hash_password(password_bytes, salt)?.to_string();
Ok(password_hash) Ok(password_hash)
} }
@@ -61,7 +62,8 @@ mod tests {
#[test] #[test]
fn test_hash_password() { fn test_hash_password() {
let some_password = String::from("somethingrandom"); let some_password = String::from("somethingrandom");
match hash_password(&some_password) { let salt = generate_salt().unwrap();
match hash_password(&some_password, &salt) {
Ok(p) => match verify_password(&some_password, p.clone()) { Ok(p) => match verify_password(&some_password, p.clone()) {
Ok(res) => { Ok(res) => {
assert_eq!(res, true); assert_eq!(res, true);

View File

@@ -29,8 +29,8 @@ pub mod user {
) -> Result<uuid::Uuid, sqlx::Error> { ) -> Result<uuid::Uuid, sqlx::Error> {
let row = sqlx::query( let row = sqlx::query(
r#" r#"
INSERT INTO "user" (username, password, email, phone, firstname, lastname, email_verified, status) INSERT INTO "user" (username, password, email, phone, firstname, lastname, email_verified, status, salt_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id, date_created; RETURNING id, date_created;
"#) "#)
.bind(&user.username) .bind(&user.username)
@@ -41,6 +41,7 @@ pub mod user {
.bind(&user.lastname) .bind(&user.lastname)
.bind(user.email_verified) .bind(user.email_verified)
.bind(&user.status) .bind(&user.status)
.bind(user.salt_id)
.fetch_one(pool) .fetch_one(pool)
.await .await
.map_err(|e| { .map_err(|e| {
@@ -62,3 +63,42 @@ pub mod user {
} }
} }
} }
pub mod salt {
use sqlx::Row;
#[derive(Debug, serde::Serialize, sqlx::FromRow)]
pub struct InsertedData {
pub id: uuid::Uuid,
}
pub async fn insert(
pool: &sqlx::PgPool,
salt: &icarus_models::user::salt::Salt,
) -> Result<uuid::Uuid, sqlx::Error> {
let row = sqlx::query(
r#"
INSERT INTO "salt" (salt)
VALUES ($1)
RETURNING id;
"#,
)
.bind(&salt.salt)
.fetch_one(pool)
.await
.map_err(|e| {
eprintln!("Error inserting item: {}", e);
e
})?;
let result = InsertedData {
id: row.try_get("id").map_err(|_e| sqlx::Error::RowNotFound)?,
};
if !result.id.is_nil() {
Ok(result.id)
} else {
Err(sqlx::Error::RowNotFound)
}
}
}