mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
refactor(router): infer ip address for online mandates from request headers if absent (#1419)
This commit is contained in:
@ -432,7 +432,7 @@ pub enum AcceptanceType {
|
|||||||
pub struct OnlineMandate {
|
pub struct OnlineMandate {
|
||||||
/// Ip address of the customer machine from which the mandate was created
|
/// Ip address of the customer machine from which the mandate was created
|
||||||
#[schema(value_type = String, example = "123.32.25.123")]
|
#[schema(value_type = String, example = "123.32.25.123")]
|
||||||
pub ip_address: Secret<String, pii::IpAddress>,
|
pub ip_address: Option<Secret<String, pii::IpAddress>>,
|
||||||
/// The user-agent of the customer's browser
|
/// The user-agent of the customer's browser
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -615,7 +615,7 @@ impl ForeignTryFrom<(Option<MandateOption>, Option<String>)> for Option<payments
|
|||||||
acceptance_type: payments::AcceptanceType::Online,
|
acceptance_type: payments::AcceptanceType::Online,
|
||||||
accepted_at: mandate.accepted_at,
|
accepted_at: mandate.accepted_at,
|
||||||
online: Some(payments::OnlineMandate {
|
online: Some(payments::OnlineMandate {
|
||||||
ip_address: mandate.ip_address.unwrap_or_default(),
|
ip_address: mandate.ip_address,
|
||||||
user_agent: mandate.user_agent.unwrap_or_default(),
|
user_agent: mandate.user_agent.unwrap_or_default(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -1254,22 +1254,31 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest {
|
|||||||
_ => payment_data,
|
_ => payment_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
let setup_mandate_details =
|
let setup_mandate_details = item
|
||||||
item.request
|
.request
|
||||||
.setup_mandate_details
|
.setup_mandate_details
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|mandate_details| {
|
.and_then(|mandate_details| {
|
||||||
mandate_details
|
mandate_details
|
||||||
.customer_acceptance
|
.customer_acceptance
|
||||||
.as_ref()?
|
.as_ref()?
|
||||||
.online
|
.online
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|online_details| StripeMandateRequest {
|
.map(|online_details| {
|
||||||
|
Ok::<_, error_stack::Report<errors::ConnectorError>>(StripeMandateRequest {
|
||||||
mandate_type: StripeMandateType::Online,
|
mandate_type: StripeMandateType::Online,
|
||||||
ip_address: online_details.ip_address.to_owned(),
|
ip_address: online_details
|
||||||
|
.ip_address
|
||||||
|
.clone()
|
||||||
|
.get_required_value("ip_address")
|
||||||
|
.change_context(errors::ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "ip_address",
|
||||||
|
})?,
|
||||||
user_agent: online_details.user_agent.to_owned(),
|
user_agent: online_details.user_agent.to_owned(),
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
amount: item.request.amount, //hopefully we don't loose some cents here
|
amount: item.request.amount, //hopefully we don't loose some cents here
|
||||||
|
|||||||
@ -3,13 +3,13 @@ use error_stack::ResultExt;
|
|||||||
use crate::{
|
use crate::{
|
||||||
core::errors::{self, RouterResult},
|
core::errors::{self, RouterResult},
|
||||||
headers, logger,
|
headers, logger,
|
||||||
types::{self, api::payments as payment_types},
|
types::{self, api},
|
||||||
utils::{Encode, ValueExt},
|
utils::{Encode, ValueExt},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn populate_ip_into_browser_info(
|
pub fn populate_ip_into_browser_info(
|
||||||
req: &actix_web::HttpRequest,
|
req: &actix_web::HttpRequest,
|
||||||
payload: &mut payment_types::PaymentsRequest,
|
payload: &mut api::PaymentsRequest,
|
||||||
) -> RouterResult<()> {
|
) -> RouterResult<()> {
|
||||||
let mut browser_info: types::BrowserInformation = payload
|
let mut browser_info: types::BrowserInformation = payload
|
||||||
.browser_info
|
.browser_info
|
||||||
@ -32,29 +32,46 @@ pub fn populate_ip_into_browser_info(
|
|||||||
ip_address: None,
|
ip_address: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
browser_info.ip_address = browser_info
|
// Parse the IP Address from the "X-Forwarded-For" header
|
||||||
.ip_address
|
// This header will contain multiple IP addresses for each ALB hop which has
|
||||||
.or_else(|| {
|
// a comma separated list of IP addresses: 'X.X.X.X, Y.Y.Y.Y, Z.Z.Z.Z'
|
||||||
// Parse the IP Address from the "X-Forwarded-For" header
|
// The first one here will be the client IP which we want to retrieve
|
||||||
// This header will contain multiple IP addresses for each ALB hop which has
|
let ip_address_from_header = req.headers()
|
||||||
// a comma separated list of IP addresses: 'X.X.X.X, Y.Y.Y.Y, Z.Z.Z.Z'
|
.get(headers::X_FORWARDED_FOR)
|
||||||
// The first one here will be the client IP which we want to retrieve
|
.map(|val| val.to_str())
|
||||||
req.headers()
|
.transpose()
|
||||||
.get(headers::X_FORWARDED_FOR)
|
.unwrap_or_else(|e| {
|
||||||
.map(|val| val.to_str())
|
logger::error!(error=?e, message="failed to retrieve ip address from X-Forwarded-For header");
|
||||||
.transpose()
|
None
|
||||||
.unwrap_or_else(|e| {
|
})
|
||||||
logger::error!(error=?e, message="failed to retrieve ip address from X-Forwarded-For header");
|
.and_then(|ips| ips.split(',').next());
|
||||||
None
|
|
||||||
})
|
browser_info.ip_address = browser_info.ip_address.or_else(|| {
|
||||||
.and_then(|ips| ips.split(',').next())
|
ip_address_from_header
|
||||||
.map(|ip| ip.parse())
|
.map(|ip| ip.parse())
|
||||||
.transpose()
|
.transpose()
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
logger::error!(error=?e, message="failed to parse ip address from X-Forwarded-For");
|
logger::error!(error=?e, message="failed to parse ip address from X-Forwarded-For");
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if let Some(api::MandateData {
|
||||||
|
customer_acceptance:
|
||||||
|
Some(api::CustomerAcceptance {
|
||||||
|
online:
|
||||||
|
Some(api::OnlineMandate {
|
||||||
|
ip_address: req_ip, ..
|
||||||
|
}),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
..
|
||||||
|
}) = &mut payload.mandate_data
|
||||||
|
{
|
||||||
|
*req_ip = req_ip
|
||||||
|
.clone()
|
||||||
|
.or_else(|| ip_address_from_header.map(|ip| masking::Secret::new(ip.to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
let encoded = Encode::<types::BrowserInformation>::encode_to_value(&browser_info)
|
let encoded = Encode::<types::BrowserInformation>::encode_to_value(&browser_info)
|
||||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||||
|
|||||||
@ -73,7 +73,7 @@ impl MandateResponseExt for MandateResponse {
|
|||||||
},
|
},
|
||||||
accepted_at: mandate.customer_accepted_at,
|
accepted_at: mandate.customer_accepted_at,
|
||||||
online: Some(api::payments::OnlineMandate {
|
online: Some(api::payments::OnlineMandate {
|
||||||
ip_address: mandate.customer_ip_address.unwrap_or_default(),
|
ip_address: mandate.customer_ip_address,
|
||||||
user_agent: mandate.customer_user_agent.unwrap_or_default(),
|
user_agent: mandate.customer_user_agent.unwrap_or_default(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -43,7 +43,7 @@ impl CustomerAcceptanceExt for CustomerAcceptance {
|
|||||||
fn get_ip_address(&self) -> Option<String> {
|
fn get_ip_address(&self) -> Option<String> {
|
||||||
self.online
|
self.online
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|data| data.ip_address.peek().to_owned())
|
.and_then(|data| data.ip_address.as_ref().map(|ip| ip.peek().to_owned()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_user_agent(&self) -> Option<String> {
|
fn get_user_agent(&self) -> Option<String> {
|
||||||
|
|||||||
Reference in New Issue
Block a user