diff --git a/crates/common_utils/src/macros.rs b/crates/common_utils/src/macros.rs index abd24ac867..06554ee9b5 100644 --- a/crates/common_utils/src/macros.rs +++ b/crates/common_utils/src/macros.rs @@ -301,3 +301,14 @@ mod id_type { }; } } + +/// Get the type name for a type +#[macro_export] +macro_rules! type_name { + ($type:ty) => { + std::any::type_name::<$type>() + .rsplit("::") + .nth(1) + .unwrap_or_default(); + }; +} diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 779dcdb2fb..08903748c0 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -5,7 +5,7 @@ use common_utils::{ date_time, encryption::Encryption, errors::{CustomResult, ValidationError}, - pii, + pii, type_name, types::keymanager, }; use diesel_models::business_profile::{ @@ -15,7 +15,7 @@ use diesel_models::business_profile::{ use error_stack::ResultExt; use masking::{PeekInterface, Secret}; -use crate::type_encryption::{decrypt_optional, AsyncLift}; +use crate::type_encryption::{crypto_operation, AsyncLift, CryptoOperation}; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -348,8 +348,16 @@ impl super::behaviour::Conversion for BusinessProfile { .collect_billing_details_from_wallet_connector, outgoing_webhook_custom_http_headers: item .outgoing_webhook_custom_http_headers - .async_lift(|inner| { - decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, }) @@ -725,8 +733,16 @@ impl super::behaviour::Conversion for BusinessProfile { .collect_billing_details_from_wallet_connector, outgoing_webhook_custom_http_headers: item .outgoing_webhook_custom_http_headers - .async_lift(|inner| { - decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, routing_algorithm_id: item.routing_algorithm_id, diff --git a/crates/hyperswitch_domain_models/src/customer.rs b/crates/hyperswitch_domain_models/src/customer.rs index 6b08e30d33..42c66b74c0 100644 --- a/crates/hyperswitch_domain_models/src/customer.rs +++ b/crates/hyperswitch_domain_models/src/customer.rs @@ -110,17 +110,21 @@ impl super::behaviour::Conversion for Customer { where Self: Sized, { - let decrypted = types::batch_decrypt( + let decrypted = types::crypto_operation( state, - CustomerRequestWithEncryption::to_encryptable(CustomerRequestWithEncryption { - name: item.name.clone(), - phone: item.phone.clone(), - email: item.email.clone(), - }), + common_utils::type_name!(Self::DstType), + types::CryptoOperation::BatchDecrypt(CustomerRequestWithEncryption::to_encryptable( + CustomerRequestWithEncryption { + name: item.name.clone(), + phone: item.phone.clone(), + email: item.email.clone(), + }, + )), keymanager::Identifier::Merchant(item.merchant_id.clone()), key.peek(), ) .await + .and_then(|val| val.try_into_batchoperation()) .change_context(ValidationError::InvalidValue { message: "Failed while decrypting customer data".to_string(), })?; @@ -206,17 +210,21 @@ impl super::behaviour::Conversion for Customer { where Self: Sized, { - let decrypted = types::batch_decrypt( + let decrypted = types::crypto_operation( state, - CustomerRequestWithEncryption::to_encryptable(CustomerRequestWithEncryption { - name: item.name.clone(), - phone: item.phone.clone(), - email: item.email.clone(), - }), + type_name!(Self::DstType), + types::CryptoOperation::BatchDecrypt(CustomerRequestWithEncryption::to_encryptable( + CustomerRequestWithEncryption { + name: item.name.clone(), + phone: item.phone.clone(), + email: item.email.clone(), + }, + )), keymanager::Identifier::Merchant(item.merchant_id.clone()), key.peek(), ) .await + .and_then(|val| val.try_into_batchoperation()) .change_context(ValidationError::InvalidValue { message: "Failed while decrypting customer data".to_string(), })?; diff --git a/crates/hyperswitch_domain_models/src/merchant_account.rs b/crates/hyperswitch_domain_models/src/merchant_account.rs index 1697b78275..8ce0b3a5e4 100644 --- a/crates/hyperswitch_domain_models/src/merchant_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_account.rs @@ -4,7 +4,7 @@ use common_utils::{ encryption::Encryption, errors::{CustomResult, ValidationError}, ext_traits::ValueExt, - pii, + pii, type_name, types::keymanager::{self}, }; use diesel_models::{ @@ -15,7 +15,7 @@ use error_stack::ResultExt; use masking::{PeekInterface, Secret}; use router_env::logger; -use crate::type_encryption::{decrypt_optional, AsyncLift}; +use crate::type_encryption::{crypto_operation, AsyncLift, CryptoOperation}; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -565,14 +565,30 @@ impl super::behaviour::Conversion for MerchantAccount { id, merchant_name: item .merchant_name - .async_lift(|inner| { - decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, merchant_details: item .merchant_details - .async_lift(|inner| { - decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, publishable_key, @@ -679,14 +695,30 @@ impl super::behaviour::Conversion for MerchantAccount { redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post, merchant_name: item .merchant_name - .async_lift(|inner| { - decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, merchant_details: item .merchant_details - .async_lift(|inner| { - decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, webhook_details: item.webhook_details, diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs index cea595aed6..006fd5d775 100644 --- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs +++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs @@ -3,7 +3,7 @@ use common_utils::{ date_time, encryption::Encryption, errors::{CustomResult, ValidationError}, - pii, + pii, type_name, types::keymanager::{Identifier, KeyManagerState}, }; use diesel_models::{enums, merchant_connector_account::MerchantConnectorAccountUpdateInternal}; @@ -11,7 +11,7 @@ use error_stack::ResultExt; use masking::{PeekInterface, Secret}; use super::behaviour; -use crate::type_encryption::{decrypt, decrypt_optional, AsyncLift}; +use crate::type_encryption::{crypto_operation, AsyncLift, CryptoOperation}; #[cfg(all( any(feature = "v1", feature = "v2"), @@ -185,13 +185,15 @@ impl behaviour::Conversion for MerchantConnectorAccount { Ok(Self { merchant_id: other.merchant_id, connector_name: other.connector_name, - connector_account_details: decrypt( + connector_account_details: crypto_operation( state, - other.connector_account_details, + type_name!(Self::DstType), + CryptoOperation::Decrypt(other.connector_account_details), identifier.clone(), key.peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(ValidationError::InvalidValue { message: "Failed while decrypting connector account details".to_string(), })?, @@ -216,18 +218,35 @@ impl behaviour::Conversion for MerchantConnectorAccount { status: other.status, connector_wallets_details: other .connector_wallets_details - .async_lift(|inner| decrypt_optional(state, inner, identifier.clone(), key.peek())) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) + }) .await .change_context(ValidationError::InvalidValue { message: "Failed while decrypting connector wallets details".to_string(), })?, additional_merchant_data: if let Some(data) = other.additional_merchant_data { Some( - decrypt(state, data, identifier, key.peek()) - .await - .change_context(ValidationError::InvalidValue { - message: "Failed while decrypting additional_merchant_data".to_string(), - })?, + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::Decrypt(data), + identifier, + key.peek(), + ) + .await + .and_then(|val| val.try_into_operation()) + .change_context(ValidationError::InvalidValue { + message: "Failed while decrypting additional_merchant_data".to_string(), + })?, ) } else { None @@ -309,13 +328,15 @@ impl behaviour::Conversion for MerchantConnectorAccount { id: other.id, merchant_id: other.merchant_id, connector_name: other.connector_name, - connector_account_details: decrypt( + connector_account_details: crypto_operation( state, - other.connector_account_details, + type_name!(Self::DstType), + CryptoOperation::Decrypt(other.connector_account_details), identifier.clone(), key.peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(ValidationError::InvalidValue { message: "Failed while decrypting connector account details".to_string(), })?, @@ -335,18 +356,35 @@ impl behaviour::Conversion for MerchantConnectorAccount { status: other.status, connector_wallets_details: other .connector_wallets_details - .async_lift(|inner| decrypt_optional(state, inner, identifier.clone(), key.peek())) + .async_lift(|inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) + }) .await .change_context(ValidationError::InvalidValue { message: "Failed while decrypting connector wallets details".to_string(), })?, additional_merchant_data: if let Some(data) = other.additional_merchant_data { Some( - decrypt(state, data, identifier, key.peek()) - .await - .change_context(ValidationError::InvalidValue { - message: "Failed while decrypting additional_merchant_data".to_string(), - })?, + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::Decrypt(data), + identifier, + key.peek(), + ) + .await + .and_then(|val| val.try_into_operation()) + .change_context(ValidationError::InvalidValue { + message: "Failed while decrypting additional_merchant_data".to_string(), + })?, ) } else { None diff --git a/crates/hyperswitch_domain_models/src/merchant_key_store.rs b/crates/hyperswitch_domain_models/src/merchant_key_store.rs index bfd75a08fa..d24e23c579 100644 --- a/crates/hyperswitch_domain_models/src/merchant_key_store.rs +++ b/crates/hyperswitch_domain_models/src/merchant_key_store.rs @@ -2,13 +2,14 @@ use common_utils::{ crypto::Encryptable, custom_serde, date_time, errors::{CustomResult, ValidationError}, + type_name, types::keymanager::{self, KeyManagerState}, }; use error_stack::ResultExt; use masking::{PeekInterface, Secret}; use time::PrimitiveDateTime; -use crate::type_encryption::decrypt; +use crate::type_encryption::{crypto_operation, CryptoOperation}; #[derive(Clone, Debug, serde::Serialize)] pub struct MerchantKeyStore { @@ -40,12 +41,20 @@ impl super::behaviour::Conversion for MerchantKeyStore { Self: Sized, { let identifier = keymanager::Identifier::Merchant(item.merchant_id.clone()); + Ok(Self { - key: decrypt(state, item.key, identifier, key.peek()) - .await - .change_context(ValidationError::InvalidValue { - message: "Failed while decrypting customer data".to_string(), - })?, + key: crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::Decrypt(item.key), + identifier, + key.peek(), + ) + .await + .and_then(|val| val.try_into_operation()) + .change_context(ValidationError::InvalidValue { + message: "Failed while decrypting customer data".to_string(), + })?, merchant_id: item.merchant_id, created_at: item.created_at, }) diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 15c5aded50..79818d5b15 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -3,7 +3,7 @@ use common_enums as storage_enums; use common_utils::{ encryption::Encryption, errors::{CustomResult, ValidationError}, - id_type, pii, + id_type, pii, type_name, types::{ keymanager::{self, KeyManagerState}, MinorUnit, @@ -18,7 +18,7 @@ use super::PaymentIntent; use crate::{ behaviour, errors, mandates::{MandateDataType, MandateDetails}, - type_encryption::{decrypt_optional, AsyncLift}, + type_encryption::{crypto_operation, AsyncLift, CryptoOperation}, ForeignIDRef, RemoteStorageObject, }; @@ -553,8 +553,17 @@ impl behaviour::Conversion for PaymentIntent { Self: Sized, { async { - let inner_decrypt = - |inner| decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()); + let inner_decrypt = |inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) + }; Ok::>(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, @@ -742,8 +751,17 @@ impl behaviour::Conversion for PaymentIntent { Self: Sized, { async { - let inner_decrypt = - |inner| decrypt_optional(state, inner, key_manager_identifier.clone(), key.peek()); + let inner_decrypt = |inner| async { + crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) + }; Ok::>(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, diff --git a/crates/hyperswitch_domain_models/src/type_encryption.rs b/crates/hyperswitch_domain_models/src/type_encryption.rs index a36969478d..0ff37b0bc2 100644 --- a/crates/hyperswitch_domain_models/src/type_encryption.rs +++ b/crates/hyperswitch_domain_models/src/type_encryption.rs @@ -9,6 +9,7 @@ use common_utils::{ }; use encrypt::TypeEncryption; use masking::Secret; +use router_env::{instrument, tracing}; use rustc_hash::FxHashMap; mod encrypt { @@ -831,12 +832,12 @@ impl + Lift = V> + Send> AsyncLift for V { } #[inline] -pub async fn encrypt( +async fn encrypt( state: &KeyManagerState, inner: Secret, identifier: Identifier, key: &[u8], -) -> CustomResult>, errors::CryptoError> +) -> CustomResult>, CryptoError> where S: masking::Strategy, crypto::Encryptable>: TypeEncryption, @@ -851,12 +852,12 @@ where } #[inline] -pub async fn batch_encrypt( +async fn batch_encrypt( state: &KeyManagerState, inner: FxHashMap>, identifier: Identifier, key: &[u8], -) -> CustomResult>>, errors::CryptoError> +) -> CustomResult>>, CryptoError> where S: masking::Strategy, crypto::Encryptable>: TypeEncryption, @@ -881,12 +882,12 @@ where } #[inline] -pub async fn encrypt_optional( +async fn encrypt_optional( state: &KeyManagerState, inner: Option>, identifier: Identifier, key: &[u8], -) -> CustomResult>>, errors::CryptoError> +) -> CustomResult>>, CryptoError> where Secret: Send, S: masking::Strategy, @@ -899,12 +900,12 @@ where } #[inline] -pub async fn decrypt_optional>( +async fn decrypt_optional>( state: &KeyManagerState, inner: Option, identifier: Identifier, key: &[u8], -) -> CustomResult>>, errors::CryptoError> +) -> CustomResult>>, CryptoError> where crypto::Encryptable>: TypeEncryption, { @@ -915,12 +916,12 @@ where } #[inline] -pub async fn decrypt>( +async fn decrypt>( state: &KeyManagerState, inner: Encryption, identifier: Identifier, key: &[u8], -) -> CustomResult>, errors::CryptoError> +) -> CustomResult>, CryptoError> where crypto::Encryptable>: TypeEncryption, { @@ -934,12 +935,12 @@ where } #[inline] -pub async fn batch_decrypt( +async fn batch_decrypt( state: &KeyManagerState, inner: FxHashMap, identifier: Identifier, key: &[u8], -) -> CustomResult>>, errors::CryptoError> +) -> CustomResult>>, CryptoError> where S: masking::Strategy, crypto::Encryptable>: TypeEncryption, @@ -963,6 +964,65 @@ where } } +pub enum CryptoOperation> { + Encrypt(Secret), + EncryptOptional(Option>), + Decrypt(Encryption), + DecryptOptional(Option), + BatchEncrypt(FxHashMap>), + BatchDecrypt(FxHashMap), +} + +use errors::CryptoError; + +#[derive(router_derive::TryGetEnumVariant)] +#[error(CryptoError::EncodingFailed)] +pub enum CryptoOutput> { + Operation(crypto::Encryptable>), + OptionalOperation(Option>>), + BatchOperation(FxHashMap>>), +} + +#[instrument(skip_all, fields(table = table_name))] +pub async fn crypto_operation>( + state: &KeyManagerState, + table_name: &str, + operation: CryptoOperation, + identifier: Identifier, + key: &[u8], +) -> CustomResult, CryptoError> +where + Secret: Send, + crypto::Encryptable>: TypeEncryption, +{ + match operation { + CryptoOperation::Encrypt(data) => { + let data = encrypt(state, data, identifier, key).await?; + Ok(CryptoOutput::Operation(data)) + } + CryptoOperation::EncryptOptional(data) => { + let data = encrypt_optional(state, data, identifier, key).await?; + Ok(CryptoOutput::OptionalOperation(data)) + } + CryptoOperation::Decrypt(data) => { + let data = decrypt(state, data, identifier, key).await?; + Ok(CryptoOutput::Operation(data)) + } + CryptoOperation::DecryptOptional(data) => { + let data = decrypt_optional(state, data, identifier, key).await?; + Ok(CryptoOutput::OptionalOperation(data)) + } + CryptoOperation::BatchEncrypt(data) => { + let data = batch_encrypt(state, data, identifier, key).await?; + Ok(CryptoOutput::BatchOperation(data)) + } + CryptoOperation::BatchDecrypt(data) => { + let data = batch_decrypt(state, data, identifier, key).await?; + Ok(CryptoOutput::BatchOperation(data)) + } + } +} + pub(crate) mod metrics { use router_env::{counter_metric, global_meter, histogram_metric, metrics_context, once_cell}; diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index f5eeaeff9b..a1cf93a0ac 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -8,7 +8,7 @@ use base64::Engine; use common_utils::{ date_time, ext_traits::{AsyncExt, Encode, ValueExt}, - id_type, pii, + id_type, pii, type_name, types::keymanager::{self as km_types, KeyManagerState}, }; use diesel_models::configs; @@ -216,13 +216,15 @@ pub async fn create_merchant_account( let key_store = domain::MerchantKeyStore { merchant_id: merchant_id.clone(), - key: domain_types::encrypt( + key: domain_types::crypto_operation( key_manager_state, - key.to_vec().into(), + type_name!(domain::MerchantKeyStore), + domain_types::CryptoOperation::Encrypt(key.to_vec().into()), identifier.clone(), master_key, ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to decrypt data from key store")?, created_at: date_time::now(), @@ -341,23 +343,29 @@ impl MerchantAccountCreateBridge for api::MerchantAccountCreate { merchant_id: identifier.clone(), merchant_name: self .merchant_name - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + domain_types::crypto_operation( &key_manager_state, - inner, + type_name!(domain::MerchantAccount), + domain_types::CryptoOperation::EncryptOptional(inner), km_types::Identifier::Merchant(key_store.merchant_id.clone()), key.peek(), ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, merchant_details: merchant_details - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + domain_types::crypto_operation( &key_manager_state, - inner, + type_name!(domain::MerchantAccount), + domain_types::CryptoOperation::EncryptOptional(inner), km_types::Identifier::Merchant(key_store.merchant_id.clone()), key.peek(), ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, return_url: self.return_url.map(|a| a.to_string()), @@ -646,23 +654,30 @@ impl MerchantAccountCreateBridge for api::MerchantAccountCreate { domain::MerchantAccount::from(domain::MerchantAccountSetter { id, merchant_name: Some( - domain_types::encrypt( + domain_types::crypto_operation( &key_manager_state, - self.merchant_name - .map(|merchant_name| merchant_name.into_inner()), + type_name!(domain::MerchantAccount), + domain_types::CryptoOperation::Encrypt( + self.merchant_name + .map(|merchant_name| merchant_name.into_inner()), + ), identifier.clone(), key.peek(), ) - .await?, + .await + .and_then(|val| val.try_into_operation())?, ), merchant_details: merchant_details - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + domain_types::crypto_operation( &key_manager_state, - inner, + type_name!(domain::MerchantAccount), + domain_types::CryptoOperation::EncryptOptional(inner), identifier.clone(), key.peek(), ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await?, routing_algorithm: Some(serde_json::json!({ @@ -918,25 +933,31 @@ impl MerchantAccountUpdateBridge for api::MerchantAccountUpdate { merchant_name: self .merchant_name .map(Secret::new) - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + domain_types::crypto_operation( key_manager_state, - inner, + type_name!(storage::MerchantAccount), + domain_types::CryptoOperation::EncryptOptional(inner), identifier.clone(), key, ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt merchant name")?, merchant_details: merchant_details - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + domain_types::crypto_operation( key_manager_state, - inner, + type_name!(storage::MerchantAccount), + domain_types::CryptoOperation::EncryptOptional(inner), km_types::Identifier::Merchant(key_store.merchant_id.clone()), key, ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await .change_context(errors::ApiErrorResponse::InternalServerError) @@ -2006,13 +2027,16 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect connector_label: self.connector_label.clone(), connector_account_details: self .connector_account_details - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + domain_types::crypto_operation( key_manager_state, - inner, + type_name!(storage::MerchantConnectorAccount), + domai_types::CryptoOperation::EncryptOptional(inner), km_types::Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.get_inner().peek(), ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await .change_context(errors::ApiErrorResponse::InternalServerError) @@ -2141,13 +2165,16 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect connector_label: self.connector_label.clone(), connector_account_details: self .connector_account_details - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + domain_types::crypto_operation( key_manager_state, - inner, + type_name!(storage::MerchantConnectorAccount), + domain_types::CryptoOperation::EncryptOptional(inner), km_types::Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.get_inner().peek(), ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await .change_context(errors::ApiErrorResponse::InternalServerError) @@ -2268,17 +2295,19 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { merchant_id: business_profile.merchant_id.clone(), connector_type: self.connector_type, connector_name: self.connector_name.to_string(), - connector_account_details: domain_types::encrypt( + connector_account_details: domain_types::crypto_operation( key_manager_state, - self.connector_account_details.ok_or( + type_name!(domain::MerchantConnectorAccount), + domain_types::CryptoOperation::Encrypt(self.connector_account_details.ok_or( errors::ApiErrorResponse::MissingRequiredField { field_name: "connector_account_details", }, - )?, + )?), identifier.clone(), key_store.key.peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt connector account details")?, payment_methods_enabled, @@ -2306,13 +2335,15 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { status: connector_status, connector_wallets_details: helpers::get_encrypted_apple_pay_connector_wallets_details(state, &key_store, &self.metadata).await?, additional_merchant_data: if let Some(mcd) = merchant_recipient_data { - Some(domain_types::encrypt( + Some(domain_types::crypto_operation( key_manager_state, - Secret::new(mcd), + type_name!(domain::MerchantConnectorAccount), + domain_types::CryptoOperation::Encrypt(Secret::new(mcd)), identifier, key_store.key.peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt additional_merchant_data")?) } else { @@ -2434,17 +2465,19 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { connector_type: self.connector_type, connector_name: self.connector_name.to_string(), merchant_connector_id: utils::generate_id(consts::ID_LENGTH, "mca"), - connector_account_details: domain_types::encrypt( + connector_account_details: domain_types::crypto_operation( key_manager_state, - self.connector_account_details.ok_or( + type_name!(domain::MerchantConnectorAccount), + domain_types::CryptoOperation::Encrypt(self.connector_account_details.ok_or( errors::ApiErrorResponse::MissingRequiredField { field_name: "connector_account_details", }, - )?, + )?), identifier.clone(), key_store.key.peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt connector account details")?, payment_methods_enabled, @@ -2475,13 +2508,15 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { business_label: self.business_label.clone(), business_sub_label: self.business_sub_label.clone(), additional_merchant_data: if let Some(mcd) = merchant_recipient_data { - Some(domain_types::encrypt( + Some(domain_types::crypto_operation( key_manager_state, - Secret::new(mcd), + type_name!(domain::MerchantConnectorAccount), + domain_types::CryptoOperation::Encrypt(Secret::new(mcd)), identifier, key_store.key.peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt additional_merchant_data")?) } else { diff --git a/crates/router/src/core/apple_pay_certificates_migration.rs b/crates/router/src/core/apple_pay_certificates_migration.rs index 8fe61f75ca..44be8f33bb 100644 --- a/crates/router/src/core/apple_pay_certificates_migration.rs +++ b/crates/router/src/core/apple_pay_certificates_migration.rs @@ -1,5 +1,5 @@ use api_models::apple_pay_certificates_migration; -use common_utils::{errors::CustomResult, types::keymanager::Identifier}; +use common_utils::{errors::CustomResult, type_name, types::keymanager::Identifier}; use error_stack::ResultExt; use masking::{PeekInterface, Secret}; @@ -64,17 +64,19 @@ pub async fn apple_pay_certificates_migration( }) .ok(); if let Some(apple_pay_metadata) = connector_apple_pay_metadata { - let encrypted_apple_pay_metadata = domain_types::encrypt( + let encrypted_apple_pay_metadata = domain_types::crypto_operation( &(&state).into(), - Secret::new( + type_name!(storage::MerchantConnectorAccount), + domain_types::CryptoOperation::Encrypt(Secret::new( serde_json::to_value(apple_pay_metadata) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to serialize apple pay metadata as JSON")?, - ), + )), Identifier::Merchant(merchant_id.clone()), key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Unable to encrypt connector apple pay metadata")?; diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs index 73368cba0e..69bf4052d7 100644 --- a/crates/router/src/core/customers.rs +++ b/crates/router/src/core/customers.rs @@ -4,13 +4,11 @@ use common_utils::{crypto::Encryptable, ext_traits::OptionExt, types::Descriptio use common_utils::{ errors::ReportSwitchExt, ext_traits::AsyncExt, - id_type, + id_type, type_name, types::keymanager::{Identifier, KeyManagerState, ToEncryptable}, }; use error_stack::{report, ResultExt}; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use hyperswitch_domain_models::type_encryption::encrypt; -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] use masking::{Secret, SwitchStrategy}; use router_env::{instrument, tracing}; @@ -145,17 +143,21 @@ impl CustomerCreateBridge for customers::CustomerRequest { .encrypt_customer_address_and_set_to_db(db) .await?; - let encrypted_data = types::batch_encrypt( + let encrypted_data = types::crypto_operation( key_manager_state, - CustomerRequestWithEmail::to_encryptable(CustomerRequestWithEmail { - name: self.name.clone(), - email: self.email.clone(), - phone: self.phone.clone(), - }), + type_name!(domain::Customer), + types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( + CustomerRequestWithEmail { + name: self.name.clone(), + email: self.email.clone(), + phone: self.phone.clone(), + }, + )), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_batchoperation()) .switch() .attach_printable("Failed while encrypting Customer")?; @@ -227,17 +229,21 @@ impl CustomerCreateBridge for customers::CustomerRequest { let merchant_id = merchant_account.get_id().clone(); let key = key_store.key.get_inner().peek(); - let encrypted_data = types::batch_encrypt( + let encrypted_data = types::crypto_operation( key_state, - CustomerRequestWithEmail::to_encryptable(CustomerRequestWithEmail { - name: Some(self.name.clone()), - email: Some(self.email.clone()), - phone: self.phone.clone(), - }), + type_name!(domain::Customer), + types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( + CustomerRequestWithEmail { + name: Some(self.name.clone()), + email: Some(self.email.clone()), + phone: self.phone.clone(), + }, + )), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_batchoperation()) .switch() .attach_printable("Failed while encrypting Customer")?; @@ -508,13 +514,15 @@ pub async fn delete_customer( let key = key_store.key.get_inner().peek(); let identifier = Identifier::Merchant(key_store.merchant_id.clone()); - let redacted_encrypted_value: Encryptable> = encrypt( + let redacted_encrypted_value: Encryptable> = types::crypto_operation( key_manager_state, - REDACTED.to_string().into(), + type_name!(storage::Address), + types::CryptoOperation::Encrypt(REDACTED.to_string().into()), identifier.clone(), key, ) .await + .and_then(|val| val.try_into_operation()) .switch()?; let redacted_encrypted_email = Encryptable::new( @@ -566,13 +574,15 @@ pub async fn delete_customer( let updated_customer = storage::CustomerUpdate::Update { name: Some(redacted_encrypted_value.clone()), email: Some( - encrypt( + types::crypto_operation( key_manager_state, - REDACTED.to_string().into(), + type_name!(storage::Customer), + types::CryptoOperation::Encrypt(REDACTED.to_string().into()), identifier, key, ) .await + .and_then(|val| val.try_into_operation()) .switch()?, ), phone: Box::new(Some(redacted_encrypted_value.clone())), @@ -697,17 +707,21 @@ pub async fn update_customer( None => None, } }; - let encrypted_data = types::batch_encrypt( + let encrypted_data = types::crypto_operation( &(&state).into(), - CustomerRequestWithEmail::to_encryptable(CustomerRequestWithEmail { - name: update_customer.name.clone(), - email: update_customer.email.clone(), - phone: update_customer.phone.clone(), - }), + type_name!(domain::Customer), + types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( + CustomerRequestWithEmail { + name: update_customer.name.clone(), + email: update_customer.email.clone(), + phone: update_customer.phone.clone(), + }, + )), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_batchoperation()) .switch()?; let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) .change_context(errors::CustomersErrorResponse::InternalServerError)?; diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index a7a240339e..9f13530fbd 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -25,7 +25,7 @@ use common_utils::{ crypto::Encryptable, encryption::Encryption, ext_traits::{AsyncExt, Encode, StringExt, ValueExt}, - generate_id, id_type, + generate_id, id_type, type_name, types::{ keymanager::{Identifier, KeyManagerState}, MinorUnit, @@ -76,7 +76,7 @@ use crate::{ services, types::{ api::{self, routing as routing_types, PaymentMethodCreateExt}, - domain::{self, types::decrypt_optional}, + domain, storage::{self, enums, PaymentMethodListContext, PaymentTokenData}, transformers::{ForeignFrom, ForeignTryFrom}, }, @@ -1219,13 +1219,18 @@ pub async fn update_customer_payment_method( } // Fetch the existing payment method data from db - let existing_card_data = decrypt_optional::( + let existing_card_data = domain::types::crypto_operation::< + serde_json::Value, + masking::WithType, + >( &(&state).into(), - pm.payment_method_data.clone(), + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::DecryptOptional(pm.payment_method_data.clone()), Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to decrypt card details")? .map(|x| x.into_inner().expose()) @@ -1479,13 +1484,16 @@ pub async fn add_bank_to_locker( let secret: Secret = Secret::new(v.to_string()); secret }) - .async_lift(|inner| { - domain::types::encrypt_optional( + .async_lift(|inner| async { + domain::types::crypto_operation( &key_manager_state, - inner, + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::EncryptOptional(inner), Identifier::Merchant(key_store.merchant_id.clone()), key, ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await } @@ -1693,13 +1701,17 @@ pub async fn decode_and_decrypt_locker_data( .change_context(errors::VaultError::ResponseDeserializationFailed) .attach_printable("Failed to decode hex string into bytes")?; // Decrypt - decrypt_optional( + domain::types::crypto_operation( &state.into(), - Some(Encryption::new(decoded_bytes.into())), + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::DecryptOptional(Some(Encryption::new( + decoded_bytes.into(), + ))), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::VaultError::FetchPaymentMethodFailed)? .map_or( Err(report!(errors::VaultError::FetchPaymentMethodFailed)), @@ -4505,13 +4517,15 @@ where { let key = key_store.key.get_inner().peek(); let identifier = Identifier::Merchant(key_store.merchant_id.clone()); - let decrypted_data = decrypt_optional::( + let decrypted_data = domain::types::crypto_operation::( &state.into(), - data, + type_name!(T), + domain::types::CryptoOperation::DecryptOptional(data), identifier, key, ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::StorageError::DecryptionError) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to decrypt data")?; @@ -4531,13 +4545,15 @@ pub async fn get_card_details_with_locker_fallback( ) -> errors::RouterResult> { let key = key_store.key.get_inner().peek(); let identifier = Identifier::Merchant(key_store.merchant_id.clone()); - let card_decrypted = decrypt_optional::( + let card_decrypted = domain::types::crypto_operation::( &state.into(), - pm.payment_method_data.clone(), + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::DecryptOptional(pm.payment_method_data.clone()), identifier, key, ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::StorageError::DecryptionError) .attach_printable("unable to decrypt card details") .ok() @@ -4567,13 +4583,15 @@ pub async fn get_card_details_without_locker_fallback( ) -> errors::RouterResult { let key = key_store.key.get_inner().peek(); let identifier = Identifier::Merchant(key_store.merchant_id.clone()); - let card_decrypted = decrypt_optional::( + let card_decrypted = domain::types::crypto_operation::( &state.into(), - pm.payment_method_data.clone(), + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::DecryptOptional(pm.payment_method_data.clone()), identifier, key, ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::StorageError::DecryptionError) .attach_printable("unable to decrypt card details") .ok() @@ -4642,26 +4660,29 @@ async fn get_masked_bank_details( ) -> errors::RouterResult> { let key = key_store.key.get_inner().peek(); let identifier = Identifier::Merchant(key_store.merchant_id.clone()); - let payment_method_data = decrypt_optional::( - &state.into(), - pm.payment_method_data.clone(), - identifier, - key, - ) - .await - .change_context(errors::StorageError::DecryptionError) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to decrypt bank details")? - .map(|x| x.into_inner().expose()) - .map( - |v| -> Result> { - v.parse_value::("PaymentMethodsData") - .change_context(errors::StorageError::DeserializationFailed) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to deserialize Payment Method Auth config") - }, - ) - .transpose()?; + let payment_method_data = + domain::types::crypto_operation::( + &state.into(), + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::DecryptOptional(pm.payment_method_data.clone()), + identifier, + key, + ) + .await + .and_then(|val| val.try_into_optionaloperation()) + .change_context(errors::StorageError::DecryptionError) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to decrypt bank details")? + .map(|x| x.into_inner().expose()) + .map( + |v| -> Result> { + v.parse_value::("PaymentMethodsData") + .change_context(errors::StorageError::DeserializationFailed) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to deserialize Payment Method Auth config") + }, + ) + .transpose()?; match payment_method_data { Some(pmd) => match pmd { @@ -4682,26 +4703,29 @@ async fn get_bank_account_connector_details( ) -> errors::RouterResult> { let key = key_store.key.get_inner().peek(); let identifier = Identifier::Merchant(key_store.merchant_id.clone()); - let payment_method_data = decrypt_optional::( - &state.into(), - pm.payment_method_data.clone(), - identifier, - key, - ) - .await - .change_context(errors::StorageError::DecryptionError) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unable to decrypt bank details")? - .map(|x| x.into_inner().expose()) - .map( - |v| -> Result> { - v.parse_value::("PaymentMethodsData") - .change_context(errors::StorageError::DeserializationFailed) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to deserialize Payment Method Auth config") - }, - ) - .transpose()?; + let payment_method_data = + domain::types::crypto_operation::( + &state.into(), + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::DecryptOptional(pm.payment_method_data.clone()), + identifier, + key, + ) + .await + .and_then(|val| val.try_into_optionaloperation()) + .change_context(errors::StorageError::DecryptionError) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unable to decrypt bank details")? + .map(|x| x.into_inner().expose()) + .map( + |v| -> Result> { + v.parse_value::("PaymentMethodsData") + .change_context(errors::StorageError::DeserializationFailed) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to deserialize Payment Method Auth config") + }, + ) + .transpose()?; match payment_method_data { Some(pmd) => match pmd { @@ -5125,11 +5149,17 @@ where let secret_data = Secret::<_, masking::WithType>::new(encoded_data); - let encrypted_data = - domain::types::encrypt(&key_manager_state, secret_data, identifier.clone(), key) - .await - .change_context(errors::StorageError::EncryptionError) - .attach_printable("Unable to encrypt data")?; + let encrypted_data = domain::types::crypto_operation( + &key_manager_state, + type_name!(payment_method::PaymentMethod), + domain::types::CryptoOperation::Encrypt(secret_data), + identifier.clone(), + key, + ) + .await + .and_then(|val| val.try_into_operation()) + .change_context(errors::StorageError::EncryptionError) + .attach_printable("Unable to encrypt data")?; Ok(encrypted_data) } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 6b39ec672e..c3f7b25b0c 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -11,7 +11,7 @@ use common_enums::ConnectorType; use common_utils::{ crypto::Encryptable, ext_traits::{AsyncExt, ByteSliceExt, Encode, ValueExt}, - fp_utils, generate_id, id_type, pii, + fp_utils, generate_id, id_type, pii, type_name, types::{ keymanager::{Identifier, KeyManagerState, ToEncryptable}, MinorUnit, @@ -166,20 +166,24 @@ pub async fn create_or_update_address_for_payment_by_request( Ok(match address_id { Some(id) => match req_address { Some(address) => { - let encrypted_data = types::batch_encrypt( + let encrypted_data = types::crypto_operation( &session_state.into(), - AddressDetailsWithPhone::to_encryptable(AddressDetailsWithPhone { - address: address.address.clone(), - phone_number: address - .phone - .as_ref() - .and_then(|phone| phone.number.clone()), - email: address.email.clone(), - }), + type_name!(domain::Address), + types::CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( + AddressDetailsWithPhone { + address: address.address.clone(), + phone_number: address + .phone + .as_ref() + .and_then(|phone| phone.number.clone()), + email: address.email.clone(), + }, + )), Identifier::Merchant(merchant_key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_batchoperation()) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while encrypting address")?; let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) @@ -353,20 +357,24 @@ pub async fn get_domain_address( ) -> CustomResult { async { let address_details = &address.address.as_ref(); - let encrypted_data = types::batch_encrypt( + let encrypted_data = types::crypto_operation( &session_state.into(), - AddressDetailsWithPhone::to_encryptable(AddressDetailsWithPhone { - address: address_details.cloned(), - phone_number: address - .phone - .as_ref() - .and_then(|phone| phone.number.clone()), - email: address.email.clone(), - }), + type_name!(domain::Address), + types::CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( + AddressDetailsWithPhone { + address: address_details.cloned(), + phone_number: address + .phone + .as_ref() + .and_then(|phone| phone.number.clone()), + email: address.email.clone(), + }, + )), Identifier::Merchant(merchant_id.to_owned()), key, ) - .await?; + .await + .and_then(|val| val.try_into_batchoperation())?; let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) .change_context(common_utils::errors::CryptoError::EncodingFailed)?; Ok(domain::Address { @@ -1645,17 +1653,21 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R>( ) .await?; let key = key_store.key.get_inner().peek(); - let encrypted_data = types::batch_encrypt( + let encrypted_data = types::crypto_operation( key_manager_state, - CustomerRequestWithEmail::to_encryptable(CustomerRequestWithEmail { - name: request_customer_details.name.clone(), - email: request_customer_details.email.clone(), - phone: request_customer_details.phone.clone(), - }), + type_name!(domain::Customer), + types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( + CustomerRequestWithEmail { + name: request_customer_details.name.clone(), + email: request_customer_details.email.clone(), + phone: request_customer_details.phone.clone(), + }, + )), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_batchoperation()) .change_context(errors::StorageError::SerializationFailed) .attach_printable("Failed while encrypting Customer while Update")?; let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) @@ -4186,13 +4198,16 @@ pub async fn get_encrypted_apple_pay_connector_wallets_details( .map(masking::Secret::new); let key_manager_state: KeyManagerState = state.into(); let encrypted_connector_apple_pay_details = connector_apple_pay_details - .async_lift(|wallets_details| { - types::encrypt_optional( + .async_lift(|wallets_details| async { + types::crypto_operation( &key_manager_state, - wallets_details, + type_name!(domain::MerchantConnectorAccount), + types::CryptoOperation::EncryptOptional(wallets_details), Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.get_inner().peek(), ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 108e0dfbdc..10aad010d1 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -9,6 +9,7 @@ use api_models::{ use async_trait::async_trait; use common_utils::{ ext_traits::{AsyncExt, Encode, StringExt, ValueExt}, + type_name, types::keymanager::Identifier, }; use error_stack::{report, ResultExt}; @@ -39,7 +40,10 @@ use crate::{ types::{ self, api::{self, ConnectorCallType, PaymentIdTypeExt}, - domain::{self, types::decrypt_optional}, + domain::{ + self, + types::{crypto_operation, CryptoOperation}, + }, storage::{self, enums as storage_enums}, }, utils::{self, OptionExt}, @@ -1084,13 +1088,15 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let key = key_store.key.get_inner().peek(); let card_detail_from_locker: Option = - decrypt_optional::( + crypto_operation::( key_manager_state, - pm.payment_method_data.clone(), + type_name!(storage::PaymentMethod), + CryptoOperation::DecryptOptional(pm.payment_method_data.clone()), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::StorageError::DecryptionError) .attach_printable("unable to decrypt card details") .ok() diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index fa22a2f5ae..9f5035de79 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -6,6 +6,7 @@ use api_models::{ use async_trait::async_trait; use common_utils::{ ext_traits::{AsyncExt, Encode, ValueExt}, + type_name, types::{keymanager::Identifier, MinorUnit}, }; use diesel_models::{ephemeral_key, PaymentMethod}; @@ -13,7 +14,7 @@ use error_stack::{self, ResultExt}; use hyperswitch_domain_models::{ mandates::{MandateData, MandateDetails}, payments::{payment_attempt::PaymentAttempt, payment_intent::CustomerData}, - type_encryption::decrypt_optional, + type_encryption::{crypto_operation, CryptoOperation}, }; use masking::{ExposeInterface, PeekInterface, Secret}; use router_derive::PaymentOperation; @@ -866,13 +867,15 @@ impl PaymentCreate { additional_pm_data = payment_method_info .as_ref() .async_map(|pm_info| async { - decrypt_optional::( + crypto_operation::( &state.into(), - pm_info.payment_method_data.clone(), + type_name!(PaymentMethod), + CryptoOperation::DecryptOptional(pm_info.payment_method_data.clone()), Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_optionaloperation()) .map_err(|err| logger::error!("Failed to decrypt card details: {:?}", err)) .ok() .flatten() diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index c4010490c2..6b0f202647 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -5,7 +5,7 @@ use common_utils::{ encryption::Encryption, errors::CustomResult, ext_traits::{AsyncExt, StringExt}, - fp_utils, id_type, + fp_utils, id_type, type_name, types::{ keymanager::{Identifier, KeyManagerState}, MinorUnit, @@ -15,7 +15,7 @@ use common_utils::{ use common_utils::{generate_customer_id_of_default_length, types::keymanager::ToEncryptable}; use error_stack::{report, ResultExt}; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use hyperswitch_domain_models::type_encryption::batch_encrypt; +use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation}; use masking::{PeekInterface, Secret}; use router_env::logger; @@ -39,10 +39,7 @@ use crate::{ services, types::{ api::{self, enums as api_enums}, - domain::{ - self, - types::{self as domain_types, AsyncLift}, - }, + domain::{self, types::AsyncLift}, storage, transformers::ForeignFrom, }, @@ -252,13 +249,16 @@ pub async fn save_payout_data_to_locker( let secret: Secret = Secret::new(v.to_string()); secret }) - .async_lift(|inner| { - domain_types::encrypt_optional( + .async_lift(|inner| async { + crypto_operation( &key_manager_state, - inner, + type_name!(storage::PaymentMethod), + CryptoOperation::EncryptOptional(inner), Identifier::Merchant(key_store.merchant_id.clone()), key, ) + .await + .and_then(|val| val.try_into_optionaloperation()) }) .await } @@ -644,17 +644,21 @@ pub async fn get_or_create_customer_details( { Some(customer) => Ok(Some(customer)), None => { - let encrypted_data = batch_encrypt( + let encrypted_data = crypto_operation( &state.into(), - CustomerRequestWithEmail::to_encryptable(CustomerRequestWithEmail { - name: customer_details.name.clone(), - email: customer_details.email.clone(), - phone: customer_details.phone.clone(), - }), + type_name!(domain::Customer), + CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable( + CustomerRequestWithEmail { + name: customer_details.name.clone(), + email: customer_details.email.clone(), + phone: customer_details.phone.clone(), + }, + )), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_batchoperation()) .change_context(errors::ApiErrorResponse::InternalServerError)?; let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data) diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 8d237da5ed..fae690732e 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -14,7 +14,7 @@ use common_utils::{ consts, crypto::{HmacSha256, SignMessage}, ext_traits::AsyncExt, - generate_id, + generate_id, type_name, types::{self as util_types, keymanager::Identifier, AmountConvertor}, }; use error_stack::ResultExt; @@ -45,7 +45,7 @@ use crate::{ services::{pm_auth as pm_auth_services, ApplicationResponse}, types::{ self, - domain::{self, types::decrypt_optional}, + domain::{self, types::crypto_operation}, storage, transformers::ForeignTryFrom, }, @@ -349,13 +349,15 @@ async fn store_bank_details_in_payment_methods( for pm in payment_methods { if pm.payment_method == Some(enums::PaymentMethod::BankDebit) { - let bank_details_pm_data = decrypt_optional::( + let bank_details_pm_data = crypto_operation::( &(&state).into(), - pm.payment_method_data.clone(), + type_name!(storage::PaymentMethod), + domain::types::CryptoOperation::DecryptOptional(pm.payment_method_data.clone()), Identifier::Merchant(key_store.merchant_id.clone()), key, ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(ApiErrorResponse::InternalServerError) .attach_printable("unable to decrypt bank account details")? .map(|x| x.into_inner().expose()) diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index 457a71dff8..042e2c19e7 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -4,7 +4,7 @@ use api_models::{ payments::RedirectionResponse, user::{self as user_api, InviteMultipleUserResponse}, }; -use common_utils::types::keymanager::Identifier; +use common_utils::{type_name, types::keymanager::Identifier}; #[cfg(feature = "email")] use diesel_models::user_role::UserRoleUpdate; use diesel_models::{ @@ -1929,13 +1929,15 @@ pub async fn update_totp( totp_status: None, totp_secret: Some( // TODO: Impl conversion trait for User and move this there - domain::types::encrypt::( + domain::types::crypto_operation::( &(&state).into(), - totp.get_secret_base32().into(), + type_name!(storage_user::User), + domain::types::CryptoOperation::Encrypt(totp.get_secret_base32().into()), Identifier::User(key_store.user_id.clone()), key_store.key.peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(UserErrors::InternalServerError)? .into(), ), diff --git a/crates/router/src/core/webhooks/outgoing.rs b/crates/router/src/core/webhooks/outgoing.rs index 416075050b..25c93f8465 100644 --- a/crates/router/src/core/webhooks/outgoing.rs +++ b/crates/router/src/core/webhooks/outgoing.rs @@ -4,10 +4,12 @@ use api_models::{ webhook_events::{OutgoingWebhookRequestContent, OutgoingWebhookResponseContent}, webhooks, }; -use common_utils::{ext_traits::Encode, request::RequestContent, types::keymanager::Identifier}; +use common_utils::{ + ext_traits::Encode, request::RequestContent, type_name, types::keymanager::Identifier, +}; use diesel_models::process_tracker::business_status; use error_stack::{report, ResultExt}; -use hyperswitch_domain_models::type_encryption::decrypt_optional; +use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation}; use masking::{ExposeInterface, Mask, PeekInterface, Secret}; use router_env::{ instrument, @@ -31,8 +33,7 @@ use crate::{ routes::{app::SessionStateInfo, SessionState}, services, types::{ - api, - domain::{self, types as domain_types}, + api, domain, storage::{self, enums}, transformers::ForeignFrom, }, @@ -113,17 +114,21 @@ pub(crate) async fn create_event_and_trigger_outgoing_webhook( idempotent_event_id: Some(idempotent_event_id.clone()), initial_attempt_id: Some(event_id.clone()), request: Some( - domain_types::encrypt( + crypto_operation( key_manager_state, - request_content - .encode_to_string_of_json() - .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) - .attach_printable("Failed to encode outgoing webhook request content") - .map(Secret::new)?, + type_name!(domain::Event), + CryptoOperation::Encrypt( + request_content + .encode_to_string_of_json() + .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) + .attach_printable("Failed to encode outgoing webhook request content") + .map(Secret::new)?, + ), Identifier::Merchant(merchant_key_store.merchant_id.clone()), merchant_key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::ApiErrorResponse::WebhookProcessingFailure) .attach_printable("Failed to encrypt outgoing webhook request content")?, ), @@ -570,15 +575,19 @@ pub(crate) async fn get_outgoing_webhook_request( let transformed_outgoing_webhook = WebhookType::from(outgoing_webhook); let payment_response_hash_key = business_profile.payment_response_hash_key.clone(); - let custom_headers = decrypt_optional::( + let custom_headers = crypto_operation::( &state.into(), - business_profile - .outgoing_webhook_custom_http_headers - .clone(), + type_name!(domain::Event), + CryptoOperation::DecryptOptional( + business_profile + .outgoing_webhook_custom_http_headers + .clone(), + ), Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::WebhooksFlowError::OutgoingWebhookEncodingFailed) .attach_printable("Failed to decrypt outgoing webhook custom HTTP headers")? .map(|decrypted_value| { @@ -660,18 +669,22 @@ async fn update_event_if_client_error( let event_update = domain::EventUpdate::UpdateResponse { is_webhook_notified, response: Some( - domain_types::encrypt( + crypto_operation( key_manager_state, - response_to_store - .encode_to_string_of_json() - .change_context( - errors::WebhooksFlowError::OutgoingWebhookResponseEncodingFailed, - ) - .map(Secret::new)?, + type_name!(domain::Event), + CryptoOperation::Encrypt( + response_to_store + .encode_to_string_of_json() + .change_context( + errors::WebhooksFlowError::OutgoingWebhookResponseEncodingFailed, + ) + .map(Secret::new)?, + ), Identifier::Merchant(merchant_key_store.merchant_id.clone()), merchant_key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::WebhooksFlowError::WebhookEventUpdationFailed) .attach_printable("Failed to encrypt outgoing webhook response content")?, ), @@ -778,18 +791,22 @@ async fn update_event_in_storage( let event_update = domain::EventUpdate::UpdateResponse { is_webhook_notified, response: Some( - domain_types::encrypt( + crypto_operation( key_manager_state, - response_to_store - .encode_to_string_of_json() - .change_context( - errors::WebhooksFlowError::OutgoingWebhookResponseEncodingFailed, - ) - .map(Secret::new)?, + type_name!(domain::Event), + CryptoOperation::Encrypt( + response_to_store + .encode_to_string_of_json() + .change_context( + errors::WebhooksFlowError::OutgoingWebhookResponseEncodingFailed, + ) + .map(Secret::new)?, + ), Identifier::Merchant(merchant_key_store.merchant_id.clone()), merchant_key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .change_context(errors::WebhooksFlowError::WebhookEventUpdationFailed) .attach_printable("Failed to encrypt outgoing webhook response content")?, ), diff --git a/crates/router/src/db/events.rs b/crates/router/src/db/events.rs index 0cecea9c62..3b0f789cf0 100644 --- a/crates/router/src/db/events.rs +++ b/crates/router/src/db/events.rs @@ -770,7 +770,7 @@ impl EventInterface for MockDb { mod tests { use std::sync::Arc; - use common_utils::types::keymanager::Identifier; + use common_utils::{type_name, types::keymanager::Identifier}; use diesel_models::{enums, events::EventMetadata}; use time::macros::datetime; @@ -818,13 +818,17 @@ mod tests { key_manager_state, domain::MerchantKeyStore { merchant_id: merchant_id.clone(), - key: domain::types::encrypt( + key: domain::types::crypto_operation( key_manager_state, - services::generate_aes256_key().unwrap().to_vec().into(), + type_name!(domain::MerchantKeyStore), + domain::types::CryptoOperation::Encrypt( + services::generate_aes256_key().unwrap().to_vec().into(), + ), Identifier::Merchant(merchant_id.to_owned()), master_key, ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), created_at: datetime!(2023-02-01 0:00), }, diff --git a/crates/router/src/db/merchant_connector_account.rs b/crates/router/src/db/merchant_connector_account.rs index 34ee502ebd..d628ad0f25 100644 --- a/crates/router/src/db/merchant_connector_account.rs +++ b/crates/router/src/db/merchant_connector_account.rs @@ -1420,7 +1420,7 @@ mod merchant_connector_account_cache_tests { not(feature = "merchant_connector_account_v2") ))] use api_models::enums::CountryAlpha2; - use common_utils::{date_time, types::keymanager::Identifier}; + use common_utils::{date_time, type_name, types::keymanager::Identifier}; use diesel_models::enums::ConnectorType; use error_stack::ResultExt; use masking::PeekInterface; @@ -1493,13 +1493,17 @@ mod merchant_connector_account_cache_tests { key_manager_state, domain::MerchantKeyStore { merchant_id: merchant_id.clone(), - key: domain::types::encrypt( + key: domain::types::crypto_operation( key_manager_state, - services::generate_aes256_key().unwrap().to_vec().into(), + type_name!(domain::MerchantKeyStore), + domain::types::CryptoOperation::Encrypt( + services::generate_aes256_key().unwrap().to_vec().into(), + ), Identifier::Merchant(merchant_id.clone()), master_key, ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), created_at: datetime!(2023-02-01 0:00), }, @@ -1520,13 +1524,15 @@ mod merchant_connector_account_cache_tests { let mca = domain::MerchantConnectorAccount { merchant_id: merchant_id.to_owned(), connector_name: "stripe".to_string(), - connector_account_details: domain::types::encrypt( + connector_account_details: domain::types::crypto_operation( key_manager_state, - serde_json::Value::default().into(), + type_name!(domain::MerchantConnectorAccount), + domain::types::CryptoOperation::Encrypt(serde_json::Value::default().into()), Identifier::Merchant(merchant_key.merchant_id.clone()), merchant_key.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), test_mode: None, disabled: None, @@ -1547,13 +1553,15 @@ mod merchant_connector_account_cache_tests { pm_auth_config: None, status: common_enums::ConnectorStatus::Inactive, connector_wallets_details: Some( - domain::types::encrypt( + domain::types::crypto_operation( key_manager_state, - serde_json::Value::default().into(), + type_name!(domain::MerchantConnectorAccount), + domain::types::CryptoOperation::Encrypt(serde_json::Value::default().into()), Identifier::Merchant(merchant_key.merchant_id.clone()), merchant_key.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), ), additional_merchant_data: None, @@ -1653,13 +1661,17 @@ mod merchant_connector_account_cache_tests { key_manager_state, domain::MerchantKeyStore { merchant_id: merchant_id.clone(), - key: domain::types::encrypt( + key: domain::types::crypto_operation( key_manager_state, - services::generate_aes256_key().unwrap().to_vec().into(), + type_name!(domain::MerchantConnectorAccount), + domain::types::CryptoOperation::Encrypt( + services::generate_aes256_key().unwrap().to_vec().into(), + ), Identifier::Merchant(merchant_id.clone()), master_key, ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), created_at: datetime!(2023-02-01 0:00), }, @@ -1681,13 +1693,15 @@ mod merchant_connector_account_cache_tests { id: id.to_string(), merchant_id: merchant_id.clone(), connector_name: "stripe".to_string(), - connector_account_details: domain::types::encrypt( + connector_account_details: domain::types::crypto_operation( key_manager_state, - serde_json::Value::default().into(), + type_name!(domain::MerchantConnectorAccount), + domain::types::CryptoOperation::Encrypt(serde_json::Value::default().into()), Identifier::Merchant(merchant_key.merchant_id.clone()), merchant_key.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), disabled: None, payment_methods_enabled: None, @@ -1703,13 +1717,15 @@ mod merchant_connector_account_cache_tests { pm_auth_config: None, status: common_enums::ConnectorStatus::Inactive, connector_wallets_details: Some( - domain::types::encrypt( + domain::types::crypto_operation( key_manager_state, - serde_json::Value::default().into(), + type_name!(domain::MerchantConnectorAccount), + domain::types::CryptoOperation::Encrypt(serde_json::Value::default().into()), Identifier::Merchant(merchant_key.merchant_id.clone()), merchant_key.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), ), additional_merchant_data: None, diff --git a/crates/router/src/db/merchant_key_store.rs b/crates/router/src/db/merchant_key_store.rs index 1fe24999b6..65a5515a39 100644 --- a/crates/router/src/db/merchant_key_store.rs +++ b/crates/router/src/db/merchant_key_store.rs @@ -321,7 +321,7 @@ impl MerchantKeyStoreInterface for MockDb { mod tests { use std::{borrow::Cow, sync::Arc}; - use common_utils::types::keymanager::Identifier; + use common_utils::{type_name, types::keymanager::Identifier}; use time::macros::datetime; use tokio::sync::oneshot; @@ -364,13 +364,17 @@ mod tests { key_manager_state, domain::MerchantKeyStore { merchant_id: merchant_id.clone(), - key: domain::types::encrypt( + key: domain::types::crypto_operation( key_manager_state, - services::generate_aes256_key().unwrap().to_vec().into(), + type_name!(domain::MerchantKeyStore), + domain::types::CryptoOperation::Encrypt( + services::generate_aes256_key().unwrap().to_vec().into(), + ), identifier.clone(), master_key, ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), created_at: datetime!(2023-02-01 0:00), }, @@ -396,13 +400,17 @@ mod tests { key_manager_state, domain::MerchantKeyStore { merchant_id: merchant_id.clone(), - key: domain::types::encrypt( + key: domain::types::crypto_operation( key_manager_state, - services::generate_aes256_key().unwrap().to_vec().into(), + type_name!(domain::MerchantKeyStore), + domain::types::CryptoOperation::Encrypt( + services::generate_aes256_key().unwrap().to_vec().into(), + ), identifier.clone(), master_key, ) .await + .and_then(|val| val.try_into_operation()) .unwrap(), created_at: datetime!(2023-02-01 0:00), }, diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index e7127e5d53..c899c54b79 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -11,11 +11,12 @@ pub use api_models::{ }, organization::{OrganizationId, OrganizationRequest, OrganizationResponse}, }; -use common_utils::{ext_traits::ValueExt, types::keymanager::Identifier}; +use common_utils::{ext_traits::ValueExt, type_name, types::keymanager::Identifier}; use diesel_models::organization::OrganizationBridge; use error_stack::ResultExt; use hyperswitch_domain_models::{ - merchant_key_store::MerchantKeyStore, type_encryption::decrypt_optional, + merchant_key_store::MerchantKeyStore, + type_encryption::{crypto_operation, CryptoOperation}, }; use masking::{ExposeInterface, PeekInterface}; @@ -118,13 +119,15 @@ pub async fn business_profile_response( key_store: &MerchantKeyStore, ) -> Result> { let outgoing_webhook_custom_http_headers = - decrypt_optional::( + crypto_operation::( &state.into(), - item.outgoing_webhook_custom_http_headers.clone(), + type_name!(storage::business_profile::BusinessProfile), + CryptoOperation::DecryptOptional(item.outgoing_webhook_custom_http_headers.clone()), Identifier::Merchant(key_store.merchant_id.clone()), key_store.key.get_inner().peek(), ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(errors::ParsingError::StructParseFailure( "Outgoing webhook custom HTTP headers", )) diff --git a/crates/router/src/types/domain/address.rs b/crates/router/src/types/domain/address.rs index 55d83679db..680e26e1f6 100644 --- a/crates/router/src/types/domain/address.rs +++ b/crates/router/src/types/domain/address.rs @@ -4,7 +4,7 @@ use common_utils::{ date_time, encryption::Encryption, errors::{CustomResult, ValidationError}, - id_type, + id_type, type_name, types::keymanager::{Identifier, KeyManagerState, ToEncryptable}, }; use diesel_models::{address::AddressUpdateInternal, enums}; @@ -188,13 +188,17 @@ impl behaviour::Conversion for Address { _key_manager_identifier: Identifier, ) -> CustomResult { let identifier = Identifier::Merchant(other.merchant_id.clone()); - let decrypted: FxHashMap>> = types::batch_decrypt( + let decrypted: FxHashMap>> = types::crypto_operation( state, - diesel_models::Address::to_encryptable(other.clone()), + type_name!(Self::DstType), + types::CryptoOperation::BatchDecrypt(diesel_models::Address::to_encryptable( + other.clone(), + )), identifier.clone(), key.peek(), ) .await + .and_then(|val| val.try_into_batchoperation()) .change_context(ValidationError::InvalidValue { message: "Failed while decrypting".to_string(), })?; diff --git a/crates/router/src/types/domain/event.rs b/crates/router/src/types/domain/event.rs index 67183a2d3a..872eb30390 100644 --- a/crates/router/src/types/domain/event.rs +++ b/crates/router/src/types/domain/event.rs @@ -1,5 +1,6 @@ use common_utils::{ crypto::OptionalEncryptableSecretString, + type_name, types::keymanager::{KeyManagerState, ToEncryptable}, }; use diesel_models::{ @@ -92,16 +93,20 @@ impl super::behaviour::Conversion for Event { where Self: Sized, { - let decrypted = types::batch_decrypt( + let decrypted = types::crypto_operation( state, - EventWithEncryption::to_encryptable(EventWithEncryption { - request: item.request.clone(), - response: item.response.clone(), - }), + type_name!(Self::DstType), + types::CryptoOperation::BatchDecrypt(EventWithEncryption::to_encryptable( + EventWithEncryption { + request: item.request.clone(), + response: item.response.clone(), + }, + )), key_manager_identifier, key.peek(), ) .await + .and_then(|val| val.try_into_batchoperation()) .change_context(ValidationError::InvalidValue { message: "Failed while decrypting event data".to_string(), })?; diff --git a/crates/router/src/types/domain/types.rs b/crates/router/src/types/domain/types.rs index e105b2eba0..10657adc12 100644 --- a/crates/router/src/types/domain/types.rs +++ b/crates/router/src/types/domain/types.rs @@ -1,7 +1,6 @@ use common_utils::types::keymanager::KeyManagerState; pub use hyperswitch_domain_models::type_encryption::{ - batch_decrypt, batch_encrypt, decrypt, decrypt_optional, encrypt, encrypt_optional, AsyncLift, - Lift, + crypto_operation, AsyncLift, CryptoOperation, Lift, }; impl From<&crate::SessionState> for KeyManagerState { diff --git a/crates/router/src/types/domain/user.rs b/crates/router/src/types/domain/user.rs index 41fbc96f6d..3df0a11af0 100644 --- a/crates/router/src/types/domain/user.rs +++ b/crates/router/src/types/domain/user.rs @@ -5,7 +5,7 @@ use api_models::{ }; use common_enums::TokenPurpose; use common_utils::{ - crypto::Encryptable, errors::CustomResult, id_type, new_type::MerchantName, pii, + crypto::Encryptable, errors::CustomResult, id_type, new_type::MerchantName, pii, type_name, types::keymanager::Identifier, }; use diesel_models::{ @@ -1001,13 +1001,15 @@ impl UserFromStorage { let key_store = UserKeyStore { user_id: self.get_user_id().to_string(), - key: domain_types::encrypt( + key: domain_types::crypto_operation( key_manager_state, - key.to_vec().into(), + type_name!(UserKeyStore), + domain_types::CryptoOperation::Encrypt(key.to_vec().into()), Identifier::User(self.get_user_id().to_string()), master_key, ) .await + .and_then(|val| val.try_into_operation()) .change_context(UserErrors::InternalServerError)?, created_at: common_utils::date_time::now(), }; @@ -1051,13 +1053,15 @@ impl UserFromStorage { .await .change_context(UserErrors::InternalServerError)?; - Ok(domain_types::decrypt_optional::( + Ok(domain_types::crypto_operation::( key_manager_state, - self.0.totp_secret.clone(), + type_name!(storage_user::User), + domain_types::CryptoOperation::DecryptOptional(self.0.totp_secret.clone()), Identifier::User(user_key_store.user_id.clone()), user_key_store.key.peek(), ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(UserErrors::InternalServerError)? .map(Encryptable::into_inner)) } diff --git a/crates/router/src/types/domain/user_key_store.rs b/crates/router/src/types/domain/user_key_store.rs index b0b57732cc..696fab7eef 100644 --- a/crates/router/src/types/domain/user_key_store.rs +++ b/crates/router/src/types/domain/user_key_store.rs @@ -1,10 +1,10 @@ use common_utils::{ crypto::Encryptable, - date_time, + date_time, type_name, types::keymanager::{Identifier, KeyManagerState}, }; use error_stack::ResultExt; -use hyperswitch_domain_models::type_encryption::decrypt; +use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation}; use masking::{PeekInterface, Secret}; use time::PrimitiveDateTime; @@ -41,11 +41,18 @@ impl super::behaviour::Conversion for UserKeyStore { { let identifier = Identifier::User(item.user_id.clone()); Ok(Self { - key: decrypt(state, item.key, identifier, key.peek()) - .await - .change_context(ValidationError::InvalidValue { - message: "Failed while decrypting customer data".to_string(), - })?, + key: crypto_operation( + state, + type_name!(Self::DstType), + CryptoOperation::Decrypt(item.key), + identifier, + key.peek(), + ) + .await + .and_then(|val| val.try_into_operation()) + .change_context(ValidationError::InvalidValue { + message: "Failed while decrypting customer data".to_string(), + })?, user_id: item.user_id, created_at: item.created_at, }) diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index 5b46dce139..44396de7ac 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -22,8 +22,6 @@ use api_models::{ }; use base64::Engine; use common_utils::types::keymanager::KeyManagerState; -#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use common_utils::types::keymanager::{Identifier, ToEncryptable}; pub use common_utils::{ crypto, ext_traits::{ByteSliceExt, BytesExt, Encode, StringExt, ValueExt}, @@ -31,10 +29,15 @@ pub use common_utils::{ id_type, validation::validate_email, }; +#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] +use common_utils::{ + type_name, + types::keymanager::{Identifier, ToEncryptable}, +}; use error_stack::ResultExt; use hyperswitch_domain_models::payments::PaymentIntent; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use hyperswitch_domain_models::type_encryption::batch_encrypt; +use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation}; use image::Luma; use nanoid::nanoid; use qrcode; @@ -794,17 +797,21 @@ impl CustomerAddress for api_models::customers::CustomerRequest { storage_scheme: storage::enums::MerchantStorageScheme, merchant_id: id_type::MerchantId, ) -> CustomResult { - let encrypted_data = batch_encrypt( + let encrypted_data = crypto_operation( &state.into(), - AddressDetailsWithPhone::to_encryptable(AddressDetailsWithPhone { - address: Some(address_details.clone()), - phone_number: self.phone.clone(), - email: self.email.clone(), - }), + type_name!(storage::Address), + CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( + AddressDetailsWithPhone { + address: Some(address_details.clone()), + phone_number: self.phone.clone(), + email: self.email.clone(), + }, + )), Identifier::Merchant(merchant_id), key, ) - .await?; + .await + .and_then(|val| val.try_into_batchoperation())?; let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) .change_context(common_utils::errors::CryptoError::EncodingFailed)?; Ok(storage::AddressUpdate::Update { @@ -833,17 +840,21 @@ impl CustomerAddress for api_models::customers::CustomerRequest { key: &[u8], storage_scheme: storage::enums::MerchantStorageScheme, ) -> CustomResult { - let encrypted_data = batch_encrypt( + let encrypted_data = crypto_operation( &state.into(), - AddressDetailsWithPhone::to_encryptable(AddressDetailsWithPhone { - address: Some(address_details.clone()), - phone_number: self.phone.clone(), - email: self.email.clone(), - }), + type_name!(storage::Address), + CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable( + AddressDetailsWithPhone { + address: Some(address_details.clone()), + phone_number: self.phone.clone(), + email: self.email.clone(), + }, + )), Identifier::Merchant(merchant_id.to_owned()), key, ) - .await?; + .await + .and_then(|val| val.try_into_batchoperation())?; let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data) .change_context(common_utils::errors::CryptoError::EncodingFailed)?; let address = domain::Address { diff --git a/crates/router/src/utils/user.rs b/crates/router/src/utils/user.rs index 2dad55c4b8..1de45b7436 100644 --- a/crates/router/src/utils/user.rs +++ b/crates/router/src/utils/user.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, sync::Arc}; use api_models::user as user_api; use common_enums::UserAuthType; use common_utils::{ - encryption::Encryption, errors::CustomResult, id_type, types::keymanager::Identifier, + encryption::Encryption, errors::CustomResult, id_type, type_name, types::keymanager::Identifier, }; use diesel_models::{enums::UserStatus, user_role::UserRole}; use error_stack::{report, ResultExt}; @@ -260,15 +260,18 @@ pub async fn construct_public_and_private_db_configs( .change_context(UserErrors::InternalServerError) .attach_printable("Failed to convert auth config to json")?; - let encrypted_config = domain::types::encrypt::( - &state.into(), - private_config_value.into(), - Identifier::UserAuth(id), - encryption_key, - ) - .await - .change_context(UserErrors::InternalServerError) - .attach_printable("Failed to encrypt auth config")?; + let encrypted_config = + domain::types::crypto_operation::( + &state.into(), + type_name!(diesel_models::user::User), + domain::types::CryptoOperation::Encrypt(private_config_value.into()), + Identifier::UserAuth(id), + encryption_key, + ) + .await + .and_then(|val| val.try_into_operation()) + .change_context(UserErrors::InternalServerError) + .attach_printable("Failed to encrypt auth config")?; Ok(( Some(encrypted_config.into()), @@ -309,13 +312,15 @@ pub async fn decrypt_oidc_private_config( .change_context(UserErrors::InternalServerError) .attach_printable("Failed to decode DEK")?; - let private_config = domain::types::decrypt_optional::( + let private_config = domain::types::crypto_operation::( &state.into(), - encrypted_config, + type_name!(diesel_models::user::User), + domain::types::CryptoOperation::DecryptOptional(encrypted_config), Identifier::UserAuth(id), &user_auth_key, ) .await + .and_then(|val| val.try_into_optionaloperation()) .change_context(UserErrors::InternalServerError) .attach_printable("Failed to decrypt private config")? .ok_or(UserErrors::InternalServerError)