mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
feat(payment): customer ip field inclusion (#1370)
Co-authored-by: shashank_attarde <shashank.attarde@juspay.in>
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
use api_models::{enums, payments, webhooks};
|
||||
use cards::CardNumber;
|
||||
use error_stack::ResultExt;
|
||||
use masking::PeekInterface;
|
||||
use reqwest::Url;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -19,6 +20,7 @@ use crate::{
|
||||
storage::enums as storage_enums,
|
||||
transformers::ForeignFrom,
|
||||
},
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
@ -839,25 +841,73 @@ fn get_recurring_processing_model(
|
||||
}
|
||||
}
|
||||
|
||||
fn get_browser_info(item: &types::PaymentsAuthorizeRouterData) -> Option<AdyenBrowserInfo> {
|
||||
fn get_browser_info(
|
||||
item: &types::PaymentsAuthorizeRouterData,
|
||||
) -> Result<Option<AdyenBrowserInfo>, Error> {
|
||||
if item.auth_type == storage_enums::AuthenticationType::ThreeDs
|
||||
|| item.payment_method == storage_enums::PaymentMethod::BankRedirect
|
||||
{
|
||||
item.request
|
||||
.browser_info
|
||||
.as_ref()
|
||||
.map(|info| AdyenBrowserInfo {
|
||||
accept_header: info.accept_header.clone(),
|
||||
language: info.language.clone(),
|
||||
screen_height: info.screen_height,
|
||||
screen_width: info.screen_width,
|
||||
color_depth: info.color_depth,
|
||||
user_agent: info.user_agent.clone(),
|
||||
time_zone_offset: info.time_zone,
|
||||
java_enabled: info.java_enabled,
|
||||
.map(|info| {
|
||||
Ok(AdyenBrowserInfo {
|
||||
accept_header: info
|
||||
.accept_header
|
||||
.clone()
|
||||
.get_required_value("accept_header")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "accept_header",
|
||||
})?,
|
||||
language: info
|
||||
.language
|
||||
.clone()
|
||||
.get_required_value("language")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "language",
|
||||
})?,
|
||||
screen_height: info
|
||||
.screen_height
|
||||
.get_required_value("screen_height")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_height",
|
||||
})?,
|
||||
screen_width: info
|
||||
.screen_width
|
||||
.get_required_value("screen_width")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_width",
|
||||
})?,
|
||||
color_depth: info
|
||||
.color_depth
|
||||
.get_required_value("color_depth")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "color_depth",
|
||||
})?,
|
||||
user_agent: info
|
||||
.user_agent
|
||||
.clone()
|
||||
.get_required_value("user_agent")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "user_agent",
|
||||
})?,
|
||||
time_zone_offset: info
|
||||
.time_zone
|
||||
.get_required_value("time_zone_offset")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "time_zone_offset",
|
||||
})?,
|
||||
java_enabled: info
|
||||
.java_enabled
|
||||
.get_required_value("java_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "java_enabled",
|
||||
})?,
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
} else {
|
||||
None
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1246,7 +1296,7 @@ impl<'a>
|
||||
let shopper_interaction = AdyenShopperInteraction::from(item);
|
||||
let (recurring_processing_model, store_payment_method, shopper_reference) =
|
||||
get_recurring_processing_model(item)?;
|
||||
let browser_info = get_browser_info(item);
|
||||
let browser_info = get_browser_info(item)?;
|
||||
let additional_data = get_additional_data(item);
|
||||
let return_url = item.request.get_return_url()?;
|
||||
let payment_method = match mandate_ref_id {
|
||||
@ -1318,7 +1368,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::Card)> for AdyenPay
|
||||
let shopper_interaction = AdyenShopperInteraction::from(item);
|
||||
let (recurring_processing_model, store_payment_method, shopper_reference) =
|
||||
get_recurring_processing_model(item)?;
|
||||
let browser_info = get_browser_info(item);
|
||||
let browser_info = get_browser_info(item)?;
|
||||
let additional_data = get_additional_data(item);
|
||||
let return_url = item.request.get_return_url()?;
|
||||
let payment_method = AdyenPaymentMethod::try_from(card_data)?;
|
||||
@ -1365,7 +1415,7 @@ impl<'a>
|
||||
let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
|
||||
let shopper_interaction = AdyenShopperInteraction::from(item);
|
||||
let recurring_processing_model = get_recurring_processing_model(item)?.0;
|
||||
let browser_info = get_browser_info(item);
|
||||
let browser_info = get_browser_info(item)?;
|
||||
let additional_data = get_additional_data(item);
|
||||
let return_url = item.request.get_return_url()?;
|
||||
let payment_method = AdyenPaymentMethod::try_from(bank_debit_data)?;
|
||||
@ -1414,7 +1464,7 @@ impl<'a>
|
||||
let shopper_interaction = AdyenShopperInteraction::from(item);
|
||||
let (recurring_processing_model, store_payment_method, shopper_reference) =
|
||||
get_recurring_processing_model(item)?;
|
||||
let browser_info = get_browser_info(item);
|
||||
let browser_info = get_browser_info(item)?;
|
||||
let additional_data = get_additional_data(item);
|
||||
let return_url = item.request.get_return_url()?;
|
||||
let payment_method = AdyenPaymentMethod::try_from(bank_redirect_data)?;
|
||||
@ -1478,7 +1528,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::WalletData)>
|
||||
let (item, wallet_data) = value;
|
||||
let amount = get_amount_data(item);
|
||||
let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
|
||||
let browser_info = get_browser_info(item);
|
||||
let browser_info = get_browser_info(item)?;
|
||||
let additional_data = get_additional_data(item);
|
||||
let payment_method = AdyenPaymentMethod::try_from(wallet_data)?;
|
||||
let shopper_interaction = AdyenShopperInteraction::from(item);
|
||||
@ -1519,7 +1569,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::PayLaterData)>
|
||||
let (item, paylater_data) = value;
|
||||
let amount = get_amount_data(item);
|
||||
let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
|
||||
let browser_info = get_browser_info(item);
|
||||
let browser_info = get_browser_info(item)?;
|
||||
let additional_data = get_additional_data(item);
|
||||
let payment_method = AdyenPaymentMethod::try_from(paylater_data)?;
|
||||
let shopper_interaction = AdyenShopperInteraction::from(item);
|
||||
|
||||
@ -10,6 +10,7 @@ use crate::{
|
||||
core::errors,
|
||||
services,
|
||||
types::{self, api, storage::enums},
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
#[derive(Default, Debug, Serialize, Eq, PartialEq)]
|
||||
@ -55,24 +56,77 @@ pub struct BamboraPaymentsRequest {
|
||||
card: BamboraCard,
|
||||
}
|
||||
|
||||
fn get_browser_info(item: &types::PaymentsAuthorizeRouterData) -> Option<BamboraBrowserInfo> {
|
||||
fn get_browser_info(
|
||||
item: &types::PaymentsAuthorizeRouterData,
|
||||
) -> Result<Option<BamboraBrowserInfo>, error_stack::Report<errors::ConnectorError>> {
|
||||
if matches!(item.auth_type, enums::AuthenticationType::ThreeDs) {
|
||||
item.request
|
||||
.browser_info
|
||||
.as_ref()
|
||||
.map(|info| BamboraBrowserInfo {
|
||||
accept_header: info.accept_header.clone(),
|
||||
java_enabled: info.java_enabled,
|
||||
language: info.language.clone(),
|
||||
color_depth: info.color_depth,
|
||||
screen_height: info.screen_height,
|
||||
screen_width: info.screen_width,
|
||||
time_zone: info.time_zone,
|
||||
user_agent: info.user_agent.clone(),
|
||||
javascript_enabled: info.java_script_enabled,
|
||||
.map(|info| {
|
||||
Ok(BamboraBrowserInfo {
|
||||
accept_header: info
|
||||
.accept_header
|
||||
.clone()
|
||||
.get_required_value("accept_header")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "accept_header",
|
||||
})?,
|
||||
java_enabled: info
|
||||
.java_enabled
|
||||
.get_required_value("java_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "java_enabled",
|
||||
})?,
|
||||
language: info
|
||||
.language
|
||||
.clone()
|
||||
.get_required_value("language")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "language",
|
||||
})?,
|
||||
screen_height: info
|
||||
.screen_height
|
||||
.get_required_value("screen_height")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_height",
|
||||
})?,
|
||||
screen_width: info
|
||||
.screen_width
|
||||
.get_required_value("screen_width")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_width",
|
||||
})?,
|
||||
color_depth: info
|
||||
.color_depth
|
||||
.get_required_value("color_depth")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "color_depth",
|
||||
})?,
|
||||
user_agent: info
|
||||
.user_agent
|
||||
.clone()
|
||||
.get_required_value("user_agent")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "user_agent",
|
||||
})?,
|
||||
time_zone: info
|
||||
.time_zone
|
||||
.get_required_value("time_zone")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "time_zone",
|
||||
})?,
|
||||
javascript_enabled: info
|
||||
.java_script_enabled
|
||||
.get_required_value("javascript_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "javascript_enabled",
|
||||
})?,
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
} else {
|
||||
None
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +158,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BamboraPaymentsRequest {
|
||||
let three_ds = match item.auth_type {
|
||||
enums::AuthenticationType::ThreeDs => Some(ThreeDSecure {
|
||||
enabled: true,
|
||||
browser: get_browser_info(item),
|
||||
browser: get_browser_info(item)?,
|
||||
version: Some(2),
|
||||
auth_required: Some(true),
|
||||
}),
|
||||
|
||||
@ -760,19 +760,72 @@ fn get_card_info<F>(
|
||||
let three_d = if item.is_three_ds() {
|
||||
Some(ThreeD {
|
||||
browser_details: Some(BrowserDetails {
|
||||
accept_header: browser_info.accept_header,
|
||||
ip: browser_info.ip_address,
|
||||
java_enabled: browser_info.java_enabled.to_string().to_uppercase(),
|
||||
java_script_enabled: browser_info
|
||||
.java_script_enabled
|
||||
accept_header: browser_info
|
||||
.accept_header
|
||||
.get_required_value("accept_header")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "accept_header",
|
||||
})?,
|
||||
ip: Some(
|
||||
browser_info
|
||||
.ip_address
|
||||
.get_required_value("ip_address")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "ip_address",
|
||||
})?,
|
||||
),
|
||||
java_enabled: browser_info
|
||||
.java_enabled
|
||||
.get_required_value("java_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "java_enabled",
|
||||
})?
|
||||
.to_string()
|
||||
.to_uppercase(),
|
||||
language: browser_info.language,
|
||||
color_depth: browser_info.color_depth,
|
||||
screen_height: browser_info.screen_height,
|
||||
screen_width: browser_info.screen_width,
|
||||
time_zone: browser_info.time_zone,
|
||||
user_agent: browser_info.user_agent,
|
||||
java_script_enabled: browser_info
|
||||
.java_script_enabled
|
||||
.get_required_value("java_script_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "java_script_enabled",
|
||||
})?
|
||||
.to_string()
|
||||
.to_uppercase(),
|
||||
language: browser_info
|
||||
.language
|
||||
.get_required_value("language")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "language",
|
||||
})?,
|
||||
color_depth: browser_info
|
||||
.color_depth
|
||||
.get_required_value("color_depth")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "color_depth",
|
||||
})?,
|
||||
screen_height: browser_info
|
||||
.screen_height
|
||||
.get_required_value("screen_height")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_height",
|
||||
})?,
|
||||
screen_width: browser_info
|
||||
.screen_width
|
||||
.get_required_value("screen_width")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_width",
|
||||
})?,
|
||||
time_zone: browser_info
|
||||
.time_zone
|
||||
.get_required_value("time_zone_offset")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "time_zone_offset",
|
||||
})?,
|
||||
user_agent: browser_info
|
||||
.user_agent
|
||||
.get_required_value("user_agent")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "user_agent",
|
||||
})?,
|
||||
}),
|
||||
v2_additional_params: additional_params,
|
||||
notification_url: item.request.complete_authorize_url.clone(),
|
||||
|
||||
@ -15,6 +15,7 @@ use crate::{
|
||||
core::errors,
|
||||
services,
|
||||
types::{self, api, storage::enums, BrowserInformation},
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
type Error = error_stack::Report<errors::ConnectorError>;
|
||||
@ -218,35 +219,91 @@ fn get_card_request_data(
|
||||
amount: String,
|
||||
ccard: &api_models::payments::Card,
|
||||
return_url: String,
|
||||
) -> TrustpayPaymentsRequest {
|
||||
TrustpayPaymentsRequest::CardsPaymentRequest(Box::new(PaymentRequestCards {
|
||||
amount,
|
||||
currency: item.request.currency.to_string(),
|
||||
pan: ccard.card_number.clone(),
|
||||
cvv: ccard.card_cvc.clone(),
|
||||
expiry_date: ccard.get_card_expiry_month_year_2_digit_with_delimiter("/".to_owned()),
|
||||
cardholder: ccard.card_holder_name.clone(),
|
||||
reference: item.attempt_id.clone(),
|
||||
redirect_url: return_url,
|
||||
billing_city: params.billing_city,
|
||||
billing_country: params.billing_country,
|
||||
billing_street1: params.billing_street1,
|
||||
billing_postcode: params.billing_postcode,
|
||||
customer_email: item.request.email.clone(),
|
||||
customer_ip_address: browser_info.ip_address,
|
||||
browser_accept_header: browser_info.accept_header.clone(),
|
||||
browser_language: browser_info.language.clone(),
|
||||
browser_screen_height: browser_info.screen_height.clone().to_string(),
|
||||
browser_screen_width: browser_info.screen_width.clone().to_string(),
|
||||
browser_timezone: browser_info.time_zone.clone().to_string(),
|
||||
browser_user_agent: browser_info.user_agent.clone(),
|
||||
browser_java_enabled: browser_info.java_enabled.clone().to_string(),
|
||||
browser_java_script_enabled: browser_info.java_script_enabled.clone().to_string(),
|
||||
browser_screen_color_depth: browser_info.color_depth.clone().to_string(),
|
||||
browser_challenge_window: "1".to_string(),
|
||||
payment_action: None,
|
||||
payment_type: "Plain".to_string(),
|
||||
}))
|
||||
) -> Result<TrustpayPaymentsRequest, Error> {
|
||||
Ok(TrustpayPaymentsRequest::CardsPaymentRequest(Box::new(
|
||||
PaymentRequestCards {
|
||||
amount,
|
||||
currency: item.request.currency.to_string(),
|
||||
pan: ccard.card_number.clone(),
|
||||
cvv: ccard.card_cvc.clone(),
|
||||
expiry_date: ccard.get_card_expiry_month_year_2_digit_with_delimiter("/".to_owned()),
|
||||
cardholder: ccard.card_holder_name.clone(),
|
||||
reference: item.attempt_id.clone(),
|
||||
redirect_url: return_url,
|
||||
billing_city: params.billing_city,
|
||||
billing_country: params.billing_country,
|
||||
billing_street1: params.billing_street1,
|
||||
billing_postcode: params.billing_postcode,
|
||||
customer_email: item.request.email.clone(),
|
||||
customer_ip_address: browser_info.ip_address,
|
||||
browser_accept_header: browser_info
|
||||
.accept_header
|
||||
.clone()
|
||||
.get_required_value("accept_header")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "accept_header",
|
||||
})?,
|
||||
browser_language: browser_info
|
||||
.language
|
||||
.clone()
|
||||
.get_required_value("language")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "language",
|
||||
})?,
|
||||
browser_screen_height: browser_info
|
||||
.screen_height
|
||||
.get_required_value("screen_height")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_height",
|
||||
})?
|
||||
.to_string(),
|
||||
browser_screen_width: browser_info
|
||||
.screen_width
|
||||
.get_required_value("screen_width")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_width",
|
||||
})?
|
||||
.to_string(),
|
||||
browser_timezone: browser_info
|
||||
.time_zone
|
||||
.get_required_value("time_zone_offset")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "time_zone_offset",
|
||||
})?
|
||||
.to_string(),
|
||||
browser_user_agent: browser_info
|
||||
.user_agent
|
||||
.clone()
|
||||
.get_required_value("user_agent")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "user_agent",
|
||||
})?,
|
||||
browser_java_enabled: browser_info
|
||||
.java_enabled
|
||||
.get_required_value("java_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "java_enabled",
|
||||
})?
|
||||
.to_string(),
|
||||
browser_java_script_enabled: browser_info
|
||||
.java_script_enabled
|
||||
.get_required_value("java_script_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "java_script_enabled",
|
||||
})?
|
||||
.to_string(),
|
||||
browser_screen_color_depth: browser_info
|
||||
.color_depth
|
||||
.get_required_value("color_depth")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "color_depth",
|
||||
})?
|
||||
.to_string(),
|
||||
browser_challenge_window: "1".to_string(),
|
||||
payment_action: None,
|
||||
payment_type: "Plain".to_string(),
|
||||
},
|
||||
)))
|
||||
}
|
||||
|
||||
fn get_bank_redirection_request_data(
|
||||
@ -284,15 +341,15 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
|
||||
type Error = Error;
|
||||
fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
|
||||
let default_browser_info = BrowserInformation {
|
||||
color_depth: 24,
|
||||
java_enabled: false,
|
||||
java_script_enabled: true,
|
||||
language: "en-US".to_string(),
|
||||
screen_height: 1080,
|
||||
screen_width: 1920,
|
||||
time_zone: 3600,
|
||||
accept_header: "*".to_string(),
|
||||
user_agent: "none".to_string(),
|
||||
color_depth: Some(24),
|
||||
java_enabled: Some(false),
|
||||
java_script_enabled: Some(true),
|
||||
language: Some("en-US".to_string()),
|
||||
screen_height: Some(1080),
|
||||
screen_width: Some(1920),
|
||||
time_zone: Some(3600),
|
||||
accept_header: Some("*".to_string()),
|
||||
user_agent: Some("none".to_string()),
|
||||
ip_address: None,
|
||||
};
|
||||
let browser_info = item
|
||||
@ -318,7 +375,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
|
||||
amount,
|
||||
ccard,
|
||||
item.request.get_return_url()?,
|
||||
)),
|
||||
)?),
|
||||
api::PaymentMethodData::BankRedirect(ref bank_redirection_data) => {
|
||||
get_bank_redirection_request_data(item, bank_redirection_data, amount, auth)
|
||||
}
|
||||
|
||||
@ -13,11 +13,11 @@ use crate::{
|
||||
connector::utils::{
|
||||
self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, RouterData,
|
||||
},
|
||||
core::errors,
|
||||
core::errors::{self, CustomResult},
|
||||
services::{self, Method},
|
||||
types::{self, api, storage::enums, transformers::ForeignTryFrom, BrowserInformation},
|
||||
types::{self, api, storage::enums, transformers::ForeignTryFrom},
|
||||
utils::OptionExt,
|
||||
};
|
||||
|
||||
// Auth Struct
|
||||
pub struct ZenAuthType {
|
||||
pub(super) api_key: String,
|
||||
@ -345,9 +345,23 @@ fn get_item_object(
|
||||
}
|
||||
|
||||
fn get_browser_details(
|
||||
browser_info: &BrowserInformation,
|
||||
) -> Result<ZenBrowserDetails, error_stack::Report<errors::ConnectorError>> {
|
||||
let window_size = match (browser_info.screen_height, browser_info.screen_width) {
|
||||
browser_info: &types::BrowserInformation,
|
||||
) -> CustomResult<ZenBrowserDetails, errors::ConnectorError> {
|
||||
let screen_height = browser_info
|
||||
.screen_height
|
||||
.get_required_value("screen_height")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_height",
|
||||
})?;
|
||||
|
||||
let screen_width = browser_info
|
||||
.screen_width
|
||||
.get_required_value("screen_width")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "screen_width",
|
||||
})?;
|
||||
|
||||
let window_size = match (screen_height, screen_width) {
|
||||
(250, 400) => "01",
|
||||
(390, 400) => "02",
|
||||
(500, 600) => "03",
|
||||
@ -355,16 +369,52 @@ fn get_browser_details(
|
||||
_ => "05",
|
||||
}
|
||||
.to_string();
|
||||
|
||||
Ok(ZenBrowserDetails {
|
||||
color_depth: browser_info.color_depth.to_string(),
|
||||
java_enabled: browser_info.java_enabled,
|
||||
lang: browser_info.language.clone(),
|
||||
screen_height: browser_info.screen_height.to_string(),
|
||||
screen_width: browser_info.screen_width.to_string(),
|
||||
timezone: browser_info.time_zone.to_string(),
|
||||
accept_header: browser_info.accept_header.clone(),
|
||||
color_depth: browser_info
|
||||
.color_depth
|
||||
.get_required_value("color_depth")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "color_depth",
|
||||
})?
|
||||
.to_string(),
|
||||
java_enabled: browser_info
|
||||
.java_enabled
|
||||
.get_required_value("java_enabled")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "java_enabled",
|
||||
})?,
|
||||
lang: browser_info
|
||||
.language
|
||||
.clone()
|
||||
.get_required_value("language")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "language",
|
||||
})?,
|
||||
screen_height: screen_height.to_string(),
|
||||
screen_width: screen_width.to_string(),
|
||||
timezone: browser_info
|
||||
.time_zone
|
||||
.get_required_value("time_zone")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "time_zone",
|
||||
})?
|
||||
.to_string(),
|
||||
accept_header: browser_info
|
||||
.accept_header
|
||||
.clone()
|
||||
.get_required_value("accept_header")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "accept_header",
|
||||
})?,
|
||||
user_agent: browser_info
|
||||
.user_agent
|
||||
.clone()
|
||||
.get_required_value("user_agent")
|
||||
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||
field_name: "user_agent",
|
||||
})?,
|
||||
window_size,
|
||||
user_agent: browser_info.user_agent.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ pub mod transformers;
|
||||
use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant};
|
||||
|
||||
use api_models::payments::Metadata;
|
||||
use common_utils::pii::Email;
|
||||
use common_utils::pii;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
use futures::future::join_all;
|
||||
use masking::Secret;
|
||||
@ -970,7 +970,7 @@ where
|
||||
pub disputes: Vec<storage::Dispute>,
|
||||
pub sessions_token: Vec<api::SessionToken>,
|
||||
pub card_cvc: Option<Secret<String>>,
|
||||
pub email: Option<Email>,
|
||||
pub email: Option<pii::Email>,
|
||||
pub creds_identifier: Option<String>,
|
||||
pub pm_token: Option<String>,
|
||||
pub connector_customer_id: Option<String>,
|
||||
@ -982,7 +982,7 @@ where
|
||||
pub struct CustomerDetails {
|
||||
pub customer_id: Option<String>,
|
||||
pub name: Option<Secret<String, masking::WithType>>,
|
||||
pub email: Option<Email>,
|
||||
pub email: Option<pii::Email>,
|
||||
pub phone: Option<Secret<String, masking::WithType>>,
|
||||
pub phone_country_code: Option<String>,
|
||||
}
|
||||
|
||||
@ -56,6 +56,7 @@ pub mod headers {
|
||||
pub const TOKEN: &str = "token";
|
||||
pub const X_API_KEY: &str = "X-API-KEY";
|
||||
pub const X_API_VERSION: &str = "X-ApiVersion";
|
||||
pub const X_FORWARDED_FOR: &str = "X-Forwarded-For";
|
||||
pub const X_MERCHANT_ID: &str = "X-Merchant-Id";
|
||||
pub const X_LOGIN: &str = "X-Login";
|
||||
pub const X_TRANS_KEY: &str = "X-Trans-Key";
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
pub mod helpers;
|
||||
|
||||
use actix_web::{web, Responder};
|
||||
use error_stack::report;
|
||||
use router_env::{instrument, tracing, Flow};
|
||||
@ -321,6 +323,10 @@ pub async fn payments_confirm(
|
||||
return http_not_implemented();
|
||||
};
|
||||
|
||||
if let Err(err) = helpers::populate_ip_into_browser_info(&req, &mut payload) {
|
||||
return api::log_and_return_error_response(err);
|
||||
}
|
||||
|
||||
let payment_id = path.into_inner();
|
||||
payload.payment_id = Some(payment_types::PaymentIdType::PaymentIntentId(payment_id));
|
||||
payload.confirm = Some(true);
|
||||
|
||||
67
crates/router/src/routes/payments/helpers.rs
Normal file
67
crates/router/src/routes/payments/helpers.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use error_stack::ResultExt;
|
||||
|
||||
use crate::{
|
||||
core::errors::{self, RouterResult},
|
||||
headers, logger,
|
||||
types::{self, api::payments as payment_types},
|
||||
utils::{Encode, ValueExt},
|
||||
};
|
||||
|
||||
pub fn populate_ip_into_browser_info(
|
||||
req: &actix_web::HttpRequest,
|
||||
payload: &mut payment_types::PaymentsRequest,
|
||||
) -> RouterResult<()> {
|
||||
let mut browser_info: types::BrowserInformation = payload
|
||||
.browser_info
|
||||
.clone()
|
||||
.map(|v| v.parse_value("BrowserInformation"))
|
||||
.transpose()
|
||||
.change_context_lazy(|| errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "invalid format for 'browser_info' provided".to_string(),
|
||||
})?
|
||||
.unwrap_or(types::BrowserInformation {
|
||||
color_depth: None,
|
||||
java_enabled: None,
|
||||
java_script_enabled: None,
|
||||
language: None,
|
||||
screen_height: None,
|
||||
screen_width: None,
|
||||
time_zone: None,
|
||||
accept_header: None,
|
||||
user_agent: None,
|
||||
ip_address: None,
|
||||
});
|
||||
|
||||
browser_info.ip_address = browser_info
|
||||
.ip_address
|
||||
.or_else(|| {
|
||||
// Parse the IP Address from the "X-Forwarded-For" header
|
||||
// This header will contain multiple IP addresses for each ALB hop which has
|
||||
// a comma separated list of IP addresses: 'X.X.X.X, Y.Y.Y.Y, Z.Z.Z.Z'
|
||||
// The first one here will be the client IP which we want to retrieve
|
||||
req.headers()
|
||||
.get(headers::X_FORWARDED_FOR)
|
||||
.map(|val| val.to_str())
|
||||
.transpose()
|
||||
.unwrap_or_else(|e| {
|
||||
logger::error!(error=?e, message="failed to retrieve ip address from X-Forwarded-For header");
|
||||
None
|
||||
})
|
||||
.and_then(|ips| ips.split(',').next())
|
||||
.map(|ip| ip.parse())
|
||||
.transpose()
|
||||
.unwrap_or_else(|e| {
|
||||
logger::error!(error=?e, message="failed to parse ip address from X-Forwarded-For");
|
||||
None
|
||||
})
|
||||
});
|
||||
|
||||
let encoded = Encode::<types::BrowserInformation>::encode_to_value(&browser_info)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable(
|
||||
"failed to re-encode browser information to json after setting ip address",
|
||||
)?;
|
||||
|
||||
payload.browser_info = Some(encoded);
|
||||
Ok(())
|
||||
}
|
||||
@ -444,16 +444,16 @@ pub struct RefundsData {
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct BrowserInformation {
|
||||
pub color_depth: u8,
|
||||
pub java_enabled: bool,
|
||||
pub java_script_enabled: bool,
|
||||
pub language: String,
|
||||
pub screen_height: u32,
|
||||
pub screen_width: u32,
|
||||
pub time_zone: i32,
|
||||
pub color_depth: Option<u8>,
|
||||
pub java_enabled: Option<bool>,
|
||||
pub java_script_enabled: Option<bool>,
|
||||
pub language: Option<String>,
|
||||
pub screen_height: Option<u32>,
|
||||
pub screen_width: Option<u32>,
|
||||
pub time_zone: Option<i32>,
|
||||
pub ip_address: Option<std::net::IpAddr>,
|
||||
pub accept_header: String,
|
||||
pub user_agent: String,
|
||||
pub accept_header: Option<String>,
|
||||
pub user_agent: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -36,15 +36,15 @@ impl utils::Connector for TrustpayTest {
|
||||
|
||||
fn get_default_browser_info() -> BrowserInformation {
|
||||
BrowserInformation {
|
||||
color_depth: 24,
|
||||
java_enabled: false,
|
||||
java_script_enabled: true,
|
||||
language: "en-US".to_string(),
|
||||
screen_height: 1080,
|
||||
screen_width: 1920,
|
||||
time_zone: 3600,
|
||||
accept_header: "*".to_string(),
|
||||
user_agent: "none".to_string(),
|
||||
color_depth: Some(24),
|
||||
java_enabled: Some(false),
|
||||
java_script_enabled: Some(true),
|
||||
language: Some("en-US".to_string()),
|
||||
screen_height: Some(1080),
|
||||
screen_width: Some(1920),
|
||||
time_zone: Some(3600),
|
||||
accept_header: Some("*".to_string()),
|
||||
user_agent: Some("none".to_string()),
|
||||
ip_address: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -549,15 +549,15 @@ impl Default for PaymentCancelType {
|
||||
impl Default for BrowserInfoType {
|
||||
fn default() -> Self {
|
||||
let data = types::BrowserInformation {
|
||||
user_agent: "".to_string(),
|
||||
accept_header: "".to_string(),
|
||||
language: "nl-NL".to_string(),
|
||||
color_depth: 24,
|
||||
screen_height: 723,
|
||||
screen_width: 1536,
|
||||
time_zone: 0,
|
||||
java_enabled: true,
|
||||
java_script_enabled: true,
|
||||
user_agent: Some("".to_string()),
|
||||
accept_header: Some("".to_string()),
|
||||
language: Some("nl-NL".to_string()),
|
||||
color_depth: Some(24),
|
||||
screen_height: Some(723),
|
||||
screen_width: Some(1536),
|
||||
time_zone: Some(0),
|
||||
java_enabled: Some(true),
|
||||
java_script_enabled: Some(true),
|
||||
ip_address: Some("127.0.0.1".parse().unwrap()),
|
||||
};
|
||||
Self(data)
|
||||
|
||||
Reference in New Issue
Block a user