Starting to see services being made

This commit is contained in:
Franklin 2023-09-20 23:31:16 -04:00
parent 67a990de1f
commit c31586573b
6 changed files with 97 additions and 7 deletions

1
Cargo.lock generated
View File

@ -1609,6 +1609,7 @@ dependencies = [
"chrono", "chrono",
"data-encoding", "data-encoding",
"futures-util", "futures-util",
"log",
"ring", "ring",
"serde", "serde",
"sqlx", "sqlx",

View File

@ -16,4 +16,5 @@ sqlx = { version = "0.7", features = [ "runtime-tokio", "tls-rustls", "postgres"
chrono = { version = "0.4", features = [ "serde" ] } chrono = { version = "0.4", features = [ "serde" ] }
ring = "0.16.20" ring = "0.16.20"
data-encoding = "2.3.2" data-encoding = "2.3.2"
futures-util = "0.3" futures-util = "0.3"
log = "0.4.19"

View File

@ -32,3 +32,10 @@ pub async fn fetch_user_credentials(
) -> Result<Vec<Credential>, Error> { ) -> Result<Vec<Credential>, Error> {
sqlx::query_as(r#"SELECT user_id, credential_type as "credential_type: _", credential, validated, time_created, last_updated FROM credential WHERE user_id = $1 "#).bind(user_id).fetch_all(conn).await sqlx::query_as(r#"SELECT user_id, credential_type as "credential_type: _", credential, validated, time_created, last_updated FROM credential WHERE user_id = $1 "#).bind(user_id).fetch_all(conn).await
} }
pub async fn get_credential(
conn: &PgPool,
credential: String,
) -> Result<Option<Credential>, Error> {
sqlx::query_as(r#"SELECT user_id, credential_type as "credential_type: _", credential, validated, time_created, last_updated FROM credential WHERE credential = $1"#).bind(credential).fetch_optional(conn).await
}

View File

@ -26,7 +26,7 @@ pub const ERROR_INVALID_PASSWORD: (&str, &str) = (
pub const ERROR_USER_ALREADY_EXISTS: (&str, &str) = ( pub const ERROR_USER_ALREADY_EXISTS: (&str, &str) = (
"ERROR.USER_ALREADY_EXISTS", "ERROR.USER_ALREADY_EXISTS",
"A user with that email already exists.", "A user with that credential already exists.",
); );
pub const ERROR_USER_DOES_NOT_EXIST: (&str, &str) = ( pub const ERROR_USER_DOES_NOT_EXIST: (&str, &str) = (
@ -60,3 +60,8 @@ pub const ERROR_CREATING_TOKEN: (&str, &str) = (
"ERROR.CREATING_TOKEN", "ERROR.CREATING_TOKEN",
"The server had an error creating the auth tokens.", "The server had an error creating the auth tokens.",
); );
pub const ERROR_TOO_MANY_CREDENTIALS: (&str, &str) = (
"ERROR.TOO_MANY_CREDENTIALS",
"Only up to 3 credentials are allowed. One of each type.",
);

View File

@ -1,5 +1,76 @@
use std::error::Error;
use log::{error, log};
use crate::dao::credential::get_credential;
use crate::domain::credential::Credential;
use crate::dto::users::UserRegisterPayload; use crate::dto::users::UserRegisterPayload;
use crate::resources::error_messages::{ERROR_TOO_MANY_CREDENTIALS, ERROR_USER_ALREADY_EXISTS, ErrorResource};
use crate::validation::user_validator::validate_user_for_creation;
pub async fn register_user(db_conn: &sqlx::PgPool, user: UserRegisterPayload) -> Result<(), ()> { pub async fn register_user(db_conn: &sqlx::PgPool, user: UserRegisterPayload) -> Result<(), Vec<ErrorResource>> {
let mut error_resources: Vec<ErrorResource> = Vec::new();
// Validate user
validate_user_for_creation(&user, &mut error_resources);
// Find if user exists
if user.credentials.len() > 3 {
error_resources.push(ERROR_TOO_MANY_CREDENTIALS);
}
for credential_dto in user.credentials.iter() {
match get_credential(
&db_conn,
credential_dto.credential.clone(),
)
.await
{
Ok(credential_opt) => {
match credential_opt {
None => {}
Some(_) => {
error_resources.push(
ERROR_USER_ALREADY_EXISTS);
}
}
}
Err(e) => {
error!("{}", e);
error_resources.push(("ERROR.DATABASE_ERROR", ""));
}
};
}
// If validation gave any errors blow up and send them back to the client
if error_resources.len() > 0 {
return Err(error_resources);
}
/* TODO:
// Get salt and hashed password from hashing function then give the results to the user
let hash_result = hasher::hash_password(&user_to_insert.password);
user_to_insert.password = hash_result.hash;
user_to_insert.salt = hash_result.salt;
// Insert user in DB
match insert_user(&db_conn, &user_to_insert).await{
Ok(resultrs) => {
user_to_insert.id = resultrs.last_insert_id() as u32;
},
Err(error) => {
println!("Error while inserting user in database from create_user method. Log: {}", error);
return HttpResponse::InternalServerError().finish();
}};
// Create token and send it back.
let tokens: Vec<String> = hasher::generate_multiple_random_token_with_rng(2).await.expect("Error creating multiple random tokens.");
let mut token_to_insert =
Token::new(user_to_insert.id,
tokens.get(0).expect("Error. Token doesn't exist in list.").to_string(),
tokens.get(1).expect("Error. Token doesn't exist in list.").to_string()
);
// Insert token in DB
match insert_token(&db_conn, &token_to_insert).await{
Ok(resultrs) => {token_to_insert.id = resultrs.last_insert_id() as u32},
Err(_e) => {return HttpResponse::InternalServerError().finish()}
}
*/
Ok(()) Ok(())
} }

View File

@ -9,7 +9,9 @@ use tokio::task::JoinError;
const SALT_ROUNDS: u32 = 1000; const SALT_ROUNDS: u32 = 1000;
pub async fn generate_multiple_random_token_with_rng(amount: u8) -> Result<Vec<String>, JoinError> { pub(crate) async fn generate_multiple_random_token_with_rng(
amount: u8,
) -> Result<Vec<String>, JoinError> {
// Get a new instance of a Random Number Generator // Get a new instance of a Random Number Generator
let rng = SystemRandom::new(); let rng = SystemRandom::new();
@ -20,7 +22,7 @@ pub async fn generate_multiple_random_token_with_rng(amount: u8) -> Result<Vec<S
let future_token = async move { let future_token = async move {
let mut token_arr = [0u8; digest::SHA512_OUTPUT_LEN]; let mut token_arr = [0u8; digest::SHA512_OUTPUT_LEN];
match cloned_rng.fill(&mut token_arr) { match cloned_rng.fill(&mut token_arr) {
Ok(()) => BASE64.encode(&token_arr), //TODO: Remove this panic, make your own error and fix this Ok(()) => BASE64.encode(&token_arr),
Err(_e) => { Err(_e) => {
panic!("Failed to generate random token for some reason.") panic!("Failed to generate random token for some reason.")
} }
@ -42,7 +44,10 @@ pub async fn generate_multiple_random_token_with_rng(amount: u8) -> Result<Vec<S
Ok(all_tokens_solved) Ok(all_tokens_solved)
} }
pub fn hash_password_with_existing_salt(password: &String, input_salt: &String) -> HashResult { pub(crate) fn hash_password_with_existing_salt(
password: &String,
input_salt: &String,
) -> HashResult {
// Get output length from a sha512 hash // Get output length from a sha512 hash
const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN; const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN;
let n_iter = NonZeroU32::new(SALT_ROUNDS).unwrap(); let n_iter = NonZeroU32::new(SALT_ROUNDS).unwrap();
@ -65,7 +70,7 @@ pub fn hash_password_with_existing_salt(password: &String, input_salt: &String)
HashResult::new(BASE64.encode(&salt), BASE64.encode(&pbkdf2_hash)) HashResult::new(BASE64.encode(&salt), BASE64.encode(&pbkdf2_hash))
} }
pub fn hash_password(password: &String) -> HashResult { pub(crate) fn hash_password(password: &String) -> HashResult {
// Get output length from a sha512 hash // Get output length from a sha512 hash
const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN; const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN;
let n_iter = NonZeroU32::new(SALT_ROUNDS).unwrap(); let n_iter = NonZeroU32::new(SALT_ROUNDS).unwrap();