diff --git a/config/config.example.toml b/config/config.example.toml index 6835cfdb4a1a..5d575b5ba095 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -623,4 +623,4 @@ refunds = "hyperswitch-refund-events" disputes = "hyperswitch-dispute-events" [saved_payment_methods] -sdk_eligible_payment_methods = "card" \ No newline at end of file +sdk_eligible_payment_methods = "card" diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml index c9b35a1f359c..5b6c5fe152de 100644 --- a/config/deployments/integration_test.toml +++ b/config/deployments/integration_test.toml @@ -327,4 +327,4 @@ connectors_with_webhook_source_verification_call = "paypal" # List of co keys = "user-agent" [saved_payment_methods] -sdk_eligible_payment_methods = "card" \ No newline at end of file +sdk_eligible_payment_methods = "card" diff --git a/config/deployments/production.toml b/config/deployments/production.toml index 938c034c9d16..b5441f0059de 100644 --- a/config/deployments/production.toml +++ b/config/deployments/production.toml @@ -338,4 +338,4 @@ connectors_with_webhook_source_verification_call = "paypal" # List of connec keys = "user-agent" [saved_payment_methods] -sdk_eligible_payment_methods = "card" \ No newline at end of file +sdk_eligible_payment_methods = "card" diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index 7388d5bb8a76..e168fab121d2 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -342,4 +342,4 @@ connectors_with_webhook_source_verification_call = "paypal" # List of con keys = "user-agent" [saved_payment_methods] -sdk_eligible_payment_methods = "card" \ No newline at end of file +sdk_eligible_payment_methods = "card" diff --git a/config/docker_compose.toml b/config/docker_compose.toml index c13c436a19c4..0d615b11b5cf 100644 --- a/config/docker_compose.toml +++ b/config/docker_compose.toml @@ -486,4 +486,4 @@ refunds = "hyperswitch-refund-events" disputes = "hyperswitch-dispute-events" [saved_payment_methods] -sdk_eligible_payment_methods = "card" \ No newline at end of file +sdk_eligible_payment_methods = "card" diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index 866db8cc18db..7b33097d2b32 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -273,6 +273,15 @@ pub enum AuthenticationConnectors { Gpayments, } +impl AuthenticationConnectors { + pub fn is_separate_version_call_required(&self) -> bool { + match self { + Self::Threedsecureio | Self::Netcetera => false, + Self::Gpayments => true, + } + } +} + #[cfg(feature = "payouts")] #[derive( Clone, diff --git a/crates/router/src/connector/gpayments.rs b/crates/router/src/connector/gpayments.rs index 9608f44b9daf..71c6a65e6d4c 100644 --- a/crates/router/src/connector/gpayments.rs +++ b/crates/router/src/connector/gpayments.rs @@ -204,6 +204,7 @@ impl api::IncomingWebhook for Gpayments { impl api::ExternalAuthentication for Gpayments {} impl api::ConnectorAuthentication for Gpayments {} impl api::ConnectorPreAuthentication for Gpayments {} +impl api::ConnectorPreAuthenticationVersionCall for Gpayments {} impl api::ConnectorPostAuthentication for Gpayments {} impl ConnectorIntegration< @@ -221,6 +222,14 @@ impl > for Gpayments { } +impl + ConnectorIntegration< + api::PreAuthenticationVersionCall, + types::authentication::PreAuthNRequestData, + types::authentication::AuthenticationResponseData, + > for Gpayments +{ +} impl ConnectorIntegration< api::PostAuthentication, diff --git a/crates/router/src/connector/netcetera.rs b/crates/router/src/connector/netcetera.rs index 71072a046dea..43df87db40f4 100644 --- a/crates/router/src/connector/netcetera.rs +++ b/crates/router/src/connector/netcetera.rs @@ -228,6 +228,7 @@ fn build_endpoint( } impl api::ConnectorPreAuthentication for Netcetera {} +impl api::ConnectorPreAuthenticationVersionCall for Netcetera {} impl api::ExternalAuthentication for Netcetera {} impl api::ConnectorAuthentication for Netcetera {} impl api::ConnectorPostAuthentication for Netcetera {} @@ -451,3 +452,12 @@ impl > for Netcetera { } + +impl + ConnectorIntegration< + api::PreAuthenticationVersionCall, + types::authentication::PreAuthNRequestData, + types::authentication::AuthenticationResponseData, + > for Netcetera +{ +} diff --git a/crates/router/src/connector/threedsecureio.rs b/crates/router/src/connector/threedsecureio.rs index 77fda3e864e8..75a746648f10 100644 --- a/crates/router/src/connector/threedsecureio.rs +++ b/crates/router/src/connector/threedsecureio.rs @@ -211,6 +211,7 @@ impl api::IncomingWebhook for Threedsecureio { } impl api::ConnectorPreAuthentication for Threedsecureio {} +impl api::ConnectorPreAuthenticationVersionCall for Threedsecureio {} impl api::ExternalAuthentication for Threedsecureio {} impl api::ConnectorAuthentication for Threedsecureio {} impl api::ConnectorPostAuthentication for Threedsecureio {} @@ -409,10 +410,6 @@ impl data: data.clone(), http_code: res.status_code, }) - // Ok(types::authentication::PreAuthNRouterData { - // response, - // ..data.clone() - // }) } fn get_error_response( @@ -527,3 +524,12 @@ impl self.build_error_response(res, event_builder) } } + +impl + ConnectorIntegration< + api::PreAuthenticationVersionCall, + types::authentication::PreAuthNRequestData, + types::authentication::AuthenticationResponseData, + > for Threedsecureio +{ +} diff --git a/crates/router/src/core/authentication.rs b/crates/router/src/core/authentication.rs index 1b050394b39a..5acd14bb3ee2 100644 --- a/crates/router/src/core/authentication.rs +++ b/crates/router/src/core/authentication.rs @@ -140,12 +140,41 @@ pub async fn perform_pre_authentication( ) .await?; - let router_data = transformers::construct_pre_authentication_router_data( - authentication_connector_name.clone(), - card_number, - &three_ds_connector_account, - business_profile.merchant_id.clone(), - )?; + let authentication = if authentication_connector.is_separate_version_call_required() { + let router_data: core_types::authentication::PreAuthNVersionCallRouterData = + transformers::construct_pre_authentication_router_data( + authentication_connector_name.clone(), + card_number.clone(), + &three_ds_connector_account, + business_profile.merchant_id.clone(), + )?; + let router_data = utils::do_auth_connector_call( + state, + authentication_connector_name.clone(), + router_data, + ) + .await?; + + let updated_authentication = + utils::update_trackers(state, router_data, authentication, acquirer_details.clone()) + .await?; + // from version call response, we will get to know the maximum supported 3ds version. + // If the version is not greater than or equal to 3DS 2.0, We should not do the successive pre authentication call. + if !updated_authentication.is_separate_authn_required() { + return Ok(updated_authentication); + } + updated_authentication + } else { + authentication + }; + + let router_data: core_types::authentication::PreAuthNRouterData = + transformers::construct_pre_authentication_router_data( + authentication_connector_name.clone(), + card_number, + &three_ds_connector_account, + business_profile.merchant_id.clone(), + )?; let router_data = utils::do_auth_connector_call(state, authentication_connector_name, router_data).await?; diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index 3c48b20ffa2a..e0e9ee0b5263 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -109,12 +109,18 @@ pub fn construct_post_authentication_router_data( ) } -pub fn construct_pre_authentication_router_data( +pub fn construct_pre_authentication_router_data( authentication_connector: String, card_holder_account_number: cards::CardNumber, merchant_connector_account: &payments_helpers::MerchantConnectorAccountType, merchant_id: String, -) -> RouterResult { +) -> RouterResult< + types::RouterData< + F, + types::authentication::PreAuthNRequestData, + types::authentication::AuthenticationResponseData, + >, +> { let router_request = types::authentication::PreAuthNRequestData { card_holder_account_number, }; diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index a8425896dd7b..5cb610e4b068 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -2568,6 +2568,7 @@ macro_rules! default_imp_for_connector_authentication { $( impl api::ExternalAuthentication for $path::$connector {} impl api::ConnectorAuthentication for $path::$connector {} impl api::ConnectorPreAuthentication for $path::$connector {} + impl api::ConnectorPreAuthenticationVersionCall for $path::$connector {} impl api::ConnectorPostAuthentication for $path::$connector {} impl services::ConnectorIntegration< @@ -2583,6 +2584,13 @@ macro_rules! default_imp_for_connector_authentication { types::authentication::AuthenticationResponseData, > for $path::$connector {} + impl + services::ConnectorIntegration< + api::PreAuthenticationVersionCall, + types::authentication::PreAuthNRequestData, + types::authentication::AuthenticationResponseData, + > for $path::$connector + {} impl services::ConnectorIntegration< api::PostAuthentication, @@ -2599,6 +2607,8 @@ impl api::ExternalAuthentication for connector::DummyConnector { #[cfg(feature = "dummy_connector")] impl api::ConnectorPreAuthentication for connector::DummyConnector {} #[cfg(feature = "dummy_connector")] +impl api::ConnectorPreAuthenticationVersionCall for connector::DummyConnector {} +#[cfg(feature = "dummy_connector")] impl api::ConnectorAuthentication for connector::DummyConnector {} #[cfg(feature = "dummy_connector")] impl api::ConnectorPostAuthentication for connector::DummyConnector {} @@ -2622,6 +2632,15 @@ impl { } #[cfg(feature = "dummy_connector")] +impl + services::ConnectorIntegration< + api::PreAuthenticationVersionCall, + types::authentication::PreAuthNRequestData, + types::authentication::AuthenticationResponseData, + > for connector::DummyConnector +{ +} +#[cfg(feature = "dummy_connector")] impl services::ConnectorIntegration< api::PostAuthentication, diff --git a/crates/router/src/types/api/authentication.rs b/crates/router/src/types/api/authentication.rs index 5b8e3238fb7f..0f86f4621672 100644 --- a/crates/router/src/types/api/authentication.rs +++ b/crates/router/src/types/api/authentication.rs @@ -10,6 +10,9 @@ use crate::core::errors; #[derive(Debug, Clone)] pub struct PreAuthentication; +#[derive(Debug, Clone)] +pub struct PreAuthenticationVersionCall; + #[derive(Debug, Clone)] pub struct Authentication; @@ -94,6 +97,15 @@ pub trait ConnectorPreAuthentication: { } +pub trait ConnectorPreAuthenticationVersionCall: + services::ConnectorIntegration< + PreAuthenticationVersionCall, + types::authentication::PreAuthNRequestData, + types::authentication::AuthenticationResponseData, +> +{ +} + pub trait ConnectorPostAuthentication: services::ConnectorIntegration< PostAuthentication, @@ -107,6 +119,7 @@ pub trait ExternalAuthentication: super::ConnectorCommon + ConnectorAuthentication + ConnectorPreAuthentication + + ConnectorPreAuthenticationVersionCall + ConnectorPostAuthentication { } diff --git a/crates/router/src/types/authentication.rs b/crates/router/src/types/authentication.rs index 7ea937b9ffd8..91ab768e28a1 100644 --- a/crates/router/src/types/authentication.rs +++ b/crates/router/src/types/authentication.rs @@ -125,6 +125,9 @@ pub struct ConnectorPostAuthenticationRequestData { pub type PreAuthNRouterData = RouterData; +pub type PreAuthNVersionCallRouterData = + RouterData; + pub type ConnectorAuthenticationRouterData = RouterData;