mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 20:23:43 +08:00
feat(connector): implement auth and post auth flows for gpayments (#4746)
Co-authored-by: hrithikesh026 <hrithikesh.vm@juspay.in> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com>
This commit is contained in:
@ -9,6 +9,7 @@ use transformers as gpayments;
|
||||
|
||||
use crate::{
|
||||
configs::settings,
|
||||
connector::{gpayments::gpayments_types::GpaymentsConnectorMetaData, utils::to_connector_meta},
|
||||
core::errors::{self, CustomResult},
|
||||
events::connector_api_logs::ConnectorEvent,
|
||||
headers, services,
|
||||
@ -214,8 +215,103 @@ impl
|
||||
types::authentication::AuthenticationResponseData,
|
||||
> for Gpayments
|
||||
{
|
||||
}
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &types::authentication::ConnectorAuthenticationRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
self.common_get_content_type()
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
req: &types::authentication::ConnectorAuthenticationRouterData,
|
||||
_connectors: &settings::Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
let connector_metadata: GpaymentsConnectorMetaData = to_connector_meta(
|
||||
req.request
|
||||
.pre_authentication_data
|
||||
.connector_metadata
|
||||
.clone(),
|
||||
)?;
|
||||
Ok(connector_metadata.authentication_url)
|
||||
}
|
||||
|
||||
fn get_request_body(
|
||||
&self,
|
||||
req: &types::authentication::ConnectorAuthenticationRouterData,
|
||||
_connectors: &settings::Connectors,
|
||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||
let connector_router_data = gpayments::GpaymentsRouterData::try_from((0, req))?;
|
||||
let req_obj =
|
||||
gpayments_types::GpaymentsAuthenticationRequest::try_from(&connector_router_data)?;
|
||||
Ok(RequestContent::Json(Box::new(req_obj)))
|
||||
}
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &types::authentication::ConnectorAuthenticationRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||
let gpayments_auth_type = gpayments::GpaymentsAuthType::try_from(&req.connector_auth_type)?;
|
||||
Ok(Some(
|
||||
services::RequestBuilder::new()
|
||||
.method(services::Method::Post)
|
||||
.url(
|
||||
&types::authentication::ConnectorAuthenticationType::get_url(
|
||||
self, req, connectors,
|
||||
)?,
|
||||
)
|
||||
.attach_default_headers()
|
||||
.headers(
|
||||
types::authentication::ConnectorAuthenticationType::get_headers(
|
||||
self, req, connectors,
|
||||
)?,
|
||||
)
|
||||
.set_body(
|
||||
types::authentication::ConnectorAuthenticationType::get_request_body(
|
||||
self, req, connectors,
|
||||
)?,
|
||||
)
|
||||
.add_certificate(Some(gpayments_auth_type.certificate))
|
||||
.add_certificate_key(Some(gpayments_auth_type.private_key))
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &types::authentication::ConnectorAuthenticationRouterData,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
res: Response,
|
||||
) -> CustomResult<
|
||||
types::authentication::ConnectorAuthenticationRouterData,
|
||||
errors::ConnectorError,
|
||||
> {
|
||||
let response: gpayments_types::GpaymentsAuthenticationSuccessResponse = res
|
||||
.response
|
||||
.parse_struct("gpayments GpaymentsAuthenticationResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
types::RouterData::try_from(types::ResponseRouterData {
|
||||
response,
|
||||
data: data.clone(),
|
||||
http_code: res.status_code,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: Response,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||
self.build_error_response(res, event_builder)
|
||||
}
|
||||
}
|
||||
impl
|
||||
ConnectorIntegration<
|
||||
api::PostAuthentication,
|
||||
@ -223,6 +319,92 @@ impl
|
||||
types::authentication::AuthenticationResponseData,
|
||||
> for Gpayments
|
||||
{
|
||||
fn get_headers(
|
||||
&self,
|
||||
req: &types::authentication::ConnectorPostAuthenticationRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<Vec<(String, request::Maskable<String>)>, errors::ConnectorError> {
|
||||
self.build_headers(req, connectors)
|
||||
}
|
||||
|
||||
fn get_content_type(&self) -> &'static str {
|
||||
self.common_get_content_type()
|
||||
}
|
||||
|
||||
fn get_url(
|
||||
&self,
|
||||
req: &types::authentication::ConnectorPostAuthenticationRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<String, errors::ConnectorError> {
|
||||
let base_url = build_endpoint(self.base_url(connectors), &req.connector_meta_data)?;
|
||||
Ok(format!(
|
||||
"{}/api/v2/auth/brw/result?threeDSServerTransID={}",
|
||||
base_url, req.request.threeds_server_transaction_id,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_request(
|
||||
&self,
|
||||
req: &types::authentication::ConnectorPostAuthenticationRouterData,
|
||||
connectors: &settings::Connectors,
|
||||
) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
|
||||
let gpayments_auth_type = gpayments::GpaymentsAuthType::try_from(&req.connector_auth_type)?;
|
||||
Ok(Some(
|
||||
services::RequestBuilder::new()
|
||||
.method(services::Method::Get)
|
||||
.url(
|
||||
&types::authentication::ConnectorPostAuthenticationType::get_url(
|
||||
self, req, connectors,
|
||||
)?,
|
||||
)
|
||||
.attach_default_headers()
|
||||
.headers(
|
||||
types::authentication::ConnectorPostAuthenticationType::get_headers(
|
||||
self, req, connectors,
|
||||
)?,
|
||||
)
|
||||
.add_certificate(Some(gpayments_auth_type.certificate))
|
||||
.add_certificate_key(Some(gpayments_auth_type.private_key))
|
||||
.build(),
|
||||
))
|
||||
}
|
||||
|
||||
fn handle_response(
|
||||
&self,
|
||||
data: &types::authentication::ConnectorPostAuthenticationRouterData,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
res: Response,
|
||||
) -> CustomResult<
|
||||
types::authentication::ConnectorPostAuthenticationRouterData,
|
||||
errors::ConnectorError,
|
||||
> {
|
||||
let response: gpayments_types::GpaymentsPostAuthenticationResponse = res
|
||||
.response
|
||||
.parse_struct("gpayments PaymentsSyncResponse")
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
|
||||
event_builder.map(|i| i.set_response_body(&response));
|
||||
router_env::logger::info!(connector_response=?response);
|
||||
Ok(
|
||||
types::authentication::ConnectorPostAuthenticationRouterData {
|
||||
response: Ok(
|
||||
types::authentication::AuthenticationResponseData::PostAuthNResponse {
|
||||
trans_status: response.trans_status.into(),
|
||||
authentication_value: response.authentication_value,
|
||||
eci: response.eci,
|
||||
},
|
||||
),
|
||||
..data.clone()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn get_error_response(
|
||||
&self,
|
||||
res: Response,
|
||||
event_builder: Option<&mut ConnectorEvent>,
|
||||
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
|
||||
self.build_error_response(res, event_builder)
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
use api_models::payments::ThreeDsCompletionIndicator;
|
||||
use cards::CardNumber;
|
||||
use common_utils::types;
|
||||
use masking::{Deserialize, Serialize};
|
||||
use masking::{Deserialize, Secret, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GpaymentsConnectorMetaData {
|
||||
pub authentication_url: String,
|
||||
pub three_ds_requestor_trans_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GpaymentsPreAuthVersionCallRequest {
|
||||
@ -38,6 +38,9 @@ pub struct TDS2ApiError {
|
||||
pub error_description: String,
|
||||
pub error_detail: Option<String>,
|
||||
pub error_message_type: Option<String>,
|
||||
/// Always returns 'Error' to indicate that this message is an error.
|
||||
///
|
||||
/// Example: "Error"
|
||||
pub message_type: String,
|
||||
pub message_version: Option<String>,
|
||||
#[serde(rename = "sdkTransID")]
|
||||
@ -122,3 +125,112 @@ pub struct GpaymentsPreAuthenticationResponse {
|
||||
#[serde(rename = "threeDSServerTransID")]
|
||||
pub three_ds_server_trans_id: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GpaymentsAuthenticationRequest {
|
||||
pub acct_number: CardNumber,
|
||||
pub authentication_ind: String,
|
||||
pub browser_info_collected: BrowserInfoCollected,
|
||||
pub card_expiry_date: String,
|
||||
#[serde(rename = "notificationURL")]
|
||||
pub notification_url: String,
|
||||
pub merchant_id: String,
|
||||
#[serde(rename = "threeDSCompInd")]
|
||||
pub three_ds_comp_ind: ThreeDsCompletionIndicator,
|
||||
pub message_category: String,
|
||||
pub purchase_amount: String,
|
||||
pub purchase_date: String,
|
||||
#[serde(rename = "threeDSServerTransID")]
|
||||
pub three_ds_server_trans_id: String,
|
||||
}
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BrowserInfoCollected {
|
||||
pub browser_accept_header: Option<String>,
|
||||
pub browser_color_depth: Option<String>,
|
||||
#[serde(rename = "browserIP")]
|
||||
pub browser_ip: Option<Secret<String, common_utils::pii::IpAddress>>,
|
||||
pub browser_javascript_enabled: Option<bool>,
|
||||
pub browser_java_enabled: Option<bool>,
|
||||
pub browser_language: Option<String>,
|
||||
pub browser_screen_height: Option<String>,
|
||||
pub browser_screen_width: Option<String>,
|
||||
#[serde(rename = "browserTZ")]
|
||||
pub browser_tz: Option<String>,
|
||||
pub browser_user_agent: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum AuthenticationInd {
|
||||
#[serde(rename = "01")]
|
||||
PaymentTransaction,
|
||||
#[serde(rename = "02")]
|
||||
RecurringTransaction,
|
||||
#[serde(rename = "03")]
|
||||
InstalmentTransaction,
|
||||
#[serde(rename = "04")]
|
||||
AddCard,
|
||||
#[serde(rename = "05")]
|
||||
MaintainCard,
|
||||
#[serde(rename = "06")]
|
||||
CardholderVerification,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GpaymentsAuthenticationSuccessResponse {
|
||||
#[serde(rename = "dsReferenceNumber")]
|
||||
pub ds_reference_number: String,
|
||||
#[serde(rename = "dsTransID")]
|
||||
pub ds_trans_id: String,
|
||||
#[serde(rename = "threeDSServerTransID")]
|
||||
pub three_ds_server_trans_id: String,
|
||||
#[serde(rename = "messageVersion")]
|
||||
pub message_version: String,
|
||||
#[serde(rename = "transStatus")]
|
||||
pub trans_status: AuthStatus,
|
||||
#[serde(rename = "acsTransID")]
|
||||
pub acs_trans_id: String,
|
||||
#[serde(rename = "challengeUrl")]
|
||||
pub acs_url: Option<url::Url>,
|
||||
#[serde(rename = "acsReferenceNumber")]
|
||||
pub acs_reference_number: String,
|
||||
pub authentication_value: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone, Serialize, PartialEq)]
|
||||
pub enum AuthStatus {
|
||||
/// Authentication/ Account Verification Successful
|
||||
Y,
|
||||
/// Not Authenticated /Account Not Verified; Transaction denied
|
||||
N,
|
||||
/// Authentication/ Account Verification Could Not Be Performed; Technical or other problem, as indicated in ARes or RReq
|
||||
U,
|
||||
/// Attempts Processing Performed; Not Authenticated/Verified , but a proof of attempted authentication/verification is provided
|
||||
A,
|
||||
/// Authentication/ Account Verification Rejected; Issuer is rejecting authentication/verification and request that authorisation not be attempted.
|
||||
R,
|
||||
/// Challenge required
|
||||
C,
|
||||
}
|
||||
|
||||
impl From<AuthStatus> for common_enums::TransactionStatus {
|
||||
fn from(value: AuthStatus) -> Self {
|
||||
match value {
|
||||
AuthStatus::Y => Self::Success,
|
||||
AuthStatus::N => Self::Failure,
|
||||
AuthStatus::U => Self::VerificationNotPerformed,
|
||||
AuthStatus::A => Self::NotVerified,
|
||||
AuthStatus::R => Self::Rejected,
|
||||
AuthStatus::C => Self::ChallengeRequired,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GpaymentsPostAuthenticationResponse {
|
||||
pub authentication_value: Option<String>,
|
||||
pub trans_status: AuthStatus,
|
||||
pub eci: Option<String>,
|
||||
}
|
||||
|
||||
@ -1,16 +1,25 @@
|
||||
use api_models::payments::DeviceChannel;
|
||||
use base64::Engine;
|
||||
use common_utils::date_time;
|
||||
use error_stack::ResultExt;
|
||||
use masking::Secret;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use masking::{ExposeInterface, Secret};
|
||||
use serde::Deserialize;
|
||||
use serde_json::to_string;
|
||||
|
||||
use super::gpayments_types;
|
||||
use crate::{
|
||||
connector::utils,
|
||||
consts,
|
||||
connector::{
|
||||
gpayments::gpayments_types::{
|
||||
AuthStatus, BrowserInfoCollected, GpaymentsAuthenticationSuccessResponse,
|
||||
},
|
||||
utils,
|
||||
utils::{get_card_details, CardData},
|
||||
},
|
||||
consts::BASE64_ENGINE,
|
||||
core::errors,
|
||||
types::{self, api},
|
||||
types::{self, api, api::MessageCategory, authentication::ChallengeParams},
|
||||
};
|
||||
|
||||
//TODO: Fill the struct with respective fields
|
||||
pub struct GpaymentsRouterData<T> {
|
||||
pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
|
||||
pub router_data: T,
|
||||
@ -26,7 +35,6 @@ impl<T> TryFrom<(i64, T)> for GpaymentsRouterData<T> {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Fill the struct with respective fields
|
||||
// Auth Struct
|
||||
pub struct GpaymentsAuthType {
|
||||
/// base64 encoded certificate
|
||||
@ -68,15 +76,6 @@ impl TryFrom<&GpaymentsRouterData<&types::authentication::PreAuthNVersionCallRou
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Fill the struct with respective fields
|
||||
#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct GpaymentsErrorResponse {
|
||||
pub status_code: u16,
|
||||
pub code: String,
|
||||
pub message: String,
|
||||
pub reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq)]
|
||||
pub struct GpaymentsMetaData {
|
||||
pub endpoint_prefix: String,
|
||||
@ -146,11 +145,9 @@ impl TryFrom<&GpaymentsRouterData<&types::authentication::PreAuthNRouterData>>
|
||||
acct_number: router_data.request.card_holder_account_number.clone(),
|
||||
card_scheme: None,
|
||||
challenge_window_size: Some(gpayments_types::ChallengeWindowSize::FullScreen),
|
||||
// This is a required field but we don't listen to event callbacks
|
||||
event_callback_url: "https://webhook.site/55e3db24-7c4e-4432-9941-d806f68d210b"
|
||||
.to_string(),
|
||||
merchant_id: metadata.merchant_id,
|
||||
// Since this feature is not in our favour, hard coded it to true
|
||||
skip_auto_browser_info_collect: Some(true),
|
||||
// should auto generate this id.
|
||||
three_ds_requestor_trans_id: uuid::Uuid::new_v4().hyphenated().to_string(),
|
||||
@ -158,6 +155,151 @@ impl TryFrom<&GpaymentsRouterData<&types::authentication::PreAuthNRouterData>>
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&GpaymentsRouterData<&types::authentication::ConnectorAuthenticationRouterData>>
|
||||
for gpayments_types::GpaymentsAuthenticationRequest
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
|
||||
fn try_from(
|
||||
item: &GpaymentsRouterData<&types::authentication::ConnectorAuthenticationRouterData>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let request = &item.router_data.request;
|
||||
let browser_details = match request.browser_details.clone() {
|
||||
Some(details) => Ok::<Option<types::BrowserInformation>, Self::Error>(Some(details)),
|
||||
None => {
|
||||
if request.device_channel == DeviceChannel::Browser {
|
||||
Err(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "browser_info",
|
||||
})?
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}?;
|
||||
let card_details = get_card_details(request.payment_method_data.clone(), "gpayments")?;
|
||||
|
||||
let metadata = GpaymentsMetaData::try_from(&item.router_data.connector_meta_data)?;
|
||||
|
||||
Ok(Self {
|
||||
acct_number: card_details.card_number.clone(),
|
||||
authentication_ind: "01".into(),
|
||||
card_expiry_date: card_details.get_expiry_date_as_yymm()?.expose(),
|
||||
merchant_id: metadata.merchant_id,
|
||||
message_category: match item.router_data.request.message_category.clone() {
|
||||
MessageCategory::Payment => "01".into(),
|
||||
MessageCategory::NonPayment => "02".into(),
|
||||
},
|
||||
notification_url: request
|
||||
.return_url
|
||||
.clone()
|
||||
.ok_or(errors::ConnectorError::RequestEncodingFailed)
|
||||
.attach_printable("missing return_url")?,
|
||||
three_ds_comp_ind: request.threeds_method_comp_ind.clone(),
|
||||
purchase_amount: item.amount.to_string(),
|
||||
purchase_date: date_time::DateTime::<date_time::YYYYMMDDHHmmss>::from(date_time::now())
|
||||
.to_string(),
|
||||
three_ds_server_trans_id: request
|
||||
.pre_authentication_data
|
||||
.threeds_server_transaction_id
|
||||
.clone(),
|
||||
browser_info_collected: BrowserInfoCollected {
|
||||
browser_javascript_enabled: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.java_script_enabled),
|
||||
browser_accept_header: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.accept_header.clone()),
|
||||
browser_ip: browser_details
|
||||
.clone()
|
||||
.and_then(|details| details.ip_address.map(|ip| Secret::new(ip.to_string()))),
|
||||
browser_java_enabled: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.java_enabled),
|
||||
browser_language: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.language.clone()),
|
||||
browser_color_depth: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.color_depth.map(|a| a.to_string())),
|
||||
browser_screen_height: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.screen_height.map(|a| a.to_string())),
|
||||
browser_screen_width: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.screen_width.map(|a| a.to_string())),
|
||||
browser_tz: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.time_zone.map(|a| a.to_string())),
|
||||
browser_user_agent: browser_details
|
||||
.as_ref()
|
||||
.and_then(|details| details.user_agent.clone().map(|a| a.to_string())),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
impl
|
||||
TryFrom<
|
||||
types::ResponseRouterData<
|
||||
api::Authentication,
|
||||
GpaymentsAuthenticationSuccessResponse,
|
||||
types::authentication::ConnectorAuthenticationRequestData,
|
||||
types::authentication::AuthenticationResponseData,
|
||||
>,
|
||||
> for types::authentication::ConnectorAuthenticationRouterData
|
||||
{
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
fn try_from(
|
||||
item: types::ResponseRouterData<
|
||||
api::Authentication,
|
||||
GpaymentsAuthenticationSuccessResponse,
|
||||
types::authentication::ConnectorAuthenticationRequestData,
|
||||
types::authentication::AuthenticationResponseData,
|
||||
>,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let response_auth = item.response;
|
||||
let creq = serde_json::json!({
|
||||
"threeDSServerTransID": response_auth.three_ds_server_trans_id,
|
||||
"acsTransID": response_auth.acs_trans_id,
|
||||
"messageVersion": response_auth.message_version,
|
||||
"messageType": "CReq",
|
||||
"challengeWindowSize": "01",
|
||||
});
|
||||
let creq_str = to_string(&creq)
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)
|
||||
.attach_printable("error while constructing creq_str")?;
|
||||
let creq_base64 = Engine::encode(&BASE64_ENGINE, creq_str)
|
||||
.trim_end_matches('=')
|
||||
.to_owned();
|
||||
let response: Result<
|
||||
types::authentication::AuthenticationResponseData,
|
||||
types::ErrorResponse,
|
||||
> = Ok(
|
||||
types::authentication::AuthenticationResponseData::AuthNResponse {
|
||||
trans_status: response_auth.trans_status.clone().into(),
|
||||
authn_flow_type: if response_auth.trans_status == AuthStatus::C {
|
||||
types::authentication::AuthNFlowType::Challenge(Box::new(ChallengeParams {
|
||||
acs_url: response_auth.acs_url,
|
||||
challenge_request: Some(creq_base64),
|
||||
acs_reference_number: Some(response_auth.acs_reference_number.clone()),
|
||||
acs_trans_id: Some(response_auth.acs_trans_id.clone()),
|
||||
three_dsserver_trans_id: Some(response_auth.three_ds_server_trans_id),
|
||||
acs_signed_content: None,
|
||||
}))
|
||||
} else {
|
||||
types::authentication::AuthNFlowType::Frictionless
|
||||
},
|
||||
authentication_value: response_auth.authentication_value,
|
||||
ds_trans_id: Some(response_auth.ds_trans_id),
|
||||
connector_metadata: None,
|
||||
},
|
||||
);
|
||||
Ok(Self {
|
||||
response,
|
||||
..item.data.clone()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl
|
||||
TryFrom<
|
||||
types::ResponseRouterData<
|
||||
@ -186,11 +328,11 @@ impl
|
||||
"threeDSServerTransID": threeds_method_response.three_ds_server_trans_id,
|
||||
"threeDSMethodNotificationURL": "https://webhook.site/bd06863d-82c2-42ea-b35b-5ffd5ecece71"
|
||||
});
|
||||
serde_json::to_string(&three_ds_method_data_json)
|
||||
to_string(&three_ds_method_data_json)
|
||||
.change_context(errors::ConnectorError::ResponseDeserializationFailed)
|
||||
.attach_printable("error while constructing three_ds_method_data_str")
|
||||
.map(|three_ds_method_data_string| {
|
||||
base64::Engine::encode(&consts::BASE64_ENGINE, three_ds_method_data_string)
|
||||
Engine::encode(&BASE64_ENGINE, three_ds_method_data_string)
|
||||
})
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
Reference in New Issue
Block a user