Create user endpoint perfected and finished

This commit is contained in:
franklinblanco 2022-06-27 17:54:51 -04:00
parent a71402aad0
commit 964e655e1c
13 changed files with 96 additions and 23 deletions

View File

@ -13,4 +13,5 @@ sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "mysql", "chrono"
actix-web = "4"
chrono = { version = "0.4", features = [ "serde" ] }
ring = "0.16.20"
data-encoding = "2.3.2"
data-encoding = "2.3.2"
futures-util = "0.3"

View File

@ -4,6 +4,6 @@ CREATE TABLE IF NOT EXISTS user (
last_updated TIMESTAMP NOT NULL,
email VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
salt VARCHAR(255) NOT NULL
password TEXT NOT NULL,
salt TEXT NOT NULL
)

View File

@ -3,6 +3,6 @@ CREATE TABLE IF NOT EXISTS token (
user_id INT NOT NULL,
time_created TIMESTAMP NOT NULL,
last_updated TIMESTAMP NOT NULL,
auth_token VARCHAR(255) NOT NULL,
refresh_token VARCHAR(255) NOT NULL
auth_token TEXT NOT NULL,
refresh_token TEXT NOT NULL
)

View File

@ -3,6 +3,6 @@ CREATE TABLE IF NOT EXISTS token (
user_id INT NOT NULL,
time_created TIMESTAMP NOT NULL,
last_updated TIMESTAMP NOT NULL,
auth_token VARCHAR(255) NOT NULL,
refresh_token VARCHAR(255) NOT NULL
auth_token TEXT NOT NULL,
refresh_token TEXT NOT NULL
)

View File

@ -4,6 +4,6 @@ CREATE TABLE IF NOT EXISTS user (
last_updated TIMESTAMP NOT NULL,
email VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,
password TEXT NOT NULL,
salt VARCHAR(255) NOT NULL
)

View File

@ -1,2 +1,3 @@
pub mod main_dao;
pub mod user_dao;
pub mod user_dao;
pub mod token_dao;

7
src/dao/token_dao.rs Normal file
View File

@ -0,0 +1,7 @@
use sqlx::{MySqlConnection, mysql::MySqlQueryResult};
use crate::r#do::token::Token;
pub async fn insert_token(conn: &mut MySqlConnection, token: &Token) -> Result<MySqlQueryResult, sqlx::Error> {
sqlx::query_file!("sql/schema/token/insert.sql", token.user_id, token.auth_token, token.refresh_token).execute(conn).await
}

View File

@ -1,2 +1,3 @@
pub mod shared_state;
pub mod user;
pub mod user;
pub mod token;

24
src/do/token.rs Normal file
View File

@ -0,0 +1,24 @@
use chrono::NaiveDateTime;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Token {
pub id: i32,
pub user_id: i32,
pub time_created: Option<NaiveDateTime>,
pub last_updated: Option<NaiveDateTime>,
pub auth_token: String,
pub refresh_token: String
}
impl Token{
pub fn new(user_id: i32, auth_token: String, refresh_token: String) -> Token{
Token {
id: 0,
user_id,
time_created: None,
last_updated: None,
auth_token,
refresh_token
}
}
}

View File

@ -1,11 +1,10 @@
use std::{sync::Mutex};
use actix_web::{HttpServer, App, web};
use crate::r#do::shared_state::SharedStateObj;
use crate::{r#do::shared_state::SharedStateObj};
use super::user_routes;
// This function is to be used in case code is meant to be run after server startup
pub fn after_startup_fn(){
pub fn after_startup_fn() {
println!("{}", "Started server.");
}
@ -47,6 +46,6 @@ pub async fn start_all_routes(after_startup_fn_call: &dyn Fn(), state: SharedSta
// Actual server start and after startup call
let (server_start_result, _after_startup_value) =
tokio::join!(server_future, async {after_startup_fn_call();});
tokio::join!(server_future, async {after_startup_fn_call});
return server_start_result; // Return server
}

View File

@ -1,9 +1,9 @@
use std::sync::Mutex;
use actix_web::{web::{self, Data}, HttpResponse, post};
use sqlx::{MySqlConnection};
use sqlx::MySqlConnection;
use crate::{r#do::user::User, dao::user_dao::{insert_user}, dto::{user_dtos::UserForCreationDto, message_resources_dtos::MessageResourceDto}, validation::user_validator, util::hasher};
use crate::{r#do::user::User, dao::{user_dao::{insert_user}, token_dao::insert_token}, dto::{user_dtos::UserForCreationDto, message_resources_dtos::MessageResourceDto}, validation::user_validator, util::hasher, r#do::token::Token};
/*#[get("/user/{id}")]
pub async fn get_user_from_db(id: Path<i32>, db_conn: Data<Mutex<MySqlConnection>>) -> HttpResponse {
@ -38,13 +38,27 @@ pub async fn create_user(incoming_user: web::Json<UserForCreationDto>, db_conn:
// Try to insert user in DB
match insert_user(&mut db_conn.lock().unwrap(), &user_to_insert).await{
Ok(_resultrs) => {},
Ok(resultrs) => {
user_to_insert.id = resultrs.last_insert_id() as i32;
},
Err(error) => {
println!("Error while inserting user in database from create_user method. Log: {}", error);
return HttpResponse::InternalServerError().json(web::Json(()))
}};
// TODO: Create token and send it back.
// Create token and send it back.
let tokens: Vec<String> = hasher::generate_multiple_random_token_with_rng(2).await.expect("msg");
let mut token_to_insert =
Token::new(user_to_insert.id,
tokens.get(0).expect("msg").to_string(),
tokens.get(1).expect("msg").to_string()
);
match insert_token(&mut db_conn.lock().unwrap(), &token_to_insert).await{
Ok(resultrs) => {token_to_insert.id = resultrs.last_insert_id() as i32},
Err(e) => {panic!("{e}")}
}
// All good? Send an OK!
HttpResponse::Ok().body(())
HttpResponse::Ok().json(web::Json(token_to_insert))
}

View File

@ -1,9 +1,35 @@
use std::{num::NonZeroU32};
use std::num::NonZeroU32;
use data_encoding::HEXUPPER;
use ring::{digest, rand::{SecureRandom, SystemRandom}, pbkdf2, error::Unspecified};
use tokio::task::JoinError;
use crate::dto::hash_dtos::HashResult;
pub async fn generate_multiple_random_token_with_rng(amount: u8) -> Result<Vec<String>, JoinError> {
// Get a new instance of a Random Number Generator
let rng = SystemRandom::new();
let mut tokens = Vec::with_capacity(amount.into());
for _i in 0 .. amount {
let cloned_rng = rng.clone();
let future_token = async move {
let mut token_arr = [0u8; digest::SHA512_OUTPUT_LEN];
match cloned_rng.fill(&mut token_arr){
Ok(()) => {HEXUPPER.encode(&token_arr)},
Err(_e) => { panic!("Failed to generate random token for some reason.") }
}};
tokens.push(tokio::spawn(future_token));
}
let all_tokens = futures_util::future::join_all(tokens).await;
let all_tokens_solved: Vec<String> = all_tokens.into_iter().map(|result| match result {
Ok(string) => {string},
Err(_e) => {"".to_string()}
}).rev().collect();
Ok(all_tokens_solved)
}
pub fn hash_password(password: &String) -> HashResult{
// Get output length from a sha512 hash

View File

@ -19,13 +19,13 @@ fn validate_user_password(password: &String) -> bool {
}
// User dto SHOULD die here.
pub fn validate_user_for_creation(user: UserForCreationDto, message_resources: &mut Vec<MessageResourceDto>){
if validate_user_email(&user.email) {
if !validate_user_email(&user.email) {
message_resources.push(MessageResourceDto::new_from_error_message(ERROR_INVALID_EMAIL));
}
if validate_user_name(&user.name) {
if !validate_user_name(&user.name) {
message_resources.push(MessageResourceDto::new_from_error_message(ERROR_INVALID_NAME));
}
if validate_user_password(&user.password) {
if !validate_user_password(&user.password) {
message_resources.push(MessageResourceDto::new_from_error_message(ERROR_INVALID_PASSWORD));
}
}