diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index ee6ac7731c..33e188b8ca 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -46,6 +46,8 @@ use super::surcharge_decision_configs::{ }; #[cfg(not(feature = "connector_choice_mca_id"))] use crate::core::utils::get_connector_label; +#[cfg(feature = "payouts")] +use crate::types::domain::types::AsyncLift; use crate::{ configs::settings, core::{ @@ -67,10 +69,7 @@ use crate::{ services, types::{ api::{self, routing as routing_types, PaymentMethodCreateExt}, - domain::{ - self, - types::{decrypt, encrypt_optional, AsyncLift}, - }, + domain::{self, types::decrypt}, storage::{self, enums, PaymentMethodListContext, PaymentTokenData}, transformers::{ForeignFrom, ForeignTryFrom}, }, @@ -351,9 +350,14 @@ pub async fn skip_locker_call_and_migrate_payment_method( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed to parse connector mandate details")?; - let payment_method_billing_address = create_encrypted_data(key_store, req.billing.clone()) + let payment_method_billing_address: Option>> = req + .billing + .clone() + .async_map(|billing| create_encrypted_data(key_store, billing)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt Payment method billing address")?; let customer = db .find_customer_by_customer_id_merchant_id( @@ -484,10 +488,13 @@ pub async fn skip_locker_call_and_migrate_payment_method( .as_ref() .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()))); - let payment_method_data_encrypted = - create_encrypted_data(key_store, payment_method_card_details) + let payment_method_data_encrypted: Option>> = + payment_method_card_details + .async_map(|card_details| create_encrypted_data(key_store, card_details)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt Payment method card details")?; let payment_method_metadata: Option = req.metadata.as_ref().map(|data| data.peek()).cloned(); @@ -508,7 +515,7 @@ pub async fn skip_locker_call_and_migrate_payment_method( payment_method_issuer: req.payment_method_issuer.clone(), scheme: req.card_network.clone(), metadata: payment_method_metadata.map(Secret::new), - payment_method_data: payment_method_data_encrypted, + payment_method_data: payment_method_data_encrypted.map(Into::into), connector_mandate_details: Some(connector_mandate_details), customer_acceptance: None, client_secret: None, @@ -527,7 +534,7 @@ pub async fn skip_locker_call_and_migrate_payment_method( created_at: current_time, last_modified: current_time, last_used_at: current_time, - payment_method_billing_address, + payment_method_billing_address: payment_method_billing_address.map(Into::into), updated_by: None, }, merchant_account.storage_scheme, @@ -591,9 +598,14 @@ pub async fn get_client_secret_or_add_payment_method( #[cfg(feature = "payouts")] let condition = req.card.is_some() || req.bank_transfer.is_some() || req.wallet.is_some(); - let payment_method_billing_address = create_encrypted_data(key_store, req.billing.clone()) + let payment_method_billing_address: Option>> = req + .billing + .clone() + .async_map(|billing| create_encrypted_data(key_store, billing)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt Payment method billing address")?; let connector_mandate_details = req .connector_mandate_details @@ -622,7 +634,7 @@ pub async fn get_client_secret_or_add_payment_method( Some(enums::PaymentMethodStatus::AwaitingData), None, merchant_account.storage_scheme, - payment_method_billing_address, + payment_method_billing_address.map(Into::into), None, ) .await?; @@ -793,13 +805,17 @@ pub async fn add_payment_method_data( saved_to_locker: true, }; - let updated_pmd = Some(PaymentMethodsData::Card(updated_card)); - let pm_data_encrypted = create_encrypted_data(&key_store, updated_pmd) + let pm_data_encrypted: Encryptable> = + create_encrypted_data( + &key_store, + PaymentMethodsData::Card(updated_card), + ) .await - .map(|details| details.into()); + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt payment method data")?; let pm_update = storage::PaymentMethodUpdate::AdditionalDataUpdate { - payment_method_data: pm_data_encrypted, + payment_method_data: Some(pm_data_encrypted.into()), status: Some(enums::PaymentMethodStatus::Active), locker_id: Some(locker_id), payment_method: req.payment_method, @@ -870,9 +886,14 @@ pub async fn add_payment_method( let merchant_id = &merchant_account.merchant_id; let customer_id = req.customer_id.clone().get_required_value("customer_id")?; let payment_method = req.payment_method.get_required_value("payment_method")?; - let payment_method_billing_address = create_encrypted_data(key_store, req.billing.clone()) + let payment_method_billing_address: Option>> = req + .billing + .clone() + .async_map(|billing| create_encrypted_data(key_store, billing)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt Payment method billing address")?; let connector_mandate_details = req .connector_mandate_details @@ -1041,12 +1062,16 @@ pub async fn add_payment_method( let updated_pmd = updated_card.as_ref().map(|card| { PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())) }); - let pm_data_encrypted = create_encrypted_data(key_store, updated_pmd) - .await - .map(|details| details.into()); + let pm_data_encrypted: Option>> = + updated_pmd + .async_map(|updated_pmd| create_encrypted_data(key_store, updated_pmd)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt payment method data")?; let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate { - payment_method_data: pm_data_encrypted, + payment_method_data: pm_data_encrypted.map(Into::into), }; db.update_payment_method( @@ -1086,7 +1111,7 @@ pub async fn add_payment_method( connector_mandate_details, req.network_transaction_id.clone(), merchant_account.storage_scheme, - payment_method_billing_address, + payment_method_billing_address.map(Into::into), ) .await?; @@ -1117,9 +1142,14 @@ pub async fn insert_payment_method( .card .clone() .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()))); - let pm_data_encrypted = create_encrypted_data(key_store, pm_card_details) + + let pm_data_encrypted: Option>> = pm_card_details + .clone() + .async_map(|pm_card| create_encrypted_data(key_store, pm_card)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt payment method data")?; create_payment_method( db, @@ -1130,7 +1160,7 @@ pub async fn insert_payment_method( merchant_id, pm_metadata, customer_acceptance, - pm_data_encrypted, + pm_data_encrypted.map(Into::into), key_store, connector_mandate_details, None, @@ -1307,12 +1337,16 @@ pub async fn update_customer_payment_method( let updated_pmd = updated_card .as_ref() .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()))); - let pm_data_encrypted = create_encrypted_data(&key_store, updated_pmd) + + let pm_data_encrypted: Option>> = updated_pmd + .async_map(|updated_pmd| create_encrypted_data(&key_store, updated_pmd)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt payment method data")?; let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate { - payment_method_data: pm_data_encrypted, + payment_method_data: pm_data_encrypted.map(Into::into), }; add_card_resp @@ -1436,7 +1470,7 @@ pub async fn add_bank_to_locker( let secret: Secret = Secret::new(v.to_string()); secret }) - .async_lift(|inner| encrypt_optional(inner, key)) + .async_lift(|inner| domain::types::encrypt_optional(inner, key)) .await } .await @@ -4563,31 +4597,25 @@ pub async fn delete_payment_method( pub async fn create_encrypted_data( key_store: &domain::MerchantKeyStore, - data: Option, -) -> Option>> + data: T, +) -> Result>, error_stack::Report> where T: Debug + serde::Serialize, { let key = key_store.key.get_inner().peek(); - data.as_ref() - .map(Encode::encode_to_value) - .transpose() + let encoded_data = Encode::encode_to_value(&data) .change_context(errors::StorageError::SerializationFailed) - .attach_printable("Unable to convert data to a value") - .unwrap_or_else(|error| { - logger::error!(?error); - None - }) - .map(Secret::<_, masking::WithType>::new) - .async_lift(|inner| encrypt_optional(inner, key)) + .attach_printable("Unable to encode data")?; + + let secret_data = Secret::<_, masking::WithType>::new(encoded_data); + + let encrypted_data = domain::types::encrypt(secret_data, key) .await .change_context(errors::StorageError::EncryptionError) - .attach_printable("Unable to encrypt data") - .unwrap_or_else(|error| { - logger::error!(?error); - None - }) + .attach_printable("Unable to encrypt data")?; + + Ok(encrypted_data) } pub async fn list_countries_currencies_for_connector_payment_method( diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 8183a01fca..4249955c24 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1612,8 +1612,11 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R>( payment_data.payment_intent.customer_details = raw_customer_details .clone() - .async_and_then(|_| async { create_encrypted_data(key_store, raw_customer_details).await }) - .await; + .async_map(|customer_details| create_encrypted_data(key_store, customer_details)) + .await + .transpose() + .change_context(errors::StorageError::EncryptionError) + .attach_printable("Unable to encrypt customer details")?; let customer_id = request_customer_details .customer_id diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 771ee13747..3af3bc5219 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -1222,12 +1222,20 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let billing_address = payment_data.address.get_payment_billing(); let billing_details = billing_address - .async_and_then(|_| async { create_encrypted_data(key_store, billing_address).await }) - .await; + .async_map(|billing_details| create_encrypted_data(key_store, billing_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt billing details")?; + let shipping_address = payment_data.address.get_shipping(); let shipping_details = shipping_address - .async_and_then(|_| async { create_encrypted_data(key_store, shipping_address).await }) - .await; + .async_map(|shipping_details| create_encrypted_data(key_store, shipping_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt shipping details")?; + let m_payment_data_payment_intent = payment_data.payment_intent.clone(); let m_customer_id = customer_id.clone(); let m_shipping_address_id = shipping_address_id.clone(); diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 4e0bbec9f1..b7076d0782 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -642,10 +642,11 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen // details are provided in Payment Create Request let customer_details = raw_customer_details .clone() - .async_and_then(|_| async { - create_encrypted_data(key_store, raw_customer_details).await - }) - .await; + .async_map(|customer_details| create_encrypted_data(key_store, customer_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt customer details")?; payment_data.payment_intent = state .store @@ -1047,20 +1048,22 @@ impl PaymentCreate { let billing_details = request .billing .clone() - .async_and_then(|_| async { - create_encrypted_data(key_store, request.billing.clone()).await - }) - .await; + .async_map(|billing_details| create_encrypted_data(key_store, billing_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt billing details")?; // Derivation of directly supplied Shipping Address data in our Payment Create Request // Encrypting our Shipping Address Details to be stored in Payment Intent let shipping_details = request .shipping .clone() - .async_and_then(|_| async { - create_encrypted_data(key_store, request.shipping.clone()).await - }) - .await; + .async_map(|shipping_details| create_encrypted_data(key_store, shipping_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt shipping details")?; // Derivation of directly supplied Customer data in our Payment Create Request let raw_customer_details = if request.get_customer_id().is_none() @@ -1080,11 +1083,12 @@ impl PaymentCreate { }; // Encrypting our Customer Details to be stored in Payment Intent - let customer_details = if raw_customer_details.is_some() { - create_encrypted_data(key_store, raw_customer_details).await - } else { - None - }; + let customer_details = raw_customer_details + .async_map(|customer_details| create_encrypted_data(key_store, customer_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt customer details")?; Ok(storage::PaymentIntent { payment_id: payment_id.to_string(), diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 8af5a86d7c..98006e574c 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -715,22 +715,21 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let billing_details = payment_data .address .get_payment_billing() - .async_and_then(|_| async { - create_encrypted_data( - key_store, - payment_data.address.get_payment_billing().cloned(), - ) - .await - }) - .await; + .async_map(|billing_details| create_encrypted_data(key_store, billing_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt billing details")?; let shipping_details = payment_data .address .get_shipping() - .async_and_then(|_| async { - create_encrypted_data(key_store, payment_data.address.get_shipping().cloned()).await - }) - .await; + .async_map(|shipping_details| create_encrypted_data(key_store, shipping_details)) + .await + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt shipping details")?; + let order_details = payment_data.payment_intent.order_details.clone(); let metadata = payment_data.payment_intent.metadata.clone(); let frm_metadata = payment_data.payment_intent.frm_metadata.clone(); diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 3fb67abd57..b77bdb7515 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -3,11 +3,12 @@ use std::collections::HashMap; use api_models::payment_methods::PaymentMethodsData; use common_enums::PaymentMethod; use common_utils::{ - ext_traits::{Encode, ValueExt}, + crypto::Encryptable, + ext_traits::{AsyncExt, Encode, ValueExt}, id_type, pii, }; use error_stack::{report, ResultExt}; -use masking::{ExposeInterface, PeekInterface}; +use masking::{ExposeInterface, PeekInterface, Secret}; use router_env::{instrument, metrics::add_attributes, tracing}; use super::helpers; @@ -15,7 +16,9 @@ use crate::{ consts, core::{ errors::{self, ConnectorErrorExt, RouterResult, StorageErrorExt}, - mandate, payment_methods, payments, + mandate, + payment_methods::{self, cards::create_encrypted_data}, + payments, }, logger, routes::{metrics, SessionState}, @@ -64,7 +67,7 @@ pub async fn save_payment_method( key_store: &domain::MerchantKeyStore, amount: Option, currency: Option, - billing_name: Option>, + billing_name: Option>, payment_method_billing_address: Option<&api::Address>, business_profile: &storage::business_profile::BusinessProfile, ) -> RouterResult<(Option, Option)> @@ -209,18 +212,22 @@ where PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())) }); - let pm_data_encrypted = - payment_methods::cards::create_encrypted_data(key_store, pm_card_details) + let pm_data_encrypted: Option>> = + pm_card_details + .async_map(|pm_card| create_encrypted_data(key_store, pm_card)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt payment method data")?; - let encrypted_payment_method_billing_address = - payment_methods::cards::create_encrypted_data( - key_store, - payment_method_billing_address, - ) + let encrypted_payment_method_billing_address: Option< + Encryptable>, + > = payment_method_billing_address + .async_map(|address| create_encrypted_data(key_store, address.clone())) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt payment method billing address")?; let mut payment_method_id = resp.payment_method_id.clone(); let mut locker_id = None; @@ -311,13 +318,14 @@ where merchant_id, pm_metadata, customer_acceptance, - pm_data_encrypted, + pm_data_encrypted.map(Into::into), key_store, connector_mandate_details, None, network_transaction_id, merchant_account.storage_scheme, - encrypted_payment_method_billing_address, + encrypted_payment_method_billing_address + .map(Into::into), resp.card.and_then(|card| { card.card_network .map(|card_network| card_network.to_string()) @@ -411,7 +419,8 @@ where connector_mandate_details, network_transaction_id, merchant_account.storage_scheme, - encrypted_payment_method_billing_address, + encrypted_payment_method_billing_address + .map(Into::into), ) .await } else { @@ -506,18 +515,19 @@ where card.clone(), )) }); - let pm_data_encrypted = - payment_methods::cards::create_encrypted_data( - key_store, - updated_pmd, - ) + let pm_data_encrypted: Option< + Encryptable>, + > = updated_pmd + .async_map(|pmd| create_encrypted_data(key_store, pmd)) .await - .map(|details| details.into()); + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt payment method data")?; payment_methods::cards::update_payment_method_and_last_used( db, existing_pm, - pm_data_encrypted, + pm_data_encrypted.map(Into::into), merchant_account.storage_scheme, ) .await @@ -599,13 +609,13 @@ where merchant_id, pm_metadata, customer_acceptance, - pm_data_encrypted, + pm_data_encrypted.map(Into::into), key_store, connector_mandate_details, None, network_transaction_id, merchant_account.storage_scheme, - encrypted_payment_method_billing_address, + encrypted_payment_method_billing_address.map(Into::into), resp.card.and_then(|card| { card.card_network .map(|card_network| card_network.to_string()) @@ -877,9 +887,9 @@ pub fn update_router_data_with_payment_method_token_result( match payment_method_token_result.payment_method_token_result { Ok(pm_token_result) => { router_data.payment_method_token = pm_token_result.map(|pm_token| { - hyperswitch_domain_models::router_data::PaymentMethodToken::Token( - masking::Secret::new(pm_token), - ) + hyperswitch_domain_models::router_data::PaymentMethodToken::Token(Secret::new( + pm_token, + )) }); true diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index fcd4f4aeeb..2b71fedb2a 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -452,9 +452,12 @@ pub async fn save_payout_data_to_locker( ) }); ( - cards::create_encrypted_data(key_store, Some(pm_data)) - .await - .map(|details| details.into()), + Some( + cards::create_encrypted_data(key_store, pm_data) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt customer details")?, + ), payment_method, ) } else { @@ -494,7 +497,7 @@ pub async fn save_payout_data_to_locker( &merchant_account.merchant_id, None, None, - card_details_encrypted.clone(), + card_details_encrypted.clone().map(Into::into), key_store, None, None, @@ -557,7 +560,7 @@ pub async fn save_payout_data_to_locker( // Update card's metadata in payment_methods table let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate { - payment_method_data: card_details_encrypted, + payment_method_data: card_details_encrypted.map(Into::into), }; db.update_payment_method(existing_pm, pm_update, merchant_account.storage_scheme) .await diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index b3d228ced6..2a9dc1a4e9 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -432,13 +432,13 @@ async fn store_bank_details_in_payment_methods( ); let payment_method_data = payment_methods::PaymentMethodsData::BankDetails(pmd); - let encrypted_data = - cards::create_encrypted_data(&key_store, Some(payment_method_data)) - .await - .map(|details| details.into()) - .ok_or(ApiErrorResponse::InternalServerError)?; + let encrypted_data = cards::create_encrypted_data(&key_store, payment_method_data) + .await + .change_context(ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt customer details")?; + let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate { - payment_method_data: Some(encrypted_data), + payment_method_data: Some(encrypted_data.into()), }; update_entries.push((pm.clone(), pm_update)); @@ -447,8 +447,8 @@ async fn store_bank_details_in_payment_methods( let encrypted_data = cards::create_encrypted_data(&key_store, Some(payment_method_data)) .await - .map(|details| details.into()) - .ok_or(ApiErrorResponse::InternalServerError)?; + .change_context(ApiErrorResponse::InternalServerError) + .attach_printable("Unable to encrypt customer details")?; let pm_id = generate_id(consts::ID_LENGTH, "pm"); let now = common_utils::date_time::now(); let pm_new = storage::PaymentMethodNew { @@ -461,7 +461,7 @@ async fn store_bank_details_in_payment_methods( payment_method_issuer: None, scheme: None, metadata: None, - payment_method_data: Some(encrypted_data), + payment_method_data: Some(encrypted_data.into()), payment_method_issuer_code: None, accepted_currency: None, token: None,