Register endpoint #16

Merged
phoenix merged 56 commits from register_endpoint-init into devel 2025-04-05 19:26:59 +00:00
3 changed files with 59 additions and 9 deletions
Showing only changes of commit b45a0475ed - Show all commits

View File

@@ -1,5 +1,6 @@
use axum::{Json, http::StatusCode};
use crate::hashing;
use crate::repo;
pub mod request {
@@ -48,6 +49,7 @@ pub async fn register_user(
email_verified: true,
date_created: String::from("2025-01-01 12:00:00"),
last_login: String::from("nil"),
salt_id: uuid::Uuid::nil(),
};
match repo::user::exists(&pool, &user.username).await {
@@ -61,6 +63,12 @@ pub async fn register_user(
}),
)
} 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 {
Ok(id) => {
user.id = id;

View File

@@ -9,17 +9,18 @@ use argon2::{
};
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);
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();
// 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)
// You could customize parameters here if needed, but defaults are strong
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
// The output is a PasswordHash string format that includes algorithm, version,
// 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)
}
@@ -61,7 +62,8 @@ mod tests {
#[test]
fn test_hash_password() {
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(res) => {
assert_eq!(res, true);

View File

@@ -29,8 +29,8 @@ pub mod user {
) -> Result<uuid::Uuid, sqlx::Error> {
let row = sqlx::query(
r#"
INSERT INTO "user" (username, password, email, phone, firstname, lastname, email_verified, status)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
INSERT INTO "user" (username, password, email, phone, firstname, lastname, email_verified, status, salt_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id, date_created;
"#)
.bind(&user.username)
@@ -41,6 +41,7 @@ pub mod user {
.bind(&user.lastname)
.bind(user.email_verified)
.bind(&user.status)
.bind(user.salt_id)
.fetch_one(pool)
.await
.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)
}
}
}