feat(router): skip apple pay session call if the browser is not Safari (#5136)

This commit is contained in:
Shankar Singh C
2024-06-27 18:08:07 +05:30
committed by GitHub
parent 9c49ded104
commit d4dba55fed
26 changed files with 213 additions and 62 deletions

View File

@ -461,6 +461,7 @@ where
&customer,
session_surcharge_details,
&business_profile,
header_payload.clone(),
))
.await?
}
@ -1610,6 +1611,7 @@ where
call_connector_action,
connector_request,
business_profile,
header_payload.clone(),
)
.await
} else {
@ -1673,6 +1675,7 @@ pub async fn call_multiple_connectors_service<F, Op, Req>(
customer: &Option<domain::Customer>,
session_surcharge_details: Option<api::SessionSurchargeDetails>,
business_profile: &storage::business_profile::BusinessProfile,
header_payload: HeaderPayload,
) -> RouterResult<PaymentData<F>>
where
Op: Debug,
@ -1736,6 +1739,7 @@ where
CallConnectorAction::Trigger,
None,
business_profile,
header_payload.clone(),
);
join_handlers.push(res);

View File

@ -47,6 +47,7 @@ pub trait Feature<F, T> {
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
business_profile: &storage::business_profile::BusinessProfile,
header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self>
where
Self: Sized,

View File

@ -52,6 +52,7 @@ impl Feature<api::Approve, types::PaymentsApproveData>
_call_connector_action: payments::CallConnectorAction,
_connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
Err(ApiErrorResponse::NotImplemented {
message: NotImplementedMessage::Reason("Flow not supported".to_string()),

View File

@ -65,6 +65,7 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
api::Authorize,

View File

@ -52,6 +52,7 @@ impl Feature<api::Void, types::PaymentsCancelData>
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
metrics::PAYMENT_CANCEL_COUNT.add(
&metrics::CONTEXT,

View File

@ -52,6 +52,7 @@ impl Feature<api::Capture, types::PaymentsCaptureData>
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
api::Capture,

View File

@ -66,6 +66,7 @@ impl Feature<api::CompleteAuthorize, types::CompleteAuthorizeData>
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
api::CompleteAuthorize,

View File

@ -59,6 +59,7 @@ impl Feature<api::IncrementalAuthorization, types::PaymentsIncrementalAuthorizat
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
api::IncrementalAuthorization,

View File

@ -55,6 +55,7 @@ impl Feature<api::PSync, types::PaymentsSyncData>
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
api::PSync,

View File

@ -51,6 +51,7 @@ impl Feature<api::Reject, types::PaymentsRejectData>
_call_connector_action: payments::CallConnectorAction,
_connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
Err(ApiErrorResponse::NotImplemented {
message: NotImplementedMessage::Reason("Flow not supported".to_string()),

View File

@ -65,6 +65,7 @@ impl Feature<api::Session, types::PaymentsSessionData> for types::PaymentsSessio
call_connector_action: payments::CallConnectorAction,
_connector_request: Option<services::Request>,
business_profile: &storage::business_profile::BusinessProfile,
header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
metrics::SESSION_TOKEN_CREATED.add(
&metrics::CONTEXT,
@ -77,6 +78,7 @@ impl Feature<api::Session, types::PaymentsSessionData> for types::PaymentsSessio
Some(true),
call_connector_action,
business_profile,
header_payload,
)
.await
}
@ -155,6 +157,7 @@ async fn create_applepay_session_token(
router_data: &types::PaymentsSessionRouterData,
connector: &api::ConnectorData,
business_profile: &storage::business_profile::BusinessProfile,
header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<types::PaymentsSessionRouterData> {
let delayed_response = is_session_response_delayed(state, connector);
if delayed_response {
@ -188,9 +191,10 @@ async fn create_applepay_session_token(
// Get payment request data , apple pay session request and merchant keys
let (
payment_request_data,
apple_pay_session_request,
apple_pay_session_request_optional,
apple_pay_merchant_cert,
apple_pay_merchant_cert_key,
apple_pay_merchant_identifier,
merchant_business_country,
) = match apple_pay_metadata {
payment_types::ApplepaySessionTokenMetadata::ApplePayCombined(
@ -213,7 +217,7 @@ async fn create_applepay_session_token(
let merchant_business_country = session_token_data.merchant_business_country;
let apple_pay_session_request = get_session_request_for_simplified_apple_pay(
merchant_identifier,
merchant_identifier.clone(),
session_token_data,
);
@ -233,9 +237,10 @@ async fn create_applepay_session_token(
(
payment_request_data,
apple_pay_session_request,
Ok(apple_pay_session_request),
apple_pay_merchant_cert,
apple_pay_merchant_cert_key,
merchant_identifier,
merchant_business_country,
)
}
@ -255,6 +260,7 @@ async fn create_applepay_session_token(
apple_pay_session_request,
session_token_data.certificate.clone(),
session_token_data.certificate_keys,
session_token_data.merchant_identifier,
merchant_business_country,
)
}
@ -273,7 +279,11 @@ async fn create_applepay_session_token(
apple_pay_metadata.payment_request_data,
apple_pay_session_request,
apple_pay_metadata.session_token_data.certificate.clone(),
apple_pay_metadata.session_token_data.certificate_keys,
apple_pay_metadata
.session_token_data
.certificate_keys
.clone(),
apple_pay_metadata.session_token_data.merchant_identifier,
merchant_business_country,
)
}
@ -323,48 +333,63 @@ async fn create_applepay_session_token(
amount_info,
payment_request_data,
router_data.request.to_owned(),
apple_pay_session_request.merchant_identifier.as_str(),
apple_pay_merchant_identifier.as_str(),
merchant_business_country,
required_billing_contact_fields,
required_shipping_contact_fields,
)?;
let applepay_session_request = build_apple_pay_session_request(
state,
apple_pay_session_request,
apple_pay_merchant_cert,
apple_pay_merchant_cert_key,
)?;
let response = services::call_connector_api(
state,
applepay_session_request,
"create_apple_pay_session_token",
)
.await;
let apple_pay_session_response = match (
header_payload.browser_name,
header_payload.x_client_platform,
) {
(Some(common_enums::BrowserName::Safari), Some(common_enums::ClientPlatform::Web))
| (None, None) => {
let apple_pay_session_request = apple_pay_session_request_optional
.attach_printable("Failed to obtain apple pay session request")?;
let applepay_session_request = build_apple_pay_session_request(
state,
apple_pay_session_request,
apple_pay_merchant_cert,
apple_pay_merchant_cert_key,
)?;
// logging the error if present in session call response
log_session_response_if_error(&response);
let response = services::call_connector_api(
state,
applepay_session_request,
"create_apple_pay_session_token",
)
.await;
let apple_pay_session_response = response
.ok()
.and_then(|apple_pay_res| {
apple_pay_res
.map(|res| {
let response: Result<
payment_types::NoThirdPartySdkSessionResponse,
Report<common_utils::errors::ParsingError>,
> = res.response.parse_struct("NoThirdPartySdkSessionResponse");
// logging the error if present in session call response
log_session_response_if_error(&response);
// logging the parsing failed error
if let Err(error) = response.as_ref() {
logger::error!(?error);
};
response.ok()
})
response
.ok()
})
.flatten();
.and_then(|apple_pay_res| {
apple_pay_res
.map(|res| {
let response: Result<
payment_types::NoThirdPartySdkSessionResponse,
Report<common_utils::errors::ParsingError>,
> = res.response.parse_struct("NoThirdPartySdkSessionResponse");
// logging the parsing failed error
if let Err(error) = response.as_ref() {
logger::error!(?error);
};
response.ok()
})
.ok()
})
.flatten()
}
_ => {
logger::debug!("Skipping apple pay session call based on the browser name");
None
}
};
let session_response =
apple_pay_session_response.map(payment_types::ApplePaySessionResponse::NoThirdPartySdk);
@ -394,13 +419,17 @@ fn get_session_request_for_simplified_apple_pay(
fn get_session_request_for_manual_apple_pay(
session_token_data: payment_types::SessionTokenInfo,
) -> payment_types::ApplepaySessionRequest {
payment_types::ApplepaySessionRequest {
) -> RouterResult<payment_types::ApplepaySessionRequest> {
let initiative_context = session_token_data
.initiative_context
.ok_or(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to get initiative_context for apple pay session call")?;
Ok(payment_types::ApplepaySessionRequest {
merchant_identifier: session_token_data.merchant_identifier.clone(),
display_name: session_token_data.display_name.clone(),
initiative: session_token_data.initiative.clone(),
initiative_context: session_token_data.initiative_context,
}
initiative: session_token_data.initiative.to_string(),
initiative_context,
})
}
fn get_apple_pay_amount_info(
@ -461,7 +490,7 @@ fn create_apple_pay_session_response(
response: Ok(types::PaymentsResponseData::SessionResponse {
session_token: payment_types::SessionToken::ApplePay(Box::new(
payment_types::ApplepaySessionTokenResponse {
session_token_data: response,
session_token_data: Some(response),
payment_request_data: apple_pay_payment_request,
connector: connector_name,
delayed_session_token: delayed_response,
@ -476,7 +505,18 @@ fn create_apple_pay_session_response(
}),
None => Ok(types::PaymentsSessionRouterData {
response: Ok(types::PaymentsResponseData::SessionResponse {
session_token: payment_types::SessionToken::NoSessionTokenReceived,
session_token: payment_types::SessionToken::ApplePay(Box::new(
payment_types::ApplepaySessionTokenResponse {
session_token_data: None,
payment_request_data: apple_pay_payment_request,
connector: connector_name,
delayed_session_token: delayed_response,
sdk_next_action: { payment_types::SdkNextAction { next_action } },
connector_reference_id: None,
connector_sdk_public_key: None,
connector_merchant_id: None,
},
)),
}),
..router_data.clone()
}),
@ -650,6 +690,7 @@ where
_confirm: Option<bool>,
call_connector_action: payments::CallConnectorAction,
business_profile: &storage::business_profile::BusinessProfile,
header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self>;
}
@ -698,13 +739,21 @@ impl RouterDataSession for types::PaymentsSessionRouterData {
_confirm: Option<bool>,
call_connector_action: payments::CallConnectorAction,
business_profile: &storage::business_profile::BusinessProfile,
header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
match connector.get_token {
api::GetToken::GpayMetadata => {
create_gpay_session_token(state, self, connector, business_profile)
}
api::GetToken::ApplePayMetadata => {
create_applepay_session_token(state, self, connector, business_profile).await
create_applepay_session_token(
state,
self,
connector,
business_profile,
header_payload,
)
.await
}
api::GetToken::PaypalSdkMetadata => {
create_paypal_sdk_session_token(state, self, connector, business_profile)

View File

@ -57,6 +57,7 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
call_connector_action: payments::CallConnectorAction,
connector_request: Option<services::Request>,
_business_profile: &storage::business_profile::BusinessProfile,
_header_payload: api_models::payments::HeaderPayload,
) -> RouterResult<Self> {
let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
api::SetupMandate,