Merge pull request #125 from EETagent/password_reset_fix

Fix Password reset, improve EncryptedApplication data structure
This commit is contained in:
Vojtěch Jungmann 2023-01-08 20:39:19 +01:00 committed by GitHub
commit 9a9d4355a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 193 additions and 203 deletions

View file

@ -108,7 +108,6 @@ pub async fn get_details(
let private_key = session.get_private_key(); let private_key = session.get_private_key();
let candidate: entity::candidate::Model = session.into(); let candidate: entity::candidate::Model = session.into();
// let handle = tokio::spawn(async move {
let details = ApplicationService::decrypt_all_details(private_key, db, candidate) let details = ApplicationService::decrypt_all_details(private_key, db, candidate)
.await .await
.map(|x| Json(x)) .map(|x| Json(x))

View file

@ -26,7 +26,7 @@ impl Mutation {
.insert(db) .insert(db)
.await?; .await?;
info!("CANDIDATE CREATED"); info!("CANDIDATE {} CREATED", application_id);
Ok(insert) Ok(insert)
} }
@ -48,6 +48,7 @@ impl Mutation {
pub_key: String, pub_key: String,
priv_key_enc: String, priv_key_enc: String,
) -> Result<candidate::Model, DbErr> { ) -> Result<candidate::Model, DbErr> {
let application = candidate.application;
let mut candidate: candidate::ActiveModel = candidate.into(); let mut candidate: candidate::ActiveModel = candidate.into();
candidate.code = Set(new_password_hash); candidate.code = Set(new_password_hash);
candidate.public_key = Set(pub_key); candidate.public_key = Set(pub_key);
@ -55,33 +56,34 @@ impl Mutation {
let update = candidate.update(db).await?; let update = candidate.update(db).await?;
warn!("CANDIDATE PASSWORD CHANGED"); warn!("CANDIDATE {} PASSWORD CHANGED", application);
Ok(update) Ok(update)
} }
pub async fn add_candidate_details( pub async fn update_candidate_details(
db: &DbConn, db: &DbConn,
user: candidate::Model, user: candidate::Model,
enc_candidate: EncryptedCandidateDetails, enc_candidate: EncryptedCandidateDetails,
) -> Result<candidate::Model, sea_orm::DbErr> { ) -> Result<candidate::Model, sea_orm::DbErr> {
let application = user.application;
let mut user: candidate::ActiveModel = user.into(); let mut user: candidate::ActiveModel = user.into();
user.name = Set(Some(enc_candidate.name.into())); user.name = Set(enc_candidate.name.map(|e| e.into()));
user.surname = Set(Some(enc_candidate.surname.into())); user.surname = Set(enc_candidate.surname.map(|e| e.into()));
user.birthplace = Set(Some(enc_candidate.birthplace.into())); user.birthplace = Set(enc_candidate.birthplace.map(|e| e.into()));
user.birthdate = Set(Some(enc_candidate.birthdate.into())); user.birthdate = Set(enc_candidate.birthdate.map(|e| e.into()));
user.address = Set(Some(enc_candidate.address.into())); user.address = Set(enc_candidate.address.map(|e| e.into()));
user.telephone = Set(Some(enc_candidate.telephone.into())); user.telephone = Set(enc_candidate.telephone.map(|e| e.into()));
user.citizenship = Set(Some(enc_candidate.citizenship.into())); user.citizenship = Set(enc_candidate.citizenship.map(|e| e.into()));
user.email = Set(Some(enc_candidate.email.into())); user.email = Set(enc_candidate.email.map(|e| e.into()));
user.sex = Set(Some(enc_candidate.sex.into())); user.sex = Set(enc_candidate.sex.map(|e| e.into()));
user.personal_identification_number = Set(enc_candidate.personal_id_number.into()); // TODO: do not set this here, it is already set in the create_candidate mutation??? user.personal_identification_number = Set(enc_candidate.personal_id_number.map(|e| e.into()).unwrap_or_default()); // TODO: do not set this here, it is already set in the create_candidate mutation???
user.study = Set(Some(enc_candidate.study.into())); user.study = Set(enc_candidate.study.map(|e| e.into()));
user.updated_at = Set(chrono::offset::Local::now().naive_local()); user.updated_at = Set(chrono::offset::Local::now().naive_local());
let update = user.update(db).await?; let update = user.update(db).await?;
info!("CANDIDATE DETAILS ADDED"); info!("CANDIDATE {} DETAILS UPDATED", application);
Ok(update) Ok(update)
} }
@ -139,7 +141,7 @@ mod tests {
vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()], vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()],
).await.unwrap(); ).await.unwrap();
Mutation::add_candidate_details(&db, candidate, encrypted_details.candidate).await.unwrap(); Mutation::update_candidate_details(&db, candidate, encrypted_details.candidate).await.unwrap();
let candidate = Query::find_candidate_by_id(&db, APPLICATION_ID) let candidate = Query::find_candidate_by_id(&db, APPLICATION_ID)
.await .await

View file

@ -15,16 +15,22 @@ impl Mutation {
.await .await
} }
pub async fn delete_parent(db: &DbConn, parent: Model) -> Result<DeleteResult, DbErr> {
parent
.delete(db)
.await
}
pub async fn add_parent_details( pub async fn add_parent_details(
db: &DbConn, db: &DbConn,
parent: Model, parent: Model,
enc_parent: EncryptedParentDetails, enc_parent: EncryptedParentDetails,
) -> Result<Model, sea_orm::DbErr> { ) -> Result<Model, sea_orm::DbErr> {
let mut parent: parent::ActiveModel = parent.into(); let mut parent: parent::ActiveModel = parent.into();
parent.name = Set(Some(enc_parent.name.into())); parent.name = Set(enc_parent.name.map(|e| e.into()));
parent.surname = Set(Some(enc_parent.surname.into())); parent.surname = Set(enc_parent.surname.map(|e| e.into()));
parent.telephone = Set(Some(enc_parent.telephone.into())); parent.telephone = Set(enc_parent.telephone.map(|e| e.into()));
parent.email = Set(Some(enc_parent.email.into())); parent.email = Set(enc_parent.email.map(|e| e.into()));
parent.updated_at = Set(chrono::offset::Local::now().naive_local()); parent.updated_at = Set(chrono::offset::Local::now().naive_local());

View file

@ -1,5 +1,5 @@
use chrono::{Utc, Duration, NaiveDateTime}; use chrono::{Utc, Duration, NaiveDateTime};
use ::entity::{session, candidate}; use ::entity::session;
use sea_orm::{*, prelude::Uuid}; use sea_orm::{*, prelude::Uuid};
use crate::Mutation; use crate::Mutation;

View file

@ -5,7 +5,7 @@ use serde::{Serialize, Deserialize};
use crate::{error::ServiceError, database::query::candidate::CandidateResult, services::portfolio_service::SubmissionProgress}; use crate::{error::ServiceError, database::query::candidate::CandidateResult, services::portfolio_service::SubmissionProgress};
use super::candidate_details::decrypt_if_exists; use super::candidate_details::EncryptedString;
/// Minimal candidate response containing database only not null fields /// Minimal candidate response containing database only not null fields
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
@ -101,7 +101,7 @@ pub struct Row {
impl NewCandidateResponse { impl NewCandidateResponse {
pub async fn from_encrypted(private_key: &String, c: candidate::Model) -> Result<Self, ServiceError> { pub async fn from_encrypted(private_key: &String, c: candidate::Model) -> Result<Self, ServiceError> {
let id_number = decrypt_if_exists(private_key, Some(c.personal_identification_number)).await?; let id_number = EncryptedString::from(c.personal_identification_number).decrypt(private_key).await?;
Ok( Ok(
Self { Self {
application_id: c.application, application_id: c.application,
@ -117,20 +117,20 @@ impl BaseCandidateResponse {
c: CandidateResult, c: CandidateResult,
progress: Option<SubmissionProgress>, progress: Option<SubmissionProgress>,
) -> Result<Self, ServiceError> { ) -> Result<Self, ServiceError> {
let name = decrypt_if_exists(private_key, c.name).await?; let name = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.name).ok(), private_key).await?;
let surname = decrypt_if_exists(private_key, c.surname).await?; let surname = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.surname).ok(), private_key).await?;
let email = decrypt_if_exists(private_key, c.email).await?; let email = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.email).ok(), private_key).await?;
let telephone = decrypt_if_exists(private_key, c.telephone).await?; let telephone = EncryptedString::decrypt_option(&EncryptedString::try_from(&c.telephone).ok(), private_key).await?;
let progress = progress.unwrap_or(SubmissionProgress::NoneInCache);
Ok( Ok(
Self { Self {
application_id: c.application, application_id: c.application,
name, name: name.unwrap_or_default(),
surname, surname: surname.unwrap_or_default(),
email, email: email.unwrap_or_default(),
telephone, telephone: telephone.unwrap_or_default(),
study: c.study.unwrap_or("".to_string()), study: c.study.unwrap_or_default(),
progress, progress: progress.unwrap_or(SubmissionProgress::NoneInCache),
} }
) )
} }

View file

@ -14,25 +14,25 @@ pub struct EncryptedString(String);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EncryptedCandidateDetails { pub struct EncryptedCandidateDetails {
pub name: EncryptedString, pub name: Option<EncryptedString>,
pub surname: EncryptedString, pub surname: Option<EncryptedString>,
pub birthplace: EncryptedString, pub birthplace: Option<EncryptedString>,
pub birthdate: EncryptedString, pub birthdate: Option<EncryptedString>,
pub address: EncryptedString, pub address: Option<EncryptedString>,
pub telephone: EncryptedString, pub telephone: Option<EncryptedString>,
pub citizenship: EncryptedString, pub citizenship: Option<EncryptedString>,
pub email: EncryptedString, pub email: Option<EncryptedString>,
pub sex: EncryptedString, pub sex: Option<EncryptedString>,
pub personal_id_number: EncryptedString, pub personal_id_number: Option<EncryptedString>,
pub study: String, pub study: Option<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EncryptedParentDetails { pub struct EncryptedParentDetails {
pub name: EncryptedString, pub name: Option<EncryptedString>,
pub surname: EncryptedString, pub surname: Option<EncryptedString>,
pub telephone: EncryptedString, pub telephone: Option<EncryptedString>,
pub email: EncryptedString, pub email: Option<EncryptedString>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EncryptedApplicationDetails { pub struct EncryptedApplicationDetails {
@ -50,9 +50,16 @@ impl EncryptedString {
} }
pub async fn decrypt(&self, private_key: &String) -> Result<String, ServiceError> { pub async fn decrypt(&self, private_key: &String) -> Result<String, ServiceError> {
match crypto::decrypt_password_with_private_key(&self.0, private_key).await { crypto::decrypt_password_with_private_key(&self.0, private_key).await
Ok(decrypted) => Ok(decrypted), }
Err(_) => Err(ServiceError::CryptoDecryptFailed),
pub async fn decrypt_option(
s: &Option<EncryptedString>,
private_key: &String,
) -> Result<Option<String>, ServiceError> {
match s {
Some(s) => Ok(Some(s.decrypt(private_key).await?)),
None => Ok(None),
} }
} }
@ -77,6 +84,7 @@ impl TryFrom<&Option<String>> for EncryptedString {
} }
} }
} }
impl From<String> for EncryptedString { impl From<String> for EncryptedString {
fn from(s: String) -> Self { fn from(s: String) -> Self {
Self(s) Self(s)
@ -115,72 +123,68 @@ impl EncryptedCandidateDetails {
Ok( Ok(
EncryptedCandidateDetails { EncryptedCandidateDetails {
name: d.0, name: Some(d.0),
surname: d.1, surname: Some(d.1),
birthplace: d.2, birthplace: Some(d.2),
birthdate: d.3, birthdate: Some(d.3),
address: d.4, address: Some(d.4),
telephone: d.5, telephone: Some(d.5),
citizenship: d.6, citizenship: Some(d.6),
email: d.7, email: Some(d.7),
sex: d.8, sex: Some(d.8),
personal_id_number: d.9, personal_id_number: Some(d.9),
study: form.study.clone(), study: Some(form.study.clone()),
} }
) )
} }
pub async fn decrypt(self, priv_key: &String) -> Result<CandidateDetails, ServiceError> { pub async fn decrypt(&self, priv_key: &String) -> Result<CandidateDetails, ServiceError> {
let d = tokio::try_join!( let d = tokio::try_join!(
self.name.decrypt(priv_key), // 0 EncryptedString::decrypt_option(&self.name, priv_key), // 0
self.surname.decrypt(priv_key), // 1 EncryptedString::decrypt_option(&self.surname, priv_key), // 1
self.birthplace.decrypt(priv_key), // 2 EncryptedString::decrypt_option(&self.birthplace, priv_key), // 2
self.birthdate.decrypt(priv_key), // 3 EncryptedString::decrypt_option(&self.birthdate, priv_key), // 3
self.address.decrypt(priv_key), // 4 EncryptedString::decrypt_option(&self.address, priv_key), // 4
self.telephone.decrypt(priv_key), // 5 EncryptedString::decrypt_option(&self.telephone, priv_key), // 5
self.citizenship.decrypt(priv_key), // 6 EncryptedString::decrypt_option(&self.citizenship, priv_key), // 6
self.email.decrypt(priv_key), // 7 EncryptedString::decrypt_option(&self.email, priv_key), // 7
self.sex.decrypt(priv_key), // 8 EncryptedString::decrypt_option(&self.sex, priv_key), // 8
self.personal_id_number.decrypt(priv_key),// 9 EncryptedString::decrypt_option(&self.personal_id_number, priv_key),// 9
)?; )?;
Ok(CandidateDetails { Ok(CandidateDetails {
name: d.0, name: d.0.unwrap_or_default(),
surname: d.1, surname: d.1.unwrap_or_default(),
birthplace: d.2, birthplace: d.2.unwrap_or_default(),
birthdate: NaiveDate::parse_from_str(&d.3, NAIVE_DATE_FMT).unwrap(), birthdate: NaiveDate::parse_from_str(&d.3.unwrap_or_default(), NAIVE_DATE_FMT).unwrap_or(NaiveDate::from_ymd(1, 1, 1)),
address: d.4, address: d.4.unwrap_or_default(),
telephone: d.5, telephone: d.5.unwrap_or_default(),
citizenship: d.6, citizenship: d.6.unwrap_or_default(),
email: d.7, email: d.7.unwrap_or_default(),
sex: d.8, sex: d.8.unwrap_or_default(),
personal_id_number: d.9, personal_id_number: d.9.unwrap_or_default(),
study: self.study, study: self.study.clone().unwrap_or_default(),
} }
) )
} }
} }
impl TryFrom<&candidate::Model> for EncryptedCandidateDetails { impl From<&candidate::Model> for EncryptedCandidateDetails {
type Error = ServiceError; fn from(
fn try_from(
candidate: &candidate::Model, candidate: &candidate::Model,
) -> Result<Self, Self::Error> { ) -> Self {
Ok( EncryptedCandidateDetails {
EncryptedCandidateDetails { name: EncryptedString::try_from(&candidate.name).ok(),
name: EncryptedString::try_from(&candidate.name)?, surname: EncryptedString::try_from(&candidate.surname).ok(),
surname: EncryptedString::try_from(&candidate.surname)?, birthplace: EncryptedString::try_from(&candidate.birthplace).ok(),
birthplace: EncryptedString::try_from(&candidate.birthplace)?, birthdate: EncryptedString::try_from(&candidate.birthdate).ok(),
birthdate: EncryptedString::try_from(&candidate.birthdate)?, address: EncryptedString::try_from(&candidate.address).ok(),
address: EncryptedString::try_from(&candidate.address)?, telephone: EncryptedString::try_from(&candidate.telephone).ok(),
telephone: EncryptedString::try_from(&candidate.telephone)?, citizenship: EncryptedString::try_from(&candidate.citizenship).ok(),
citizenship: EncryptedString::try_from(&candidate.citizenship)?, email: EncryptedString::try_from(&candidate.email).ok(),
email: EncryptedString::try_from(&candidate.email)?, sex: EncryptedString::try_from(&candidate.sex).ok(),
sex: EncryptedString::try_from(&candidate.sex)?, personal_id_number: Some(EncryptedString::from(candidate.personal_identification_number.to_owned())),
personal_id_number: EncryptedString::from(candidate.personal_identification_number.to_owned()), study: candidate.study.clone(),
study: candidate.study.as_ref().ok_or(ServiceError::CandidateDetailsNotSet)?.to_string(), }
}
)
} }
} }
@ -198,44 +202,41 @@ impl EncryptedParentDetails {
Ok( Ok(
EncryptedParentDetails { EncryptedParentDetails {
name: d.0, name: Some(d.0),
surname: d.1, surname: Some(d.1),
telephone: d.2, telephone: Some(d.2),
email: d.3, email: Some(d.3),
} }
) )
} }
pub async fn decrypt(&self, priv_key: &String) -> Result<ParentDetails, ServiceError> { pub async fn decrypt(&self, priv_key: &String) -> Result<ParentDetails, ServiceError> {
let d = tokio::try_join!( let d = tokio::try_join!(
self.name.decrypt(&priv_key), EncryptedString::decrypt_option(&self.name, &priv_key),
self.surname.decrypt(&priv_key), EncryptedString::decrypt_option(&self.surname, &priv_key),
self.telephone.decrypt(&priv_key), EncryptedString::decrypt_option(&self.telephone, &priv_key),
self.email.decrypt(&priv_key), EncryptedString::decrypt_option(&self.email, &priv_key),
)?; )?;
Ok(ParentDetails { Ok(ParentDetails {
name: d.0, name: d.0.unwrap_or_default(),
surname: d.1, surname: d.1.unwrap_or_default(),
telephone: d.2, telephone: d.2.unwrap_or_default(),
email: d.3, email: d.3.unwrap_or_default(),
} }
) )
} }
} }
impl TryFrom<&parent::Model> for EncryptedParentDetails { impl From<&parent::Model> for EncryptedParentDetails {
type Error = ServiceError; fn from(
fn try_from(
parent: &parent::Model, parent: &parent::Model,
) -> Result<Self, Self::Error> { ) -> Self {
Ok(EncryptedParentDetails { EncryptedParentDetails {
name: EncryptedString::try_from(&parent.name)?, name: EncryptedString::try_from(&parent.name).ok(),
surname: EncryptedString::try_from(&parent.surname)?, surname: EncryptedString::try_from(&parent.surname).ok(),
telephone: EncryptedString::try_from(&parent.telephone)?, telephone: EncryptedString::try_from(&parent.telephone).ok(),
email: EncryptedString::try_from(&parent.email)?, email: EncryptedString::try_from(&parent.email).ok(),
} }
)
} }
} }
@ -273,20 +274,18 @@ impl EncryptedApplicationDetails {
} }
} }
impl TryFrom<(&candidate::Model, Vec<parent::Model>)> for EncryptedApplicationDetails { impl From<(&candidate::Model, Vec<parent::Model>)> for EncryptedApplicationDetails {
type Error = ServiceError; fn from(
fn try_from(
(candidate, parents): (&candidate::Model, Vec<parent::Model>), (candidate, parents): (&candidate::Model, Vec<parent::Model>),
) -> Result<Self, Self::Error> { ) -> Self {
let enc_parents = parents.iter() let enc_parents = parents.iter()
.map(|m| EncryptedParentDetails::try_from(m)) .map(|m| EncryptedParentDetails::from(m))
.collect::<Result<Vec<EncryptedParentDetails>, ServiceError>>()?; .collect::<Vec<EncryptedParentDetails>>();
Ok(EncryptedApplicationDetails { EncryptedApplicationDetails {
candidate: EncryptedCandidateDetails::try_from(candidate)?, candidate: EncryptedCandidateDetails::from(candidate),
parents: enc_parents, parents: enc_parents,
}) }
} }
} }
@ -298,30 +297,30 @@ impl TryFrom<Row> for EncryptedApplicationDetails {
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
Ok(EncryptedApplicationDetails { Ok(EncryptedApplicationDetails {
candidate: EncryptedCandidateDetails { candidate: EncryptedCandidateDetails {
name: EncryptedString::try_from(&cp.name)?, name: EncryptedString::try_from(&cp.name).ok(),
surname: EncryptedString::try_from(&cp.surname)?, surname: EncryptedString::try_from(&cp.surname).ok(),
birthplace: EncryptedString::try_from(&cp.birthplace)?, birthplace: EncryptedString::try_from(&cp.birthplace).ok(),
birthdate: EncryptedString::try_from(&cp.birthdate)?, birthdate: EncryptedString::try_from(&cp.birthdate).ok(),
address: EncryptedString::try_from(&cp.address)?, address: EncryptedString::try_from(&cp.address).ok(),
telephone: EncryptedString::try_from(&cp.telephone)?, telephone: EncryptedString::try_from(&cp.telephone).ok(),
citizenship: EncryptedString::try_from(&cp.citizenship)?, citizenship: EncryptedString::try_from(&cp.citizenship).ok(),
email: EncryptedString::try_from(&cp.email)?, email: EncryptedString::try_from(&cp.email).ok(),
sex: EncryptedString::try_from(&cp.sex)?, sex: EncryptedString::try_from(&cp.sex).ok(),
personal_id_number: EncryptedString::try_from(&cp.personal_identification_number)?, personal_id_number: EncryptedString::try_from(&cp.personal_identification_number).ok(),
study: cp.study.ok_or(ServiceError::CandidateDetailsNotSet)?, study: cp.study.ok_or(ServiceError::CandidateDetailsNotSet).ok(),
}, },
parents: vec![EncryptedParentDetails { parents: vec![EncryptedParentDetails {
name: EncryptedString::try_from(&cp.parent_name)?, name: EncryptedString::try_from(&cp.parent_name).ok(),
surname: EncryptedString::try_from(&cp.parent_surname)?, surname: EncryptedString::try_from(&cp.parent_surname).ok(),
telephone: EncryptedString::try_from(&cp.parent_telephone)?, telephone: EncryptedString::try_from(&cp.parent_telephone).ok(),
email: EncryptedString::try_from(&cp.parent_email)?, email: EncryptedString::try_from(&cp.parent_email).ok(),
}] }]
}) })
} }
} }
pub async fn decrypt_if_exists( /* pub async fn decrypt_if_exists(
private_key: &String, private_key: &String,
encrypted_string: Option<String>, encrypted_string: Option<String>,
) -> Result<String, ServiceError> { ) -> Result<String, ServiceError> {
@ -329,7 +328,7 @@ pub async fn decrypt_if_exists(
Ok(encrypted_string) => Ok(encrypted_string.decrypt(private_key).await?), Ok(encrypted_string) => Ok(encrypted_string.decrypt(private_key).await?),
Err(_) => Ok(String::from("")), Err(_) => Ok(String::from("")),
} }
} } */
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
@ -419,19 +418,19 @@ pub mod tests {
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
crypto::decrypt_password_with_private_key(&encrypted_details.candidate.name.0, PRIVATE_KEY) crypto::decrypt_password_with_private_key(&encrypted_details.candidate.name.unwrap().0, PRIVATE_KEY)
.await .await
.unwrap(), .unwrap(),
"name" "name"
); );
assert_eq!( assert_eq!(
crypto::decrypt_password_with_private_key(&encrypted_details.candidate.email.0, PRIVATE_KEY) crypto::decrypt_password_with_private_key(&encrypted_details.candidate.email.unwrap().0, PRIVATE_KEY)
.await .await
.unwrap(), .unwrap(),
"email" "email"
); );
assert_eq!( assert_eq!(
crypto::decrypt_password_with_private_key(&encrypted_details.candidate.sex.0, PRIVATE_KEY) crypto::decrypt_password_with_private_key(&encrypted_details.candidate.sex.unwrap().0, PRIVATE_KEY)
.await .await
.unwrap(), .unwrap(),
"sex" "sex"

View file

@ -43,10 +43,11 @@ impl ApplicationService {
private_key: String, private_key: String,
db: &DbConn, db: &DbConn,
candidate: candidate::Model, candidate: candidate::Model,
// parents: Vec<parent::Model>,
) -> Result<ApplicationDetails, ServiceError> { ) -> Result<ApplicationDetails, ServiceError> {
println!("Decrypting all details: privkey: {}", private_key);
let parents = Query::find_candidate_parents(db, &candidate).await?; let parents = Query::find_candidate_parents(db, &candidate).await?;
let enc_details = EncryptedApplicationDetails::try_from((&candidate, parents))?; let enc_details = EncryptedApplicationDetails::from((&candidate, parents));
enc_details.decrypt(private_key).await enc_details.decrypt(private_key).await
} }

View file

@ -10,35 +10,8 @@ use crate::{
Mutation, Query, models::{candidate::{BaseCandidateResponse, CreateCandidateResponse}, auth::AuthenticableTrait}, utils::db::get_recipients, Mutation, Query, models::{candidate::{BaseCandidateResponse, CreateCandidateResponse}, auth::AuthenticableTrait}, utils::db::get_recipients,
}; };
use super::{session_service::SessionService, application_service::ApplicationService, portfolio_service::PortfolioService}; use super::{session_service::SessionService, portfolio_service::PortfolioService};
// TODO validation
/* pub struct FieldOfStudy {
pub short_name: String,
pub full_name: String,
pub code: i32,
}
impl FieldOfStudy {
pub fn new(short_name: String, full_name: String, code: i32) -> Self {
Self {
short_name,
full_name,
code,
}
}
pub fn code_str(&self) -> String {
format!("{:04}", self.code)
}
}
pub enum FieldsOfStudy {
KB(FieldOfStudy),
IT(FieldOfStudy),
G(FieldOfStudy),
} */
const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"]; const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"];
@ -111,36 +84,40 @@ impl CandidateService {
let new_password_hash = crypto::hash_password(new_password_plain.clone()).await?; let new_password_hash = crypto::hash_password(new_password_plain.clone()).await?;
let (pubkey, priv_key_plain_text) = crypto::create_identity(); let (pubkey, priv_key_plain_text) = crypto::create_identity();
let encrypted_priv_key = crypto::encrypt_password(priv_key_plain_text, let encrypted_priv_key = crypto::encrypt_password(priv_key_plain_text.clone(),
new_password_plain.to_string() new_password_plain.to_string()
).await?; ).await?;
Self::delete_old_sessions(db, &candidate, 0).await?; Self::delete_old_sessions(db, &candidate, 0).await?;
let candidate = Mutation::update_candidate_password_and_keys(db, let candidate = Mutation::update_candidate_password_and_keys(db,
candidate, candidate,
new_password_hash, new_password_hash,
pubkey, pubkey.clone(),
encrypted_priv_key encrypted_priv_key
).await?; ).await?;
// user might no have filled his details yet, but personal id number is filled from beginning // user might no have filled his details yet, but personal id number is filled from beginning
let personal_id_number = EncryptedString::from(candidate.personal_identification_number.clone()) let personal_id_number = EncryptedString::from(candidate.personal_identification_number.clone())
.decrypt(&admin_private_key) .decrypt(&admin_private_key)
.await?; .await?;
let recipients = get_recipients(db, &pubkey).await?;
let enc_details_opt = EncryptedApplicationDetails::try_from( let dec_details = EncryptedApplicationDetails::from((&candidate, parents.clone()))
(&candidate, parents) .decrypt(admin_private_key).await?;
); let enc_details = EncryptedApplicationDetails::new(&dec_details, recipients).await?;
if let Ok(enc_details) = enc_details_opt { Mutation::update_candidate_details(db, candidate, enc_details.candidate).await?;
let application_details = enc_details.decrypt(admin_private_key).await?; for i in 0..enc_details.parents.len() {
ApplicationService::add_all_details(db, candidate, &application_details).await?; Mutation::add_parent_details(db, parents[i].clone(), enc_details.parents[i].clone()).await?;
} }
Ok( Ok(
CreateCandidateResponse { CreateCandidateResponse {
application_id: id, application_id: id,
personal_id_number: personal_id_number, personal_id_number,
password: new_password_plain, password: new_password_plain,
} }
) )
@ -160,7 +137,7 @@ impl CandidateService {
recipients: &Vec<String>, recipients: &Vec<String>,
) -> Result<entity::candidate::Model, ServiceError> { ) -> Result<entity::candidate::Model, ServiceError> {
let enc_details = EncryptedCandidateDetails::new(&details, recipients).await?; let enc_details = EncryptedCandidateDetails::new(&details, recipients).await?;
let model = Mutation::add_candidate_details(db, candidate, enc_details).await?; let model = Mutation::update_candidate_details(db, candidate, enc_details).await?;
Ok(model) Ok(model)
} }

View file

@ -22,10 +22,11 @@ impl ParentService {
parents_details: &Vec<ParentDetails>, parents_details: &Vec<ParentDetails>,
recipients: &Vec<String>, recipients: &Vec<String>,
) -> Result<Vec<parent::Model>, ServiceError> { ) -> Result<Vec<parent::Model>, ServiceError> {
let found_parents = Query::find_candidate_parents(db, ref_candidate).await?; if parents_details.len() > 2 {
if found_parents.len() > 2 {
return Err(ServiceError::ParentOverflow); return Err(ServiceError::ParentOverflow);
} }
let found_parents = Query::find_candidate_parents(db, ref_candidate).await?;
let mut result = vec![]; let mut result = vec![];
for i in 0..parents_details.len() { for i in 0..parents_details.len() {
@ -38,6 +39,11 @@ impl ParentService {
result.push(parent); result.push(parent);
} }
// delete parents that are not in the form
for i in parents_details.len()..found_parents.len() {
Mutation::delete_parent(db, found_parents[i].to_owned()).await?;
}
Ok(result) Ok(result)
} }
} }