Files
hyperswitch/crates/router/src/core/authentication.rs
Prasunna Soppa f81416e4df refactor(core): Use hyperswitch_domain_models within the Payments Core instead of api_models (#5511)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com>
2024-08-09 09:15:15 +00:00

185 lines
7.1 KiB
Rust

pub(crate) mod utils;
pub mod transformers;
pub mod types;
use api_models::payments;
use common_enums::Currency;
use common_utils::errors::CustomResult;
use error_stack::ResultExt;
use masking::ExposeInterface;
use super::errors::StorageErrorExt;
use crate::{
core::{errors::ApiErrorResponse, payments as payments_core},
routes::SessionState,
types::{self as core_types, api, domain, storage},
utils::check_if_pull_mechanism_for_external_3ds_enabled_from_connector_metadata,
};
#[allow(clippy::too_many_arguments)]
pub async fn perform_authentication(
state: &SessionState,
merchant_id: common_utils::id_type::MerchantId,
authentication_connector: String,
payment_method_data: domain::PaymentMethodData,
payment_method: common_enums::PaymentMethod,
billing_address: payments::Address,
shipping_address: Option<payments::Address>,
browser_details: Option<core_types::BrowserInformation>,
merchant_connector_account: payments_core::helpers::MerchantConnectorAccountType,
amount: Option<common_utils::types::MinorUnit>,
currency: Option<Currency>,
message_category: api::authentication::MessageCategory,
device_channel: payments::DeviceChannel,
authentication_data: storage::Authentication,
return_url: Option<String>,
sdk_information: Option<payments::SdkInformation>,
threeds_method_comp_ind: payments::ThreeDsCompletionIndicator,
email: Option<common_utils::pii::Email>,
webhook_url: String,
three_ds_requestor_url: String,
) -> CustomResult<api::authentication::AuthenticationResponse, ApiErrorResponse> {
let router_data = transformers::construct_authentication_router_data(
merchant_id,
authentication_connector.clone(),
payment_method_data,
payment_method,
billing_address,
shipping_address,
browser_details,
amount,
currency,
message_category,
device_channel,
merchant_connector_account,
authentication_data.clone(),
return_url,
sdk_information,
threeds_method_comp_ind,
email,
webhook_url,
three_ds_requestor_url,
)?;
let response =
utils::do_auth_connector_call(state, authentication_connector.clone(), router_data).await?;
let authentication =
utils::update_trackers(state, response.clone(), authentication_data, None).await?;
response
.response
.map_err(|err| ApiErrorResponse::ExternalConnectorError {
code: err.code,
message: err.message,
connector: authentication_connector,
status_code: err.status_code,
reason: err.reason,
})?;
api::authentication::AuthenticationResponse::try_from(authentication)
}
pub async fn perform_post_authentication(
state: &SessionState,
key_store: &domain::MerchantKeyStore,
business_profile: domain::BusinessProfile,
authentication_id: String,
) -> CustomResult<storage::Authentication, ApiErrorResponse> {
let (authentication_connector, three_ds_connector_account) =
utils::get_authentication_connector_data(state, key_store, &business_profile).await?;
let is_pull_mechanism_enabled =
check_if_pull_mechanism_for_external_3ds_enabled_from_connector_metadata(
three_ds_connector_account
.get_metadata()
.map(|metadata| metadata.expose()),
);
let authentication = state
.store
.find_authentication_by_merchant_id_authentication_id(
&business_profile.merchant_id,
authentication_id.clone(),
)
.await
.to_not_found_response(ApiErrorResponse::InternalServerError)
.attach_printable_lazy(|| format!("Error while fetching authentication record with authentication_id {authentication_id}"))?;
if !authentication.authentication_status.is_terminal_status() && is_pull_mechanism_enabled {
let router_data = transformers::construct_post_authentication_router_data(
authentication_connector.to_string(),
business_profile,
three_ds_connector_account,
&authentication,
)?;
let router_data =
utils::do_auth_connector_call(state, authentication_connector.to_string(), router_data)
.await?;
utils::update_trackers(state, router_data, authentication, None).await
} else {
Ok(authentication)
}
}
pub async fn perform_pre_authentication(
state: &SessionState,
key_store: &domain::MerchantKeyStore,
card_number: cards::CardNumber,
token: String,
business_profile: &domain::BusinessProfile,
acquirer_details: Option<types::AcquirerDetails>,
payment_id: Option<String>,
) -> CustomResult<storage::Authentication, ApiErrorResponse> {
let (authentication_connector, three_ds_connector_account) =
utils::get_authentication_connector_data(state, key_store, business_profile).await?;
let authentication_connector_name = authentication_connector.to_string();
let authentication = utils::create_new_authentication(
state,
business_profile.merchant_id.clone(),
authentication_connector_name.clone(),
token,
business_profile.profile_id.clone(),
payment_id,
three_ds_connector_account
.get_mca_id()
.ok_or(ApiErrorResponse::InternalServerError)
.attach_printable("Error while finding mca_id from merchant_connector_account")?,
)
.await?;
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?;
utils::update_trackers(state, router_data, authentication, acquirer_details).await
}