mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +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());
|
||||||
|
let decrypted_data = crypto_operation(
|
||||||
|
state,
|
||||||
|
type_name!(Self::DstType),
|
||||||
|
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(),
|
||||||
|
key.peek(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.and_then(|val| val.try_into_batchoperation())
|
||||||
|
.change_context(ValidationError::InvalidValue {
|
||||||
|
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 {
|
Ok(Self {
|
||||||
merchant_id: other.merchant_id,
|
merchant_id: other.merchant_id,
|
||||||
connector_name: other.connector_name,
|
connector_name: other.connector_name,
|
||||||
connector_account_details: crypto_operation(
|
connector_account_details: decrypted_data.connector_account_details,
|
||||||
state,
|
|
||||||
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(),
|
|
||||||
})?,
|
|
||||||
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());
|
||||||
|
|
||||||
|
let decrypted_data = crypto_operation(
|
||||||
|
state,
|
||||||
|
type_name!(Self::DstType),
|
||||||
|
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(),
|
||||||
|
key.peek(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.and_then(|val| val.try_into_batchoperation())
|
||||||
|
.change_context(ValidationError::InvalidValue {
|
||||||
|
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 {
|
Ok(Self {
|
||||||
id: other.id,
|
id: other.id,
|
||||||
merchant_id: other.merchant_id,
|
merchant_id: other.merchant_id,
|
||||||
connector_name: other.connector_name,
|
connector_name: other.connector_name,
|
||||||
connector_account_details: crypto_operation(
|
connector_account_details: decrypted_data.connector_account_details,
|
||||||
state,
|
|
||||||
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(),
|
|
||||||
})?,
|
|
||||||
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")?;
|
||||||
|
|
||||||
|
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(),
|
||||||
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(),
|
||||||
@ -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