From 5bd9535b8539cdb5b0d73a14cd68c71ec44fca1a Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Mon, 24 Oct 2022 16:36:21 +0200 Subject: [PATCH 1/9] refactor: use DATABASE_URL env variable for db connection instead of url var in Rocket.toml --- api/Cargo.toml | 1 + api/src/pool.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/api/Cargo.toml b/api/Cargo.toml index 9b40183..80dfd3c 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -12,6 +12,7 @@ futures-util = { version = "^0.3" } rocket = { version = "0.5.0-rc.2", features = [ "json", ] } +dotenv = "0.15.0" serde_json = { version = "^1" } diff --git a/api/src/pool.rs b/api/src/pool.rs index 69287ae..4b123bc 100644 --- a/api/src/pool.rs +++ b/api/src/pool.rs @@ -21,15 +21,21 @@ impl sea_orm_rocket::Pool for SeaOrmPool { type Connection = sea_orm::DatabaseConnection; async fn init(figment: &Figment) -> Result { - let config = figment.extract::().unwrap(); - let mut options: ConnectOptions = config.url.into(); + dotenv::dotenv().ok(); + let database_url = std::env::var("DATABASE_URL").unwrap(); + let mut options: ConnectOptions = database_url.into(); options + .max_connections(1024) + .min_connections(0) + .connect_timeout(Duration::from_secs(3)); + + /* options .max_connections(config.max_connections as u32) .min_connections(config.min_connections.unwrap_or_default()) .connect_timeout(Duration::from_secs(config.connect_timeout)); if let Some(idle_timeout) = config.idle_timeout { options.idle_timeout(Duration::from_secs(idle_timeout)); - } + } */ let conn = sea_orm::Database::connect(options).await?; Ok(SeaOrmPool { conn }) From d44082d3d83c85052cb3ed632ca430e6544cd19c Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Mon, 24 Oct 2022 18:36:01 +0200 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20create=20candidate=20&=20generate?= =?UTF-8?q?=20code,=20s=20autoincrementem=20application=20id=20uchaze?= =?UTF-8?q?=C4=8De=20normalne=20funguje?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/src/lib.rs | 18 +++++++++--------- core/Cargo.toml | 3 +++ core/src/crypto.rs | 25 +++++++++++++++++++++++++ core/src/lib.rs | 1 + core/src/mutation.rs | 15 ++++++++++++++- entity/src/admin.rs | 4 +--- entity/src/candidate.rs | 21 +++++++++++++-------- entity/src/mod.rs | 7 +++++++ entity/src/parent.rs | 14 ++++++-------- entity/src/prelude.rs | 2 ++ 10 files changed, 81 insertions(+), 29 deletions(-) create mode 100644 core/src/crypto.rs create mode 100644 entity/src/mod.rs diff --git a/api/src/lib.rs b/api/src/lib.rs index df560b8..bb72f81 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -1,12 +1,9 @@ #[macro_use] extern crate rocket; +use rocket::{Rocket, Build}; use rocket::serde::json::Json; - use rocket::fairing::{self, AdHoc}; -use rocket::form::{ Form}; -use rocket::fs::{relative, FileServer}; -use rocket::response::{Flash, Redirect}; -use rocket::{Build, Rocket}; +use rocket::response::status::BadRequest; use portfolio_core::{Mutation, Query}; use migration::MigratorTrait; @@ -18,18 +15,21 @@ use pool::Db; pub use entity::candidate; pub use entity::candidate::Entity as Candidate; +use portfolio_core::crypto::{self, random_8_char_string}; + #[post("/", data = "")] -async fn create(conn: Connection<'_, Db>, post_form: Json) -> Flash { +async fn create(conn: Connection<'_, Db>, post_form: Json) -> Result> { let db = conn.into_inner(); - let form = post_form.into_inner(); - Mutation::create_candidate(db, form) + let plain_text_password = random_8_char_string(); + + Mutation::create_candidate(db, form, &plain_text_password) .await .expect("could not insert post"); - Flash::success(Redirect::to("/"), "Post successfully added.") + Ok(plain_text_password) } #[get("/hello")] diff --git a/core/Cargo.toml b/core/Cargo.toml index 3793774..098a79a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -5,6 +5,9 @@ edition = "2021" [dependencies] portfolio-entity = { path = "../entity" } +rand = "0.8.5" +rust-argon2 = "1.0.0" +chrono = "0.4.22" [dependencies.sea-orm] version = "^0.10.0" diff --git a/core/src/crypto.rs b/core/src/crypto.rs new file mode 100644 index 0000000..31eb606 --- /dev/null +++ b/core/src/crypto.rs @@ -0,0 +1,25 @@ +use argon2::{self, Config}; +use rand::Rng; + +pub fn random_8_char_string() -> String { + rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(8) + .map(char::from) + .collect::() +} + +pub fn hash_password(password_plaint_text: &str) -> String { + let hash = argon2::hash_encoded( + password_plaint_text.as_bytes(), + b"secretlytestingeverything", + &Config::default() + ) + .unwrap(); + + hash +} + +pub fn verify_password(password_plaint_text: &str, hash: &str) -> bool { + argon2::verify_encoded(hash, password_plaint_text.as_bytes()).unwrap() +} \ No newline at end of file diff --git a/core/src/lib.rs b/core/src/lib.rs index 4a80f23..0ebcef0 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,5 +1,6 @@ mod mutation; mod query; +pub mod crypto; pub use mutation::*; pub use query::*; diff --git a/core/src/mutation.rs b/core/src/mutation.rs index f3f9e61..16ec10a 100644 --- a/core/src/mutation.rs +++ b/core/src/mutation.rs @@ -1,5 +1,6 @@ use ::entity::{candidate, candidate::Entity as Candidate}; use sea_orm::*; +use crate::crypto::{self, hash_password}; pub struct Mutation; @@ -7,7 +8,19 @@ impl Mutation { pub async fn create_candidate( db: &DbConn, form_data: candidate::Model, + plain_text_password: &String, ) -> Result { - todo!() + let hashed_password = hash_password(plain_text_password); + candidate::ActiveModel { + application: Set(145 as i32), // TODO NEFUNGUJE + code: Set(hashed_password), + public_key: Set("lorem ipsum pub key".to_string()), + private_key: Set("lorem ipsum priv key".to_string()), + created_at: Set(chrono::offset::Local::now().naive_local()), + updated_at: Set(chrono::offset::Local::now().naive_local()), + ..Default::default() + } + .save(db) + .await } } diff --git a/entity/src/admin.rs b/entity/src/admin.rs index 1dd8420..ccfab5a 100644 --- a/entity/src/admin.rs +++ b/entity/src/admin.rs @@ -1,10 +1,8 @@ //! SeaORM Entity. Generated by sea-orm-codegen 0.9.3 use sea_orm::entity::prelude::*; -use rocket::serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] -#[serde(crate = "rocket::serde")] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] #[sea_orm(table_name = "admin")] pub struct Model { #[sea_orm(primary_key)] diff --git a/entity/src/candidate.rs b/entity/src/candidate.rs index 7c20178..9638590 100644 --- a/entity/src/candidate.rs +++ b/entity/src/candidate.rs @@ -1,7 +1,8 @@ -//! SeaORM Entity. Generated by sea-orm-codegen 0.10.0 -use chrono::{DateTime, NaiveDate, Local}; -use rocket::serde::{Deserialize, Serialize}; +//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3 + use sea_orm::entity::prelude::*; +use rocket::serde::{self, Deserialize, Serialize}; + #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] @@ -9,26 +10,30 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub application: i32, + #[serde(skip_deserializing, skip_serializing)] pub code: String, pub name: Option, pub surname: Option, pub birth_surname: Option, pub birthplace: Option, - pub birthdate: Option, + pub birthdate: Option, pub address: Option, pub telephone: Option, - #[sea_orm(default_value="Česká republika")] pub citizenship: Option, pub email: Option, pub sex: Option, pub study: Option, pub personal_identification_number: Option, - #[sea_orm(column_type = "Text")] + #[sea_orm(column_type = "Text", nullable)] pub personal_identification_number_hash: Option, + #[serde(skip_deserializing, skip_serializing)] pub public_key: String, + #[serde(skip_deserializing, skip_serializing)] pub private_key: String, - pub created_at: DateTime, - pub updated_at: DateTime, + #[serde(skip_deserializing, skip_serializing)] + pub created_at: DateTime, + #[serde(skip_deserializing, skip_serializing)] + pub updated_at: DateTime, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/entity/src/mod.rs b/entity/src/mod.rs new file mode 100644 index 0000000..642518a --- /dev/null +++ b/entity/src/mod.rs @@ -0,0 +1,7 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3 + +pub mod prelude; + +pub mod admin; +pub mod candidate; +pub mod parent; diff --git a/entity/src/parent.rs b/entity/src/parent.rs index 48e1f7c..4cf47cc 100644 --- a/entity/src/parent.rs +++ b/entity/src/parent.rs @@ -1,10 +1,8 @@ -//! SeaORM Entity. Generated by sea-orm-codegen 0.10.0 -use sea_orm::entity::prelude::*; -use chrono::{DateTime, Local}; -use rocket::serde::{Deserialize, Serialize}; +//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3 -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] -#[serde(crate = "rocket::serde")] +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel)] #[sea_orm(table_name = "parent")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] @@ -13,8 +11,8 @@ pub struct Model { pub surname: Option, pub telephone: Option, pub email: Option, - pub created_at: DateTime, - pub updated_at: DateTime, + pub created_at: DateTime, + pub updated_at: DateTime, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/entity/src/prelude.rs b/entity/src/prelude.rs index eba3b7f..06a7e4b 100644 --- a/entity/src/prelude.rs +++ b/entity/src/prelude.rs @@ -1,3 +1,5 @@ +//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3 + pub use super::admin::Entity as Admin; pub use super::candidate::Entity as Candidate; pub use super::parent::Entity as Parent; From 00e050986ee0d7eaea2a510687bf57d5022e8a13 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Mon, 24 Oct 2022 19:15:16 +0200 Subject: [PATCH 3/9] =?UTF-8?q?fix:=20unable=20to=20insert=20kv=C5=AFli=20?= =?UTF-8?q?primary=20key=20-=20using=20insert=20instead=20of=20save?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/mutation.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/mutation.rs b/core/src/mutation.rs index 16ec10a..30d7c04 100644 --- a/core/src/mutation.rs +++ b/core/src/mutation.rs @@ -9,10 +9,10 @@ impl Mutation { db: &DbConn, form_data: candidate::Model, plain_text_password: &String, - ) -> Result { + ) -> Result { let hashed_password = hash_password(plain_text_password); candidate::ActiveModel { - application: Set(145 as i32), // TODO NEFUNGUJE + application: Set(form_data.application), // TODO NEFUNGUJE code: Set(hashed_password), public_key: Set("lorem ipsum pub key".to_string()), private_key: Set("lorem ipsum priv key".to_string()), @@ -20,7 +20,7 @@ impl Mutation { updated_at: Set(chrono::offset::Local::now().naive_local()), ..Default::default() } - .save(db) + .insert(db) .await } } From b7da8d579cb5cd9470e4770deed09fcff0a16fac Mon Sep 17 00:00:00 2001 From: EETagent Date: Mon, 24 Oct 2022 19:24:58 +0200 Subject: [PATCH 4/9] =?UTF-8?q?chore:=20mod.rs=20z=20entity=20znovu=20pry?= =?UTF-8?q?=C4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entity/src/mod.rs | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 entity/src/mod.rs diff --git a/entity/src/mod.rs b/entity/src/mod.rs deleted file mode 100644 index 642518a..0000000 --- a/entity/src/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3 - -pub mod prelude; - -pub mod admin; -pub mod candidate; -pub mod parent; From 50abef29e390a7cd0315a413ab07831d0427d1ed Mon Sep 17 00:00:00 2001 From: EETagent Date: Mon, 24 Oct 2022 19:54:36 +0200 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20nov=C3=BD=20argon2,=20vracen=C3=AD?= =?UTF-8?q?=20result?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/Cargo.toml | 2 +- core/src/crypto.rs | 35 +++++++++++++++++++++++------------ core/src/mutation.rs | 3 ++- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/core/Cargo.toml b/core/Cargo.toml index 098a79a..4b41cec 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] portfolio-entity = { path = "../entity" } rand = "0.8.5" -rust-argon2 = "1.0.0" +argon2 = "0.4.1" chrono = "0.4.22" [dependencies.sea-orm] diff --git a/core/src/crypto.rs b/core/src/crypto.rs index 31eb606..fb6c4c6 100644 --- a/core/src/crypto.rs +++ b/core/src/crypto.rs @@ -1,4 +1,6 @@ -use argon2::{self, Config}; +use argon2::{ + Argon2, PasswordHasher as ArgonPasswordHasher, PasswordVerifier as ArgonPasswordVerifier, +}; use rand::Rng; pub fn random_8_char_string() -> String { @@ -9,17 +11,26 @@ pub fn random_8_char_string() -> String { .collect::() } -pub fn hash_password(password_plaint_text: &str) -> String { - let hash = argon2::hash_encoded( - password_plaint_text.as_bytes(), - b"secretlytestingeverything", - &Config::default() - ) - .unwrap(); +pub fn hash_password(password_plaint_text: &str) -> Result { + let password = password_plaint_text.as_bytes(); + let salt = "c2VjcmV0bHl0ZXN0aW5nZXZlcnl0aGluZw"; - hash + let argon_config = Argon2::default(); + + let hash = argon_config.hash_password(password, salt)?; + + return Ok(hash.to_string()); } -pub fn verify_password(password_plaint_text: &str, hash: &str) -> bool { - argon2::verify_encoded(hash, password_plaint_text.as_bytes()).unwrap() -} \ No newline at end of file +pub fn verify_password( + password_plaint_text: &str, + hash: &str, +) -> Result { + let argon_config = Argon2::default(); + + let parsed_hash = argon2::PasswordHash::new(&hash)?; + + return Ok(argon_config + .verify_password(password_plaint_text.as_bytes(), &parsed_hash) + .is_ok()); +} diff --git a/core/src/mutation.rs b/core/src/mutation.rs index 30d7c04..d5ae79b 100644 --- a/core/src/mutation.rs +++ b/core/src/mutation.rs @@ -10,7 +10,8 @@ impl Mutation { form_data: candidate::Model, plain_text_password: &String, ) -> Result { - let hashed_password = hash_password(plain_text_password); + // TODO: unwrap pro testing.. + let hashed_password = hash_password(plain_text_password).unwrap(); candidate::ActiveModel { application: Set(form_data.application), // TODO NEFUNGUJE code: Set(hashed_password), From 29ff462ef951de9d5ac027316b5a69a19b157e6d Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Mon, 24 Oct 2022 20:39:36 +0200 Subject: [PATCH 6/9] style: code cleanup --- api/src/lib.rs | 14 +++++++------- core/src/mutation.rs | 4 ++-- entity/src/candidate.rs | 2 +- entity/src/lib.rs | 3 --- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/api/src/lib.rs b/api/src/lib.rs index bb72f81..5ba1fbd 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -3,10 +3,10 @@ extern crate rocket; use rocket::{Rocket, Build}; use rocket::serde::json::Json; use rocket::fairing::{self, AdHoc}; -use rocket::response::status::BadRequest; -use portfolio_core::{Mutation, Query}; +use rocket::response::status::Custom; +use portfolio_core::{Mutation}; -use migration::MigratorTrait; +use migration::{MigratorTrait}; use sea_orm_rocket::{Connection, Database}; mod pool; @@ -15,11 +15,11 @@ use pool::Db; pub use entity::candidate; pub use entity::candidate::Entity as Candidate; -use portfolio_core::crypto::{self, random_8_char_string}; +use portfolio_core::crypto::random_8_char_string; #[post("/", data = "")] -async fn create(conn: Connection<'_, Db>, post_form: Json) -> Result> { +async fn create(conn: Connection<'_, Db>, post_form: Json) -> Result> { let db = conn.into_inner(); let form = post_form.into_inner(); @@ -27,9 +27,9 @@ async fn create(conn: Connection<'_, Db>, post_form: Json) -> Mutation::create_candidate(db, form, &plain_text_password) .await - .expect("could not insert post"); + .expect("Could not insert candidate"); - Ok(plain_text_password) + Ok(plain_text_password) } #[get("/hello")] diff --git a/core/src/mutation.rs b/core/src/mutation.rs index d5ae79b..db5844c 100644 --- a/core/src/mutation.rs +++ b/core/src/mutation.rs @@ -1,6 +1,6 @@ -use ::entity::{candidate, candidate::Entity as Candidate}; +use ::entity::{candidate}; use sea_orm::*; -use crate::crypto::{self, hash_password}; +use crate::crypto::hash_password; pub struct Mutation; diff --git a/entity/src/candidate.rs b/entity/src/candidate.rs index 9638590..d9199ce 100644 --- a/entity/src/candidate.rs +++ b/entity/src/candidate.rs @@ -1,7 +1,7 @@ //! SeaORM Entity. Generated by sea-orm-codegen 0.9.3 use sea_orm::entity::prelude::*; -use rocket::serde::{self, Deserialize, Serialize}; +use rocket::serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] diff --git a/entity/src/lib.rs b/entity/src/lib.rs index ffaaadc..5c0177c 100644 --- a/entity/src/lib.rs +++ b/entity/src/lib.rs @@ -1,6 +1,3 @@ -#[macro_use] -extern crate rocket; - pub mod prelude; pub mod admin; From 15205e8ec4bf729e55f7e9397873a87410d0098d Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Mon, 24 Oct 2022 21:37:47 +0200 Subject: [PATCH 7/9] feat: foolproof random string function --- core/src/crypto.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/core/src/crypto.rs b/core/src/crypto.rs index fb6c4c6..6ea97b9 100644 --- a/core/src/crypto.rs +++ b/core/src/crypto.rs @@ -3,12 +3,29 @@ use argon2::{ }; use rand::Rng; + +/// Foolproof random 8 char string +/// only uppercase letters (except for 0 and O) and numbers +/// TODO tests pub fn random_8_char_string() -> String { - rand::thread_rng() + let iterator = rand::thread_rng() .sample_iter(&rand::distributions::Alphanumeric) - .take(8) - .map(char::from) - .collect::() + .map(char::from); + + + let mut s = String::new(); + for c in iterator { // remove all uppercase and lowercase characters, exclude 0 and O + if ('1'..='9').contains(&c) || + ('A'..='N').contains(&c) || + ('P'..'Z').contains(&c) + { + s.push(c); + if s.len() == 8 { + break; + } + } + } + s } pub fn hash_password(password_plaint_text: &str) -> Result { From 3c35762455874577f79c8b8e820c53831247e699 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Mon, 24 Oct 2022 22:05:22 +0200 Subject: [PATCH 8/9] style: typo --- core/src/crypto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/crypto.rs b/core/src/crypto.rs index 6ea97b9..7047e55 100644 --- a/core/src/crypto.rs +++ b/core/src/crypto.rs @@ -14,7 +14,7 @@ pub fn random_8_char_string() -> String { let mut s = String::new(); - for c in iterator { // remove all uppercase and lowercase characters, exclude 0 and O + for c in iterator { // add all characters except for: lowercase chars, 0 and O if ('1'..='9').contains(&c) || ('A'..='N').contains(&c) || ('P'..'Z').contains(&c) From 6c98b7e7ce487beaccc0c44b9faf27a9770cac2d Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Mon, 24 Oct 2022 22:14:57 +0200 Subject: [PATCH 9/9] style: typo --- core/src/mutation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mutation.rs b/core/src/mutation.rs index db5844c..ac04626 100644 --- a/core/src/mutation.rs +++ b/core/src/mutation.rs @@ -13,7 +13,7 @@ impl Mutation { // TODO: unwrap pro testing.. let hashed_password = hash_password(plain_text_password).unwrap(); candidate::ActiveModel { - application: Set(form_data.application), // TODO NEFUNGUJE + application: Set(form_data.application), code: Set(hashed_password), public_key: Set("lorem ipsum pub key".to_string()), private_key: Set("lorem ipsum priv key".to_string()),