diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index 0bfa1d5..5aa2045 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -1,58 +1,17 @@ use chrono::NaiveDate; use entity::candidate; -use sea_orm::{DbConn, prelude::Uuid}; +use sea_orm::{prelude::Uuid, DbConn}; -use crate::{Mutation, crypto::{hash_password, self}, error::{ServiceError}, Query}; +use crate::{ + crypto::{self, hash_password}, + error::ServiceError, + Mutation, Query, +}; use super::session_service::SessionService; const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"]; -pub struct EncryptedAddUserData { - pub name: String, - pub surname: String, - pub birthplace: String, - pub birthdate: NaiveDate, - pub address: String, - pub telephone: String, - pub citizenship: String, - pub email: String, - pub sex: String, - pub study: String, -} - -pub struct AddUserDetailsForm { - pub application_id: i32, - - pub name: String, - pub surname: String, - pub birthplace: String, - pub birthdate: NaiveDate, - pub address: String, - pub telephone: String, - pub citizenship: String, - pub email: String, - pub sex: String, - pub study: String, -} - -impl AddUserDetailsForm { - pub async fn to_encrypted(self, recipients: Vec<&str>) -> EncryptedAddUserData { - EncryptedAddUserData { - name: crypto::encrypt_password_with_recipients(&self.name, &recipients).await.unwrap(), - surname: crypto::encrypt_password_with_recipients(&self.surname, &recipients).await.unwrap(), - birthplace: crypto::encrypt_password_with_recipients(&self.birthplace, &recipients).await.unwrap(), - birthdate: self.birthdate, // TODO: encrypt - address: crypto::encrypt_password_with_recipients(&self.address, &recipients).await.unwrap(), - telephone: crypto::encrypt_password_with_recipients(&self.telephone, &recipients).await.unwrap(), - citizenship: crypto::encrypt_password_with_recipients(&self.citizenship, &recipients).await.unwrap(), - email: crypto::encrypt_password_with_recipients(&self.email, &recipients).await.unwrap(), - sex: crypto::encrypt_password_with_recipients(&self.sex, &recipients).await.unwrap(), - study: crypto::encrypt_password_with_recipients(&self.study, &recipients).await.unwrap(), - } - } -} - pub struct CandidateService; impl CandidateService { @@ -65,68 +24,132 @@ impl CandidateService { db: &DbConn, application_id: i32, plain_text_password: &String, - personal_id_number: String - ) -> Result{ + personal_id_number: String, + ) -> Result { // Check if application id starts with 101, 102 or 103 if !CandidateService::is_application_id_valid(application_id) { - return Err(ServiceError::InvalidApplicationId) + return Err(ServiceError::InvalidApplicationId); } // Check if user with that application id already exists - if Query::find_candidate_by_id(db, application_id).await.unwrap().is_some() { - return Err(ServiceError::UserAlreadyExists) + if Query::find_candidate_by_id(db, application_id) + .await + .unwrap() + .is_some() + { + return Err(ServiceError::UserAlreadyExists); } // TODO: unwrap pro testing.. - let hashed_password = hash_password(plain_text_password.to_string()).await.unwrap(); + let hashed_password = hash_password(plain_text_password.to_string()) + .await + .unwrap(); let (pubkey, priv_key_plain_text) = crypto::create_identity(); - let encrypted_priv_key = crypto::encrypt_password(priv_key_plain_text, plain_text_password.to_string()).await.unwrap(); + let encrypted_priv_key = + crypto::encrypt_password(priv_key_plain_text, plain_text_password.to_string()) + .await + .unwrap(); - let encrypted_personal_id_number = crypto::encrypt_password_with_recipients( + let hashed_personal_id_number = hash_password(personal_id_number).await.unwrap(); + /* let encrypted_personal_id_number = crypto::encrypt_password_with_recipients( &personal_id_number, &vec![&pubkey] - ).await.unwrap(); + ).await.unwrap(); */ Mutation::create_candidate( db, application_id, hashed_password, - encrypted_personal_id_number, + hashed_personal_id_number, pubkey, - encrypted_priv_key + encrypted_priv_key, ) - .await - .map_err(|_| ServiceError::DbError) + .await + .map_err(|_| ServiceError::DbError) } pub async fn add_user_details( db: &DbConn, - details: AddUserDetailsForm, + application_id: i32, + name: String, + surname: String, + birthplace: String, + birthdate: String, + address: String, + telephone: String, + citizenship: String, + email: String, + sex: String, + study: String, ) -> Result { - let user = Query::find_candidate_by_id(db, details.application_id).await.unwrap().unwrap(); - let recipients = vec![&*user.public_key]; - let encrypted = details.to_encrypted(recipients).await; - Mutation::add_user_details(db, user, encrypted).await + let user = Query::find_candidate_by_id(db, application_id) + .await? + .unwrap(); + + let admin_public_keys = Query::get_all_admin_public_keys(db).await?; + let mut admin_public_keys_refrence: Vec<&str> = admin_public_keys.iter().map(|s| &**s).collect(); + + let mut recipients = vec![&*user.public_key]; + + recipients.append(&mut admin_public_keys_refrence); + + let ( + enc_name, + enc_surname, + enc_birthplace, + enc_birthdate, + enc_address, + enc_telephone, + enc_citizenship, + enc_email, + enc_sex, + enc_study, + ) = tokio::join!( + crypto::encrypt_password_with_recipients(&name, &recipients), + crypto::encrypt_password_with_recipients(&surname, &recipients), + crypto::encrypt_password_with_recipients(&birthplace, &recipients), + crypto::encrypt_password_with_recipients(&birthdate, &recipients), + crypto::encrypt_password_with_recipients(&address, &recipients), + crypto::encrypt_password_with_recipients(&telephone, &recipients), + crypto::encrypt_password_with_recipients(&citizenship, &recipients), + crypto::encrypt_password_with_recipients(&email, &recipients), + crypto::encrypt_password_with_recipients(&sex, &recipients), + crypto::encrypt_password_with_recipients(&study, &recipients), + ); + + Mutation::add_candidate_details( + db, + user, + enc_name.unwrap(), + enc_surname.unwrap(), + enc_birthplace.unwrap(), + enc_birthdate.unwrap(), + enc_address.unwrap(), + enc_telephone.unwrap(), + enc_citizenship.unwrap(), + enc_email.unwrap(), + enc_sex.unwrap(), + enc_study.unwrap(), + ) + .await } pub async fn login( db: &DbConn, user_id: i32, password: String, - ip_addr: String + ip_addr: String, ) -> Result { SessionService::new_session(db, user_id, password, ip_addr).await } - pub async fn auth( - db: &DbConn, - session_uuid: Uuid, - ) -> Result { + pub async fn auth(db: &DbConn, session_uuid: Uuid) -> Result { SessionService::auth_user_session(db, session_uuid).await } fn is_application_id_valid(application_id: i32) -> bool { let s = &application_id.to_string(); - if s.len() <= 3 { // TODO: does the field of study prefix have to be exactly 6 digits? + if s.len() <= 3 { + // TODO: does the field of study prefix have to be exactly 6 digits? return false; } let field_of_study_prefix = &s[0..3]; @@ -134,7 +157,6 @@ impl CandidateService { } } - #[cfg(test)] mod tests { use chrono::NaiveDate; @@ -142,8 +164,6 @@ mod tests { use crate::{crypto, services::candidate_service::CandidateService}; - use super::AddUserDetailsForm; - #[tokio::test] async fn test_application_id_validation() { assert!(CandidateService::is_application_id_valid(101_101)); @@ -158,16 +178,17 @@ mod tests { #[cfg(test)] async fn get_memory_sqlite_connection() -> DbConn { use entity::candidate; - use sea_orm::{DbBackend, sea_query::TableCreateStatement, ConnectionTrait}; use sea_orm::Schema; - + use sea_orm::{sea_query::TableCreateStatement, ConnectionTrait, DbBackend}; let base_url = "sqlite::memory:"; let db: DbConn = Database::connect(base_url).await.unwrap(); - + let schema = Schema::new(DbBackend::Sqlite); let stmt: TableCreateStatement = schema.create_table_from_entity(candidate::Entity); - db.execute(db.get_database_backend().build(&stmt)).await.unwrap(); + db.execute(db.get_database_backend().build(&stmt)) + .await + .unwrap(); db } @@ -179,41 +200,56 @@ mod tests { let secret_message = "trnka".to_string(); - - let candidate = CandidateService::create(&db, 103151, &plain_text_password, "".to_string()).await.ok().unwrap(); + let candidate = CandidateService::create(&db, 103151, &plain_text_password, "".to_string()) + .await + .ok() + .unwrap(); - let encrypted_message = crypto::encrypt_password_with_recipients(&secret_message, &vec![&candidate.public_key]).await.unwrap(); + let encrypted_message = + crypto::encrypt_password_with_recipients(&secret_message, &vec![&candidate.public_key]) + .await + .unwrap(); - let private_key_plain_text = crypto::decrypt_password(candidate.private_key, plain_text_password).await.unwrap(); + let private_key_plain_text = + crypto::decrypt_password(candidate.private_key, plain_text_password) + .await + .unwrap(); - let decrypted_message = crypto::decrypt_password_with_private_key(&encrypted_message, &private_key_plain_text).await.unwrap(); + let decrypted_message = + crypto::decrypt_password_with_private_key(&encrypted_message, &private_key_plain_text) + .await + .unwrap(); assert_eq!(secret_message, decrypted_message); - } #[tokio::test] async fn test_put_user_data() { let db = get_memory_sqlite_connection().await; let plain_text_password = "test".to_string(); - let candidate = CandidateService::create(&db, 103151, &plain_text_password, "".to_string()).await.ok().unwrap(); + let candidate = CandidateService::create(&db, 103151, &plain_text_password, "".to_string()) + .await + .ok() + .unwrap(); - let form = AddUserDetailsForm { - application_id: candidate.application, - name: "test".to_string(), - surname: "a".to_string(), - birthplace: "b".to_string(), - birthdate: NaiveDate::from_ymd(1999, 1, 1), - address: "test".to_string(), - telephone: "test".to_string(), - citizenship: "test".to_string(), - email: "test".to_string(), - sex: "test".to_string(), - study: "test".to_string(), - }; - - let candidate = CandidateService::add_user_details(&db, form).await.ok().unwrap(); + let candidate = CandidateService::add_user_details( + &db, + candidate.application, + "test".to_string(), + "a".to_string(), + "b".to_string(), + NaiveDate::from_ymd(1999, 1, 1).to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + ) + .await + .ok() + .unwrap(); assert!(candidate.name.is_some()); } -} \ No newline at end of file +}