use magic_crypt::{MagicCrypt, MagicCryptTrait, SecureBit}; use rand::{distributions::Alphanumeric, Rng}; #[derive(Debug, Clone)] /// A structure responsible of encrypting and decrypting data such as auth token, passwords and email addresses. pub struct Encryption { /// The encryption key must be keeped secret and is loaded from the $CRYPT_KEY environment variable pub key: String, } impl Encryption { pub fn new(key: String) -> Self { Encryption { key } } /// Gets a string as an argument and returns a base64 hash of the string based on the secret key and magic_crypt::SecureBit::Bit256 algorithm pub fn encrypt(&self, source: &String) -> String { let mc = MagicCrypt::new(&self.key, SecureBit::Bit256, None::<String>); mc.encrypt_str_to_base64(source) } /// Gets a string base64 hash as an argument and returns the decryted string. /// Panics if the source base64 string cannot be decrypted (should happen if trying to decrypt a regular string) #[cfg(test)] pub fn decrypt(&self, source: &String) -> String { let mc = MagicCrypt::new(&self.key, SecureBit::Bit256, None::<String>); mc.decrypt_base64_to_string(source).unwrap() } /// Generates a random ascii lowercase string. Length being given as argument. pub fn random_ascii_lc_string(&self, length: usize) -> String { // Thanks to https://stackoverflow.com/questions/54275459/how-do-i-create-a-random-string-by-sampling-from-alphanumeric-characters#54277357 rand::thread_rng() .sample_iter(&Alphanumeric) .take(length) .map(char::from) .collect::<String>() .to_ascii_lowercase() } } /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ * _______ ______ ______ _______ *@@ * |__ __@ | ____@ / ____@ |__ __@ *@@ * | @ | @__ \_ @_ | @ *@@ * | @ | __@ \ @_ | @ *@@ * | @ | @___ ____\ @ | @ *@@ * |__@ |______@ \______@ |__@ *@@ * *@@ *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@@ *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*@*/ #[cfg(test)] mod test_encryption { use super::*; #[test] fn test_random_ascii_lc_string() { dotenv::dotenv().ok(); let key = std::env::var("CRYPT_KEY").unwrap(); let enc = Encryption::new(key); let rdm_str = enc.random_ascii_lc_string(32); assert_eq!(rdm_str.len(), 32); assert!(rdm_str.chars().all(char::is_alphanumeric)); assert_eq!(rdm_str, rdm_str.to_lowercase()); } #[test] fn test_encrypt() { dotenv::dotenv().ok(); let key = std::env::var("CRYPT_KEY").unwrap(); let enc = Encryption::new(key); let an_email = String::from("kuadrado-email@test.com"); let email_hash = enc.encrypt(&an_email); assert_ne!(an_email, email_hash); } #[test] fn test_decrypt() { dotenv::dotenv().ok(); let key = std::env::var("CRYPT_KEY").unwrap(); let enc = Encryption::new(key); let an_email = String::from("kuadrado-email@test.com"); let email_hash = enc.encrypt(&an_email); let decrypted = enc.decrypt(&email_hash); assert_eq!(an_email, decrypted); } }