mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-10-30 09:38:33 +08:00 
			
		
		
		
	fix: batch encrypt/decrypt on merchant connector account (#6206)
This commit is contained in:
		| @ -4,14 +4,15 @@ use common_utils::{ | |||||||
|     encryption::Encryption, |     encryption::Encryption, | ||||||
|     errors::{CustomResult, ValidationError}, |     errors::{CustomResult, ValidationError}, | ||||||
|     id_type, pii, type_name, |     id_type, pii, type_name, | ||||||
|     types::keymanager::{Identifier, KeyManagerState}, |     types::keymanager::{Identifier, KeyManagerState, ToEncryptable}, | ||||||
| }; | }; | ||||||
| use diesel_models::{enums, merchant_connector_account::MerchantConnectorAccountUpdateInternal}; | use diesel_models::{enums, merchant_connector_account::MerchantConnectorAccountUpdateInternal}; | ||||||
| use error_stack::ResultExt; | use error_stack::ResultExt; | ||||||
| use masking::{PeekInterface, Secret}; | use masking::{PeekInterface, Secret}; | ||||||
|  | use rustc_hash::FxHashMap; | ||||||
|  |  | ||||||
| use super::behaviour; | use super::behaviour; | ||||||
| use crate::type_encryption::{crypto_operation, AsyncLift, CryptoOperation}; | use crate::type_encryption::{crypto_operation, CryptoOperation}; | ||||||
|  |  | ||||||
| #[cfg(feature = "v1")] | #[cfg(feature = "v1")] | ||||||
| #[derive(Clone, Debug)] | #[derive(Clone, Debug)] | ||||||
| @ -175,21 +176,33 @@ impl behaviour::Conversion for MerchantConnectorAccount { | |||||||
|         _key_manager_identifier: Identifier, |         _key_manager_identifier: Identifier, | ||||||
|     ) -> CustomResult<Self, ValidationError> { |     ) -> CustomResult<Self, ValidationError> { | ||||||
|         let identifier = Identifier::Merchant(other.merchant_id.clone()); |         let identifier = Identifier::Merchant(other.merchant_id.clone()); | ||||||
|         Ok(Self { |         let decrypted_data = crypto_operation( | ||||||
|             merchant_id: other.merchant_id, |  | ||||||
|             connector_name: other.connector_name, |  | ||||||
|             connector_account_details: crypto_operation( |  | ||||||
|             state, |             state, | ||||||
|             type_name!(Self::DstType), |             type_name!(Self::DstType), | ||||||
|                 CryptoOperation::Decrypt(other.connector_account_details), |             CryptoOperation::BatchDecrypt(EncryptedMca::to_encryptable(EncryptedMca { | ||||||
|  |                 connector_account_details: other.connector_account_details, | ||||||
|  |                 additional_merchant_data: other.additional_merchant_data, | ||||||
|  |                 connector_wallets_details: other.connector_wallets_details, | ||||||
|  |             })), | ||||||
|             identifier.clone(), |             identifier.clone(), | ||||||
|             key.peek(), |             key.peek(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|             .and_then(|val| val.try_into_operation()) |         .and_then(|val| val.try_into_batchoperation()) | ||||||
|         .change_context(ValidationError::InvalidValue { |         .change_context(ValidationError::InvalidValue { | ||||||
|             message: "Failed while decrypting connector account details".to_string(), |             message: "Failed while decrypting connector account details".to_string(), | ||||||
|             })?, |         })?; | ||||||
|  |  | ||||||
|  |         let decrypted_data = EncryptedMca::from_encryptable(decrypted_data).change_context( | ||||||
|  |             ValidationError::InvalidValue { | ||||||
|  |                 message: "Failed while decrypting connector account details".to_string(), | ||||||
|  |             }, | ||||||
|  |         )?; | ||||||
|  |  | ||||||
|  |         Ok(Self { | ||||||
|  |             merchant_id: other.merchant_id, | ||||||
|  |             connector_name: other.connector_name, | ||||||
|  |             connector_account_details: decrypted_data.connector_account_details, | ||||||
|             test_mode: other.test_mode, |             test_mode: other.test_mode, | ||||||
|             disabled: other.disabled, |             disabled: other.disabled, | ||||||
|             merchant_connector_id: other.merchant_connector_id, |             merchant_connector_id: other.merchant_connector_id, | ||||||
| @ -213,41 +226,8 @@ impl behaviour::Conversion for MerchantConnectorAccount { | |||||||
|             applepay_verified_domains: other.applepay_verified_domains, |             applepay_verified_domains: other.applepay_verified_domains, | ||||||
|             pm_auth_config: other.pm_auth_config, |             pm_auth_config: other.pm_auth_config, | ||||||
|             status: other.status, |             status: other.status, | ||||||
|             connector_wallets_details: other |             connector_wallets_details: decrypted_data.connector_wallets_details, | ||||||
|                 .connector_wallets_details |             additional_merchant_data: decrypted_data.additional_merchant_data, | ||||||
|                 .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( |  | ||||||
|                     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 |  | ||||||
|             }, |  | ||||||
|             version: other.version, |             version: other.version, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| @ -324,22 +304,35 @@ impl behaviour::Conversion for MerchantConnectorAccount { | |||||||
|         _key_manager_identifier: Identifier, |         _key_manager_identifier: Identifier, | ||||||
|     ) -> CustomResult<Self, ValidationError> { |     ) -> CustomResult<Self, ValidationError> { | ||||||
|         let identifier = Identifier::Merchant(other.merchant_id.clone()); |         let identifier = Identifier::Merchant(other.merchant_id.clone()); | ||||||
|         Ok(Self { |  | ||||||
|             id: other.id, |         let decrypted_data = crypto_operation( | ||||||
|             merchant_id: other.merchant_id, |  | ||||||
|             connector_name: other.connector_name, |  | ||||||
|             connector_account_details: crypto_operation( |  | ||||||
|             state, |             state, | ||||||
|             type_name!(Self::DstType), |             type_name!(Self::DstType), | ||||||
|                 CryptoOperation::Decrypt(other.connector_account_details), |             CryptoOperation::BatchDecrypt(EncryptedMca::to_encryptable(EncryptedMca { | ||||||
|  |                 connector_account_details: other.connector_account_details, | ||||||
|  |                 additional_merchant_data: other.additional_merchant_data, | ||||||
|  |                 connector_wallets_details: other.connector_wallets_details, | ||||||
|  |             })), | ||||||
|             identifier.clone(), |             identifier.clone(), | ||||||
|             key.peek(), |             key.peek(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|             .and_then(|val| val.try_into_operation()) |         .and_then(|val| val.try_into_batchoperation()) | ||||||
|         .change_context(ValidationError::InvalidValue { |         .change_context(ValidationError::InvalidValue { | ||||||
|             message: "Failed while decrypting connector account details".to_string(), |             message: "Failed while decrypting connector account details".to_string(), | ||||||
|             })?, |         })?; | ||||||
|  |  | ||||||
|  |         let decrypted_data = EncryptedMca::from_encryptable(decrypted_data).change_context( | ||||||
|  |             ValidationError::InvalidValue { | ||||||
|  |                 message: "Failed while decrypting connector account details".to_string(), | ||||||
|  |             }, | ||||||
|  |         )?; | ||||||
|  |  | ||||||
|  |         Ok(Self { | ||||||
|  |             id: other.id, | ||||||
|  |             merchant_id: other.merchant_id, | ||||||
|  |             connector_name: other.connector_name, | ||||||
|  |             connector_account_details: decrypted_data.connector_account_details, | ||||||
|             disabled: other.disabled, |             disabled: other.disabled, | ||||||
|             payment_methods_enabled: other.payment_methods_enabled, |             payment_methods_enabled: other.payment_methods_enabled, | ||||||
|             connector_type: other.connector_type, |             connector_type: other.connector_type, | ||||||
| @ -354,41 +347,8 @@ impl behaviour::Conversion for MerchantConnectorAccount { | |||||||
|             applepay_verified_domains: other.applepay_verified_domains, |             applepay_verified_domains: other.applepay_verified_domains, | ||||||
|             pm_auth_config: other.pm_auth_config, |             pm_auth_config: other.pm_auth_config, | ||||||
|             status: other.status, |             status: other.status, | ||||||
|             connector_wallets_details: other |             connector_wallets_details: decrypted_data.connector_wallets_details, | ||||||
|                 .connector_wallets_details |             additional_merchant_data: decrypted_data.additional_merchant_data, | ||||||
|                 .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( |  | ||||||
|                     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 |  | ||||||
|             }, |  | ||||||
|             version: other.version, |             version: other.version, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| @ -542,3 +502,121 @@ impl From<MerchantConnectorAccountUpdate> for MerchantConnectorAccountUpdateInte | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub struct McaFromRequestfromUpdate { | ||||||
|  |     pub connector_account_details: Option<pii::SecretSerdeValue>, | ||||||
|  |     pub connector_wallets_details: Option<pii::SecretSerdeValue>, | ||||||
|  |     pub additional_merchant_data: Option<pii::SecretSerdeValue>, | ||||||
|  | } | ||||||
|  | pub struct McaFromRequest { | ||||||
|  |     pub connector_account_details: pii::SecretSerdeValue, | ||||||
|  |     pub connector_wallets_details: Option<pii::SecretSerdeValue>, | ||||||
|  |     pub additional_merchant_data: Option<pii::SecretSerdeValue>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct DecryptedMca { | ||||||
|  |     pub connector_account_details: Encryptable<pii::SecretSerdeValue>, | ||||||
|  |     pub connector_wallets_details: Option<Encryptable<pii::SecretSerdeValue>>, | ||||||
|  |     pub additional_merchant_data: Option<Encryptable<pii::SecretSerdeValue>>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct EncryptedMca { | ||||||
|  |     pub connector_account_details: Encryption, | ||||||
|  |     pub connector_wallets_details: Option<Encryption>, | ||||||
|  |     pub additional_merchant_data: Option<Encryption>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub struct DecryptedUpdateMca { | ||||||
|  |     pub connector_account_details: Option<Encryptable<pii::SecretSerdeValue>>, | ||||||
|  |     pub connector_wallets_details: Option<Encryptable<pii::SecretSerdeValue>>, | ||||||
|  |     pub additional_merchant_data: Option<Encryptable<pii::SecretSerdeValue>>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl ToEncryptable<DecryptedMca, Secret<serde_json::Value>, Encryption> for EncryptedMca { | ||||||
|  |     fn from_encryptable( | ||||||
|  |         mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>, | ||||||
|  |     ) -> CustomResult<DecryptedMca, common_utils::errors::ParsingError> { | ||||||
|  |         Ok(DecryptedMca { | ||||||
|  |             connector_account_details: hashmap.remove("connector_account_details").ok_or( | ||||||
|  |                 error_stack::report!(common_utils::errors::ParsingError::EncodeError( | ||||||
|  |                     "Unable to convert from HashMap to DecryptedMca", | ||||||
|  |                 )), | ||||||
|  |             )?, | ||||||
|  |             connector_wallets_details: hashmap.remove("connector_wallets_details"), | ||||||
|  |             additional_merchant_data: hashmap.remove("additional_merchant_data"), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn to_encryptable(self) -> FxHashMap<String, Encryption> { | ||||||
|  |         let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); | ||||||
|  |  | ||||||
|  |         map.insert( | ||||||
|  |             "connector_account_details".to_string(), | ||||||
|  |             self.connector_account_details, | ||||||
|  |         ); | ||||||
|  |         self.connector_wallets_details | ||||||
|  |             .map(|s| map.insert("connector_wallets_details".to_string(), s)); | ||||||
|  |         self.additional_merchant_data | ||||||
|  |             .map(|s| map.insert("additional_merchant_data".to_string(), s)); | ||||||
|  |         map | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl ToEncryptable<DecryptedUpdateMca, Secret<serde_json::Value>, Secret<serde_json::Value>> | ||||||
|  |     for McaFromRequestfromUpdate | ||||||
|  | { | ||||||
|  |     fn from_encryptable( | ||||||
|  |         mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>, | ||||||
|  |     ) -> CustomResult<DecryptedUpdateMca, common_utils::errors::ParsingError> { | ||||||
|  |         Ok(DecryptedUpdateMca { | ||||||
|  |             connector_account_details: hashmap.remove("connector_account_details"), | ||||||
|  |             connector_wallets_details: hashmap.remove("connector_wallets_details"), | ||||||
|  |             additional_merchant_data: hashmap.remove("additional_merchant_data"), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn to_encryptable(self) -> FxHashMap<String, Secret<serde_json::Value>> { | ||||||
|  |         let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); | ||||||
|  |  | ||||||
|  |         self.connector_account_details | ||||||
|  |             .map(|cad| map.insert("connector_account_details".to_string(), cad)); | ||||||
|  |  | ||||||
|  |         self.connector_wallets_details | ||||||
|  |             .map(|s| map.insert("connector_wallets_details".to_string(), s)); | ||||||
|  |         self.additional_merchant_data | ||||||
|  |             .map(|s| map.insert("additional_merchant_data".to_string(), s)); | ||||||
|  |         map | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl ToEncryptable<DecryptedMca, Secret<serde_json::Value>, Secret<serde_json::Value>> | ||||||
|  |     for McaFromRequest | ||||||
|  | { | ||||||
|  |     fn from_encryptable( | ||||||
|  |         mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>, | ||||||
|  |     ) -> CustomResult<DecryptedMca, common_utils::errors::ParsingError> { | ||||||
|  |         Ok(DecryptedMca { | ||||||
|  |             connector_account_details: hashmap.remove("connector_account_details").ok_or( | ||||||
|  |                 error_stack::report!(common_utils::errors::ParsingError::EncodeError( | ||||||
|  |                     "Unable to convert from HashMap to DecryptedMca", | ||||||
|  |                 )), | ||||||
|  |             )?, | ||||||
|  |             connector_wallets_details: hashmap.remove("connector_wallets_details"), | ||||||
|  |             additional_merchant_data: hashmap.remove("additional_merchant_data"), | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn to_encryptable(self) -> FxHashMap<String, Secret<serde_json::Value>> { | ||||||
|  |         let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default()); | ||||||
|  |  | ||||||
|  |         map.insert( | ||||||
|  |             "connector_account_details".to_string(), | ||||||
|  |             self.connector_account_details, | ||||||
|  |         ); | ||||||
|  |         self.connector_wallets_details | ||||||
|  |             .map(|s| map.insert("connector_wallets_details".to_string(), s)); | ||||||
|  |         self.additional_merchant_data | ||||||
|  |             .map(|s| map.insert("additional_merchant_data".to_string(), s)); | ||||||
|  |         map | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -8,12 +8,15 @@ use common_utils::{ | |||||||
|     date_time, |     date_time, | ||||||
|     ext_traits::{AsyncExt, Encode, OptionExt, ValueExt}, |     ext_traits::{AsyncExt, Encode, OptionExt, ValueExt}, | ||||||
|     id_type, pii, type_name, |     id_type, pii, type_name, | ||||||
|     types::keymanager::{self as km_types, KeyManagerState}, |     types::keymanager::{self as km_types, KeyManagerState, ToEncryptable}, | ||||||
| }; | }; | ||||||
| use diesel_models::configs; | use diesel_models::configs; | ||||||
| #[cfg(all(any(feature = "v1", feature = "v2"), feature = "olap"))] | #[cfg(all(any(feature = "v1", feature = "v2"), feature = "olap"))] | ||||||
| use diesel_models::organization::OrganizationBridge; | use diesel_models::organization::OrganizationBridge; | ||||||
| use error_stack::{report, FutureExt, ResultExt}; | use error_stack::{report, FutureExt, ResultExt}; | ||||||
|  | use hyperswitch_domain_models::merchant_connector_account::{ | ||||||
|  |     McaFromRequest, McaFromRequestfromUpdate, | ||||||
|  | }; | ||||||
| use masking::{ExposeInterface, PeekInterface, Secret}; | use masking::{ExposeInterface, PeekInterface, Secret}; | ||||||
| use pm_auth::{connector::plaid::transformers::PlaidAuthType, types as pm_auth_types}; | use pm_auth::{connector::plaid::transformers::PlaidAuthType, types as pm_auth_types}; | ||||||
| use regex::Regex; | use regex::Regex; | ||||||
| @ -2089,25 +2092,37 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect | |||||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|         .attach_printable("Failed to serialize MerchantRecipientData")?; |         .attach_printable("Failed to serialize MerchantRecipientData")?; | ||||||
|  |  | ||||||
|  |         let encrypted_data = domain_types::crypto_operation( | ||||||
|  |             key_manager_state, | ||||||
|  |             type_name!(domain::MerchantConnectorAccount), | ||||||
|  |             domain_types::CryptoOperation::BatchEncrypt(McaFromRequestfromUpdate::to_encryptable( | ||||||
|  |                 McaFromRequestfromUpdate { | ||||||
|  |                     connector_account_details: self.connector_account_details, | ||||||
|  |                     connector_wallets_details: | ||||||
|  |                         helpers::get_connector_wallets_details_with_apple_pay_certificates( | ||||||
|  |                             &self.metadata, | ||||||
|  |                             &self.connector_wallets_details, | ||||||
|  |                         ) | ||||||
|  |                         .await?, | ||||||
|  |                     additional_merchant_data: merchant_recipient_data.map(Secret::new), | ||||||
|  |                 }, | ||||||
|  |             )), | ||||||
|  |             km_types::Identifier::Merchant(key_store.merchant_id.clone()), | ||||||
|  |             key_store.key.peek(), | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|  |         .and_then(|val| val.try_into_batchoperation()) | ||||||
|  |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |         .attach_printable("Failed while decrypting connector account details".to_string())?; | ||||||
|  |  | ||||||
|  |         let encrypted_data = McaFromRequestfromUpdate::from_encryptable(encrypted_data) | ||||||
|  |             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |             .attach_printable("Failed while decrypting connector account details")?; | ||||||
|  |  | ||||||
|         Ok(storage::MerchantConnectorAccountUpdate::Update { |         Ok(storage::MerchantConnectorAccountUpdate::Update { | ||||||
|             connector_type: Some(self.connector_type), |             connector_type: Some(self.connector_type), | ||||||
|             connector_label: self.connector_label.clone(), |             connector_label: self.connector_label.clone(), | ||||||
|             connector_account_details: self |             connector_account_details: encrypted_data.connector_account_details, | ||||||
|                 .connector_account_details |  | ||||||
|                 .async_lift(|inner| async { |  | ||||||
|                     domain_types::crypto_operation( |  | ||||||
|                         key_manager_state, |  | ||||||
|                         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) |  | ||||||
|                 .attach_printable("Failed while encrypting data")?, |  | ||||||
|             disabled, |             disabled, | ||||||
|             payment_methods_enabled, |             payment_methods_enabled, | ||||||
|             metadata: self.metadata, |             metadata: self.metadata, | ||||||
| @ -2123,31 +2138,8 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect | |||||||
|             applepay_verified_domains: None, |             applepay_verified_domains: None, | ||||||
|             pm_auth_config: self.pm_auth_config, |             pm_auth_config: self.pm_auth_config, | ||||||
|             status: Some(connector_status), |             status: Some(connector_status), | ||||||
|             additional_merchant_data: if let Some(mcd) = merchant_recipient_data { |             additional_merchant_data: encrypted_data.additional_merchant_data, | ||||||
|                 Some( |             connector_wallets_details: encrypted_data.connector_wallets_details, | ||||||
|                     domain_types::crypto_operation( |  | ||||||
|                         key_manager_state, |  | ||||||
|                         type_name!(domain::MerchantConnectorAccount), |  | ||||||
|                         domain_types::CryptoOperation::Encrypt(Secret::new(mcd)), |  | ||||||
|                         km_types::Identifier::Merchant(key_store.merchant_id.clone()), |  | ||||||
|                         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 { |  | ||||||
|                 None |  | ||||||
|             }, |  | ||||||
|             connector_wallets_details: |  | ||||||
|                 helpers::get_encrypted_connector_wallets_details_with_apple_pay_certificates( |  | ||||||
|                     state, |  | ||||||
|                     &key_store, |  | ||||||
|                     &metadata, |  | ||||||
|                     &self.connector_wallets_details, |  | ||||||
|                 ) |  | ||||||
|                 .await?, |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -2267,27 +2259,39 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect | |||||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|         .attach_printable("Failed to serialize MerchantRecipientData")?; |         .attach_printable("Failed to serialize MerchantRecipientData")?; | ||||||
|  |  | ||||||
|  |         let encrypted_data = domain_types::crypto_operation( | ||||||
|  |             key_manager_state, | ||||||
|  |             type_name!(domain::MerchantConnectorAccount), | ||||||
|  |             domain_types::CryptoOperation::BatchEncrypt(McaFromRequestfromUpdate::to_encryptable( | ||||||
|  |                 McaFromRequestfromUpdate { | ||||||
|  |                     connector_account_details: self.connector_account_details, | ||||||
|  |                     connector_wallets_details: | ||||||
|  |                         helpers::get_connector_wallets_details_with_apple_pay_certificates( | ||||||
|  |                             &self.metadata, | ||||||
|  |                             &self.connector_wallets_details, | ||||||
|  |                         ) | ||||||
|  |                         .await?, | ||||||
|  |                     additional_merchant_data: merchant_recipient_data.map(Secret::new), | ||||||
|  |                 }, | ||||||
|  |             )), | ||||||
|  |             km_types::Identifier::Merchant(key_store.merchant_id.clone()), | ||||||
|  |             key_store.key.peek(), | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|  |         .and_then(|val| val.try_into_batchoperation()) | ||||||
|  |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |         .attach_printable("Failed while decrypting connector account details".to_string())?; | ||||||
|  |  | ||||||
|  |         let encrypted_data = McaFromRequestfromUpdate::from_encryptable(encrypted_data) | ||||||
|  |             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |             .attach_printable("Failed while decrypting connector account details")?; | ||||||
|  |  | ||||||
|         Ok(storage::MerchantConnectorAccountUpdate::Update { |         Ok(storage::MerchantConnectorAccountUpdate::Update { | ||||||
|             connector_type: Some(self.connector_type), |             connector_type: Some(self.connector_type), | ||||||
|             connector_name: None, |             connector_name: None, | ||||||
|             merchant_connector_id: None, |             merchant_connector_id: None, | ||||||
|             connector_label: self.connector_label.clone(), |             connector_label: self.connector_label.clone(), | ||||||
|             connector_account_details: self |             connector_account_details: encrypted_data.connector_account_details, | ||||||
|                 .connector_account_details |  | ||||||
|                 .async_lift(|inner| async { |  | ||||||
|                     domain_types::crypto_operation( |  | ||||||
|                         key_manager_state, |  | ||||||
|                         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) |  | ||||||
|                 .attach_printable("Failed while encrypting data")?, |  | ||||||
|             test_mode: self.test_mode, |             test_mode: self.test_mode, | ||||||
|             disabled, |             disabled, | ||||||
|             payment_methods_enabled, |             payment_methods_enabled, | ||||||
| @ -2304,31 +2308,8 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect | |||||||
|             applepay_verified_domains: None, |             applepay_verified_domains: None, | ||||||
|             pm_auth_config: self.pm_auth_config, |             pm_auth_config: self.pm_auth_config, | ||||||
|             status: Some(connector_status), |             status: Some(connector_status), | ||||||
|             additional_merchant_data: if let Some(mcd) = merchant_recipient_data { |             additional_merchant_data: encrypted_data.additional_merchant_data, | ||||||
|                 Some( |             connector_wallets_details: encrypted_data.connector_wallets_details, | ||||||
|                     domain_types::crypto_operation( |  | ||||||
|                         key_manager_state, |  | ||||||
|                         type_name!(domain::MerchantConnectorAccount), |  | ||||||
|                         domain_types::CryptoOperation::Encrypt(Secret::new(mcd)), |  | ||||||
|                         km_types::Identifier::Merchant(key_store.merchant_id.clone()), |  | ||||||
|                         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 { |  | ||||||
|                 None |  | ||||||
|             }, |  | ||||||
|             connector_wallets_details: |  | ||||||
|                 helpers::get_encrypted_connector_wallets_details_with_apple_pay_certificates( |  | ||||||
|                     state, |  | ||||||
|                     &key_store, |  | ||||||
|                     &metadata, |  | ||||||
|                     &self.connector_wallets_details, |  | ||||||
|                 ) |  | ||||||
|                 .await?, |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -2417,25 +2398,43 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { | |||||||
|         .transpose() |         .transpose() | ||||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|         .attach_printable("Failed to serialize MerchantRecipientData")?; |         .attach_printable("Failed to serialize MerchantRecipientData")?; | ||||||
|         Ok(domain::MerchantConnectorAccount { |  | ||||||
|             merchant_id: business_profile.merchant_id.clone(), |         let encrypted_data = domain_types::crypto_operation( | ||||||
|             connector_type: self.connector_type, |  | ||||||
|             connector_name: self.connector_name.to_string(), |  | ||||||
|             connector_account_details: domain_types::crypto_operation( |  | ||||||
|             key_manager_state, |             key_manager_state, | ||||||
|             type_name!(domain::MerchantConnectorAccount), |             type_name!(domain::MerchantConnectorAccount), | ||||||
|                 domain_types::CryptoOperation::Encrypt(self.connector_account_details.ok_or( |             domain_types::CryptoOperation::BatchEncrypt(McaFromRequest::to_encryptable( | ||||||
|  |                 McaFromRequest { | ||||||
|  |                     connector_account_details: self.connector_account_details.ok_or( | ||||||
|                         errors::ApiErrorResponse::MissingRequiredField { |                         errors::ApiErrorResponse::MissingRequiredField { | ||||||
|                             field_name: "connector_account_details", |                             field_name: "connector_account_details", | ||||||
|                         }, |                         }, | ||||||
|                 )?), |                     )?, | ||||||
|  |                     connector_wallets_details: | ||||||
|  |                         helpers::get_connector_wallets_details_with_apple_pay_certificates( | ||||||
|  |                             &self.metadata, | ||||||
|  |                             &self.connector_wallets_details, | ||||||
|  |                         ) | ||||||
|  |                         .await?, | ||||||
|  |                     additional_merchant_data: merchant_recipient_data.map(Secret::new), | ||||||
|  |                 }, | ||||||
|  |             )), | ||||||
|             identifier.clone(), |             identifier.clone(), | ||||||
|             key_store.key.peek(), |             key_store.key.peek(), | ||||||
|         ) |         ) | ||||||
|         .await |         .await | ||||||
|             .and_then(|val| val.try_into_operation()) |         .and_then(|val| val.try_into_batchoperation()) | ||||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|             .attach_printable("Unable to encrypt connector account details")?, |         .attach_printable("Failed while decrypting connector account details".to_string())?; | ||||||
|  |  | ||||||
|  |         let encrypted_data = McaFromRequest::from_encryptable(encrypted_data) | ||||||
|  |             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |             .attach_printable("Failed while decrypting connector account details")?; | ||||||
|  |  | ||||||
|  |         Ok(domain::MerchantConnectorAccount { | ||||||
|  |             merchant_id: business_profile.merchant_id.clone(), | ||||||
|  |             connector_type: self.connector_type, | ||||||
|  |             connector_name: self.connector_name.to_string(), | ||||||
|  |             connector_account_details: encrypted_data.connector_account_details, | ||||||
|             payment_methods_enabled, |             payment_methods_enabled, | ||||||
|             disabled, |             disabled, | ||||||
|             metadata: self.metadata.clone(), |             metadata: self.metadata.clone(), | ||||||
| @ -2459,22 +2458,8 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { | |||||||
|             applepay_verified_domains: None, |             applepay_verified_domains: None, | ||||||
|             pm_auth_config: self.pm_auth_config.clone(), |             pm_auth_config: self.pm_auth_config.clone(), | ||||||
|             status: connector_status, |             status: connector_status, | ||||||
|             connector_wallets_details: helpers::get_encrypted_connector_wallets_details_with_apple_pay_certificates(state, &key_store, &self.metadata, &self.connector_wallets_details).await?, |             connector_wallets_details: encrypted_data.connector_wallets_details, | ||||||
|             additional_merchant_data: if let Some(mcd) =  merchant_recipient_data { |             additional_merchant_data: encrypted_data.additional_merchant_data, | ||||||
|                 Some(domain_types::crypto_operation( |  | ||||||
|                     key_manager_state, |  | ||||||
|                     type_name!(domain::MerchantConnectorAccount), |  | ||||||
|                     domain_types::CryptoOperation::Encrypt(Secret::new(mcd)), |  | ||||||
|                     km_types::Identifier::Merchant(key_store.merchant_id.clone()), |  | ||||||
|                     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 { |  | ||||||
|                 None |  | ||||||
|             }, |  | ||||||
|             version: hyperswitch_domain_models::consts::API_VERSION, |             version: hyperswitch_domain_models::consts::API_VERSION, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| @ -2582,26 +2567,44 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { | |||||||
|         .transpose() |         .transpose() | ||||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|         .attach_printable("Failed to serialize MerchantRecipientData")?; |         .attach_printable("Failed to serialize MerchantRecipientData")?; | ||||||
|  |  | ||||||
|  |         let encrypted_data = domain_types::crypto_operation( | ||||||
|  |             key_manager_state, | ||||||
|  |             type_name!(domain::MerchantConnectorAccount), | ||||||
|  |             domain_types::CryptoOperation::BatchEncrypt(McaFromRequest::to_encryptable( | ||||||
|  |                 McaFromRequest { | ||||||
|  |                     connector_account_details: self.connector_account_details.ok_or( | ||||||
|  |                         errors::ApiErrorResponse::MissingRequiredField { | ||||||
|  |                             field_name: "connector_account_details", | ||||||
|  |                         }, | ||||||
|  |                     )?, | ||||||
|  |                     connector_wallets_details: | ||||||
|  |                         helpers::get_connector_wallets_details_with_apple_pay_certificates( | ||||||
|  |                             &self.metadata, | ||||||
|  |                             &self.connector_wallets_details, | ||||||
|  |                         ) | ||||||
|  |                         .await?, | ||||||
|  |                     additional_merchant_data: merchant_recipient_data.map(Secret::new), | ||||||
|  |                 }, | ||||||
|  |             )), | ||||||
|  |             identifier.clone(), | ||||||
|  |             key_store.key.peek(), | ||||||
|  |         ) | ||||||
|  |         .await | ||||||
|  |         .and_then(|val| val.try_into_batchoperation()) | ||||||
|  |         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |         .attach_printable("Failed while decrypting connector account details".to_string())?; | ||||||
|  |  | ||||||
|  |         let encrypted_data = McaFromRequest::from_encryptable(encrypted_data) | ||||||
|  |             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||||
|  |             .attach_printable("Failed while decrypting connector account details")?; | ||||||
|  |  | ||||||
|         Ok(domain::MerchantConnectorAccount { |         Ok(domain::MerchantConnectorAccount { | ||||||
|             merchant_id: business_profile.merchant_id.clone(), |             merchant_id: business_profile.merchant_id.clone(), | ||||||
|             connector_type: self.connector_type, |             connector_type: self.connector_type, | ||||||
|             connector_name: self.connector_name.to_string(), |             connector_name: self.connector_name.to_string(), | ||||||
|             merchant_connector_id: common_utils::generate_merchant_connector_account_id_of_default_length(), |             merchant_connector_id: common_utils::generate_merchant_connector_account_id_of_default_length(), | ||||||
|             connector_account_details: domain_types::crypto_operation( |             connector_account_details: encrypted_data.connector_account_details, | ||||||
|                 key_manager_state, |  | ||||||
|                 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, |             payment_methods_enabled, | ||||||
|             disabled, |             disabled, | ||||||
|             metadata: self.metadata.clone(), |             metadata: self.metadata.clone(), | ||||||
| @ -2624,26 +2627,12 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate { | |||||||
|             applepay_verified_domains: None, |             applepay_verified_domains: None, | ||||||
|             pm_auth_config: self.pm_auth_config.clone(), |             pm_auth_config: self.pm_auth_config.clone(), | ||||||
|             status: connector_status, |             status: connector_status, | ||||||
|             connector_wallets_details: helpers::get_encrypted_connector_wallets_details_with_apple_pay_certificates(state, &key_store, &self.metadata, &self.connector_wallets_details).await?, |             connector_wallets_details: encrypted_data.connector_wallets_details, | ||||||
|             test_mode: self.test_mode, |             test_mode: self.test_mode, | ||||||
|             business_country: self.business_country, |             business_country: self.business_country, | ||||||
|             business_label: self.business_label.clone(), |             business_label: self.business_label.clone(), | ||||||
|             business_sub_label: self.business_sub_label.clone(), |             business_sub_label: self.business_sub_label.clone(), | ||||||
|             additional_merchant_data: if let Some(mcd) =  merchant_recipient_data { |             additional_merchant_data: encrypted_data.additional_merchant_data, | ||||||
|                 Some(domain_types::crypto_operation( |  | ||||||
|                     key_manager_state, |  | ||||||
|                     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 { |  | ||||||
|                 None |  | ||||||
|             }, |  | ||||||
|             version: hyperswitch_domain_models::consts::API_VERSION, |             version: hyperswitch_domain_models::consts::API_VERSION, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -76,10 +76,7 @@ use crate::{ | |||||||
|     services, |     services, | ||||||
|     types::{ |     types::{ | ||||||
|         api::{self, admin, enums as api_enums, MandateValidationFieldsExt}, |         api::{self, admin, enums as api_enums, MandateValidationFieldsExt}, | ||||||
|         domain::{ |         domain::{self, types}, | ||||||
|             self, |  | ||||||
|             types::{self, AsyncLift}, |  | ||||||
|         }, |  | ||||||
|         storage::{self, enums as storage_enums, ephemeral_key, CardTokenData}, |         storage::{self, enums as storage_enums, ephemeral_key, CardTokenData}, | ||||||
|         transformers::{ForeignFrom, ForeignTryFrom}, |         transformers::{ForeignFrom, ForeignTryFrom}, | ||||||
|         AdditionalMerchantData, AdditionalPaymentMethodConnectorResponse, ErrorResponse, |         AdditionalMerchantData, AdditionalPaymentMethodConnectorResponse, ErrorResponse, | ||||||
| @ -4555,12 +4552,10 @@ pub fn is_apple_pay_simplified_flow( | |||||||
| // As part of migration fallback this function checks apple pay details are present in connector_wallets_details | // As part of migration fallback this function checks apple pay details are present in connector_wallets_details | ||||||
| // If yes, it will encrypt connector_wallets_details and store it in the database. | // If yes, it will encrypt connector_wallets_details and store it in the database. | ||||||
| // If no, it will check if apple pay details are present in metadata and merge it with connector_wallets_details, encrypt and store it. | // If no, it will check if apple pay details are present in metadata and merge it with connector_wallets_details, encrypt and store it. | ||||||
| pub async fn get_encrypted_connector_wallets_details_with_apple_pay_certificates( | pub async fn get_connector_wallets_details_with_apple_pay_certificates( | ||||||
|     state: &SessionState, |  | ||||||
|     key_store: &domain::MerchantKeyStore, |  | ||||||
|     connector_metadata: &Option<masking::Secret<tera::Value>>, |     connector_metadata: &Option<masking::Secret<tera::Value>>, | ||||||
|     connector_wallets_details_optional: &Option<api_models::admin::ConnectorWalletDetails>, |     connector_wallets_details_optional: &Option<api_models::admin::ConnectorWalletDetails>, | ||||||
| ) -> RouterResult<Option<Encryptable<masking::Secret<serde_json::Value>>>> { | ) -> RouterResult<Option<masking::Secret<serde_json::Value>>> { | ||||||
|     let connector_wallet_details_with_apple_pay_metadata_optional = |     let connector_wallet_details_with_apple_pay_metadata_optional = | ||||||
|         get_apple_pay_metadata_if_needed(connector_metadata, connector_wallets_details_optional) |         get_apple_pay_metadata_if_needed(connector_metadata, connector_wallets_details_optional) | ||||||
|             .await?; |             .await?; | ||||||
| @ -4574,25 +4569,7 @@ pub async fn get_encrypted_connector_wallets_details_with_apple_pay_certificates | |||||||
|         .transpose()? |         .transpose()? | ||||||
|         .map(masking::Secret::new); |         .map(masking::Secret::new); | ||||||
|  |  | ||||||
|     let key_manager_state: KeyManagerState = state.into(); |     Ok(connector_wallets_details) | ||||||
|     let encrypted_connector_wallets_details = connector_wallets_details |  | ||||||
|         .clone() |  | ||||||
|         .async_lift(|wallets_details| async { |  | ||||||
|             types::crypto_operation( |  | ||||||
|                 &key_manager_state, |  | ||||||
|                 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) |  | ||||||
|         .attach_printable("Failed while encrypting connector wallets details")?; |  | ||||||
|  |  | ||||||
|     Ok(encrypted_connector_wallets_details) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| async fn get_apple_pay_metadata_if_needed( | async fn get_apple_pay_metadata_if_needed( | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Kartikeya Hegde
					Kartikeya Hegde