This commit is contained in:
Franklin 2023-09-24 12:42:56 -04:00
parent 6cca212c42
commit e853447735
5 changed files with 54 additions and 36 deletions

View File

@ -36,4 +36,4 @@ pub enum Error {
pub struct ValidationError { pub struct ValidationError {
pub what: String, pub what: String,
pub reason: String, pub reason: String,
} }

View File

@ -7,7 +7,7 @@ use sqlx::{
Postgres, Postgres,
}; };
use crate::domain::{credential::CredentialType}; use crate::domain::credential::CredentialType;
use crate::domain::error::Error; use crate::domain::error::Error;
use crate::domain::error::Error::FromStrError; use crate::domain::error::Error::FromStrError;

View File

@ -7,16 +7,19 @@ use crate::domain::user::User;
use crate::dto::token::{AuthenticateUserDto, RefreshAuthTokenForUserDto}; use crate::dto::token::{AuthenticateUserDto, RefreshAuthTokenForUserDto};
use crate::dto::users::{UserLoginPayload, UserRegisterPayload, UserResetPasswordPayload}; use crate::dto::users::{UserLoginPayload, UserRegisterPayload, UserResetPasswordPayload};
use crate::domain::error::Error::{
AlreadyExistsError, IncorrectCredentialError, NotFoundError, TooManyCredentialsError,
UnexpectedError,
};
use crate::domain::error::{Error, ValidationError};
use crate::resources::expirations::AUTH_TOKEN_EXPIRATION_TIME_MILLIS; use crate::resources::expirations::AUTH_TOKEN_EXPIRATION_TIME_MILLIS;
use crate::utils::hasher::{ use crate::utils::hasher::{
generate_multiple_random_token_with_rng, hash_password, hash_password_with_existing_salt, generate_multiple_random_token_with_rng, hash_password, hash_password_with_existing_salt,
}; };
use crate::validation::user_validator::validate_user_for_creation; use crate::validation::user_validator::validate_user_for_creation;
use chrono::Utc; use chrono::Utc;
use log::{error}; use log::error;
use sqlx::{PgConnection, Postgres, Transaction}; use sqlx::{PgConnection, Postgres, Transaction};
use crate::domain::error::{Error, ValidationError};
use crate::domain::error::Error::{AlreadyExistsError, IncorrectCredentialError, NotFoundError, TooManyCredentialsError, UnexpectedError};
pub async fn register_user<'a>( pub async fn register_user<'a>(
transaction: &mut PgConnection, transaction: &mut PgConnection,
@ -49,14 +52,13 @@ pub async fn register_user<'a>(
last_updated: now, last_updated: now,
}; };
let persisted_user= insert_user(transaction, user_to_insert).await?; let persisted_user = insert_user(transaction, user_to_insert).await?;
// Insert Credentials // Insert Credentials
for credential in user.credentials { for credential in user.credentials {
insert_credential(transaction, credential, &persisted_user.id).await?; insert_credential(transaction, credential, &persisted_user.id).await?;
} }
create_token_for_user(transaction, persisted_user.id).await create_token_for_user(transaction, persisted_user.id).await
} }
pub async fn authenticate_user<'a>( pub async fn authenticate_user<'a>(
@ -71,15 +73,15 @@ pub async fn authenticate_user<'a>(
}; };
match validate_user_token(conn, &user.id, user.auth_token.clone()).await? { match validate_user_token(conn, &user.id, user.auth_token.clone()).await? {
None => { None => Err(NotFoundError(format!("Auth Token {}", user.auth_token))),
Err(NotFoundError(format!("Auth Token {}", user.auth_token)))
}
Some(persisted_token) => { Some(persisted_token) => {
// Check if persisted_token expired // Check if persisted_token expired
if Utc::now().timestamp_millis() - persisted_token.last_updated.timestamp_millis() if Utc::now().timestamp_millis() - persisted_token.last_updated.timestamp_millis()
> AUTH_TOKEN_EXPIRATION_TIME_MILLIS > AUTH_TOKEN_EXPIRATION_TIME_MILLIS
{ {
Err(IncorrectCredentialError(String::from("Auth Token Expired. Use refresh token to get a new one."))) Err(IncorrectCredentialError(String::from(
"Auth Token Expired. Use refresh token to get a new one.",
)))
} else { } else {
// Not expired // Not expired
Ok(persisted_user) Ok(persisted_user)
@ -115,14 +117,15 @@ pub async fn reset_password(
conn: &mut PgConnection, conn: &mut PgConnection,
user: UserResetPasswordPayload, user: UserResetPasswordPayload,
) -> Result<User, Error> { ) -> Result<User, Error> {
let password_matches = validate_user_password(conn, &user.id, user.password).await?; let password_matches = validate_user_password(conn, &user.id, user.password).await?;
if let Some(persisted_user) = password_matches { if let Some(persisted_user) = password_matches {
// Change pass // Change pass
Ok(change_password(conn, persisted_user, &user.new_password).await?) Ok(change_password(conn, persisted_user, &user.new_password).await?)
} else { } else {
Err(IncorrectCredentialError(String::from("Password incorrect."))) Err(IncorrectCredentialError(String::from(
"Password incorrect.",
)))
} }
} }
@ -149,21 +152,18 @@ pub async fn password_login<'a>(
user: UserLoginPayload, user: UserLoginPayload,
) -> Result<Token, Error> { ) -> Result<Token, Error> {
let persisted_user_credential = match get_credential(conn, user.credential.clone()).await? { let persisted_user_credential = match get_credential(conn, user.credential.clone()).await? {
None => { None => return Err(NotFoundError(format!("Credential {}", user.credential))),
return Err(NotFoundError(format!("Credential {}", user.credential)))
}
Some(persisted_credential) => persisted_credential, Some(persisted_credential) => persisted_credential,
}; };
let persisted_user_opt = let persisted_user_opt =
validate_user_password(conn, &persisted_user_credential.user_id, user.password).await?; validate_user_password(conn, &persisted_user_credential.user_id, user.password).await?;
if let Some(_) = persisted_user_opt { if let Some(_) = persisted_user_opt {
Ok(create_token_for_user( Ok(create_token_for_user(conn, persisted_user_credential.user_id).await?)
conn,
persisted_user_credential.user_id,
)
.await?)
} else { } else {
Err(NotFoundError(format!("User with id: {}", persisted_user_credential.user_id))) Err(NotFoundError(format!(
"User with id: {}",
persisted_user_credential.user_id
)))
} }
} }
@ -188,14 +188,18 @@ async fn create_token_for_user<'a>(
auth_token: match tokens.get(0) { auth_token: match tokens.get(0) {
None => { None => {
error!("Tokens were not created."); error!("Tokens were not created.");
return Err(Error::UnexpectedError(String::from("Tokens were not created."))); return Err(Error::UnexpectedError(String::from(
"Tokens were not created.",
)));
} }
Some(token) => token.clone(), Some(token) => token.clone(),
}, },
refresh_token: match tokens.get(1) { refresh_token: match tokens.get(1) {
None => { None => {
error!("Tokens were not created."); error!("Tokens were not created.");
return Err(Error::UnexpectedError(String::from("Tokens were not created."))); return Err(Error::UnexpectedError(String::from(
"Tokens were not created.",
)));
} }
Some(token) => token.clone(), Some(token) => token.clone(),
}, },

View File

@ -8,9 +8,7 @@ use std::num::NonZeroU32;
const SALT_ROUNDS: u32 = 1000; const SALT_ROUNDS: u32 = 1000;
pub(crate) async fn generate_multiple_random_token_with_rng( pub(crate) async fn generate_multiple_random_token_with_rng(amount: u8) -> Vec<String> {
amount: u8,
) -> Vec<String> {
// 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();

View File

@ -3,9 +3,7 @@ use crate::domain::error::ValidationError;
use crate::dto::users::{UserLoginPayload, UserRegisterPayload}; use crate::dto::users::{UserLoginPayload, UserRegisterPayload};
use crate::resources::error_messages::ERROR_INVALID_USERNAME; use crate::resources::error_messages::ERROR_INVALID_USERNAME;
use crate::resources::{ use crate::resources::{
error_messages::{ error_messages::{ERROR_INVALID_EMAIL, ERROR_INVALID_PASSWORD, ERROR_INVALID_PHONE_NUMBER},
ERROR_INVALID_EMAIL, ERROR_INVALID_PASSWORD, ERROR_INVALID_PHONE_NUMBER,
},
variable_lengths::{ variable_lengths::{
MAX_EMAIL_LENGTH, MAX_NAME_LENGTH, MAX_PASSWORD_LENGTH, MIN_EMAIL_LENGTH, MIN_NAME_LENGTH, MAX_EMAIL_LENGTH, MAX_NAME_LENGTH, MAX_PASSWORD_LENGTH, MIN_EMAIL_LENGTH, MIN_NAME_LENGTH,
MIN_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH,
@ -47,10 +45,16 @@ pub(crate) fn validate_user_for_creation(
} }
if !validate_user_name(&user.name) { if !validate_user_name(&user.name) {
error_resources.push(ValidationError { what: String::from("UserName"), reason: ERROR_INVALID_USERNAME.0.to_string() }); error_resources.push(ValidationError {
what: String::from("UserName"),
reason: ERROR_INVALID_USERNAME.0.to_string(),
});
} }
if !validate_user_password(&user.password) { if !validate_user_password(&user.password) {
error_resources.push(ValidationError { what: String::from("Password"), reason: ERROR_INVALID_PASSWORD.0.to_string() }); error_resources.push(ValidationError {
what: String::from("Password"),
reason: ERROR_INVALID_PASSWORD.0.to_string(),
});
} }
} }
#[allow(unused)] #[allow(unused)]
@ -60,7 +64,10 @@ pub(crate) fn validate_user_for_password_authentication(
) { ) {
validate_credential(error_resources, &user.credential, &user.credential_type); validate_credential(error_resources, &user.credential, &user.credential_type);
if !validate_user_password(&user.password) { if !validate_user_password(&user.password) {
error_resources.push(ValidationError { what: String::from("Password"), reason: ERROR_INVALID_PASSWORD.0.to_string() }); error_resources.push(ValidationError {
what: String::from("Password"),
reason: ERROR_INVALID_PASSWORD.0.to_string(),
});
} }
} }
@ -72,17 +79,26 @@ fn validate_credential(
match credential_type { match credential_type {
CredentialType::Email => { CredentialType::Email => {
if !validate_user_email(credential) { if !validate_user_email(credential) {
error_resources.push(ValidationError { what: String::from("Email"), reason: ERROR_INVALID_EMAIL.0.to_string() }); error_resources.push(ValidationError {
what: String::from("Email"),
reason: ERROR_INVALID_EMAIL.0.to_string(),
});
} }
} }
CredentialType::PhoneNumber => { CredentialType::PhoneNumber => {
if !validate_user_phone_number(credential) { if !validate_user_phone_number(credential) {
error_resources.push(ValidationError { what: String::from("Phone Number"), reason: ERROR_INVALID_PHONE_NUMBER.0.to_string() }); error_resources.push(ValidationError {
what: String::from("Phone Number"),
reason: ERROR_INVALID_PHONE_NUMBER.0.to_string(),
});
} }
} }
CredentialType::Username => { CredentialType::Username => {
if !validate_user_username(credential) { if !validate_user_username(credential) {
error_resources.push(ValidationError { what: String::from("UserName"), reason: ERROR_INVALID_USERNAME.0.to_string() }); error_resources.push(ValidationError {
what: String::from("UserName"),
reason: ERROR_INVALID_USERNAME.0.to_string(),
});
} }
} }
} }