Cargo fmt & extra token daos
This commit is contained in:
parent
d3ec69b3b5
commit
67a990de1f
|
@ -1,22 +1,34 @@
|
||||||
use chrono::Utc;
|
|
||||||
use sqlx::{Error, PgPool};
|
|
||||||
use crate::domain::credential::Credential;
|
use crate::domain::credential::Credential;
|
||||||
use crate::dto::credential::CredentialDto;
|
use crate::dto::credential::CredentialDto;
|
||||||
|
use chrono::Utc;
|
||||||
|
use sqlx::{Error, PgPool};
|
||||||
|
|
||||||
pub async fn insert_credentials(conn: &PgPool, credentials: Vec<CredentialDto>, user_id: &i32) -> Result<Vec<Credential>, Error> {
|
pub async fn insert_credentials(
|
||||||
|
conn: &PgPool,
|
||||||
|
credentials: Vec<CredentialDto>,
|
||||||
|
user_id: &i32,
|
||||||
|
) -> Result<Vec<Credential>, Error> {
|
||||||
let insert_query_base = r#"INSERT INTO credential
|
let insert_query_base = r#"INSERT INTO credential
|
||||||
(user_id, credential_type, credential, validated, time_created, last_updated)
|
(user_id, credential_type, credential, validated, time_created, last_updated)
|
||||||
VALUES ($1, $2, $3, $4, $5, $5) RETURNING user_id, credential_type as "credential_type: _", credential, validated, time_created, last_updated"#;
|
VALUES ($1, $2, $3, $4, $5, $5) RETURNING user_id, credential_type as "credential_type: _", credential, validated, time_created, last_updated"#;
|
||||||
let mut persisted_credentials = Vec::new();
|
let mut persisted_credentials = Vec::new();
|
||||||
for credential_dto in credentials {
|
for credential_dto in credentials {
|
||||||
let persisted_credential: Credential = sqlx::query_as(insert_query_base)
|
let persisted_credential: Credential = sqlx::query_as(insert_query_base)
|
||||||
.bind(user_id).bind(credential_dto.credential_type).bind(credential_dto.credential).bind(false).bind(Utc::now())
|
.bind(user_id)
|
||||||
.fetch_one(conn).await?;
|
.bind(credential_dto.credential_type)
|
||||||
|
.bind(credential_dto.credential)
|
||||||
|
.bind(false)
|
||||||
|
.bind(Utc::now())
|
||||||
|
.fetch_one(conn)
|
||||||
|
.await?;
|
||||||
persisted_credentials.push(persisted_credential);
|
persisted_credentials.push(persisted_credential);
|
||||||
}
|
}
|
||||||
Ok(persisted_credentials)
|
Ok(persisted_credentials)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_user_credentials(conn: &PgPool, user_id: &i32) -> Result<Vec<Credential>, Error> {
|
pub async fn fetch_user_credentials(
|
||||||
|
conn: &PgPool,
|
||||||
|
user_id: &i32,
|
||||||
|
) -> 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
pub mod pg_queries;
|
|
||||||
pub mod user;
|
|
||||||
pub mod credential;
|
pub mod credential;
|
||||||
pub mod token;
|
pub mod pg_queries;
|
||||||
|
pub mod token;
|
||||||
|
pub mod user;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use crate::domain::token::Token;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use sqlx::{Error, PgPool};
|
use sqlx::{Error, PgPool};
|
||||||
use crate::domain::token::Token;
|
|
||||||
|
|
||||||
pub async fn insert_token(conn: &PgPool, token: Token) -> Result<Token, Error> {
|
pub async fn insert_token(conn: &PgPool, token: Token) -> Result<Token, Error> {
|
||||||
sqlx::query_as(r#"INSERT INTO token (
|
sqlx::query_as(r#"INSERT INTO token (
|
||||||
|
@ -9,13 +9,40 @@ pub async fn insert_token(conn: &PgPool, token: Token) -> Result<Token, Error> {
|
||||||
.fetch_one(conn).await
|
.fetch_one(conn).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_token(conn: &PgPool, token_id: &i32, auth_token: String) -> Result<Token, Error> {
|
pub async fn update_token(
|
||||||
sqlx::query_as(r#"UPDATE token set
|
conn: &PgPool,
|
||||||
auth_token = $2, last_updated
|
token_id: &i32,
|
||||||
WHERE id = $1 RETURNING *;"#)
|
refresh_token: String,
|
||||||
.bind(token_id).bind(auth_token).bind(Utc::now())
|
new_auth_token: String,
|
||||||
.fetch_one(conn).await
|
) -> Result<Token, Error> {
|
||||||
|
sqlx::query_as(
|
||||||
|
r#"UPDATE token set
|
||||||
|
auth_token = $3, last_updated = $4
|
||||||
|
WHERE id = $1 AND refresh_token = $2 RETURNING *;"#,
|
||||||
|
)
|
||||||
|
.bind(token_id)
|
||||||
|
.bind(refresh_token)
|
||||||
|
.bind(new_auth_token)
|
||||||
|
.bind(Utc::now())
|
||||||
|
.fetch_one(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn remove_token(conn: &PgPool, token_id: &i32) -> Result<Option<Token>, Error> {
|
||||||
|
sqlx::query_as(r#"DELETE FROM token WHERE id = $1 RETURNING *;"#)
|
||||||
|
.bind(token_id)
|
||||||
|
.fetch_optional(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn validate_user_token(
|
||||||
|
conn: &PgPool,
|
||||||
|
user_id: &i32,
|
||||||
|
auth_token: String,
|
||||||
|
) -> Result<Option<Token>, Error> {
|
||||||
|
sqlx::query_as(r#"SELECT * FROM token where user_id = $1 AND auth_token = $2;"#)
|
||||||
|
.bind(user_id)
|
||||||
|
.bind(auth_token)
|
||||||
|
.fetch_optional(conn)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
// TODO: add validate_user token (user_id, auth_token)
|
|
||||||
// Update user token (refresh_token, user_id)
|
|
||||||
// Delete user token (token_id)
|
|
|
@ -1,41 +1,56 @@
|
||||||
use sqlx::{PgPool, query_as, query_as_with};
|
|
||||||
use crate::domain::user::User;
|
use crate::domain::user::User;
|
||||||
|
use sqlx::{query_as, query_as_with, PgPool};
|
||||||
|
|
||||||
pub async fn insert_user(conn: &PgPool, user: User) -> Result<User, sqlx::Error> {
|
pub async fn insert_user(conn: &PgPool, user: User) -> Result<User, sqlx::Error> {
|
||||||
sqlx::query_as(r#"
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
INSERT INTO user (name, password, salt, time_created, last_updated)
|
INSERT INTO user (name, password, salt, time_created, last_updated)
|
||||||
VALUES ($1, $2, $3, $4, $4) RETURNING *;
|
VALUES ($1, $2, $3, $4, $4) RETURNING *;
|
||||||
"#)
|
"#,
|
||||||
.bind(user.name).bind(user.password).bind(user.salt).bind(user.time_created)
|
)
|
||||||
.fetch_one(conn)
|
.bind(user.name)
|
||||||
.await
|
.bind(user.password)
|
||||||
|
.bind(user.salt)
|
||||||
|
.bind(user.time_created)
|
||||||
|
.fetch_one(conn)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user_with_id(conn: &PgPool, user_id: &i32) -> Result<Option<User>, sqlx::Error> {
|
pub async fn get_user_with_id(conn: &PgPool, user_id: &i32) -> Result<Option<User>, sqlx::Error> {
|
||||||
sqlx::query_as(r#"
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
SELECT * FROM user where id = $1;
|
SELECT * FROM user where id = $1;
|
||||||
"#, )
|
"#,
|
||||||
.bind(user_id)
|
)
|
||||||
.fetch_optional(conn)
|
.bind(user_id)
|
||||||
.await
|
.fetch_optional(conn)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_user(conn: &PgPool, user: User) -> Result<User, sqlx::Error> {
|
pub async fn update_user(conn: &PgPool, user: User) -> Result<User, sqlx::Error> {
|
||||||
sqlx::query_as(r#"
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
UPDATE user SET
|
UPDATE user SET
|
||||||
name = $2, password = $3, salt = $4, last_updated = $5
|
name = $2, password = $3, salt = $4, last_updated = $5
|
||||||
WHERE id = $1 RETURNING *;
|
WHERE id = $1 RETURNING *;
|
||||||
"#, )
|
"#,
|
||||||
.bind(user.id).bind(user.name).bind(user.password).bind(user.salt).bind(user.last_updated)
|
)
|
||||||
.fetch_one(conn)
|
.bind(user.id)
|
||||||
.await
|
.bind(user.name)
|
||||||
|
.bind(user.password)
|
||||||
|
.bind(user.salt)
|
||||||
|
.bind(user.last_updated)
|
||||||
|
.fetch_one(conn)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_user(conn: &PgPool, user_id: &i32) -> Result<Option<User>, sqlx::Error> {
|
pub async fn delete_user(conn: &PgPool, user_id: &i32) -> Result<Option<User>, sqlx::Error> {
|
||||||
sqlx::query_as(r#"
|
sqlx::query_as(
|
||||||
|
r#"
|
||||||
DELETE FROM user where id = $1 RETURNING *;
|
DELETE FROM user where id = $1 RETURNING *;
|
||||||
"#, )
|
"#,
|
||||||
.bind(user_id)
|
)
|
||||||
.fetch_optional(conn)
|
.bind(user_id)
|
||||||
.await
|
.fetch_optional(conn)
|
||||||
}
|
.await
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
use crate::resources::variable_lengths::{
|
||||||
|
MAX_EMAIL_LENGTH, MAX_NAME_LENGTH, MAX_PHONE_NUMBER_LENGTH, MAX_USERNAME_LENGTH,
|
||||||
|
MIN_EMAIL_LENGTH, MIN_PHONE_NUMBER_LENGTH, MIN_USERNAME_LENGTH,
|
||||||
|
};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use crate::resources::variable_lengths::{MAX_EMAIL_LENGTH, MAX_NAME_LENGTH, MAX_PHONE_NUMBER_LENGTH, MAX_USERNAME_LENGTH, MIN_EMAIL_LENGTH, MIN_PHONE_NUMBER_LENGTH, MIN_USERNAME_LENGTH};
|
|
||||||
|
|
||||||
|
|
||||||
/// Is used in the user struct to signal what type of credential will be used in the credential Column.
|
/// Is used in the user struct to signal what type of credential will be used in the credential Column.
|
||||||
/// Defaults to email.
|
/// Defaults to email.
|
||||||
|
@ -15,7 +17,9 @@ pub enum CredentialType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can only have one per user per cred_type
|
/// Can only have one per user per cred_type
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, FromRow)]
|
#[derive(
|
||||||
|
Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, FromRow,
|
||||||
|
)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Credential {
|
pub struct Credential {
|
||||||
pub user_id: i32,
|
pub user_id: i32,
|
||||||
|
@ -41,4 +45,4 @@ impl CredentialType {
|
||||||
CredentialType::Username => MIN_USERNAME_LENGTH,
|
CredentialType::Username => MIN_USERNAME_LENGTH,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
|
||||||
/// Used to return a simple error from FromStr implementations
|
/// Used to return a simple error from FromStr implementations
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FromStrError;
|
pub struct FromStrError;
|
||||||
|
@ -11,4 +10,4 @@ impl Display for FromStrError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for FromStrError {}
|
impl std::error::Error for FromStrError {}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use std::{str::FromStr, fmt::Display};
|
use std::{fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use sqlx::{Postgres, postgres::{PgValueRef, PgArgumentBuffer, PgTypeInfo}, error::BoxDynError, encode::IsNull};
|
use sqlx::{
|
||||||
|
encode::IsNull,
|
||||||
|
error::BoxDynError,
|
||||||
|
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef},
|
||||||
|
Postgres,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::domain::{credential::CredentialType, error::FromStrError};
|
use crate::domain::{credential::CredentialType, error::FromStrError};
|
||||||
|
|
||||||
|
@ -12,7 +17,7 @@ impl FromStr for CredentialType {
|
||||||
"PhoneNumber" => Ok(Self::PhoneNumber),
|
"PhoneNumber" => Ok(Self::PhoneNumber),
|
||||||
"Email" => Ok(Self::Email),
|
"Email" => Ok(Self::Email),
|
||||||
"Username" => Ok(Self::Username),
|
"Username" => Ok(Self::Username),
|
||||||
_ => Err(FromStrError)
|
_ => Err(FromStrError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,4 +60,4 @@ impl sqlx::Type<Postgres> for CredentialType {
|
||||||
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||||
*ty == Self::type_info()
|
*ty == Self::type_info()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
pub mod credential;
|
pub mod credential;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod credential;
|
pub mod credential;
|
||||||
|
pub mod error;
|
||||||
|
pub mod impls;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
pub mod impls;
|
|
||||||
pub mod error;
|
|
|
@ -1,10 +1,10 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
|
|
||||||
|
#[derive(
|
||||||
#[derive(FromRow)]
|
FromRow, Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord,
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
#[serde(skip_serializing, skip_deserializing)]
|
#[serde(skip_serializing, skip_deserializing)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
|
@ -18,4 +18,4 @@ pub struct Token {
|
||||||
pub time_created: DateTime<Utc>,
|
pub time_created: DateTime<Utc>,
|
||||||
#[serde(rename = "lastUpdated")]
|
#[serde(rename = "lastUpdated")]
|
||||||
pub last_updated: DateTime<Utc>,
|
pub last_updated: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
|
|
||||||
#[derive(FromRow)]
|
#[derive(
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
FromRow, Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord,
|
||||||
|
)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -15,4 +16,4 @@ pub struct User {
|
||||||
pub time_created: DateTime<Utc>,
|
pub time_created: DateTime<Utc>,
|
||||||
#[serde(rename = "lastUpdated")]
|
#[serde(rename = "lastUpdated")]
|
||||||
pub last_updated: DateTime<Utc>,
|
pub last_updated: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use crate::domain::credential::CredentialType;
|
use crate::domain::credential::CredentialType;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CredentialDto {
|
pub struct CredentialDto {
|
||||||
pub credential: String,
|
pub credential: String,
|
||||||
pub credential_type: CredentialType,
|
pub credential_type: CredentialType,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
pub struct HashResult {
|
pub struct HashResult {
|
||||||
pub salt: String,
|
pub salt: String,
|
||||||
pub hash: String
|
pub hash: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HashResult{
|
impl HashResult {
|
||||||
pub fn new(salt: String, hash: String) -> HashResult{
|
pub fn new(salt: String, hash: String) -> HashResult {
|
||||||
HashResult { salt, hash }
|
HashResult { salt, hash }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
pub mod users;
|
|
||||||
pub mod credential;
|
pub mod credential;
|
||||||
|
pub mod hash_result;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
pub mod hash_result;
|
pub mod users;
|
||||||
|
|
|
@ -12,4 +12,4 @@ pub struct AuthenticateUserDto {
|
||||||
pub struct RefreshAuthTokenForUserDto {
|
pub struct RefreshAuthTokenForUserDto {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub refresh_token: String,
|
pub refresh_token: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use crate::domain::credential::CredentialType;
|
use crate::domain::credential::CredentialType;
|
||||||
use crate::dto::credential::CredentialDto;
|
use crate::dto::credential::CredentialDto;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Used for logging in when you don't have a token.
|
/// Used for logging in when you don't have a token.
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -17,4 +17,4 @@ pub struct UserRegisterPayload {
|
||||||
pub credentials: Vec<CredentialDto>,
|
pub credentials: Vec<CredentialDto>,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
pub mod dao;
|
pub mod dao;
|
||||||
pub mod service;
|
|
||||||
pub mod utils;
|
|
||||||
pub mod domain;
|
pub mod domain;
|
||||||
pub mod dto;
|
pub mod dto;
|
||||||
|
pub mod resources;
|
||||||
|
pub mod service;
|
||||||
|
pub mod utils;
|
||||||
pub mod validation;
|
pub mod validation;
|
||||||
pub mod resources;
|
|
|
@ -2,28 +2,61 @@
|
||||||
// Template: pub const ERROR_KEY_OR_NAME: (&str, &str) = ("ERROR.KEY", "ERROR VALUE");
|
// Template: pub const ERROR_KEY_OR_NAME: (&str, &str) = ("ERROR.KEY", "ERROR VALUE");
|
||||||
|
|
||||||
pub type ErrorResource<'a> = (&'a str, &'a str);
|
pub type ErrorResource<'a> = (&'a str, &'a str);
|
||||||
pub const ERROR_INVALID_EMAIL: (&str, &str) = ("ERROR.INVALID_EMAIL", "Invalid email. Needs to be at least 4 characters, at most 254 and correctly formatted.");
|
pub const ERROR_INVALID_EMAIL: (&str, &str) = (
|
||||||
|
"ERROR.INVALID_EMAIL",
|
||||||
|
"Invalid email. Needs to be at least 4 characters, at most 254 and correctly formatted.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_INVALID_PHONE_NUMBER: (&str, &str) = ("ERROR.INVALID_PHONE_NUMBER", "Invalid Phone number. Needs to be 10 characters.");
|
pub const ERROR_INVALID_PHONE_NUMBER: (&str, &str) = (
|
||||||
|
"ERROR.INVALID_PHONE_NUMBER",
|
||||||
|
"Invalid Phone number. Needs to be 10 characters.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_INVALID_USERNAME: (&str, &str) = ("ERROR.INVALID_USERNAME", "Invalid Username. ");
|
pub const ERROR_INVALID_USERNAME: (&str, &str) = ("ERROR.INVALID_USERNAME", "Invalid Username. ");
|
||||||
|
|
||||||
pub const ERROR_INVALID_NAME: (&str, &str) = ("ERROR.INVALID_NAME", "Invalid name. Names should have at least 4 characters in length and at most 254.");
|
pub const ERROR_INVALID_NAME: (&str, &str) = (
|
||||||
|
"ERROR.INVALID_NAME",
|
||||||
|
"Invalid name. Names should have at least 4 characters in length and at most 254.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_INVALID_PASSWORD: (&str, &str) = ("ERROR.INVALID_PASSWORD", "Invalid password. Password should have at least 8 characters and at most 128.");
|
pub const ERROR_INVALID_PASSWORD: (&str, &str) = (
|
||||||
|
"ERROR.INVALID_PASSWORD",
|
||||||
|
"Invalid password. Password should have at least 8 characters and at most 128.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_USER_ALREADY_EXISTS: (&str, &str) = ("ERROR.USER_ALREADY_EXISTS", "A user with that email already exists.");
|
pub const ERROR_USER_ALREADY_EXISTS: (&str, &str) = (
|
||||||
|
"ERROR.USER_ALREADY_EXISTS",
|
||||||
|
"A user with that email already exists.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_USER_DOES_NOT_EXIST: (&str, &str) = ("ERROR.USER_DOES_NOT_EXIST", "User with this email does not exist.");
|
pub const ERROR_USER_DOES_NOT_EXIST: (&str, &str) = (
|
||||||
|
"ERROR.USER_DOES_NOT_EXIST",
|
||||||
|
"User with this email does not exist.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_PASSWORD_INCORRECT: (&str, &str) = ("ERROR.PASSWORD_INCORRECT", "The password you have entered is incorrect.");
|
pub const ERROR_PASSWORD_INCORRECT: (&str, &str) = (
|
||||||
|
"ERROR.PASSWORD_INCORRECT",
|
||||||
|
"The password you have entered is incorrect.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_INVALID_TOKEN: (&str, &str) = ("ERROR.INVALID_TOKEN", "The token you have supplied is not formattable.");
|
pub const ERROR_INVALID_TOKEN: (&str, &str) = (
|
||||||
|
"ERROR.INVALID_TOKEN",
|
||||||
|
"The token you have supplied is not formattable.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_INCORRECT_TOKEN: (&str, &str) = ("ERROR.INCORRECT_TOKEN", "The token you have supplied does not belong to this user.");
|
pub const ERROR_INCORRECT_TOKEN: (&str, &str) = (
|
||||||
|
"ERROR.INCORRECT_TOKEN",
|
||||||
|
"The token you have supplied does not belong to this user.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_MISSING_TOKEN: (&str, &str) = ("ERROR.MISSING_TOKEN", "No token supplied.");
|
pub const ERROR_MISSING_TOKEN: (&str, &str) = ("ERROR.MISSING_TOKEN", "No token supplied.");
|
||||||
|
|
||||||
pub const ERROR_EXPIRED_TOKEN: (&str, &str) = ("ERROR.EXPIRED_TOKEN", "The token you have supplied is expired.");
|
pub const ERROR_EXPIRED_TOKEN: (&str, &str) = (
|
||||||
|
"ERROR.EXPIRED_TOKEN",
|
||||||
|
"The token you have supplied is expired.",
|
||||||
|
);
|
||||||
|
|
||||||
pub const ERROR_CREATING_TOKEN: (&str, &str) = ("ERROR.CREATING_TOKEN", "The server had an error creating the auth tokens.");
|
pub const ERROR_CREATING_TOKEN: (&str, &str) = (
|
||||||
|
"ERROR.CREATING_TOKEN",
|
||||||
|
"The server had an error creating the auth tokens.",
|
||||||
|
);
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
pub mod error_messages;
|
pub mod error_messages;
|
||||||
pub mod variable_lengths;
|
pub mod variable_lengths;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
pub const MIN_EMAIL_LENGTH: usize = 4;
|
pub const MIN_EMAIL_LENGTH: usize = 4;
|
||||||
pub const MAX_EMAIL_LENGTH: usize = 254;
|
pub const MAX_EMAIL_LENGTH: usize = 254;
|
||||||
|
|
||||||
|
@ -12,4 +11,4 @@ pub const MIN_NAME_LENGTH: usize = 4;
|
||||||
pub const MAX_NAME_LENGTH: usize = 254;
|
pub const MAX_NAME_LENGTH: usize = 254;
|
||||||
|
|
||||||
pub const MIN_PASSWORD_LENGTH: usize = 8;
|
pub const MIN_PASSWORD_LENGTH: usize = 8;
|
||||||
pub const MAX_PASSWORD_LENGTH: usize = 128;
|
pub const MAX_PASSWORD_LENGTH: usize = 128;
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
|
mod token;
|
||||||
mod user;
|
mod user;
|
||||||
mod token;
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::dto::users::UserRegisterPayload;
|
use crate::dto::users::UserRegisterPayload;
|
||||||
|
|
||||||
pub async fn register_user(db_conn: &sqlx::PgPool, user: UserRegisterPayload) -> Result<(), ()> {
|
pub async fn register_user(db_conn: &sqlx::PgPool, user: UserRegisterPayload) -> Result<(), ()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use std::num::NonZeroU32;
|
|
||||||
use data_encoding::BASE64;
|
|
||||||
use ring::{digest, rand::{SecureRandom, SystemRandom}, pbkdf2};
|
|
||||||
use tokio::task::JoinError;
|
|
||||||
use crate::dto::hash_result::HashResult;
|
use crate::dto::hash_result::HashResult;
|
||||||
|
use data_encoding::BASE64;
|
||||||
|
use ring::{
|
||||||
|
digest, pbkdf2,
|
||||||
|
rand::{SecureRandom, SystemRandom},
|
||||||
|
};
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
use tokio::task::JoinError;
|
||||||
|
|
||||||
const SALT_ROUNDS: u32 = 1000;
|
const SALT_ROUNDS: u32 = 1000;
|
||||||
|
|
||||||
|
@ -12,27 +15,34 @@ pub async fn generate_multiple_random_token_with_rng(amount: u8) -> Result<Vec<S
|
||||||
|
|
||||||
let mut tokens = Vec::with_capacity(amount.into());
|
let mut tokens = Vec::with_capacity(amount.into());
|
||||||
|
|
||||||
for _i in 0 .. amount {
|
for _i in 0..amount {
|
||||||
let cloned_rng = rng.clone();
|
let cloned_rng = rng.clone();
|
||||||
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), //TODO: Remove this panic, make your own error and fix this
|
||||||
Err(_e) => { panic!("Failed to generate random token for some reason.") }
|
Err(_e) => {
|
||||||
}};
|
panic!("Failed to generate random token for some reason.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
tokens.push(tokio::spawn(future_token));
|
tokens.push(tokio::spawn(future_token));
|
||||||
}
|
}
|
||||||
|
|
||||||
let all_tokens = futures_util::future::join_all(tokens).await;
|
let all_tokens = futures_util::future::join_all(tokens).await;
|
||||||
let all_tokens_solved: Vec<String> = all_tokens.into_iter().map(|result| match result {
|
let all_tokens_solved: Vec<String> = all_tokens
|
||||||
Ok(string) => {string},
|
.into_iter()
|
||||||
Err(_e) => {"".to_string()}
|
.map(|result| match result {
|
||||||
}).rev().collect();
|
Ok(string) => string,
|
||||||
|
Err(_e) => "".to_string(),
|
||||||
|
})
|
||||||
|
.rev()
|
||||||
|
.collect();
|
||||||
|
|
||||||
Ok(all_tokens_solved)
|
Ok(all_tokens_solved)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_password_with_existing_salt(password: &String, input_salt: &String) -> HashResult{
|
pub 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();
|
||||||
|
@ -55,8 +65,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 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();
|
||||||
|
@ -66,9 +75,11 @@ pub fn hash_password(password: &String) -> HashResult{
|
||||||
let mut salt = [0u8; CREDENTIAL_LEN];
|
let mut salt = [0u8; CREDENTIAL_LEN];
|
||||||
|
|
||||||
// Fill array with random-generated salt
|
// Fill array with random-generated salt
|
||||||
match rng.fill(&mut salt){
|
match rng.fill(&mut salt) {
|
||||||
Ok(()) => {},
|
Ok(()) => {}
|
||||||
Err(_e) => {panic!("Failed to generate random salt for some reason.")}
|
Err(_e) => {
|
||||||
|
panic!("Failed to generate random salt for some reason.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create empty 64-bit byte array for the hash + salt
|
// Create empty 64-bit byte array for the hash + salt
|
||||||
|
@ -85,4 +96,4 @@ pub fn hash_password(password: &String) -> HashResult{
|
||||||
|
|
||||||
// Return an object containing the salt and the hash
|
// Return an object containing the salt and the hash
|
||||||
HashResult::new(BASE64.encode(&salt), BASE64.encode(&pbkdf2_hash))
|
HashResult::new(BASE64.encode(&salt), BASE64.encode(&pbkdf2_hash))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
mod hasher;
|
mod hasher;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
pub mod user_validator;
|
pub mod user_validator;
|
||||||
|
|
|
@ -1,50 +1,59 @@
|
||||||
|
|
||||||
|
|
||||||
use crate::{resources::{variable_lengths::{MAX_EMAIL_LENGTH, MIN_EMAIL_LENGTH, MIN_NAME_LENGTH, MAX_NAME_LENGTH, MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH}, error_messages::{ERROR_INVALID_NAME, ERROR_INVALID_EMAIL, ERROR_INVALID_PASSWORD, ERROR_INVALID_PHONE_NUMBER}}};
|
|
||||||
use crate::domain::credential::CredentialType;
|
use crate::domain::credential::CredentialType;
|
||||||
use crate::dto::users::{UserLoginPayload, UserRegisterPayload};
|
use crate::dto::users::{UserLoginPayload, UserRegisterPayload};
|
||||||
use crate::resources::error_messages::{ERROR_INVALID_USERNAME, ErrorResource};
|
use crate::resources::error_messages::{ErrorResource, ERROR_INVALID_USERNAME};
|
||||||
|
use crate::resources::{
|
||||||
|
error_messages::{
|
||||||
|
ERROR_INVALID_EMAIL, ERROR_INVALID_NAME, ERROR_INVALID_PASSWORD, ERROR_INVALID_PHONE_NUMBER,
|
||||||
|
},
|
||||||
|
variable_lengths::{
|
||||||
|
MAX_EMAIL_LENGTH, MAX_NAME_LENGTH, MAX_PASSWORD_LENGTH, MIN_EMAIL_LENGTH, MIN_NAME_LENGTH,
|
||||||
|
MIN_PASSWORD_LENGTH,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
fn validate_user_email(email: &String) -> bool {
|
fn validate_user_email(email: &String) -> bool {
|
||||||
email.len() >= MIN_EMAIL_LENGTH.into() &&
|
email.len() >= MIN_EMAIL_LENGTH.into()
|
||||||
email.len() <= MAX_EMAIL_LENGTH.into() &&
|
&& email.len() <= MAX_EMAIL_LENGTH.into()
|
||||||
email.contains('@') &&
|
&& email.contains('@')
|
||||||
email.contains('.')
|
&& email.contains('.')
|
||||||
}
|
}
|
||||||
fn validate_user_phone_number(email: &String) -> bool {
|
fn validate_user_phone_number(email: &String) -> bool {
|
||||||
email.len() >= CredentialType::get_max_length(&CredentialType::PhoneNumber) &&
|
email.len() >= CredentialType::get_max_length(&CredentialType::PhoneNumber)
|
||||||
email.len() <= CredentialType::get_min_length(&CredentialType::PhoneNumber)
|
&& email.len() <= CredentialType::get_min_length(&CredentialType::PhoneNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_user_username(username: &String) -> bool {
|
fn validate_user_username(username: &String) -> bool {
|
||||||
username.len() >= CredentialType::get_max_length(&CredentialType::PhoneNumber) &&
|
username.len() >= CredentialType::get_max_length(&CredentialType::PhoneNumber)
|
||||||
username.len() <= CredentialType::get_min_length(&CredentialType::PhoneNumber)
|
&& username.len() <= CredentialType::get_min_length(&CredentialType::PhoneNumber)
|
||||||
}
|
}
|
||||||
fn validate_user_name(name: &String) -> bool {
|
fn validate_user_name(name: &String) -> bool {
|
||||||
name.len() >= MIN_NAME_LENGTH.into() &&
|
name.len() >= MIN_NAME_LENGTH.into() && name.len() <= MAX_NAME_LENGTH.into()
|
||||||
name.len() <= MAX_NAME_LENGTH.into()
|
|
||||||
}
|
}
|
||||||
fn validate_user_password(password: &String) -> bool {
|
fn validate_user_password(password: &String) -> bool {
|
||||||
password.len() >= MIN_PASSWORD_LENGTH.into() &&
|
password.len() >= MIN_PASSWORD_LENGTH.into() && password.len() <= MAX_PASSWORD_LENGTH.into()
|
||||||
password.len() <= MAX_PASSWORD_LENGTH.into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_user_for_creation(user: &UserRegisterPayload, error_resources: &mut Vec<ErrorResource>){
|
pub fn validate_user_for_creation(
|
||||||
for credential_dto in user.credentials {
|
user: &UserRegisterPayload,
|
||||||
|
error_resources: &mut Vec<ErrorResource>,
|
||||||
|
) {
|
||||||
|
for credential_dto in user.credentials.iter() {
|
||||||
match credential_dto.credential_type {
|
match credential_dto.credential_type {
|
||||||
CredentialType::Email =>
|
CredentialType::Email => {
|
||||||
if !validate_user_email(&credential_dto.credential) {
|
if !validate_user_email(&credential_dto.credential) {
|
||||||
error_resources.push(ERROR_INVALID_EMAIL);
|
error_resources.push(ERROR_INVALID_EMAIL);
|
||||||
},
|
}
|
||||||
CredentialType::PhoneNumber =>
|
}
|
||||||
|
CredentialType::PhoneNumber => {
|
||||||
if !validate_user_phone_number(&credential_dto.credential) {
|
if !validate_user_phone_number(&credential_dto.credential) {
|
||||||
error_resources.push(ERROR_INVALID_PHONE_NUMBER);
|
error_resources.push(ERROR_INVALID_PHONE_NUMBER);
|
||||||
},
|
}
|
||||||
CredentialType::Username =>
|
}
|
||||||
|
CredentialType::Username => {
|
||||||
if !validate_user_username(&credential_dto.credential) {
|
if !validate_user_username(&credential_dto.credential) {
|
||||||
error_resources.push(ERROR_INVALID_USERNAME);
|
error_resources.push(ERROR_INVALID_USERNAME);
|
||||||
},
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,22 +64,28 @@ pub fn validate_user_for_creation(user: &UserRegisterPayload, error_resources: &
|
||||||
error_resources.push(ERROR_INVALID_PASSWORD);
|
error_resources.push(ERROR_INVALID_PASSWORD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn validate_user_for_password_authentication(user: &UserLoginPayload, error_resources: &mut Vec<ErrorResource>){
|
pub fn validate_user_for_password_authentication(
|
||||||
|
user: &UserLoginPayload,
|
||||||
|
error_resources: &mut Vec<ErrorResource>,
|
||||||
|
) {
|
||||||
match user.credential_type {
|
match user.credential_type {
|
||||||
CredentialType::Email =>
|
CredentialType::Email => {
|
||||||
if !validate_user_email(&user.credential) {
|
if !validate_user_email(&user.credential) {
|
||||||
error_resources.push(ERROR_INVALID_EMAIL);
|
error_resources.push(ERROR_INVALID_EMAIL);
|
||||||
},
|
}
|
||||||
CredentialType::PhoneNumber =>
|
}
|
||||||
if !validate_user_phone_number(&user.credential) {
|
CredentialType::PhoneNumber => {
|
||||||
error_resources.push(ERROR_INVALID_PHONE_NUMBER);
|
if !validate_user_phone_number(&user.credential) {
|
||||||
},
|
error_resources.push(ERROR_INVALID_PHONE_NUMBER);
|
||||||
CredentialType::Username =>
|
}
|
||||||
if !validate_user_username(&user.credential) {
|
}
|
||||||
error_resources.push(ERROR_INVALID_USERNAME);
|
CredentialType::Username => {
|
||||||
},
|
if !validate_user_username(&user.credential) {
|
||||||
|
error_resources.push(ERROR_INVALID_USERNAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !validate_user_password(&user.password) {
|
if !validate_user_password(&user.password) {
|
||||||
error_resources.push(ERROR_INVALID_PASSWORD);
|
error_resources.push(ERROR_INVALID_PASSWORD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue