darkwing/server/services/
config_encryption_services.rsuse aes::cipher::generic_array::GenericArray;
use aes_gcm::{
aead::{Aead, KeyInit},
Aes256Gcm, Nonce,
};
use async_trait::async_trait;
use base64::{engine::general_purpose, Engine as _};
use mockall::automock;
use std::sync::Arc;
use crate::{
config::DarkwingConfig,
server::error::{AppResult, Error},
server::services::browser_profile_services::config::BrowserProfileConfig,
};
pub type DynConfigEncryption = Arc<dyn ConfigEncryptionTrait + Send + Sync>;
#[automock]
#[async_trait]
pub trait ConfigEncryptionTrait {
async fn encrypt_config(
&self,
config: BrowserProfileConfig,
) -> AppResult<String>;
}
#[derive(Clone)]
pub struct ConfigEncryptionService {
config: Arc<DarkwingConfig>,
}
impl ConfigEncryptionService {
pub fn new(config: Arc<DarkwingConfig>) -> Self {
Self { config }
}
fn encrypt_string(string: String, key: String) -> AppResult<String> {
let key = GenericArray::from_slice(key.as_bytes());
let cipher = Aes256Gcm::new(key);
let nonce = Nonce::from_slice(&[0u8; 12]); let ciphertext = cipher
.encrypt(nonce, string.as_bytes())
.map_err(|_| Error::AesGcmError)?;
let encoded = general_purpose::STANDARD.encode(ciphertext);
Ok(encoded)
}
}
#[async_trait]
impl ConfigEncryptionTrait for ConfigEncryptionService {
async fn encrypt_config(
&self,
config: BrowserProfileConfig,
) -> AppResult<String> {
let json = config.json()?;
Self::encrypt_string(json, self.config.config_encryption_key.clone())
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_encrypt_config() {
let text = "happy new year 2020".into();
let encoded =
"a3YrXdzPOREU8Wf7ixCIdEgGm5pLTzSAAQieJFE4/UQwAAY=".to_string();
let key = "rQFLdz7zKp4KggT7b7qmLt7MEgh598mx".into();
assert_eq!(
encoded,
ConfigEncryptionService::encrypt_string(text, key).unwrap()
);
}
}