From b6d5cd8adb7b251adc7f5b3d158817b1730f4f61 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Wed, 25 Sep 2024 18:37:53 +0530 Subject: [PATCH 01/16] feat(connector): Integrate PAZE Wallet --- config/development.toml | 4 +++ crates/api_models/src/admin.rs | 4 +++ crates/api_models/src/payments.rs | 31 +++++++++++++++++++ crates/common_enums/src/enums.rs | 1 + crates/common_enums/src/transformers.rs | 1 + crates/connector_configs/src/transformer.rs | 5 ++- crates/euclid/src/frontend/dir/enums.rs | 1 + crates/euclid/src/frontend/dir/lowering.rs | 1 + .../euclid/src/frontend/dir/transformers.rs | 1 + .../src/connectors/globepay/transformers.rs | 1 + crates/hyperswitch_connectors/src/utils.rs | 2 ++ .../src/payment_method_data.rs | 20 ++++++++++++ crates/kgraph_utils/src/mca.rs | 1 + crates/kgraph_utils/src/transformers.rs | 1 + .../router/src/connector/aci/transformers.rs | 1 + crates/router/src/connector/adyen.rs | 1 + .../src/connector/adyen/transformers.rs | 1 + .../src/connector/airwallex/transformers.rs | 1 + .../connector/authorizedotnet/transformers.rs | 1 + .../connector/bankofamerica/transformers.rs | 2 ++ .../src/connector/bluesnap/transformers.rs | 1 + .../router/src/connector/boku/transformers.rs | 1 + .../src/connector/checkout/transformers.rs | 2 ++ .../src/connector/cybersource/transformers.rs | 2 ++ crates/router/src/connector/klarna.rs | 1 + .../src/connector/mifinity/transformers.rs | 1 + .../connector/multisafepay/transformers.rs | 3 ++ .../src/connector/nexinets/transformers.rs | 1 + .../router/src/connector/nmi/transformers.rs | 1 + .../router/src/connector/noon/transformers.rs | 1 + .../src/connector/nuvei/transformers.rs | 1 + .../src/connector/payme/transformers.rs | 1 + .../src/connector/paypal/transformers.rs | 1 + .../src/connector/shift4/transformers.rs | 1 + .../src/connector/square/transformers.rs | 1 + .../src/connector/stripe/transformers.rs | 3 ++ crates/router/src/connector/utils.rs | 2 ++ .../src/connector/wellsfargo/transformers.rs | 2 ++ .../src/connector/worldpay/transformers.rs | 1 + .../router/src/connector/zen/transformers.rs | 1 + .../src/core/payments/flows/session_flow.rs | 27 ++++++++++++++++ crates/router/src/core/payments/helpers.rs | 7 +++++ .../payments/operations/payment_session.rs | 1 + crates/router/src/types/api.rs | 1 + crates/router/src/types/transformers.rs | 1 + 45 files changed, 145 insertions(+), 1 deletion(-) diff --git a/config/development.toml b/config/development.toml index 29beed992f6e..2b4532a7a87a 100644 --- a/config/development.toml +++ b/config/development.toml @@ -608,6 +608,10 @@ apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" +[paze] +paze_private_key = "PAZE_PRIVATE_KEY" +paze_private_key_passphrase = "PAZE_PRIVATE_KEY_PASSPHRASE" + [generic_link] [generic_link.payment_method_collect] sdk_url = "http://localhost:9050/HyperLoader.js" diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 6f656339569f..5f81113f0dfd 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -1558,6 +1558,10 @@ pub struct ConnectorWalletDetails { #[serde(skip_serializing_if = "Option::is_none")] #[schema(value_type = Option)] pub samsung_pay: Option, + /// This field contains the Paze certificates and credentials + #[serde(skip_serializing_if = "Option::is_none")] + #[schema(value_type = Option)] + pub paze: Option, } /// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc." diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index c1cd995b725b..c0815748e0e8 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -1967,6 +1967,7 @@ impl GetPaymentMethodType for WalletData { Self::MbWayRedirect(_) => api_enums::PaymentMethodType::MbWay, Self::MobilePayRedirect(_) => api_enums::PaymentMethodType::MobilePay, Self::PaypalRedirect(_) | Self::PaypalSdk(_) => api_enums::PaymentMethodType::Paypal, + Self::Paze(_) => api_enums::PaymentMethodType::Paze, Self::SamsungPay(_) => api_enums::PaymentMethodType::SamsungPay, Self::TwintRedirect {} => api_enums::PaymentMethodType::Twint, Self::VippsRedirect {} => api_enums::PaymentMethodType::Vipps, @@ -2856,6 +2857,8 @@ pub enum WalletData { PaypalRedirect(PaypalRedirection), /// The wallet data for Paypal PaypalSdk(PayPalWalletData), + /// The wallet data for Paze + Paze(PazeWalletData), /// The wallet data for Samsung Pay SamsungPay(Box), /// Wallet data for Twint Redirection @@ -2916,6 +2919,7 @@ impl GetAddressFromPaymentMethodData for WalletData { | Self::GooglePayRedirect(_) | Self::GooglePayThirdPartySdk(_) | Self::PaypalSdk(_) + | Self::Paze(_) | Self::SamsungPay(_) | Self::TwintRedirect {} | Self::VippsRedirect {} @@ -2928,6 +2932,13 @@ impl GetAddressFromPaymentMethodData for WalletData { } } +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub struct PazeWalletData { + /// random data for now + pub payment_data: String, +} + #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub struct SamsungPayWalletData { @@ -4949,6 +4960,17 @@ pub struct GpaySessionTokenData { pub data: GpayMetaData, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PazeSessionTokenData { + #[serde(rename = "paze")] + pub data: PazeMetadata, +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct PazeMetadata { + pub some_data: String, +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct SamsungPaySessionTokenData { #[serde(rename = "samsung_pay")] @@ -5138,10 +5160,19 @@ pub enum SessionToken { ApplePay(Box), /// Session token for OpenBanking PIS flow OpenBanking(OpenBankingSessionToken), + /// The session response structure for Paze + Paze(Box), /// Whenever there is no session token response or an error in session response NoSessionTokenReceived, } +#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)] +#[serde(rename_all = "lowercase")] +pub struct PazeSessionTokenResponse { + /// Random + pub something: String, +} + #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)] #[serde(untagged)] pub enum GpaySessionTokenResponse { diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index a9ece7e9c026..b69529084f47 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1592,6 +1592,7 @@ pub enum PaymentMethodType { OpenBankingUk, PayBright, Paypal, + Paze, Pix, PaySafeCard, Przelewy24, diff --git a/crates/common_enums/src/transformers.rs b/crates/common_enums/src/transformers.rs index db4162a8bb18..4fba749ef637 100644 --- a/crates/common_enums/src/transformers.rs +++ b/crates/common_enums/src/transformers.rs @@ -1843,6 +1843,7 @@ impl From for PaymentMethod { PaymentMethodType::OnlineBankingThailand => Self::BankRedirect, PaymentMethodType::OnlineBankingPoland => Self::BankRedirect, PaymentMethodType::OnlineBankingSlovakia => Self::BankRedirect, + PaymentMethodType::Paze => Self::Wallet, PaymentMethodType::PermataBankTransfer => Self::BankTransfer, PaymentMethodType::Pix => Self::BankTransfer, PaymentMethodType::Pse => Self::BankTransfer, diff --git a/crates/connector_configs/src/transformer.rs b/crates/connector_configs/src/transformer.rs index 68ade2909b46..88997691eb61 100644 --- a/crates/connector_configs/src/transformer.rs +++ b/crates/connector_configs/src/transformer.rs @@ -56,7 +56,10 @@ impl DashboardRequestPayload { | (Connector::Stripe, WeChatPay) => { Some(api_models::enums::PaymentExperience::DisplayQrCode) } - (_, GooglePay) | (_, ApplePay) | (_, PaymentMethodType::SamsungPay) => { + (_, GooglePay) + | (_, ApplePay) + | (_, PaymentMethodType::SamsungPay) + | (_, PaymentMethodType::Paze) => { Some(api_models::enums::PaymentExperience::InvokeSdkClient) } _ => Some(api_models::enums::PaymentExperience::RedirectToUrl), diff --git a/crates/euclid/src/frontend/dir/enums.rs b/crates/euclid/src/frontend/dir/enums.rs index 0d2f959c702c..136cdf4d9817 100644 --- a/crates/euclid/src/frontend/dir/enums.rs +++ b/crates/euclid/src/frontend/dir/enums.rs @@ -91,6 +91,7 @@ pub enum WalletType { Cashapp, Venmo, Mifinity, + Paze, } #[derive( diff --git a/crates/euclid/src/frontend/dir/lowering.rs b/crates/euclid/src/frontend/dir/lowering.rs index 33d368e96961..da589ec3748e 100644 --- a/crates/euclid/src/frontend/dir/lowering.rs +++ b/crates/euclid/src/frontend/dir/lowering.rs @@ -58,6 +58,7 @@ impl From for global_enums::PaymentMethodType { enums::WalletType::Cashapp => Self::Cashapp, enums::WalletType::Venmo => Self::Venmo, enums::WalletType::Mifinity => Self::Mifinity, + enums::WalletType::Paze => Self::Paze, } } } diff --git a/crates/euclid/src/frontend/dir/transformers.rs b/crates/euclid/src/frontend/dir/transformers.rs index 3e35bcd391c4..de0b619b1203 100644 --- a/crates/euclid/src/frontend/dir/transformers.rs +++ b/crates/euclid/src/frontend/dir/transformers.rs @@ -188,6 +188,7 @@ impl IntoDirValue for (global_enums::PaymentMethodType, global_enums::PaymentMet global_enums::PaymentMethodType::OpenBankingPIS => { Ok(dirval!(OpenBankingType = OpenBankingPIS)) } + global_enums::PaymentMethodType::Paze => Ok(dirval!(WalletType = Paze)), } } } diff --git a/crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs index 4986e8d5f32e..772f2af209e0 100644 --- a/crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs @@ -74,6 +74,7 @@ impl TryFrom<&GlobepayRouterData<&types::PaymentsAuthorizeRouterData>> for Globe | WalletData::MobilePayRedirect(_) | WalletData::PaypalRedirect(_) | WalletData::PaypalSdk(_) + | WalletData::Paze(_) | WalletData::SamsungPay(_) | WalletData::TwintRedirect {} | WalletData::VippsRedirect {} diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index f96d715f5be4..d61ce4e47895 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -1733,6 +1733,7 @@ pub enum PaymentMethodDataType { MobilePayRedirect, PaypalRedirect, PaypalSdk, + Paze, SamsungPay, TwintRedirect, VippsRedirect, @@ -1850,6 +1851,7 @@ impl From for PaymentMethodDataType { hyperswitch_domain_models::payment_method_data::WalletData::MobilePayRedirect(_) => Self::MobilePayRedirect, hyperswitch_domain_models::payment_method_data::WalletData::PaypalRedirect(_) => Self::PaypalRedirect, hyperswitch_domain_models::payment_method_data::WalletData::PaypalSdk(_) => Self::PaypalSdk, + hyperswitch_domain_models::payment_method_data::WalletData::Paze(_) => Self::Paze, hyperswitch_domain_models::payment_method_data::WalletData::SamsungPay(_) => Self::SamsungPay, hyperswitch_domain_models::payment_method_data::WalletData::TwintRedirect {} => Self::TwintRedirect, hyperswitch_domain_models::payment_method_data::WalletData::VippsRedirect {} => Self::VippsRedirect, diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 9f505f267120..1ddbdd36dc3e 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -117,6 +117,7 @@ pub enum WalletData { MobilePayRedirect(Box), PaypalRedirect(PaypalRedirection), PaypalSdk(PayPalWalletData), + Paze(PazeWalletData), SamsungPay(Box), TwintRedirect {}, VippsRedirect {}, @@ -134,6 +135,13 @@ pub struct MifinityData { pub language_preference: Option, } +//this data goes to connector: remove this comment +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "snake_case")] +pub struct PazeWalletData { + pub payment_data: String, +} + #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] pub struct SamsungPayWalletData { @@ -689,6 +697,9 @@ impl From for WalletData { token: paypal_sdk_data.token, }) } + api_models::payments::WalletData::Paze(paze_data) => { + Self::Paze(PazeWalletData::from(paze_data)) + } api_models::payments::WalletData::SamsungPay(samsung_pay_data) => { Self::SamsungPay(Box::new(SamsungPayWalletData::from(samsung_pay_data))) } @@ -754,6 +765,14 @@ impl From for ApplePayWalletData { } } +impl From for PazeWalletData { + fn from(value: api_models::payments::PazeWalletData) -> Self { + Self { + payment_data: value.payment_data, + } + } +} + impl From> for SamsungPayWalletData { fn from(value: Box) -> Self { Self { @@ -1388,6 +1407,7 @@ impl GetPaymentMethodType for WalletData { Self::MbWayRedirect(_) => api_enums::PaymentMethodType::MbWay, Self::MobilePayRedirect(_) => api_enums::PaymentMethodType::MobilePay, Self::PaypalRedirect(_) | Self::PaypalSdk(_) => api_enums::PaymentMethodType::Paypal, + Self::Paze(_) => api_enums::PaymentMethodType::Paze, Self::SamsungPay(_) => api_enums::PaymentMethodType::SamsungPay, Self::TwintRedirect {} => api_enums::PaymentMethodType::Twint, Self::VippsRedirect {} => api_enums::PaymentMethodType::Vipps, diff --git a/crates/kgraph_utils/src/mca.rs b/crates/kgraph_utils/src/mca.rs index 2ec0cbe8031b..e897292d6ff1 100644 --- a/crates/kgraph_utils/src/mca.rs +++ b/crates/kgraph_utils/src/mca.rs @@ -146,6 +146,7 @@ fn get_dir_value_payment_method( api_enums::PaymentMethodType::OpenBankingPIS => { Ok(dirval!(OpenBankingType = OpenBankingPIS)) } + api_enums::PaymentMethodType::Paze => Ok(dirval!(WalletType = Paze)), } } diff --git a/crates/kgraph_utils/src/transformers.rs b/crates/kgraph_utils/src/transformers.rs index 758a0dd3de03..1a340aa91d31 100644 --- a/crates/kgraph_utils/src/transformers.rs +++ b/crates/kgraph_utils/src/transformers.rs @@ -307,6 +307,7 @@ impl IntoDirValue for (api_enums::PaymentMethodType, api_enums::PaymentMethod) { api_enums::PaymentMethodType::OpenBankingPIS => { Ok(dirval!(OpenBankingType = OpenBankingPIS)) } + api_enums::PaymentMethodType::Paze => Ok(dirval!(WalletType = Paze)), } } } diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs index 46f312b38f26..abd99fae18ca 100644 --- a/crates/router/src/connector/aci/transformers.rs +++ b/crates/router/src/connector/aci/transformers.rs @@ -120,6 +120,7 @@ impl TryFrom<(&domain::WalletData, &types::PaymentsAuthorizeRouterData)> for Pay | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect { .. } | domain::WalletData::VippsRedirect { .. } diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index f0b84fc93c10..7d1d454baa2f 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -217,6 +217,7 @@ impl ConnectorValidation for Adyen { | PaymentMethodType::Pse | PaymentMethodType::LocalBankTransfer | PaymentMethodType::Efecty + | PaymentMethodType::Paze | PaymentMethodType::PagoEfectivo | PaymentMethodType::PromptPay | PaymentMethodType::RedCompra diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index dfb0963c70a0..d854d92086e8 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -2097,6 +2097,7 @@ impl<'a> TryFrom<(&domain::WalletData, &types::PaymentsAuthorizeRouterData)> | domain::WalletData::GooglePayRedirect(_) | domain::WalletData::GooglePayThirdPartySdk(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::WeChatPayQr(_) | domain::WalletData::CashappQr(_) | domain::WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( diff --git a/crates/router/src/connector/airwallex/transformers.rs b/crates/router/src/connector/airwallex/transformers.rs index 4d84f64534e8..868a4767c319 100644 --- a/crates/router/src/connector/airwallex/transformers.rs +++ b/crates/router/src/connector/airwallex/transformers.rs @@ -254,6 +254,7 @@ fn get_wallet_details( | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs index 868409dafc79..e352d8b79bc1 100644 --- a/crates/router/src/connector/authorizedotnet/transformers.rs +++ b/crates/router/src/connector/authorizedotnet/transformers.rs @@ -1747,6 +1747,7 @@ fn get_wallet_data( | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index f47ab4139e8b..3fdf57e9cd93 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -297,6 +297,7 @@ impl TryFrom<&types::SetupMandateRouterData> for BankOfAmericaPaymentsRequest { | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} @@ -1035,6 +1036,7 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs index 6ebcdf0e765b..b156aafb6ef7 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/router/src/connector/bluesnap/transformers.rs @@ -369,6 +369,7 @@ impl TryFrom<&BluesnapRouterData<&types::PaymentsAuthorizeRouterData>> for Blues | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/boku/transformers.rs b/crates/router/src/connector/boku/transformers.rs index 5fd6b0e6a2eb..a48e49a10cc0 100644 --- a/crates/router/src/connector/boku/transformers.rs +++ b/crates/router/src/connector/boku/transformers.rs @@ -180,6 +180,7 @@ fn get_wallet_type(wallet_data: &domain::WalletData) -> Result for TokenRequest { | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} @@ -345,6 +346,7 @@ impl TryFrom<&CheckoutRouterData<&types::PaymentsAuthorizeRouterData>> for Payme | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index 9c596f5575c2..5e86f63bb694 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -213,6 +213,7 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} @@ -1687,6 +1688,7 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} | domain::WalletData::TouchNGoRedirect(_) diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index 0e6fab805848..2c3d3651284f 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -598,6 +598,7 @@ impl | common_enums::PaymentMethodType::OpenBankingUk | common_enums::PaymentMethodType::PayBright | common_enums::PaymentMethodType::Paypal + | common_enums::PaymentMethodType::Paze | common_enums::PaymentMethodType::Pix | common_enums::PaymentMethodType::PaySafeCard | common_enums::PaymentMethodType::Przelewy24 diff --git a/crates/router/src/connector/mifinity/transformers.rs b/crates/router/src/connector/mifinity/transformers.rs index 0af3826c877f..92b6b45785d3 100644 --- a/crates/router/src/connector/mifinity/transformers.rs +++ b/crates/router/src/connector/mifinity/transformers.rs @@ -169,6 +169,7 @@ impl TryFrom<&MifinityRouterData<&types::PaymentsAuthorizeRouterData>> for Mifin | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/multisafepay/transformers.rs b/crates/router/src/connector/multisafepay/transformers.rs index 547a38ad8498..e0146bf2edad 100644 --- a/crates/router/src/connector/multisafepay/transformers.rs +++ b/crates/router/src/connector/multisafepay/transformers.rs @@ -493,6 +493,7 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} @@ -556,6 +557,7 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} @@ -714,6 +716,7 @@ impl TryFrom<&MultisafepayRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/nexinets/transformers.rs b/crates/router/src/connector/nexinets/transformers.rs index 55b2fbe41763..5bf721333840 100644 --- a/crates/router/src/connector/nexinets/transformers.rs +++ b/crates/router/src/connector/nexinets/transformers.rs @@ -722,6 +722,7 @@ fn get_wallet_details( | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect { .. } | domain::WalletData::VippsRedirect { .. } diff --git a/crates/router/src/connector/nmi/transformers.rs b/crates/router/src/connector/nmi/transformers.rs index 069a51ae52e7..57b04cdca17b 100644 --- a/crates/router/src/connector/nmi/transformers.rs +++ b/crates/router/src/connector/nmi/transformers.rs @@ -558,6 +558,7 @@ impl | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/noon/transformers.rs b/crates/router/src/connector/noon/transformers.rs index 5d9871742730..99e04018632c 100644 --- a/crates/router/src/connector/noon/transformers.rs +++ b/crates/router/src/connector/noon/transformers.rs @@ -326,6 +326,7 @@ impl TryFrom<&NoonRouterData<&types::PaymentsAuthorizeRouterData>> for NoonPayme | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs index f280d3a42a2a..d9728174f843 100644 --- a/crates/router/src/connector/nuvei/transformers.rs +++ b/crates/router/src/connector/nuvei/transformers.rs @@ -914,6 +914,7 @@ where | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index e0ab598d76d6..43647fe3ea75 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -403,6 +403,7 @@ impl TryFrom<&PaymentMethodData> for SalePaymentMethod { | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 4f5ab1337355..41fd533309e5 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -490,6 +490,7 @@ impl TryFrom<&PaypalRouterData<&types::PaymentsAuthorizeRouterData>> for PaypalP | domain::WalletData::GooglePayThirdPartySdk(_) | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/shift4/transformers.rs b/crates/router/src/connector/shift4/transformers.rs index 13c0395cf9f4..e206fe0e0aea 100644 --- a/crates/router/src/connector/shift4/transformers.rs +++ b/crates/router/src/connector/shift4/transformers.rs @@ -282,6 +282,7 @@ impl TryFrom<&domain::WalletData> for Shift4PaymentMethod { | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/square/transformers.rs b/crates/router/src/connector/square/transformers.rs index db7058f33847..34cdbae2a171 100644 --- a/crates/router/src/connector/square/transformers.rs +++ b/crates/router/src/connector/square/transformers.rs @@ -117,6 +117,7 @@ impl TryFrom<(&types::TokenizationRouterData, domain::WalletData)> for SquareTok | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 2129ad327c2c..6f7d2a63d8ac 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -727,6 +727,7 @@ impl TryFrom for StripePaymentMethodType { | enums::PaymentMethodType::MandiriVa | enums::PaymentMethodType::PermataBankTransfer | enums::PaymentMethodType::PaySafeCard + | enums::PaymentMethodType::Paze | enums::PaymentMethodType::Givex | enums::PaymentMethodType::Benefit | enums::PaymentMethodType::Knet @@ -1052,6 +1053,7 @@ impl ForeignTryFrom<&domain::WalletData> for Option { | domain::WalletData::GooglePayThirdPartySdk(_) | domain::WalletData::MbWayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} @@ -1448,6 +1450,7 @@ impl TryFrom<(&domain::WalletData, Option)> for Strip | domain::WalletData::GooglePayThirdPartySdk(_) | domain::WalletData::MbWayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 4da93e2cf017..9c7f2a9e0e83 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -2626,6 +2626,7 @@ pub enum PaymentMethodDataType { MobilePayRedirect, PaypalRedirect, PaypalSdk, + Paze, SamsungPay, TwintRedirect, VippsRedirect, @@ -2743,6 +2744,7 @@ impl From for PaymentMethodDataType { domain::payments::WalletData::MobilePayRedirect(_) => Self::MobilePayRedirect, domain::payments::WalletData::PaypalRedirect(_) => Self::PaypalRedirect, domain::payments::WalletData::PaypalSdk(_) => Self::PaypalSdk, + domain::payments::WalletData::Paze(_) => Self::Paze, domain::payments::WalletData::SamsungPay(_) => Self::SamsungPay, domain::payments::WalletData::TwintRedirect {} => Self::TwintRedirect, domain::payments::WalletData::VippsRedirect {} => Self::VippsRedirect, diff --git a/crates/router/src/connector/wellsfargo/transformers.rs b/crates/router/src/connector/wellsfargo/transformers.rs index be3cf4a1cef9..21994d900e89 100644 --- a/crates/router/src/connector/wellsfargo/transformers.rs +++ b/crates/router/src/connector/wellsfargo/transformers.rs @@ -180,6 +180,7 @@ impl TryFrom<&types::SetupMandateRouterData> for WellsfargoZeroMandateRequest { | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} @@ -1242,6 +1243,7 @@ impl TryFrom<&WellsfargoRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs index de82e11548ca..467a1cba9025 100644 --- a/crates/router/src/connector/worldpay/transformers.rs +++ b/crates/router/src/connector/worldpay/transformers.rs @@ -83,6 +83,7 @@ fn fetch_payment_instrument( | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/connector/zen/transformers.rs b/crates/router/src/connector/zen/transformers.rs index d2e8ce40283b..2b2e7e889e2c 100644 --- a/crates/router/src/connector/zen/transformers.rs +++ b/crates/router/src/connector/zen/transformers.rs @@ -486,6 +486,7 @@ impl | domain::WalletData::MbWayRedirect(_) | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalSdk(_) + | domain::WalletData::Paze(_) | domain::WalletData::SamsungPay(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 5bd81897dd86..425ccd6101c9 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -498,6 +498,32 @@ async fn create_applepay_session_token( } } +fn create_paze_session_token( + router_data: &types::PaymentsSessionRouterData, + _header_payload: api_models::payments::HeaderPayload, +) -> RouterResult { + let paze_wallet_details = router_data + .connector_wallets_details + .clone() + .parse_value::("PazeSessionTokenData") + .change_context(errors::ConnectorError::NoConnectorWalletDetails) + .change_context(errors::ApiErrorResponse::InvalidDataFormat { + field_name: "connector_wallets_details".to_string(), + expected_format: "paze_metadata_format".to_string(), + })?; + + Ok(types::PaymentsSessionRouterData { + response: Ok(types::PaymentsResponseData::SessionResponse { + session_token: payment_types::SessionToken::Paze(Box::new( + payment_types::PazeSessionTokenResponse { + something: paze_wallet_details.data.some_data, + }, + )), + }), + ..router_data.clone() + }) +} + fn create_samsung_pay_session_token( router_data: &types::PaymentsSessionRouterData, header_payload: api_models::payments::HeaderPayload, @@ -955,6 +981,7 @@ impl RouterDataSession for types::PaymentsSessionRouterData { api::GetToken::PaypalSdkMetadata => { create_paypal_sdk_session_token(state, self, connector, business_profile) } + api::GetToken::PazeMetadata => create_paze_session_token(self, header_payload), api::GetToken::Connector => { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::Session, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 23ac67c910d7..e726868d7a9d 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2546,6 +2546,7 @@ pub fn validate_payment_method_type_against_payment_method( | api_enums::PaymentMethodType::KakaoPay | api_enums::PaymentMethodType::Cashapp | api_enums::PaymentMethodType::Mifinity + | api_enums::PaymentMethodType::Paze ), api_enums::PaymentMethod::BankRedirect => matches!( payment_method_type, @@ -4624,6 +4625,9 @@ async fn get_and_merge_apple_pay_metadata( samsung_pay: connector_wallets_details_optional .as_ref() .and_then(|d| d.samsung_pay.clone()), + paze: connector_wallets_details_optional + .as_ref() + .and_then(|d| d.paze.clone()), } } api_models::payments::ApplepaySessionTokenMetadata::ApplePay(apple_pay_metadata) => { @@ -4639,6 +4643,9 @@ async fn get_and_merge_apple_pay_metadata( samsung_pay: connector_wallets_details_optional .as_ref() .and_then(|d| d.samsung_pay.clone()), + paze: connector_wallets_details_optional + .as_ref() + .and_then(|d| d.paze.clone()), } } }; diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index cc8b839cc809..2e37d26cdec5 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -492,6 +492,7 @@ impl From for api::GetToken { api_models::enums::PaymentMethodType::ApplePay => Self::ApplePayMetadata, api_models::enums::PaymentMethodType::SamsungPay => Self::SamsungPayMetadata, api_models::enums::PaymentMethodType::Paypal => Self::PaypalSdkMetadata, + api_models::enums::PaymentMethodType::Paze => Self::PazeMetadata, _ => Self::Connector, } } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index dd5e47b1005b..e868ea2c800f 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -193,6 +193,7 @@ pub enum GetToken { SamsungPayMetadata, ApplePayMetadata, PaypalSdkMetadata, + PazeMetadata, Connector, } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 992816a36160..64a2e82637fe 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -476,6 +476,7 @@ impl ForeignFrom for api_enums::PaymentMethod { | api_enums::PaymentMethodType::Dana | api_enums::PaymentMethodType::MbWay | api_enums::PaymentMethodType::MobilePay + | api_enums::PaymentMethodType::Paze | api_enums::PaymentMethodType::SamsungPay | api_enums::PaymentMethodType::Twint | api_enums::PaymentMethodType::Vipps From cfbb9bd3769a8bac579a0f536324fe4b5f68d9b2 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Mon, 30 Sep 2024 21:58:11 +0530 Subject: [PATCH 02/16] feat: Add paze decryption flow --- config/development.toml | 2 +- crates/api_models/src/payments.rs | 20 +++++++-- .../src/configs/secrets_transformers.rs | 30 +++++++++++++ crates/router/src/configs/settings.rs | 7 +++ crates/router/src/core/payments.rs | 45 +++++++++++++++---- .../src/core/payments/flows/session_flow.rs | 4 +- 6 files changed, 94 insertions(+), 14 deletions(-) diff --git a/config/development.toml b/config/development.toml index 2b4532a7a87a..b23c5f1653ae 100644 --- a/config/development.toml +++ b/config/development.toml @@ -608,7 +608,7 @@ apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" -[paze] +[paze_decrypt_keys] paze_private_key = "PAZE_PRIVATE_KEY" paze_private_key_passphrase = "PAZE_PRIVATE_KEY_PASSPHRASE" diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index c0815748e0e8..43aa279400c7 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -4968,7 +4968,9 @@ pub struct PazeSessionTokenData { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct PazeMetadata { - pub some_data: String, + pub client_id: String, + pub client_name: String, + pub client_profile_id: String, } #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -5137,6 +5139,14 @@ pub struct PaymentProcessingDetails { pub payment_processing_certificate_key: Secret, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, ToSchema)] +pub struct PazePaymentProcessingDetails { + #[schema(value_type = String)] + pub paze_private_key: Secret, + #[schema(value_type = String)] + pub paze_private_key_passphrase: Secret, +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] pub struct SessionTokenForSimplifiedApplePay { pub initiative_context: String, @@ -5169,8 +5179,12 @@ pub enum SessionToken { #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)] #[serde(rename_all = "lowercase")] pub struct PazeSessionTokenResponse { - /// Random - pub something: String, + /// Paze Client ID + pub client_id: String, + /// Client Name to be displayed on the Paze screen + pub client_name: String, + /// Paze Client Profile ID + pub client_profile_id: String, } #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)] diff --git a/crates/router/src/configs/secrets_transformers.rs b/crates/router/src/configs/secrets_transformers.rs index e1b68efc446c..6711504dcf4e 100644 --- a/crates/router/src/configs/secrets_transformers.rs +++ b/crates/router/src/configs/secrets_transformers.rs @@ -178,6 +178,27 @@ impl SecretsHandler for settings::ApplePayDecryptConfig { } } +#[async_trait::async_trait] +impl SecretsHandler for settings::PazeDecryptConfig { + async fn convert_to_raw_secret( + value: SecretStateContainer, + secret_management_client: &dyn SecretManagementInterface, + ) -> CustomResult, SecretsManagementError> { + let paze_decrypt_keys = value.get_inner(); + + let (paze_private_key, paze_private_key_passphrase) = tokio::try_join!( + secret_management_client.get_secret(paze_decrypt_keys.paze_private_key.clone()), + secret_management_client + .get_secret(paze_decrypt_keys.paze_private_key_passphrase.clone()), + )?; + + Ok(value.transition_state(|_| Self { + paze_private_key, + paze_private_key_passphrase, + })) + } +} + #[async_trait::async_trait] impl SecretsHandler for settings::ApplepayMerchantConfigs { async fn convert_to_raw_secret( @@ -380,6 +401,14 @@ pub(crate) async fn fetch_raw_secrets( .await .expect("Failed to decrypt applepay decrypt configs"); + #[allow(clippy::expect_used)] + let paze_decrypt_keys = settings::PazeDecryptConfig::convert_to_raw_secret( + conf.paze_decrypt_keys, + secret_management_client, + ) + .await + .expect("Failed to decrypt paze decrypt configs"); + #[allow(clippy::expect_used)] let applepay_merchant_configs = settings::ApplepayMerchantConfigs::convert_to_raw_secret( conf.applepay_merchant_configs, @@ -471,6 +500,7 @@ pub(crate) async fn fetch_raw_secrets( #[cfg(feature = "payouts")] payouts: conf.payouts, applepay_decrypt_keys, + paze_decrypt_keys, multiple_api_version_supported_connectors: conf.multiple_api_version_supported_connectors, applepay_merchant_configs, lock_settings: conf.lock_settings, diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index e59dd73cd3b4..e9e3bfa9bece 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -96,6 +96,7 @@ pub struct Settings { pub payouts: Payouts, pub payout_method_filters: ConnectorFilters, pub applepay_decrypt_keys: SecretStateContainer, + pub paze_decrypt_keys: SecretStateContainer, pub multiple_api_version_supported_connectors: MultipleApiVersionSupportedConnectors, pub applepay_merchant_configs: SecretStateContainer, pub lock_settings: LockSettings, @@ -722,6 +723,12 @@ pub struct ApplePayDecryptConfig { pub apple_pay_merchant_cert_key: Secret, } +#[derive(Debug, Deserialize, Clone, Default)] +pub struct PazeDecryptConfig { + pub paze_private_key: Secret, + pub paze_private_key_passphrase: Secret, +} + #[derive(Debug, Deserialize, Clone, Default)] #[serde(default)] pub struct LockerBasedRecipientConnectorList { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 283e02f975c3..781c320baf6a 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1700,6 +1700,9 @@ where ), ); } + TokenizationAction::DecryptPazeToken(payment_processing_details) => { + // Write decryption flow here. + } _ => (), }; @@ -2631,6 +2634,7 @@ pub enum TokenizationAction { SkipConnectorTokenization, DecryptApplePayToken(payments_api::PaymentProcessingDetails), TokenizeInConnectorAndApplepayPreDecrypt(payments_api::PaymentProcessingDetails), + DecryptPazeToken(payments_api::PazePaymentProcessingDetails), } #[allow(clippy::too_many_arguments)] @@ -2691,15 +2695,35 @@ where payment_data.get_payment_attempt().merchant_id.clone(), ); - let payment_method_action = decide_payment_method_tokenize_action( - state, - &connector, - payment_method, - payment_data.get_token(), - is_connector_tokenization_enabled, - apple_pay_flow, - ) - .await?; + let payment_method_action = if let Some(storage_enums::PaymentMethodType::Paze) = + payment_method_type + { + // Paze generates a one time use network token which should not be tokenized in the connector or router. + TokenizationAction::DecryptPazeToken(payments_api::PazePaymentProcessingDetails { + paze_private_key: state + .conf + .paze_decrypt_keys + .get_inner() + .paze_private_key + .clone(), + paze_private_key_passphrase: state + .conf + .paze_decrypt_keys + .get_inner() + .paze_private_key_passphrase + .clone(), + }) + } else { + decide_payment_method_tokenize_action( + state, + &connector, + payment_method, + payment_data.get_token(), + is_connector_tokenization_enabled, + apple_pay_flow, + ) + .await? + }; let connector_tokenization_action = match payment_method_action { TokenizationAction::TokenizeInRouter => { @@ -2753,6 +2777,9 @@ where ) => TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt( payment_processing_details, ), + TokenizationAction::DecryptPazeToken(paze_payment_processing_details) => { + TokenizationAction::DecryptPazeToken(paze_payment_processing_details) + } }; (payment_data.to_owned(), connector_tokenization_action) } diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 425ccd6101c9..78fab0bb4748 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -516,7 +516,9 @@ fn create_paze_session_token( response: Ok(types::PaymentsResponseData::SessionResponse { session_token: payment_types::SessionToken::Paze(Box::new( payment_types::PazeSessionTokenResponse { - something: paze_wallet_details.data.some_data, + client_id: paze_wallet_details.data.client_id, + client_name: paze_wallet_details.data.client_name, + client_profile_id: paze_wallet_details.data.client_profile_id, }, )), }), From c07a0391d13a3d8544f23eebd15226cf3542484c Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Tue, 1 Oct 2024 19:15:00 +0530 Subject: [PATCH 03/16] feat: Add paze decryption steps --- crates/api_models/src/payments.rs | 3 +- .../src/connectors/mollie/transformers.rs | 3 + .../src/connectors/stax/transformers.rs | 6 ++ .../src/payment_method_data.rs | 4 +- .../src/router_data.rs | 64 +++++++++++++++++++ .../connector/bankofamerica/transformers.rs | 6 ++ .../src/connector/braintree/transformers.rs | 6 ++ .../src/connector/checkout/transformers.rs | 6 ++ .../src/connector/cybersource/transformers.rs | 6 ++ .../src/connector/gocardless/transformers.rs | 3 +- .../src/connector/payme/transformers.rs | 3 + .../src/connector/square/transformers.rs | 3 + .../src/connector/stripe/transformers.rs | 3 + .../src/connector/wellsfargo/transformers.rs | 6 ++ crates/router/src/core/errors.rs | 10 +++ crates/router/src/core/payments.rs | 28 +++++++- crates/router/src/core/payments/helpers.rs | 63 +++++++++++++++++- .../router/src/core/payments/tokenization.rs | 5 ++ 18 files changed, 220 insertions(+), 8 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 8917b6593a95..d60f44ff4f6c 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2894,8 +2894,7 @@ impl GetAddressFromPaymentMethodData for WalletData { #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub struct PazeWalletData { - /// random data for now - pub payment_data: String, + pub complete_response: String, } #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] diff --git a/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs b/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs index d05259216321..a12434a460a7 100644 --- a/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs @@ -182,6 +182,9 @@ impl TryFrom<&MollieRouterData<&types::PaymentsAuthorizeRouterData>> for MollieP "Mollie" ))? } + PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Mollie"))? + } }), }, ))) diff --git a/crates/hyperswitch_connectors/src/connectors/stax/transformers.rs b/crates/hyperswitch_connectors/src/connectors/stax/transformers.rs index f7b2016a3705..686178e9621e 100644 --- a/crates/hyperswitch_connectors/src/connectors/stax/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/stax/transformers.rs @@ -82,6 +82,9 @@ impl TryFrom<&StaxRouterData<&types::PaymentsAuthorizeRouterData>> for StaxPayme PaymentMethodToken::ApplePayDecrypt(_) => Err( unimplemented_payment_method!("Apple Pay", "Simplified", "Stax"), )?, + PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Stax"))? + } }, idempotency_id: Some(item.router_data.connector_request_reference_id.clone()), }) @@ -99,6 +102,9 @@ impl TryFrom<&StaxRouterData<&types::PaymentsAuthorizeRouterData>> for StaxPayme PaymentMethodToken::ApplePayDecrypt(_) => Err( unimplemented_payment_method!("Apple Pay", "Simplified", "Stax"), )?, + PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Stax"))? + } }, idempotency_id: Some(item.router_data.connector_request_reference_id.clone()), }) diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 1ddbdd36dc3e..3176b56e63df 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -139,7 +139,7 @@ pub struct MifinityData { #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] pub struct PazeWalletData { - pub payment_data: String, + pub complete_response: String, } #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] @@ -768,7 +768,7 @@ impl From for ApplePayWalletData { impl From for PazeWalletData { fn from(value: api_models::payments::PazeWalletData) -> Self { Self { - payment_data: value.payment_data, + complete_response: value.complete_response, } } } diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index cd8ac85594e7..18b8d569b79a 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -220,6 +220,7 @@ pub struct AccessToken { pub enum PaymentMethodToken { Token(Secret), ApplePayDecrypt(Box), + PazeDecrypt(Box), } #[derive(Debug, Clone, serde::Deserialize)] @@ -241,6 +242,69 @@ pub struct ApplePayCryptogramData { pub eci_indicator: Option, } +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PazeDecryptedData { + pub client_id: Secret, + pub profile_id: String, + pub token: PazeToken, + pub payment_card_network: common_enums::enums::CardNetwork, + pub dynamic_data: Vec, + pub billing_address: Option, + pub consumer: PazeConsumer, + pub eci: Option, +} + +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PazeToken { + pub payment_token: cards::CardNumber, + pub token_expiration_month: Secret, + pub token_expiration_year: Secret, + pub payment_account_reference: Secret, +} + +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PazeDynamicData { + pub dynamic_data_value: Option, + pub dynamic_data_type: Option, + pub dynamic_data_expiration: Option, +} + +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PazeAddress { + pub name: Option>, + pub line1: Option>, + pub line2: Option>, + pub line3: Option>, + pub city: Option>, + pub state: Option>, + pub zip: Option>, + pub country_code: Option, +} + +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PazeConsumer { + // This is consumer data not customer data. + pub first_name: Option>, + pub last_name: Option>, + pub full_name: Secret, + pub email_address: common_utils::pii::Email, + pub mobile_number: Option, + pub country_code: Option, + pub language_code: Option, +} + +#[derive(Debug, Clone, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PazePhoneNumber { + pub country_code: Secret, + pub phone_number: Secret, +} + #[derive(Debug, Default, Clone)] pub struct RecurringMandatePaymentData { pub payment_method_type: Option, //required for making recurring payment using saved payment method through stripe diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index 3fdf57e9cd93..bf2fb93a7e17 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -962,6 +962,9 @@ impl TryFrom<&BankOfAmericaRouterData<&types::PaymentsAuthorizeRouterData>> "Bank Of America" ))? } + types::PaymentMethodToken::PazeDecrypt(_) => Err( + unimplemented_payment_method!("Paze", "Bank Of America"), + )?, }, None => { let email = item.router_data.request.get_email()?; @@ -2314,6 +2317,9 @@ impl TryFrom<(&types::SetupMandateRouterData, domain::ApplePayWalletData)> "Manual", "Bank Of America" ))?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Bank Of America"))? + } }, None => PaymentInformation::from(&apple_pay_data), }; diff --git a/crates/router/src/connector/braintree/transformers.rs b/crates/router/src/connector/braintree/transformers.rs index 05d8c1c559d6..29f741d8bdc2 100644 --- a/crates/router/src/connector/braintree/transformers.rs +++ b/crates/router/src/connector/braintree/transformers.rs @@ -1591,6 +1591,9 @@ impl types::PaymentMethodToken::ApplePayDecrypt(_) => Err( unimplemented_payment_method!("Apple Pay", "Simplified", "Braintree"), )?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Braintree"))? + } }, transaction: transaction_body, }, @@ -1689,6 +1692,9 @@ fn get_braintree_redirect_form( "Simplified", "Braintree" ))?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Braintree"))? + } }, bin: match card_details { domain::PaymentMethodData::Card(card_details) => { diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index f2d76dff288c..2950fdb6bd1a 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -302,6 +302,9 @@ impl TryFrom<&CheckoutRouterData<&types::PaymentsAuthorizeRouterData>> for Payme types::PaymentMethodToken::ApplePayDecrypt(_) => Err( unimplemented_payment_method!("Apple Pay", "Simplified", "Checkout"), )?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Checkout"))? + } }, })), domain::WalletData::ApplePay(_) => { @@ -328,6 +331,9 @@ impl TryFrom<&CheckoutRouterData<&types::PaymentsAuthorizeRouterData>> for Payme }, ))) } + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Checkout"))? + } } } domain::WalletData::AliPayQr(_) diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index 2119b9c53dce..b5b0fb1725a3 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -173,6 +173,9 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest { types::PaymentMethodToken::Token(_) => Err( unimplemented_payment_method!("Apple Pay", "Manual", "Cybersource"), )?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Cybersource"))? + } }, None => ( PaymentInformation::ApplePayToken(Box::new( @@ -1637,6 +1640,9 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> "Cybersource" ))? } + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Cybersource"))? + } }, None => { let email = item diff --git a/crates/router/src/connector/gocardless/transformers.rs b/crates/router/src/connector/gocardless/transformers.rs index ff2f9d95026e..4982aaf4d887 100644 --- a/crates/router/src/connector/gocardless/transformers.rs +++ b/crates/router/src/connector/gocardless/transformers.rs @@ -429,7 +429,8 @@ impl TryFrom<&types::SetupMandateRouterData> for GocardlessMandateRequest { let payment_method_token = item.get_payment_method_token()?; let customer_bank_account = match payment_method_token { types::PaymentMethodToken::Token(token) => Ok(token), - types::PaymentMethodToken::ApplePayDecrypt(_) => { + types::PaymentMethodToken::ApplePayDecrypt(_) + | types::PaymentMethodToken::PazeDecrypt(_) => { Err(errors::ConnectorError::NotImplemented( "Setup Mandate flow for selected payment method through Gocardless".to_string(), )) diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 43647fe3ea75..b4aa66a1c493 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -716,6 +716,9 @@ impl TryFrom<&types::PaymentsCompleteAuthorizeRouterData> for Pay3dsRequest { types::PaymentMethodToken::ApplePayDecrypt(_) => Err( unimplemented_payment_method!("Apple Pay", "Simplified", "Payme"), )?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Payme"))? + } }; Ok(Self { buyer_email, diff --git a/crates/router/src/connector/square/transformers.rs b/crates/router/src/connector/square/transformers.rs index 34cdbae2a171..0e030db21f56 100644 --- a/crates/router/src/connector/square/transformers.rs +++ b/crates/router/src/connector/square/transformers.rs @@ -268,6 +268,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for SquarePaymentsRequest { types::PaymentMethodToken::ApplePayDecrypt(_) => Err( unimplemented_payment_method!("Apple Pay", "Simplified", "Square"), )?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Square"))? + } }, amount_money: SquarePaymentsAmountData { amount: item.request.amount, diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 45e5dc2c5e5d..acd20a9978d6 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -1778,6 +1778,9 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent wallet_name: "Apple Pay".to_string(), })? } + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(crate::unimplemented_payment_method!("Paze", "Stripe"))? + } }; Some(StripePaymentMethodData::Wallet( StripeWallet::ApplepayPayment(ApplepayPayment { diff --git a/crates/router/src/connector/wellsfargo/transformers.rs b/crates/router/src/connector/wellsfargo/transformers.rs index 21994d900e89..ee34c26d6709 100644 --- a/crates/router/src/connector/wellsfargo/transformers.rs +++ b/crates/router/src/connector/wellsfargo/transformers.rs @@ -135,6 +135,9 @@ impl TryFrom<&types::SetupMandateRouterData> for WellsfargoZeroMandateRequest { types::PaymentMethodToken::Token(_) => Err( unimplemented_payment_method!("Apple Pay", "Manual", "Wellsfargo"), )?, + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Wellsfargo"))? + } }, None => ( PaymentInformation::ApplePayToken(Box::new( @@ -1159,6 +1162,9 @@ impl TryFrom<&WellsfargoRouterData<&types::PaymentsAuthorizeRouterData>> "Wellsfargo" ))? } + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Wellsfargo"))? + } }, None => { let email = item.router_data.request.get_email()?; diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index c56bfaca9135..aa4ff406a2ce 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -234,6 +234,16 @@ pub enum ApplePayDecryptionError { DerivingSharedSecretKeyFailed, } +#[derive(Debug, thiserror::Error)] +pub enum PazeDecryptionError { + #[error("Failed to base64 decode input data")] + Base64DecodingFailed, + #[error("Failed to decrypt input data")] + DecryptionFailed, + #[error("Certificate parsing failed")] + CertificateParsingFailed, +} + #[cfg(feature = "detailed_errors")] pub mod error_stack_parsing { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 4cacd27a9622..74263f840a2c 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -34,7 +34,7 @@ use diesel_models::{ephemeral_key, fraud_check::FraudCheck}; use error_stack::{report, ResultExt}; use events::EventInfo; use futures::future::join_all; -use helpers::ApplePayData; +use helpers::{decrypt_paze_token, ApplePayData}; #[cfg(feature = "v2")] use hyperswitch_domain_models::payments::PaymentIntentData; pub use hyperswitch_domain_models::{ @@ -1742,7 +1742,31 @@ where ); } TokenizationAction::DecryptPazeToken(payment_processing_details) => { - // Write decryption flow here. + let paze_data = match payment_data.get_payment_method_data() { + Some(domain::PaymentMethodData::Wallet(domain::WalletData::Paze(wallet_data))) => { + Some( + decrypt_paze_token( + wallet_data.clone(), + payment_processing_details.paze_private_key.clone(), + payment_processing_details + .paze_private_key_passphrase + .clone(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError)?, + ) + } + _ => None, + }; + let paze_decrypted_data = paze_data + .parse_value::( + "PazeDecryptedData", + ) + .change_context(errors::ApiErrorResponse::InternalServerError)?; + router_data.payment_method_token = Some( + hyperswitch_domain_models::router_data::PaymentMethodToken::PazeDecrypt(Box::new( + paze_decrypted_data, + )), + ); } _ => (), }; diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 244a3c63f6f7..b44b080f7990 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -30,7 +30,7 @@ use futures::future::Either; use hyperswitch_domain_models::payments::payment_intent::CustomerData; use hyperswitch_domain_models::{ mandates::MandateData, - payment_method_data::GetPaymentMethodType, + payment_method_data::{GetPaymentMethodType, PazeWalletData}, payments::{ payment_attempt::PaymentAttempt, payment_intent::PaymentIntentFetchConstraints, PaymentIntent, @@ -4989,6 +4989,67 @@ impl ApplePayData { } } +pub fn decrypt_paze_token( + paze_wallet_data: PazeWalletData, + paze_private_key: masking::Secret, + paze_private_key_passphrase: masking::Secret, +) -> CustomResult { + let decoded_paze_private_key = BASE64_ENGINE + .decode(paze_private_key.expose().as_bytes()) + .change_context(errors::PazeDecryptionError::Base64DecodingFailed)?; + let decrypted_private_key = openssl::rsa::Rsa::private_key_from_pem_passphrase( + decoded_paze_private_key.as_slice(), + paze_private_key_passphrase.expose().as_bytes(), + ) + .change_context(errors::PazeDecryptionError::CertificateParsingFailed)?; + let decrypted_private_key_pem = String::from_utf8( + decrypted_private_key + .private_key_to_pem() + .change_context(errors::PazeDecryptionError::CertificateParsingFailed)?, + ) + .change_context(errors::PazeDecryptionError::CertificateParsingFailed)?; + let decrypter = jwe::RSA_OAEP_256 + .decrypter_from_pem(decrypted_private_key_pem) + .change_context(errors::PazeDecryptionError::CertificateParsingFailed)?; + + let paze_complete_response: Vec<&str> = paze_wallet_data.complete_response.split('.').collect(); + let encrypted_jwe_key = paze_complete_response + .get(1) + .ok_or(errors::PazeDecryptionError::DecryptionFailed)? + .to_string(); + let decoded_jwe_key = base64::engine::general_purpose::URL_SAFE_NO_PAD + .decode(encrypted_jwe_key) + .change_context(errors::PazeDecryptionError::Base64DecodingFailed)?; + let jws_body: JwsBody = serde_json::from_slice(&decoded_jwe_key) + .change_context(errors::PazeDecryptionError::DecryptionFailed)?; + + let (dst_payload, _dst_header) = + jwe::deserialize_compact(&jws_body.secured_payload, &decrypter) + .change_context(errors::PazeDecryptionError::DecryptionFailed)?; + let encoded_secured_payload_element = String::from_utf8(dst_payload) + .change_context(errors::PazeDecryptionError::DecryptionFailed)? + .split('.') + .collect::>() + .get(1) + .ok_or(errors::PazeDecryptionError::DecryptionFailed)? + .to_string(); + let decoded_secured_payload_element = base64::engine::general_purpose::URL_SAFE_NO_PAD + .decode(encoded_secured_payload_element) + .change_context(errors::PazeDecryptionError::Base64DecodingFailed)?; + let parsed_decrypted: serde_json::Value = + serde_json::from_slice(&decoded_secured_payload_element) + .change_context(errors::PazeDecryptionError::DecryptionFailed)?; + Ok(parsed_decrypted) +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct JwsBody { + pub payload_id: String, + pub session_id: String, + pub secured_payload: String, +} + pub fn get_key_params_for_surcharge_details( payment_method_data: &domain::PaymentMethodData, ) -> Option<( diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 6815d2dfc4fe..ee75536e7c96 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -133,6 +133,11 @@ where message: "Apple Pay Decrypt token is not supported".to_string(), })? } + types::PaymentMethodToken::PazeDecrypt(_) => { + Err(errors::ApiErrorResponse::NotSupported { + message: "Paze Decrypt token is not supported".to_string(), + })? + } }; Some((connector_name, token)) } else { From 2891021269bdf8af69e02e00ca4f51e377b04ee0 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Wed, 2 Oct 2024 23:51:11 +0530 Subject: [PATCH 04/16] feat(connector): [CYBERSOURCE] Implement Wallet Paze --- config/config.example.toml | 1 + config/deployments/integration_test.toml | 1 + config/deployments/production.toml | 1 + config/deployments/sandbox.toml | 1 + config/development.toml | 1 + config/docker_compose.toml | 1 + .../src/router_data.rs | 2 +- .../src/connector/cybersource/transformers.rs | 103 +++++++++++++++++- 8 files changed, 108 insertions(+), 3 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index a6aeba7427ab..362a64f14ca8 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -537,6 +537,7 @@ debit = { currency = "USD,GBP,EUR" } apple_pay = { currency = "USD,GBP,EUR" } google_pay = { currency = "USD,GBP,EUR" } samsung_pay = { currency = "USD,GBP,EUR" } +paze = { currency = "USD" } [pm_filters.stax] credit = { currency = "USD" } diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml index 35385af59743..3ea9afdb56e6 100644 --- a/config/deployments/integration_test.toml +++ b/config/deployments/integration_test.toml @@ -306,6 +306,7 @@ debit = { currency = "USD,GBP,EUR" } apple_pay = { currency = "USD,GBP,EUR" } google_pay = { currency = "USD,GBP,EUR" } samsung_pay = { currency = "USD,GBP,EUR" } +paze = { currency = "USD" } [pm_filters.volt] open_banking_uk = {country = "DE,GB,AT,BE,CY,EE,ES,FI,FR,GR,HR,IE,IT,LT,LU,LV,MT,NL,PT,SI,SK,BG,CZ,DK,HU,NO,PL,RO,SE,AU,BR", currency = "EUR,GBP,DKK,NOK,PLN,SEK,AUD,BRL"} diff --git a/config/deployments/production.toml b/config/deployments/production.toml index cab8317dfa45..1d3a13d1446b 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -280,6 +280,7 @@ debit = { currency = "USD,GBP,EUR" } apple_pay = { currency = "USD,GBP,EUR" } google_pay = { currency = "USD,GBP,EUR" } samsung_pay = { currency = "USD,GBP,EUR" } +paze = { currency = "USD" } [pm_filters.braintree] paypal.currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index 78972c0b2907..9a7349c9f5e1 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -283,6 +283,7 @@ debit = { currency = "USD,GBP,EUR" } apple_pay = { currency = "USD,GBP,EUR" } google_pay = { currency = "USD,GBP,EUR" } samsung_pay = { currency = "USD,GBP,EUR" } +paze = { currency = "USD" } [pm_filters.braintree] paypal.currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" diff --git a/config/development.toml b/config/development.toml index b718ea576258..54da9909372a 100644 --- a/config/development.toml +++ b/config/development.toml @@ -451,6 +451,7 @@ debit = { currency = "USD,GBP,EUR" } apple_pay = { currency = "USD,GBP,EUR" } google_pay = { currency = "USD,GBP,EUR" } samsung_pay = { currency = "USD,GBP,EUR" } +paze = { currency = "USD" } [pm_filters.braintree] paypal = { currency = "AUD,BRL,CAD,CNY,CZK,DKK,EUR,HKD,HUF,ILS,JPY,MYR,MXN,TWD,NZD,NOK,PHP,PLN,GBP,RUB,SGD,SEK,CHF,THB,USD" } diff --git a/config/docker_compose.toml b/config/docker_compose.toml index fad5759648b4..7733966f98e2 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -417,6 +417,7 @@ debit = { currency = "USD,GBP,EUR" } apple_pay = { currency = "USD,GBP,EUR" } google_pay = { currency = "USD,GBP,EUR" } samsung_pay = { currency = "USD,GBP,EUR" } +paze = { currency = "USD" } [pm_filters.helcim] credit = { currency = "USD" } diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index 18b8d569b79a..d4c4e6b52659 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -250,7 +250,7 @@ pub struct PazeDecryptedData { pub token: PazeToken, pub payment_card_network: common_enums::enums::CardNetwork, pub dynamic_data: Vec, - pub billing_address: Option, + pub billing_address: PazeAddress, pub consumer: PazeConsumer, pub eci: Option, } diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index b5b0fb1725a3..95515a826b41 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -21,7 +21,7 @@ use serde_json::Value; use crate::connector::utils::PayoutsData; use crate::{ connector::utils::{ - self, AddressDetailsData, ApplePayDecrypt, CardData, NetworkTokenData, + self, AddressData, AddressDetailsData, ApplePayDecrypt, CardData, NetworkTokenData, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingData, PaymentsSetupMandateRequestData, PaymentsSyncRequestData, RecurringMandateData, RouterData, @@ -1320,6 +1320,93 @@ impl } } +impl + TryFrom<( + &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>, + Box, + )> for CybersourcePaymentsRequest +{ + type Error = error_stack::Report; + fn try_from( + (item, paze_data): ( + &CybersourceRouterData<&types::PaymentsAuthorizeRouterData>, + Box, + ), + ) -> Result { + let email = item.router_data.request.get_email()?; + let (first_name, last_name) = paze_data + .billing_address + .name + .unwrap_or( + item.router_data + .get_optional_billing() + .and_then(|address| address.get_optional_full_name()) + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "billing_address.name", + })?, + ) + .peek() + .split_once(' ') + .map(|(first, last)| (first.to_string(), last.to_string())) + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "billing_address.name", + })?; + let bill_to = BillTo { + first_name: Some(Secret::from(first_name)), + last_name: Some(Secret::from(last_name)), + address1: paze_data.billing_address.line1, + locality: paze_data.billing_address.city.map(|city| city.expose()), + administrative_area: Some(Secret::from( + //Paze wallet is currently supported in US only + common_enums::UsStatesAbbreviation::foreign_try_from( + paze_data + .billing_address + .state + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "billing_address.state", + })? + .peek() + .to_owned(), + )? + .to_string(), + )), + postal_code: paze_data.billing_address.zip, + country: paze_data.billing_address.country_code, + email, + }; + let order_information = OrderInformationWithBill::from((item, Some(bill_to))); + + let payment_information = + PaymentInformation::NetworkToken(Box::new(NetworkTokenPaymentInformation { + tokenized_card: NetworkTokenizedCard { + number: paze_data.token.payment_token, + expiration_month: paze_data.token.token_expiration_month, + expiration_year: paze_data.token.token_expiration_year, + cryptogram: Some(paze_data.token.payment_account_reference), + transaction_type: "1".to_string(), + }, + })); + + let processing_information = ProcessingInformation::try_from((item, None, None))?; + let client_reference_information = ClientReferenceInformation::from(item); + let merchant_defined_information = item + .router_data + .request + .metadata + .clone() + .map(Vec::::foreign_from); + + Ok(Self { + processing_information, + payment_information, + order_information, + client_reference_information, + consumer_authentication_information: None, + merchant_defined_information, + }) + } +} + impl TryFrom<( &CybersourceRouterData<&types::PaymentsCompleteAuthorizeRouterData>, @@ -1717,6 +1804,19 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> domain::WalletData::SamsungPay(samsung_pay_data) => { Self::try_from((item, samsung_pay_data)) } + domain::WalletData::Paze(_) => { + match item.router_data.payment_method_token.clone() { + Some(types::PaymentMethodToken::PazeDecrypt( + paze_decrypted_data, + )) => Self::try_from((item, paze_decrypted_data)), + _ => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message( + "Cybersource", + ), + ) + .into()), + } + } domain::WalletData::AliPayQr(_) | domain::WalletData::AliPayRedirect(_) | domain::WalletData::AliPayHkRedirect(_) @@ -1733,7 +1833,6 @@ impl TryFrom<&CybersourceRouterData<&types::PaymentsAuthorizeRouterData>> | domain::WalletData::MobilePayRedirect(_) | domain::WalletData::PaypalRedirect(_) | domain::WalletData::PaypalSdk(_) - | domain::WalletData::Paze(_) | domain::WalletData::TwintRedirect {} | domain::WalletData::VippsRedirect {} | domain::WalletData::TouchNGoRedirect(_) From 27a88963fd6f2a3ad48f0c8fc7d566247c9a138a Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Thu, 3 Oct 2024 00:35:24 +0530 Subject: [PATCH 05/16] chore: Fix compilation errors --- .../src/connectors/square/transformers.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/hyperswitch_connectors/src/connectors/square/transformers.rs b/crates/hyperswitch_connectors/src/connectors/square/transformers.rs index 4e2b30a574b3..ad09e7445d4f 100644 --- a/crates/hyperswitch_connectors/src/connectors/square/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/square/transformers.rs @@ -119,6 +119,7 @@ impl TryFrom<(&types::TokenizationRouterData, WalletData)> for SquareTokenReques | WalletData::MobilePayRedirect(_) | WalletData::PaypalRedirect(_) | WalletData::PaypalSdk(_) + | WalletData::Paze(_) | WalletData::SamsungPay(_) | WalletData::TwintRedirect {} | WalletData::VippsRedirect {} @@ -263,6 +264,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for SquarePaymentsRequest { PaymentMethodToken::ApplePayDecrypt(_) => Err( unimplemented_payment_method!("Apple Pay", "Simplified", "Square"), )?, + PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Square"))? + } }, amount_money: SquarePaymentsAmountData { amount: item.request.amount, From c993ab0eafa76c4a7befa72493db029547ea8d8e Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Thu, 3 Oct 2024 23:12:25 +0530 Subject: [PATCH 06/16] chore: Resolve PR Comments --- config/config.example.toml | 4 ++ config/deployments/env_specific.toml | 4 ++ crates/api_models/src/payments.rs | 10 +-- .../src/payment_method_data.rs | 2 +- crates/router/src/core/payments.rs | 67 ++++++++++--------- crates/router/src/core/payments/helpers.rs | 6 +- 6 files changed, 52 insertions(+), 41 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 7c3f8ae99fcd..493ba32d29bb 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -580,6 +580,10 @@ apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" # Private key apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" # Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" # Private key generated by RSA:2048 algorithm. Refer Hyperswitch Docs (https://docs.hyperswitch.io/hyperswitch-cloud/payment-methods-setup/wallets/apple-pay/ios-application/) to generate the private key +[paze_decrypt_keys] +paze_private_key = "PAZE_PRIVATE_KEY" # Base 64 Encoded Private Key File cakey.pem generated for Paze +paze_private_key_passphrase = "PAZE_PRIVATE_KEY_PASSPHRASE" # PEM Passphrase used for generating Private Key File cakey.pem + [applepay_merchant_configs] # Run below command to get common merchant identifier for applepay in shell # diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml index db43cac979b7..08dcc28b8876 100644 --- a/config/deployments/env_specific.toml +++ b/config/deployments/env_specific.toml @@ -29,6 +29,10 @@ apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" # Private key apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" # Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" # Private key generated by RSA:2048 algorithm. Refer Hyperswitch Docs (https://docs.hyperswitch.io/hyperswitch-cloud/payment-methods-setup/wallets/apple-pay/ios-application/) to generate the private key +[paze_decrypt_keys] +paze_private_key = "PAZE_PRIVATE_KEY" # Base 64 Encoded Private Key File cakey.pem generated for Paze +paze_private_key_passphrase = "PAZE_PRIVATE_KEY_PASSPHRASE" # PEM Passphrase used for generating Private Key File cakey.pem + [applepay_merchant_configs] common_merchant_identifier = "APPLE_PAY_COMMON_MERCHANT_IDENTIFIER" # Refer to config.example.toml to learn how you can generate this value merchant_cert = "APPLE_PAY_MERCHANT_CERTIFICATE" # Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index d60f44ff4f6c..9595f4c35c8f 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2894,7 +2894,7 @@ impl GetAddressFromPaymentMethodData for WalletData { #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub struct PazeWalletData { - pub complete_response: String, + pub complete_response: Secret, } #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] @@ -5114,14 +5114,6 @@ pub struct PaymentProcessingDetails { pub payment_processing_certificate_key: Secret, } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, ToSchema)] -pub struct PazePaymentProcessingDetails { - #[schema(value_type = String)] - pub paze_private_key: Secret, - #[schema(value_type = String)] - pub paze_private_key_passphrase: Secret, -} - #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)] pub struct SessionTokenForSimplifiedApplePay { pub initiative_context: String, diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 3176b56e63df..5a3b9cf17124 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -139,7 +139,7 @@ pub struct MifinityData { #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] pub struct PazeWalletData { - pub complete_response: String, + pub complete_response: Secret, } #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index f368a5fc18c2..5edbbe079847 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2718,6 +2718,14 @@ async fn decide_payment_method_tokenize_action( } } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, utoipa::ToSchema)] +pub struct PazePaymentProcessingDetails { + #[schema(value_type = String)] + pub paze_private_key: Secret, + #[schema(value_type = String)] + pub paze_private_key_passphrase: Secret, +} + #[derive(Clone, Debug)] pub enum TokenizationAction { TokenizeInRouter, @@ -2727,7 +2735,7 @@ pub enum TokenizationAction { SkipConnectorTokenization, DecryptApplePayToken(payments_api::PaymentProcessingDetails), TokenizeInConnectorAndApplepayPreDecrypt(payments_api::PaymentProcessingDetails), - DecryptPazeToken(payments_api::PazePaymentProcessingDetails), + DecryptPazeToken(PazePaymentProcessingDetails), } #[cfg(feature = "v2")] @@ -2808,35 +2816,34 @@ where payment_data.get_payment_attempt().merchant_id.clone(), ); - let payment_method_action = if let Some(storage_enums::PaymentMethodType::Paze) = - payment_method_type - { - // Paze generates a one time use network token which should not be tokenized in the connector or router. - TokenizationAction::DecryptPazeToken(payments_api::PazePaymentProcessingDetails { - paze_private_key: state - .conf - .paze_decrypt_keys - .get_inner() - .paze_private_key - .clone(), - paze_private_key_passphrase: state - .conf - .paze_decrypt_keys - .get_inner() - .paze_private_key_passphrase - .clone(), - }) - } else { - decide_payment_method_tokenize_action( - state, - &connector, - payment_method, - payment_data.get_token(), - is_connector_tokenization_enabled, - apple_pay_flow, - ) - .await? - }; + let payment_method_action = + if let Some(storage_enums::PaymentMethodType::Paze) = payment_method_type { + // Paze generates a one time use network token which should not be tokenized in the connector or router. + TokenizationAction::DecryptPazeToken(PazePaymentProcessingDetails { + paze_private_key: state + .conf + .paze_decrypt_keys + .get_inner() + .paze_private_key + .clone(), + paze_private_key_passphrase: state + .conf + .paze_decrypt_keys + .get_inner() + .paze_private_key_passphrase + .clone(), + }) + } else { + decide_payment_method_tokenize_action( + state, + &connector, + payment_method, + payment_data.get_token(), + is_connector_tokenization_enabled, + apple_pay_flow, + ) + .await? + }; let connector_tokenization_action = match payment_method_action { TokenizationAction::TokenizeInRouter => { diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index b44b080f7990..e43c69541b9b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -5012,7 +5012,11 @@ pub fn decrypt_paze_token( .decrypter_from_pem(decrypted_private_key_pem) .change_context(errors::PazeDecryptionError::CertificateParsingFailed)?; - let paze_complete_response: Vec<&str> = paze_wallet_data.complete_response.split('.').collect(); + let paze_complete_response: Vec<&str> = paze_wallet_data + .complete_response + .peek() + .split('.') + .collect(); let encrypted_jwe_key = paze_complete_response .get(1) .ok_or(errors::PazeDecryptionError::DecryptionFailed)? From 8d4bb36ddce61d50671257a9d4dbef0547e9c1af Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Thu, 3 Oct 2024 23:22:23 +0530 Subject: [PATCH 07/16] chore: Resolve PR Comments 2 --- crates/router/src/core/payments.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 5edbbe079847..3f36e87feac5 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1752,7 +1752,8 @@ where .paze_private_key_passphrase .clone(), ) - .change_context(errors::ApiErrorResponse::InternalServerError)?, + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to decrypt paze token")?, ) } _ => None, @@ -1761,7 +1762,8 @@ where .parse_value::( "PazeDecryptedData", ) - .change_context(errors::ApiErrorResponse::InternalServerError)?; + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse PazeDecryptedData")?; router_data.payment_method_token = Some( hyperswitch_domain_models::router_data::PaymentMethodToken::PazeDecrypt(Box::new( paze_decrypted_data, From b29fb8e0e6afed6fe284b869bcb086e412def9d7 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Fri, 4 Oct 2024 18:57:21 +0530 Subject: [PATCH 08/16] chore: Resolve PR Comments --- .../src/payment_method_data.rs | 1 - .../src/router_data.rs | 2 +- crates/router/src/core/payments.rs | 151 +++++++++--------- crates/router/src/core/payments/helpers.rs | 4 +- 4 files changed, 82 insertions(+), 76 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 5a3b9cf17124..3ccfabf021cd 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -135,7 +135,6 @@ pub struct MifinityData { pub language_preference: Option, } -//this data goes to connector: remove this comment #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "snake_case")] pub struct PazeWalletData { diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index d4c4e6b52659..b41b42eaa2d2 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -267,7 +267,7 @@ pub struct PazeToken { #[derive(Debug, Clone, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct PazeDynamicData { - pub dynamic_data_value: Option, + pub dynamic_data_value: Option>, pub dynamic_data_type: Option, pub dynamic_data_expiration: Option, } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 3f36e87feac5..1346017b8d11 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2667,54 +2667,79 @@ async fn decide_payment_method_tokenize_action( pm_parent_token: Option<&str>, is_connector_tokenization_enabled: bool, apple_pay_flow: Option, + payment_method_type: Option, ) -> RouterResult { - match pm_parent_token { - None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) { - (true, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => { - TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt( - payment_processing_details, - ) - } - (true, _) => TokenizationAction::TokenizeInConnectorAndRouter, - (false, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => { - TokenizationAction::DecryptApplePayToken(payment_processing_details) - } - (false, _) => TokenizationAction::TokenizeInRouter, - }), - Some(token) => { - let redis_conn = state - .store - .get_redis_conn() - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to get redis connection")?; - - let key = format!( - "pm_token_{}_{}_{}", - token.to_owned(), - payment_method, - connector_name - ); + if let Some(storage_enums::PaymentMethodType::Paze) = payment_method_type { + // Paze generates a one time use network token which should not be tokenized in the connector or router. + Ok(TokenizationAction::DecryptPazeToken( + PazePaymentProcessingDetails { + paze_private_key: state + .conf + .paze_decrypt_keys + .get_inner() + .paze_private_key + .clone(), + paze_private_key_passphrase: state + .conf + .paze_decrypt_keys + .get_inner() + .paze_private_key_passphrase + .clone(), + }, + )) + } else { + match pm_parent_token { + None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) { + (true, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => { + TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt( + payment_processing_details, + ) + } + (true, _) => TokenizationAction::TokenizeInConnectorAndRouter, + (false, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => { + TokenizationAction::DecryptApplePayToken(payment_processing_details) + } + (false, _) => TokenizationAction::TokenizeInRouter, + }), + Some(token) => { + let redis_conn = state + .store + .get_redis_conn() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to get redis connection")?; + + let key = format!( + "pm_token_{}_{}_{}", + token.to_owned(), + payment_method, + connector_name + ); - let connector_token_option = redis_conn - .get_key::>(&key) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Failed to fetch the token from redis")?; + let connector_token_option = redis_conn + .get_key::>(&key) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to fetch the token from redis")?; - match connector_token_option { - Some(connector_token) => Ok(TokenizationAction::ConnectorToken(connector_token)), - None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) { - (true, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => { - TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt( - payment_processing_details, - ) - } - (true, _) => TokenizationAction::TokenizeInConnectorAndRouter, - (false, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => { - TokenizationAction::DecryptApplePayToken(payment_processing_details) + match connector_token_option { + Some(connector_token) => { + Ok(TokenizationAction::ConnectorToken(connector_token)) } - (false, _) => TokenizationAction::TokenizeInRouter, - }), + None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) { + ( + true, + Some(domain::ApplePayFlow::Simplified(payment_processing_details)), + ) => TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt( + payment_processing_details, + ), + (true, _) => TokenizationAction::TokenizeInConnectorAndRouter, + ( + false, + Some(domain::ApplePayFlow::Simplified(payment_processing_details)), + ) => TokenizationAction::DecryptApplePayToken(payment_processing_details), + (false, _) => TokenizationAction::TokenizeInRouter, + }), + } } } } @@ -2818,34 +2843,16 @@ where payment_data.get_payment_attempt().merchant_id.clone(), ); - let payment_method_action = - if let Some(storage_enums::PaymentMethodType::Paze) = payment_method_type { - // Paze generates a one time use network token which should not be tokenized in the connector or router. - TokenizationAction::DecryptPazeToken(PazePaymentProcessingDetails { - paze_private_key: state - .conf - .paze_decrypt_keys - .get_inner() - .paze_private_key - .clone(), - paze_private_key_passphrase: state - .conf - .paze_decrypt_keys - .get_inner() - .paze_private_key_passphrase - .clone(), - }) - } else { - decide_payment_method_tokenize_action( - state, - &connector, - payment_method, - payment_data.get_token(), - is_connector_tokenization_enabled, - apple_pay_flow, - ) - .await? - }; + let payment_method_action = decide_payment_method_tokenize_action( + state, + &connector, + payment_method, + payment_data.get_token(), + is_connector_tokenization_enabled, + apple_pay_flow, + payment_method_type.clone(), + ) + .await?; let connector_tokenization_action = match payment_method_action { TokenizationAction::TokenizeInRouter => { diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index e43c69541b9b..9d5da12aa6cf 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -5027,10 +5027,10 @@ pub fn decrypt_paze_token( let jws_body: JwsBody = serde_json::from_slice(&decoded_jwe_key) .change_context(errors::PazeDecryptionError::DecryptionFailed)?; - let (dst_payload, _dst_header) = + let (deserialized_payload, _deserialized_header) = jwe::deserialize_compact(&jws_body.secured_payload, &decrypter) .change_context(errors::PazeDecryptionError::DecryptionFailed)?; - let encoded_secured_payload_element = String::from_utf8(dst_payload) + let encoded_secured_payload_element = String::from_utf8(deserialized_payload) .change_context(errors::PazeDecryptionError::DecryptionFailed)? .split('.') .collect::>() From c31396ecd35fb5bbace2f07e8fc0aea96e623534 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Sun, 6 Oct 2024 19:13:50 +0530 Subject: [PATCH 09/16] chore: Resolve PR comments sunday --- config/config.example.toml | 2 +- config/deployments/env_specific.toml | 2 +- .../src/configs/secrets_transformers.rs | 15 ++++---- crates/router/src/configs/settings.rs | 2 +- .../src/connector/cybersource/transformers.rs | 35 +++++++++---------- crates/router/src/core/payments.rs | 29 +++++++-------- crates/router/src/core/payments/helpers.rs | 4 +-- 7 files changed, 44 insertions(+), 45 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index 493ba32d29bb..5dde34ea486e 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -581,7 +581,7 @@ apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" # Merchant Ce apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" # Private key generated by RSA:2048 algorithm. Refer Hyperswitch Docs (https://docs.hyperswitch.io/hyperswitch-cloud/payment-methods-setup/wallets/apple-pay/ios-application/) to generate the private key [paze_decrypt_keys] -paze_private_key = "PAZE_PRIVATE_KEY" # Base 64 Encoded Private Key File cakey.pem generated for Paze +paze_private_key = "PAZE_PRIVATE_KEY" # Base 64 Encoded Private Key File cakey.pem generated for Paze -> Command to create private key: openssl req -newkey rsa:2048 -x509 -keyout cakey.pem -out cacert.pem -days 365 paze_private_key_passphrase = "PAZE_PRIVATE_KEY_PASSPHRASE" # PEM Passphrase used for generating Private Key File cakey.pem [applepay_merchant_configs] diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml index 08dcc28b8876..5dce5be9c960 100644 --- a/config/deployments/env_specific.toml +++ b/config/deployments/env_specific.toml @@ -30,7 +30,7 @@ apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" # Merchant Ce apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" # Private key generated by RSA:2048 algorithm. Refer Hyperswitch Docs (https://docs.hyperswitch.io/hyperswitch-cloud/payment-methods-setup/wallets/apple-pay/ios-application/) to generate the private key [paze_decrypt_keys] -paze_private_key = "PAZE_PRIVATE_KEY" # Base 64 Encoded Private Key File cakey.pem generated for Paze +paze_private_key = "PAZE_PRIVATE_KEY" # Base 64 Encoded Private Key File cakey.pem generated for Paze -> Command to create private key: openssl req -newkey rsa:2048 -x509 -keyout cakey.pem -out cacert.pem -days 365 paze_private_key_passphrase = "PAZE_PRIVATE_KEY_PASSPHRASE" # PEM Passphrase used for generating Private Key File cakey.pem [applepay_merchant_configs] diff --git a/crates/router/src/configs/secrets_transformers.rs b/crates/router/src/configs/secrets_transformers.rs index 2122f1551815..dbdba189ed19 100644 --- a/crates/router/src/configs/secrets_transformers.rs +++ b/crates/router/src/configs/secrets_transformers.rs @@ -410,12 +410,15 @@ pub(crate) async fn fetch_raw_secrets( .expect("Failed to decrypt applepay decrypt configs"); #[allow(clippy::expect_used)] - let paze_decrypt_keys = settings::PazeDecryptConfig::convert_to_raw_secret( - conf.paze_decrypt_keys, - secret_management_client, - ) - .await - .expect("Failed to decrypt paze decrypt configs"); + let paze_decrypt_keys = if let Some(paze_keys) = conf.paze_decrypt_keys { + Some( + settings::PazeDecryptConfig::convert_to_raw_secret(paze_keys, secret_management_client) + .await + .expect("Failed to decrypt paze decrypt configs"), + ) + } else { + None + }; #[allow(clippy::expect_used)] let applepay_merchant_configs = settings::ApplepayMerchantConfigs::convert_to_raw_secret( diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index e87a44134af5..00cceea21a1f 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -96,7 +96,7 @@ pub struct Settings { pub payouts: Payouts, pub payout_method_filters: ConnectorFilters, pub applepay_decrypt_keys: SecretStateContainer, - pub paze_decrypt_keys: SecretStateContainer, + pub paze_decrypt_keys: Option>, pub multiple_api_version_supported_connectors: MultipleApiVersionSupportedConnectors, pub applepay_merchant_configs: SecretStateContainer, pub lock_settings: LockSettings, diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs index 95515a826b41..90c583671f2a 100644 --- a/crates/router/src/connector/cybersource/transformers.rs +++ b/crates/router/src/connector/cybersource/transformers.rs @@ -21,7 +21,7 @@ use serde_json::Value; use crate::connector::utils::PayoutsData; use crate::{ connector::utils::{ - self, AddressData, AddressDetailsData, ApplePayDecrypt, CardData, NetworkTokenData, + self, AddressDetailsData, ApplePayDecrypt, CardData, NetworkTokenData, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData, PaymentsPreProcessingData, PaymentsSetupMandateRequestData, PaymentsSyncRequestData, RecurringMandateData, RouterData, @@ -1334,26 +1334,25 @@ impl ), ) -> Result { let email = item.router_data.request.get_email()?; - let (first_name, last_name) = paze_data - .billing_address - .name - .unwrap_or( - item.router_data - .get_optional_billing() - .and_then(|address| address.get_optional_full_name()) + let (first_name, last_name) = match paze_data.billing_address.name { + Some(name) => { + let (first_name, last_name) = name + .peek() + .split_once(' ') + .map(|(first, last)| (first.to_string(), last.to_string())) .ok_or(errors::ConnectorError::MissingRequiredField { field_name: "billing_address.name", - })?, - ) - .peek() - .split_once(' ') - .map(|(first, last)| (first.to_string(), last.to_string())) - .ok_or(errors::ConnectorError::MissingRequiredField { - field_name: "billing_address.name", - })?; + })?; + (Secret::from(first_name), Secret::from(last_name)) + } + None => ( + item.router_data.get_billing_first_name()?, + item.router_data.get_billing_last_name()?, + ), + }; let bill_to = BillTo { - first_name: Some(Secret::from(first_name)), - last_name: Some(Secret::from(last_name)), + first_name: Some(first_name), + last_name: Some(last_name), address1: paze_data.billing_address.line1, locality: paze_data.billing_address.city.map(|city| city.expose()), administrative_area: Some(Secret::from( diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 1346017b8d11..be217e28b28a 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2671,22 +2671,19 @@ async fn decide_payment_method_tokenize_action( ) -> RouterResult { if let Some(storage_enums::PaymentMethodType::Paze) = payment_method_type { // Paze generates a one time use network token which should not be tokenized in the connector or router. - Ok(TokenizationAction::DecryptPazeToken( - PazePaymentProcessingDetails { - paze_private_key: state - .conf - .paze_decrypt_keys - .get_inner() - .paze_private_key - .clone(), - paze_private_key_passphrase: state - .conf - .paze_decrypt_keys - .get_inner() - .paze_private_key_passphrase - .clone(), - }, - )) + match &state.conf.paze_decrypt_keys { + Some(paze_keys) => Ok(TokenizationAction::DecryptPazeToken( + PazePaymentProcessingDetails { + paze_private_key: paze_keys.get_inner().paze_private_key.clone(), + paze_private_key_passphrase: paze_keys + .get_inner() + .paze_private_key_passphrase + .clone(), + }, + )), + None => Err(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to fetch Paze configs"), + } } else { match pm_parent_token { None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) { diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 9d5da12aa6cf..54cd4e9bd17c 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -5028,7 +5028,7 @@ pub fn decrypt_paze_token( .change_context(errors::PazeDecryptionError::DecryptionFailed)?; let (deserialized_payload, _deserialized_header) = - jwe::deserialize_compact(&jws_body.secured_payload, &decrypter) + jwe::deserialize_compact(&jws_body.secured_payload.peek(), &decrypter) .change_context(errors::PazeDecryptionError::DecryptionFailed)?; let encoded_secured_payload_element = String::from_utf8(deserialized_payload) .change_context(errors::PazeDecryptionError::DecryptionFailed)? @@ -5051,7 +5051,7 @@ pub fn decrypt_paze_token( pub struct JwsBody { pub payload_id: String, pub session_id: String, - pub secured_payload: String, + pub secured_payload: masking::Secret, } pub fn get_key_params_for_surcharge_details( From 38e95d131dc4c00839558401a333dcb90d662108 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Sun, 6 Oct 2024 20:19:36 +0530 Subject: [PATCH 10/16] chore: Resolve merge conflicts and pr comments --- .../src/connectors/fiuu/transformers.rs | 4 + crates/router/src/core/payments.rs | 148 ++++++++++-------- 2 files changed, 86 insertions(+), 66 deletions(-) diff --git a/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs b/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs index eab8d878f055..c4ca017cec7c 100644 --- a/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs @@ -366,6 +366,9 @@ impl TryFrom<&FiuuRouterData<&PaymentsAuthorizeRouterData>> for FiuuPaymentReque PaymentMethodToken::ApplePayDecrypt(decrypt_data) => { FiuuPaymentMethodData::try_from(decrypt_data) } + PaymentMethodToken::PazeDecrypt(_) => { + Err(unimplemented_payment_method!("Paze", "Fiuu"))? + } } } WalletData::AliPayQr(_) @@ -384,6 +387,7 @@ impl TryFrom<&FiuuRouterData<&PaymentsAuthorizeRouterData>> for FiuuPaymentReque | WalletData::MobilePayRedirect(_) | WalletData::PaypalRedirect(_) | WalletData::PaypalSdk(_) + | WalletData::Paze(_) | WalletData::SamsungPay(_) | WalletData::TwintRedirect {} | WalletData::VippsRedirect {} diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index f66a0d4ccf9a..494e54a62313 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1709,72 +1709,9 @@ where &call_connector_action, ); - // Tokenization Action will be DecryptApplePayToken, only when payment method type is Apple Pay - // and the connector supports Apple Pay predecrypt - match &tokenization_action { - TokenizationAction::DecryptApplePayToken(payment_processing_details) - | TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt( - payment_processing_details, - ) => { - let apple_pay_data = match payment_data.get_payment_method_data() { - Some(domain::PaymentMethodData::Wallet(domain::WalletData::ApplePay( - wallet_data, - ))) => Some( - ApplePayData::token_json(domain::WalletData::ApplePay(wallet_data.clone())) - .change_context(errors::ApiErrorResponse::InternalServerError)? - .decrypt( - &payment_processing_details.payment_processing_certificate, - &payment_processing_details.payment_processing_certificate_key, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError)?, - ), - _ => None, - }; - - let apple_pay_predecrypt = apple_pay_data - .parse_value::( - "ApplePayPredecryptData", - ) - .change_context(errors::ApiErrorResponse::InternalServerError)?; - - router_data.payment_method_token = Some( - hyperswitch_domain_models::router_data::PaymentMethodToken::ApplePayDecrypt( - Box::new(apple_pay_predecrypt), - ), - ); - } - TokenizationAction::DecryptPazeToken(payment_processing_details) => { - let paze_data = match payment_data.get_payment_method_data() { - Some(domain::PaymentMethodData::Wallet(domain::WalletData::Paze(wallet_data))) => { - Some( - decrypt_paze_token( - wallet_data.clone(), - payment_processing_details.paze_private_key.clone(), - payment_processing_details - .paze_private_key_passphrase - .clone(), - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to decrypt paze token")?, - ) - } - _ => None, - }; - let paze_decrypted_data = paze_data - .parse_value::( - "PazeDecryptedData", - ) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to parse PazeDecryptedData")?; - router_data.payment_method_token = Some( - hyperswitch_domain_models::router_data::PaymentMethodToken::PazeDecrypt(Box::new( - paze_decrypted_data, - )), - ); - } - _ => (), - }; + router_data = + add_decrypted_payment_method_token(tokenization_action.clone(), payment_data, router_data) + .await?; let payment_method_token_response = router_data .add_payment_method_token( @@ -1881,6 +1818,85 @@ where Ok((router_data, merchant_connector_account)) } +pub async fn add_decrypted_payment_method_token( + tokenization_action: TokenizationAction, + payment_data: &D, + mut router_data: RouterData, +) -> RouterResult> +where + F: Send + Clone + Sync, + D: OperationSessionGetters + Send + Sync + Clone, + Req: Send + Sync, +{ + // Tokenization Action will be DecryptApplePayToken, only when payment method type is Apple Pay + // and the connector supports Apple Pay predecrypt + match &tokenization_action { + TokenizationAction::DecryptApplePayToken(payment_processing_details) + | TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt( + payment_processing_details, + ) => { + let apple_pay_data = match payment_data.get_payment_method_data() { + Some(domain::PaymentMethodData::Wallet(domain::WalletData::ApplePay( + wallet_data, + ))) => Some( + ApplePayData::token_json(domain::WalletData::ApplePay(wallet_data.clone())) + .change_context(errors::ApiErrorResponse::InternalServerError)? + .decrypt( + &payment_processing_details.payment_processing_certificate, + &payment_processing_details.payment_processing_certificate_key, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError)?, + ), + _ => None, + }; + + let apple_pay_predecrypt = apple_pay_data + .parse_value::( + "ApplePayPredecryptData", + ) + .change_context(errors::ApiErrorResponse::InternalServerError)?; + + router_data.payment_method_token = Some( + hyperswitch_domain_models::router_data::PaymentMethodToken::ApplePayDecrypt( + Box::new(apple_pay_predecrypt), + ), + ); + } + TokenizationAction::DecryptPazeToken(payment_processing_details) => { + let paze_data = match payment_data.get_payment_method_data() { + Some(domain::PaymentMethodData::Wallet(domain::WalletData::Paze(wallet_data))) => { + Some( + decrypt_paze_token( + wallet_data.clone(), + payment_processing_details.paze_private_key.clone(), + payment_processing_details + .paze_private_key_passphrase + .clone(), + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to decrypt paze token")?, + ) + } + _ => None, + }; + let paze_decrypted_data = paze_data + .parse_value::( + "PazeDecryptedData", + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse PazeDecryptedData")?; + router_data.payment_method_token = Some( + hyperswitch_domain_models::router_data::PaymentMethodToken::PazeDecrypt(Box::new( + paze_decrypted_data, + )), + ); + } + _ => (), + }; + Ok(router_data) +} + pub async fn get_merchant_bank_data_for_open_banking_connectors( merchant_connector_account: &helpers::MerchantConnectorAccountType, key_store: &domain::MerchantKeyStore, From bc3addec287d1d43f05ec8b93b683c726c8bb431 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Sun, 6 Oct 2024 21:05:28 +0530 Subject: [PATCH 11/16] chore: Resolve clippy errors --- crates/router/src/core/payments.rs | 2 +- crates/router/src/core/payments/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 494e54a62313..b6f9a96d0fa2 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2866,7 +2866,7 @@ where payment_data.get_token(), is_connector_tokenization_enabled, apple_pay_flow, - payment_method_type.clone(), + *payment_method_type, ) .await?; diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 07ed5ad44774..a39b151bd27b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -5026,7 +5026,7 @@ pub fn decrypt_paze_token( .change_context(errors::PazeDecryptionError::DecryptionFailed)?; let (deserialized_payload, _deserialized_header) = - jwe::deserialize_compact(&jws_body.secured_payload.peek(), &decrypter) + jwe::deserialize_compact(jws_body.secured_payload.peek(), &decrypter) .change_context(errors::PazeDecryptionError::DecryptionFailed)?; let encoded_secured_payload_element = String::from_utf8(deserialized_payload) .change_context(errors::PazeDecryptionError::DecryptionFailed)? From dfa95fbd572fd806ed5c6c8d3ee6bcb180eab7db Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Mon, 7 Oct 2024 19:24:23 +0530 Subject: [PATCH 12/16] chore: Resolve PR Comments --- crates/router/src/configs/settings.rs | 5 +++++ crates/router/src/configs/validations.rs | 21 +++++++++++++++++++++ crates/router/src/core/payments.rs | 11 ++++++++--- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs index 00cceea21a1f..149ee2b84562 100644 --- a/crates/router/src/configs/settings.rs +++ b/crates/router/src/configs/settings.rs @@ -871,6 +871,11 @@ impl Settings { .map(|x| x.get_inner().validate()) .transpose()?; + self.paze_decrypt_keys + .as_ref() + .map(|x| x.get_inner().validate()) + .transpose()?; + self.key_manager.get_inner().validate()?; Ok(()) diff --git a/crates/router/src/configs/validations.rs b/crates/router/src/configs/validations.rs index f109fe3f773a..7040998ccf01 100644 --- a/crates/router/src/configs/validations.rs +++ b/crates/router/src/configs/validations.rs @@ -236,6 +236,27 @@ impl super::settings::NetworkTokenizationService { } } +impl super::settings::PazeDecryptConfig { + pub fn validate(&self) -> Result<(), ApplicationError> { + use common_utils::fp_utils::when; + + when(self.paze_private_key.is_default_or_empty(), || { + Err(ApplicationError::InvalidConfigurationValueError( + "paze_private_key must not be empty".into(), + )) + })?; + + when( + self.paze_private_key_passphrase.is_default_or_empty(), + || { + Err(ApplicationError::InvalidConfigurationValueError( + "paze_private_key_passphrase must not be empty".into(), + )) + }, + ) + } +} + impl super::settings::KeyManagerConfig { pub fn validate(&self) -> Result<(), ApplicationError> { use common_utils::fp_utils::when; diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index b6f9a96d0fa2..b8a6eb65a6bc 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -1840,13 +1840,15 @@ where wallet_data, ))) => Some( ApplePayData::token_json(domain::WalletData::ApplePay(wallet_data.clone())) - .change_context(errors::ApiErrorResponse::InternalServerError)? + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to parse apple pay token to json")? .decrypt( &payment_processing_details.payment_processing_certificate, &payment_processing_details.payment_processing_certificate_key, ) .await - .change_context(errors::ApiErrorResponse::InternalServerError)?, + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to decrypt apple pay token")?, ), _ => None, }; @@ -1855,7 +1857,10 @@ where .parse_value::( "ApplePayPredecryptData", ) - .change_context(errors::ApiErrorResponse::InternalServerError)?; + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "failed to parse decrypted apple pay response to ApplePayPredecryptData", + )?; router_data.payment_method_token = Some( hyperswitch_domain_models::router_data::PaymentMethodToken::ApplePayDecrypt( From 5f470a7f38529208d40ba63b50a31a0f461314e2 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Tue, 8 Oct 2024 12:03:43 +0530 Subject: [PATCH 13/16] chore: Resolve pr comments --- crates/router/src/core/payments.rs | 43 +++++++++++++----------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index b8a6eb65a6bc..478e485bfc41 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -40,7 +40,7 @@ use hyperswitch_domain_models::payments::PaymentIntentData; pub use hyperswitch_domain_models::{ mandates::{CustomerAcceptance, MandateData}, payment_address::PaymentAddress, - router_data::RouterData, + router_data::{PaymentMethodToken, RouterData}, router_request_types::CustomerDetails, }; use masking::{ExposeInterface, PeekInterface, Secret}; @@ -1709,9 +1709,13 @@ where &call_connector_action, ); - router_data = - add_decrypted_payment_method_token(tokenization_action.clone(), payment_data, router_data) - .await?; + router_data.payment_method_token = if let Some(decrypted_token) = + add_decrypted_payment_method_token(tokenization_action.clone(), payment_data).await? + { + Some(decrypted_token) + } else { + router_data.payment_method_token + }; let payment_method_token_response = router_data .add_payment_method_token( @@ -1818,15 +1822,13 @@ where Ok((router_data, merchant_connector_account)) } -pub async fn add_decrypted_payment_method_token( +pub async fn add_decrypted_payment_method_token( tokenization_action: TokenizationAction, payment_data: &D, - mut router_data: RouterData, -) -> RouterResult> +) -> CustomResult, errors::ApiErrorResponse> where F: Send + Clone + Sync, D: OperationSessionGetters + Send + Sync + Clone, - Req: Send + Sync, { // Tokenization Action will be DecryptApplePayToken, only when payment method type is Apple Pay // and the connector supports Apple Pay predecrypt @@ -1862,11 +1864,9 @@ where "failed to parse decrypted apple pay response to ApplePayPredecryptData", )?; - router_data.payment_method_token = Some( - hyperswitch_domain_models::router_data::PaymentMethodToken::ApplePayDecrypt( - Box::new(apple_pay_predecrypt), - ), - ); + Ok(Some(PaymentMethodToken::ApplePayDecrypt(Box::new( + apple_pay_predecrypt, + )))) } TokenizationAction::DecryptPazeToken(payment_processing_details) => { let paze_data = match payment_data.get_payment_method_data() { @@ -1891,15 +1891,12 @@ where ) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed to parse PazeDecryptedData")?; - router_data.payment_method_token = Some( - hyperswitch_domain_models::router_data::PaymentMethodToken::PazeDecrypt(Box::new( - paze_decrypted_data, - )), - ); + Ok(Some(PaymentMethodToken::PazeDecrypt(Box::new( + paze_decrypted_data, + )))) } - _ => (), - }; - Ok(router_data) + _ => Ok(None), + } } pub async fn get_merchant_bank_data_for_open_banking_connectors( @@ -2766,11 +2763,9 @@ async fn decide_payment_method_tokenize_action( } } -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, utoipa::ToSchema)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)] pub struct PazePaymentProcessingDetails { - #[schema(value_type = String)] pub paze_private_key: Secret, - #[schema(value_type = String)] pub paze_private_key_passphrase: Secret, } From 2c96617f7dc2cd1d0e9f9580d66c1ff0f7016df9 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Tue, 8 Oct 2024 14:18:39 +0530 Subject: [PATCH 14/16] chore: generate openapi spec --- api-reference-v2/openapi_spec.json | 38 ++++++++++++++++++++++++++++++ api-reference/openapi_spec.json | 38 ++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 388ccb79a660..f9c7caa8e375 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -5592,6 +5592,11 @@ "type": "object", "description": "This field contains the Samsung Pay certificates and credentials", "nullable": true + }, + "paze": { + "type": "object", + "description": "This field contains the Paze certificates and credentials", + "nullable": true } }, "additionalProperties": false @@ -12548,6 +12553,7 @@ "open_banking_uk", "pay_bright", "paypal", + "paze", "pix", "pay_safe_card", "przelewy24", @@ -19377,6 +19383,27 @@ } ] }, + { + "allOf": [ + { + "$ref": "#/components/schemas/PazeSessionTokenResponse" + }, + { + "type": "object", + "required": [ + "wallet_name" + ], + "properties": { + "wallet_name": { + "type": "string", + "enum": [ + "paze" + ] + } + } + } + ] + }, { "type": "object", "required": [ @@ -20551,6 +20578,17 @@ } } }, + { + "type": "object", + "required": [ + "paze" + ], + "properties": { + "paze": { + "$ref": "#/components/schemas/PazeWalletData" + } + } + }, { "type": "object", "required": [ diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index d0e6c6ad0aaa..f3a708046662 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -8884,6 +8884,11 @@ "type": "object", "description": "This field contains the Samsung Pay certificates and credentials", "nullable": true + }, + "paze": { + "type": "object", + "description": "This field contains the Paze certificates and credentials", + "nullable": true } }, "additionalProperties": false @@ -16185,6 +16190,7 @@ "open_banking_uk", "pay_bright", "paypal", + "paze", "pix", "pay_safe_card", "przelewy24", @@ -23139,6 +23145,27 @@ } ] }, + { + "allOf": [ + { + "$ref": "#/components/schemas/PazeSessionTokenResponse" + }, + { + "type": "object", + "required": [ + "wallet_name" + ], + "properties": { + "wallet_name": { + "type": "string", + "enum": [ + "paze" + ] + } + } + } + ] + }, { "type": "object", "required": [ @@ -24395,6 +24422,17 @@ } } }, + { + "type": "object", + "required": [ + "paze" + ], + "properties": { + "paze": { + "$ref": "#/components/schemas/PazeWalletData" + } + } + }, { "type": "object", "required": [ From 5abec8a1a0e19e1a89566e74fdbd0b7cbe783214 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Tue, 8 Oct 2024 14:45:24 +0530 Subject: [PATCH 15/16] chore: generate openapi spec --- crates/openapi/src/openapi.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index a76726eb8ac7..24fbadc0a596 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -389,6 +389,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentsCaptureRequest, api_models::payments::PaymentsSessionRequest, api_models::payments::PaymentsSessionResponse, + api_models::payments::PazeWalletData, api_models::payments::SessionToken, api_models::payments::ApplePaySessionResponse, api_models::payments::ThirdPartySdkSessionResponse, @@ -445,6 +446,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::GooglePayRedirectData, api_models::payments::GooglePayThirdPartySdk, api_models::payments::GooglePaySessionResponse, + api_models::payments::PazeSessionTokenResponse, api_models::payments::SamsungPaySessionTokenResponse, api_models::payments::SamsungPayMerchantPaymentInformation, api_models::payments::SamsungPayAmountDetails, From 9c977f6cfda73a5ea7aaad6268d5827e27241794 Mon Sep 17 00:00:00 2001 From: deepanshu-iiitu Date: Tue, 8 Oct 2024 15:13:12 +0530 Subject: [PATCH 16/16] chore: Resolve pr comments chore: generate openapi spec chore: generate openapi spec chore: generate openapi spec --- api-reference-v2/openapi_spec.json | 33 ++++++++++++++++++++++++++++++ api-reference/openapi_spec.json | 33 ++++++++++++++++++++++++++++++ crates/api_models/src/payments.rs | 1 + crates/openapi/src/openapi_v2.rs | 2 ++ 4 files changed, 69 insertions(+) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index f9c7caa8e375..44ac1d3e08dc 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -17144,6 +17144,39 @@ } } }, + "PazeSessionTokenResponse": { + "type": "object", + "required": [ + "client_id", + "client_name", + "client_profile_id" + ], + "properties": { + "client_id": { + "type": "string", + "description": "Paze Client ID" + }, + "client_name": { + "type": "string", + "description": "Client Name to be displayed on the Paze screen" + }, + "client_profile_id": { + "type": "string", + "description": "Paze Client Profile ID" + } + } + }, + "PazeWalletData": { + "type": "object", + "required": [ + "complete_response" + ], + "properties": { + "complete_response": { + "type": "string" + } + } + }, "PhoneDetails": { "type": "object", "properties": { diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index f3a708046662..90239bb8a0a2 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -20889,6 +20889,39 @@ } } }, + "PazeSessionTokenResponse": { + "type": "object", + "required": [ + "client_id", + "client_name", + "client_profile_id" + ], + "properties": { + "client_id": { + "type": "string", + "description": "Paze Client ID" + }, + "client_name": { + "type": "string", + "description": "Client Name to be displayed on the Paze screen" + }, + "client_profile_id": { + "type": "string", + "description": "Paze Client Profile ID" + } + } + }, + "PazeWalletData": { + "type": "object", + "required": [ + "complete_response" + ], + "properties": { + "complete_response": { + "type": "string" + } + } + }, "PhoneDetails": { "type": "object", "properties": { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 03e35de07239..a758d4578582 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2898,6 +2898,7 @@ impl GetAddressFromPaymentMethodData for WalletData { #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub struct PazeWalletData { + #[schema(value_type = String)] pub complete_response: Secret, } diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 05a2c72ba941..bc44068030b4 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -323,6 +323,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentsSessionResponse, api_models::payments::PaymentsCreateIntentRequest, api_models::payments::PaymentsCreateIntentResponse, + api_models::payments::PazeWalletData, api_models::payments::AmountDetails, api_models::payments::SessionToken, api_models::payments::ApplePaySessionResponse, @@ -358,6 +359,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::GooglePayPaymentMethodInfo, api_models::payments::ApplePayWalletData, api_models::payments::ApplepayPaymentMethod, + api_models::payments::PazeSessionTokenResponse, api_models::payments::SamsungPaySessionTokenResponse, api_models::payments::SamsungPayMerchantPaymentInformation, api_models::payments::SamsungPayAmountDetails,