pub(crate) mod crypter; pub(crate) mod from; use self::crypter::{Crypter, CrypterError}; use crate::{ AddressType, Credential, CredentialType, IdentityId, SecdError, Session, SESSION_DURATION, SESSION_SIZE_BYTES, }; use sha2::{Digest, Sha256}; use std::str::from_utf8; use time::OffsetDateTime; pub(crate) fn hash(i: &[u8]) -> Vec { let mut hasher = Sha256::new(); hasher.update(i); hasher.finalize().to_vec() } impl AddressType { pub fn get_value(&self) -> Option { match &self { AddressType::Email { email_address } => { email_address.as_ref().map(|a| a.to_string().clone()) } AddressType::Sms { phone_number } => phone_number.as_ref().cloned(), } } } impl Session { pub(crate) fn new(identity_id: IdentityId) -> Result { let token = (0..SESSION_SIZE_BYTES) .map(|_| rand::random::()) .collect::>(); let now = OffsetDateTime::now_utc(); Ok(Session { identity_id, token, created_at: now, expired_at: now .checked_add(time::Duration::new(SESSION_DURATION, 0)) .ok_or(SecdError::Todo)?, revoked_at: None, }) } } impl Credential { pub(crate) fn encrypt(&mut self, crypter: &Crypter) -> Result<(), SecdError> { Ok(match self.t { CredentialType::Passphrase { key: _, ref mut value, } => { *value = hex::encode(crypter.encrypt(value.as_bytes())?); } _ => {} }) } pub(crate) fn decrypt(&mut self, crypter: &Crypter) -> Result<(), SecdError> { Ok(match self.t { CredentialType::Passphrase { key: _, ref mut value, } => { *value = from_utf8( &crypter.decrypt( &hex::decode(value.clone()) .map_err(|e| CrypterError::DecodeError(e.to_string()))?, )?, ) .map_err(|e| CrypterError::DecodeError(e.to_string()))? .to_string() } _ => {} }) } pub(crate) fn hash(&mut self, crypter: &Crypter) -> Result<(), SecdError> { Ok(match self.t { CredentialType::Passphrase { key: _, ref mut value, } => { *value = crypter.hash(value.as_bytes())?; } _ => {} }) } } #[cfg(test)] mod test { use uuid::Uuid; use super::*; #[test] fn test_credential_encrypt() { let c = Crypter::new("AMAZING_KEY".as_bytes()); let plaintext_secret = "super_password".to_string(); let mut credential = Credential { id: Uuid::new_v4(), identity_id: Uuid::new_v4(), t: CredentialType::Passphrase { key: "super_user".into(), value: plaintext_secret.clone(), }, created_at: OffsetDateTime::now_utc(), revoked_at: None, deleted_at: None, }; credential.encrypt(&c).unwrap(); match &credential.t { CredentialType::Passphrase { key: _, value } => { assert_ne!(plaintext_secret.clone(), value.clone()) } _ => {} }; credential.decrypt(&c).unwrap(); match &credential.t { CredentialType::Passphrase { key: _, value } => { assert_eq!(plaintext_secret.clone(), value.clone()) } _ => {} }; } }