mirror of
https://github.com/danbulant/Portfolio
synced 2026-07-06 19:40:49 +00:00
feat: set personal id number when user is created
This commit is contained in:
parent
8a9b7a4ae4
commit
d9f4090c6a
7 changed files with 41 additions and 26 deletions
|
|
@ -46,6 +46,11 @@ impl TryFrom<Option<String>> for EncryptedString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl From<String> for EncryptedString {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<Option<NaiveDate>> for EncryptedString {
|
impl TryFrom<Option<NaiveDate>> for EncryptedString {
|
||||||
// TODO: take a look at this
|
// TODO: take a look at this
|
||||||
|
|
@ -180,7 +185,7 @@ impl TryFrom<(candidate::Model, parent::Model)> for EncryptedApplicationDetails
|
||||||
citizenship: EncryptedString::try_from(candidate.citizenship)?,
|
citizenship: EncryptedString::try_from(candidate.citizenship)?,
|
||||||
email: EncryptedString::try_from(candidate.email)?,
|
email: EncryptedString::try_from(candidate.email)?,
|
||||||
sex: EncryptedString::try_from(candidate.sex)?,
|
sex: EncryptedString::try_from(candidate.sex)?,
|
||||||
personal_id_number: EncryptedString::try_from(candidate.personal_identification_number)?,
|
personal_id_number: EncryptedString::from(candidate.personal_identification_number),
|
||||||
study: candidate.study.ok_or(ServiceError::CandidateDetailsNotSet)?,
|
study: candidate.study.ok_or(ServiceError::CandidateDetailsNotSet)?,
|
||||||
|
|
||||||
parent_name: EncryptedString::try_from(parent.name)?,
|
parent_name: EncryptedString::try_from(parent.name)?,
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ impl Mutation {
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
application_id: i32,
|
application_id: i32,
|
||||||
hashed_password: String,
|
hashed_password: String,
|
||||||
hashed_personal_id_number: String,
|
enc_personal_id_number: String,
|
||||||
pubkey: String,
|
pubkey: String,
|
||||||
encrypted_priv_key: String,
|
encrypted_priv_key: String,
|
||||||
) -> Result<candidate::Model, DbErr> {
|
) -> Result<candidate::Model, DbErr> {
|
||||||
candidate::ActiveModel {
|
candidate::ActiveModel {
|
||||||
application: Set(application_id),
|
application: Set(application_id),
|
||||||
personal_identification_number_hash: Set(hashed_personal_id_number),
|
personal_identification_number: Set(enc_personal_id_number),
|
||||||
code: Set(hashed_password),
|
code: Set(hashed_password),
|
||||||
public_key: Set(pubkey),
|
public_key: Set(pubkey),
|
||||||
private_key: Set(encrypted_priv_key),
|
private_key: Set(encrypted_priv_key),
|
||||||
|
|
@ -26,7 +26,7 @@ impl Mutation {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_candidate_password_with_keys(
|
pub async fn update_candidate_password_and_keys(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
candidate: candidate::Model,
|
candidate: candidate::Model,
|
||||||
new_password_hash: String,
|
new_password_hash: String,
|
||||||
|
|
@ -56,7 +56,7 @@ impl Mutation {
|
||||||
user.citizenship = Set(Some(enc_details.citizenship.into()));
|
user.citizenship = Set(Some(enc_details.citizenship.into()));
|
||||||
user.email = Set(Some(enc_details.email.into()));
|
user.email = Set(Some(enc_details.email.into()));
|
||||||
user.sex = Set(Some(enc_details.sex.into()));
|
user.sex = Set(Some(enc_details.sex.into()));
|
||||||
user.personal_identification_number = Set(Some(enc_details.personal_id_number.into()));
|
user.personal_identification_number = Set(enc_details.personal_id_number.into()); // TODO: do not set this here, it is already set in the create_candidate mutation???
|
||||||
user.study = Set(Some(enc_details.study.into()));
|
user.study = Set(Some(enc_details.study.into()));
|
||||||
|
|
||||||
user.updated_at = Set(chrono::offset::Local::now().naive_local());
|
user.updated_at = Set(chrono::offset::Local::now().naive_local());
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ mod tests {
|
||||||
code: Set("test".to_string()),
|
code: Set("test".to_string()),
|
||||||
public_key: Set("test".to_string()),
|
public_key: Set("test".to_string()),
|
||||||
private_key: Set("test".to_string()),
|
private_key: Set("test".to_string()),
|
||||||
personal_identification_number_hash: Set("test".to_string()),
|
personal_identification_number: Set("test".to_string()),
|
||||||
created_at: Set(chrono::offset::Local::now().naive_local()),
|
created_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
@ -141,7 +141,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let candidate = Query::find_candidate_by_id(&db, candidate.application)
|
let candidate = Query::find_candidate_by_id(&db, candidate.application)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(candidate.is_some());
|
assert!(candidate.is_some());
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ mod tests {
|
||||||
code: Set("test".to_string()),
|
code: Set("test".to_string()),
|
||||||
public_key: Set("test".to_string()),
|
public_key: Set("test".to_string()),
|
||||||
private_key: Set("test".to_string()),
|
private_key: Set("test".to_string()),
|
||||||
personal_identification_number_hash: Set("test".to_string()),
|
personal_identification_number: Set("test".to_string()),
|
||||||
created_at: Set(chrono::offset::Local::now().naive_local()),
|
created_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
updated_at: Set(chrono::offset::Local::now().naive_local()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ impl CandidateService {
|
||||||
return Err(ServiceError::UserAlreadyExists);
|
return Err(ServiceError::UserAlreadyExists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let hashed_password = hash_password(plain_text_password.to_string()).await?;
|
let hashed_password = hash_password(plain_text_password.to_string()).await?;
|
||||||
|
|
||||||
let (pubkey, priv_key_plain_text) = crypto::create_identity();
|
let (pubkey, priv_key_plain_text) = crypto::create_identity();
|
||||||
|
|
@ -83,7 +84,16 @@ impl CandidateService {
|
||||||
let encrypted_priv_key =
|
let encrypted_priv_key =
|
||||||
crypto::encrypt_password(priv_key_plain_text, plain_text_password.to_string()).await?;
|
crypto::encrypt_password(priv_key_plain_text, plain_text_password.to_string()).await?;
|
||||||
|
|
||||||
let hashed_personal_id_number = hash_password(personal_id_number).await?;
|
|
||||||
|
let admin_public_keys = Query::get_all_admin_public_keys(db).await?;
|
||||||
|
let mut admin_public_keys_ref = admin_public_keys.iter().map(|s| &**s).collect();
|
||||||
|
let mut recipients = vec![&*pubkey];
|
||||||
|
recipients.append(&mut admin_public_keys_ref);
|
||||||
|
|
||||||
|
let enc_personal_id_number = EncryptedString::new(
|
||||||
|
&personal_id_number,
|
||||||
|
&recipients,
|
||||||
|
).await?;
|
||||||
|
|
||||||
tokio::fs::create_dir_all(Self::get_file_store_path().join(&application_id.to_string()).join("cache")).await?;
|
tokio::fs::create_dir_all(Self::get_file_store_path().join(&application_id.to_string()).join("cache")).await?;
|
||||||
|
|
||||||
|
|
@ -91,7 +101,7 @@ impl CandidateService {
|
||||||
db,
|
db,
|
||||||
application_id,
|
application_id,
|
||||||
hashed_password,
|
hashed_password,
|
||||||
hashed_personal_id_number,
|
enc_personal_id_number.to_string(),
|
||||||
pubkey,
|
pubkey,
|
||||||
encrypted_priv_key,
|
encrypted_priv_key,
|
||||||
)
|
)
|
||||||
|
|
@ -120,11 +130,11 @@ impl CandidateService {
|
||||||
|
|
||||||
|
|
||||||
SessionService::revoke_all_sessions(db, Some(id), None).await?;
|
SessionService::revoke_all_sessions(db, Some(id), None).await?;
|
||||||
Mutation::update_candidate_password_with_keys(db, candidate.clone(), new_password_hash, pubkey, encrypted_priv_key).await?;
|
Mutation::update_candidate_password_and_keys(db, candidate.clone(), new_password_hash, pubkey, encrypted_priv_key).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
|
||||||
// TODO: make personal id number required
|
// TODO: make personal id number required
|
||||||
let personal_id_number = EncryptedString::try_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?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ pub struct Model {
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
pub sex: Option<String>,
|
pub sex: Option<String>,
|
||||||
pub study: Option<String>,
|
pub study: Option<String>,
|
||||||
pub personal_identification_number: Option<String>,
|
pub personal_identification_number: String,
|
||||||
#[sea_orm(column_type = "Text")]
|
#[sea_orm(column_type = "Text", nullable)]
|
||||||
pub personal_identification_number_hash: String,
|
pub personal_identification_number_hash: Option<String>,
|
||||||
pub public_key: String,
|
pub public_key: String,
|
||||||
pub private_key: String,
|
pub private_key: String,
|
||||||
pub created_at: DateTime,
|
pub created_at: DateTime,
|
||||||
|
|
@ -30,16 +30,10 @@ pub struct Model {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
#[sea_orm(has_many = "super::parent::Entity")]
|
|
||||||
Parent,
|
|
||||||
#[sea_orm(has_many = "super::session::Entity")]
|
#[sea_orm(has_many = "super::session::Entity")]
|
||||||
Session,
|
Session,
|
||||||
}
|
#[sea_orm(has_many = "super::parent::Entity")]
|
||||||
|
Parent,
|
||||||
impl Related<super::parent::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::Parent.def()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::session::Entity> for Entity {
|
impl Related<super::session::Entity> for Entity {
|
||||||
|
|
@ -48,4 +42,10 @@ impl Related<super::session::Entity> for Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::parent::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Parent.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ impl MigrationTrait for Migration {
|
||||||
.col(ColumnDef::new(Candidate::Email).string())
|
.col(ColumnDef::new(Candidate::Email).string())
|
||||||
.col(ColumnDef::new(Candidate::Sex).string())
|
.col(ColumnDef::new(Candidate::Sex).string())
|
||||||
.col(ColumnDef::new(Candidate::Study).string())
|
.col(ColumnDef::new(Candidate::Study).string())
|
||||||
.col(ColumnDef::new(Candidate::PersonalIdentificationNumber).string())
|
.col(ColumnDef::new(Candidate::PersonalIdentificationNumber).string().not_null())
|
||||||
.col(ColumnDef::new(Candidate::PersonalIdentificationNumberHash).text().not_null())
|
.col(ColumnDef::new(Candidate::PersonalIdentificationNumberHash).text())
|
||||||
.col(ColumnDef::new(Candidate::PublicKey).string().not_null())
|
.col(ColumnDef::new(Candidate::PublicKey).string().not_null())
|
||||||
.col(ColumnDef::new(Candidate::PrivateKey).string().not_null())
|
.col(ColumnDef::new(Candidate::PrivateKey).string().not_null())
|
||||||
.col(ColumnDef::new(Candidate::CreatedAt).date_time().not_null())
|
.col(ColumnDef::new(Candidate::CreatedAt).date_time().not_null())
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue