mirror of
https://github.com/danbulant/Portfolio
synced 2026-07-05 19:11:06 +00:00
feat: portfolio reencrypt
This commit is contained in:
parent
d2dc5217a8
commit
c402d6f4b9
6 changed files with 86 additions and 23 deletions
|
|
@ -200,6 +200,19 @@ pub fn create_identity() -> (String, String) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn encrypt_buffer_with_recipients(
|
||||||
|
input_buffer: &[u8],
|
||||||
|
recipients: &Vec<String>,
|
||||||
|
) -> Result<Vec<u8>, ServiceError> {
|
||||||
|
let mut output_buffer = vec![];
|
||||||
|
age_encrypt_with_recipients(input_buffer,
|
||||||
|
&mut output_buffer,
|
||||||
|
&recipients.iter().map(|s| s.as_str()).collect()
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
Ok(output_buffer)
|
||||||
|
}
|
||||||
|
|
||||||
async fn age_encrypt_with_recipients<W: tokio::io::AsyncWrite + Unpin>(
|
async fn age_encrypt_with_recipients<W: tokio::io::AsyncWrite + Unpin>(
|
||||||
input_buffer: &[u8],
|
input_buffer: &[u8],
|
||||||
output_buffer: &mut W,
|
output_buffer: &mut W,
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ mod tests {
|
||||||
|
|
||||||
let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new(
|
let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new(
|
||||||
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
||||||
vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()],
|
&vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()],
|
||||||
).await.unwrap();
|
).await.unwrap();
|
||||||
|
|
||||||
let candidate = Mutation::update_candidate_opt_details(&db, candidate, encrypted_details.candidate, 1).await.unwrap();
|
let candidate = Mutation::update_candidate_opt_details(&db, candidate, encrypted_details.candidate, 1).await.unwrap();
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ mod tests {
|
||||||
|
|
||||||
let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new(
|
let encrypted_details: EncryptedApplicationDetails = EncryptedApplicationDetails::new(
|
||||||
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
||||||
vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()],
|
&vec!["age1u889gp407hsz309wn09kxx9anl6uns30m27lfwnctfyq9tq4qpus8tzmq5".to_string()],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
||||||
|
|
@ -321,7 +321,7 @@ impl From<&parent::Model> for EncryptedParentDetails {
|
||||||
impl EncryptedApplicationDetails {
|
impl EncryptedApplicationDetails {
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
form: &ApplicationDetails,
|
form: &ApplicationDetails,
|
||||||
recipients: Vec<String>,
|
recipients: &Vec<String>,
|
||||||
) -> Result<EncryptedApplicationDetails, ServiceError> {
|
) -> Result<EncryptedApplicationDetails, ServiceError> {
|
||||||
let candidate = EncryptedCandidateDetails::new(&form.candidate, &recipients).await?;
|
let candidate = EncryptedCandidateDetails::new(&form.candidate, &recipients).await?;
|
||||||
let enc_parents = future::try_join_all(
|
let enc_parents = future::try_join_all(
|
||||||
|
|
@ -459,7 +459,7 @@ pub mod tests {
|
||||||
async fn test_encrypted_application_details_new() {
|
async fn test_encrypted_application_details_new() {
|
||||||
let encrypted_details = EncryptedApplicationDetails::new(
|
let encrypted_details = EncryptedApplicationDetails::new(
|
||||||
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
||||||
vec![PUBLIC_KEY.to_string()],
|
&vec![PUBLIC_KEY.to_string()],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -488,7 +488,7 @@ pub mod tests {
|
||||||
async fn test_encrypted_application_details_decrypt() {
|
async fn test_encrypted_application_details_decrypt() {
|
||||||
let encrypted_details = EncryptedApplicationDetails::new(
|
let encrypted_details = EncryptedApplicationDetails::new(
|
||||||
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
&APPLICATION_DETAILS.lock().unwrap().clone(),
|
||||||
vec![PUBLIC_KEY.to_string()],
|
&vec![PUBLIC_KEY.to_string()],
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
||||||
|
|
@ -265,8 +265,6 @@ impl ApplicationService {
|
||||||
).await
|
).await
|
||||||
})
|
})
|
||||||
).await
|
).await
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn decrypt_private_key(
|
async fn decrypt_private_key(
|
||||||
|
|
@ -291,7 +289,6 @@ impl ApplicationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
pub async fn reset_password(
|
pub async fn reset_password(
|
||||||
admin_private_key: String,
|
admin_private_key: String,
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
|
|
@ -300,7 +297,6 @@ impl ApplicationService {
|
||||||
let application = Query::find_application_by_id(db, id).await?
|
let application = Query::find_application_by_id(db, id).await?
|
||||||
.ok_or(ServiceError::CandidateNotFound)?;
|
.ok_or(ServiceError::CandidateNotFound)?;
|
||||||
let candidate = ApplicationService::find_related_candidate(db, &application).await?;
|
let candidate = ApplicationService::find_related_candidate(db, &application).await?;
|
||||||
let parents = Query::find_candidate_parents(db, &candidate).await?;
|
|
||||||
|
|
||||||
let new_password_plain = crypto::random_12_char_string();
|
let new_password_plain = crypto::random_12_char_string();
|
||||||
let new_password_hash = crypto::hash_password(new_password_plain.clone()).await?;
|
let new_password_hash = crypto::hash_password(new_password_plain.clone()).await?;
|
||||||
|
|
@ -319,6 +315,7 @@ impl ApplicationService {
|
||||||
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(application.personal_id_number.clone())
|
let personal_id_number = EncryptedString::from(application.personal_id_number.clone())
|
||||||
.decrypt(&admin_private_key)
|
.decrypt(&admin_private_key)
|
||||||
|
|
@ -330,8 +327,37 @@ impl ApplicationService {
|
||||||
recipients.append(&mut admin_public_keys);
|
recipients.append(&mut admin_public_keys);
|
||||||
recipients.append(&mut applications.iter().map(|a| a.public_key.to_owned()).collect());
|
recipients.append(&mut applications.iter().map(|a| a.public_key.to_owned()).collect());
|
||||||
|
|
||||||
|
let candidate = Self::update_all_application_details(db,
|
||||||
|
application.id,
|
||||||
|
candidate,
|
||||||
|
&recipients,
|
||||||
|
&admin_private_key
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
PortfolioService::reencrypt_portfolio(
|
||||||
|
candidate.id,
|
||||||
|
admin_private_key,
|
||||||
|
&recipients
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
Ok(
|
||||||
|
CreateCandidateResponse {
|
||||||
|
application_id: id,
|
||||||
|
personal_id_number,
|
||||||
|
password: new_password_plain,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update_all_application_details(db: &DbConn,
|
||||||
|
application_id: i32,
|
||||||
|
candidate: candidate::Model,
|
||||||
|
recipients: &Vec<String>,
|
||||||
|
admin_private_key: &String
|
||||||
|
) -> Result<candidate::Model, ServiceError> {
|
||||||
|
let parents = Query::find_candidate_parents(db, &candidate).await?;
|
||||||
let dec_details = EncryptedApplicationDetails::from((&candidate, &parents))
|
let dec_details = EncryptedApplicationDetails::from((&candidate, &parents))
|
||||||
.decrypt(admin_private_key).await?;
|
.decrypt(admin_private_key.to_owned()).await?;
|
||||||
|
|
||||||
let enc_details = EncryptedApplicationDetails::new(&dec_details, recipients).await?;
|
let enc_details = EncryptedApplicationDetails::new(&dec_details, recipients).await?;
|
||||||
|
|
||||||
|
|
@ -341,23 +367,17 @@ impl ApplicationService {
|
||||||
.ok_or(ServiceError::CandidateDetailsNotSet)?.to_string()
|
.ok_or(ServiceError::CandidateDetailsNotSet)?.to_string()
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
Mutation::update_candidate_opt_details(db,
|
let candidate = Mutation::update_candidate_opt_details(db,
|
||||||
candidate,
|
candidate,
|
||||||
enc_details.candidate,
|
enc_details.candidate,
|
||||||
application.id
|
application_id
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
for i in 0..enc_details.parents.len() {
|
for i in 0..enc_details.parents.len() {
|
||||||
Mutation::add_parent_details(db, parents[i].clone(), enc_details.parents[i].clone()).await?;
|
Mutation::add_parent_details(db, parents[i].clone(), enc_details.parents[i].clone()).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(candidate)
|
||||||
CreateCandidateResponse {
|
|
||||||
application_id: id,
|
|
||||||
personal_id_number,
|
|
||||||
password: new_password_plain,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -368,15 +368,45 @@ impl PortfolioService {
|
||||||
/// Returns decrypted portfolio zip as Vec of bytes
|
/// Returns decrypted portfolio zip as Vec of bytes
|
||||||
pub async fn get_portfolio(candidate_id: i32, private_key: String) -> Result<Vec<u8>, ServiceError> {
|
pub async fn get_portfolio(candidate_id: i32, private_key: String) -> Result<Vec<u8>, ServiceError> {
|
||||||
info!("PORTFOLIO {} DECRYPT STARTED", candidate_id);
|
info!("PORTFOLIO {} DECRYPT STARTED", candidate_id);
|
||||||
let path = Self::get_file_store_path().join(&candidate_id.to_string()).to_path_buf();
|
let path = Self::get_file_store_path()
|
||||||
|
.join(&candidate_id.to_string())
|
||||||
let path = path.join(FileType::Age.as_str());
|
.join(FileType::Age.as_str())
|
||||||
|
.to_path_buf();
|
||||||
|
|
||||||
let buffer = crypto::decrypt_file_with_private_key_as_buffer(path, &private_key).await?;
|
let buffer = crypto::decrypt_file_with_private_key_as_buffer(path, &private_key).await?;
|
||||||
|
|
||||||
info!("PORTFOLIO {} DECRYPT FINISHED", candidate_id);
|
info!("PORTFOLIO {} DECRYPT FINISHED", candidate_id);
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn reencrypt_portfolio(candidate_id: i32,
|
||||||
|
private_key: String,
|
||||||
|
recipients: &Vec<String>
|
||||||
|
) -> Result<(), ServiceError> {
|
||||||
|
info!("PORTFOLIO {} REENCRYPT STARTED", candidate_id);
|
||||||
|
let path = Self::get_file_store_path()
|
||||||
|
.join(&candidate_id.to_string())
|
||||||
|
.join(FileType::Age.as_str())
|
||||||
|
.to_path_buf();
|
||||||
|
|
||||||
|
let plain_portfolio = crypto::decrypt_file_with_private_key_as_buffer(
|
||||||
|
path.to_owned(),
|
||||||
|
&private_key
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
tokio::fs::remove_file(path.to_owned()).await?;
|
||||||
|
|
||||||
|
let enc_portfolio= crypto::encrypt_buffer_with_recipients(
|
||||||
|
&plain_portfolio,
|
||||||
|
recipients
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
tokio::fs::write(path, enc_portfolio).await?;
|
||||||
|
|
||||||
|
info!("PORTFOLIO {} REENCRYPT FINISHED", candidate_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue