diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 7df67b13a5..a3fa8fba2b 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -432,7 +432,7 @@ pub enum AcceptanceType { pub struct OnlineMandate { /// Ip address of the customer machine from which the mandate was created #[schema(value_type = String, example = "123.32.25.123")] - pub ip_address: Secret, + pub ip_address: Option>, /// The user-agent of the customer's browser pub user_agent: String, } diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index 8f57ee6850..5860cc7230 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -615,7 +615,7 @@ impl ForeignTryFrom<(Option, Option)> for Option for PaymentIntentRequest { _ => payment_data, }; - let setup_mandate_details = - item.request - .setup_mandate_details - .as_ref() - .and_then(|mandate_details| { - mandate_details - .customer_acceptance - .as_ref()? - .online - .as_ref() - .map(|online_details| StripeMandateRequest { + let setup_mandate_details = item + .request + .setup_mandate_details + .as_ref() + .and_then(|mandate_details| { + mandate_details + .customer_acceptance + .as_ref()? + .online + .as_ref() + .map(|online_details| { + Ok::<_, error_stack::Report>(StripeMandateRequest { 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(), }) - }); + }) + }) + .transpose()?; Ok(Self { amount: item.request.amount, //hopefully we don't loose some cents here diff --git a/crates/router/src/routes/payments/helpers.rs b/crates/router/src/routes/payments/helpers.rs index f5a87eee19..7a1c26b057 100644 --- a/crates/router/src/routes/payments/helpers.rs +++ b/crates/router/src/routes/payments/helpers.rs @@ -3,13 +3,13 @@ use error_stack::ResultExt; use crate::{ core::errors::{self, RouterResult}, headers, logger, - types::{self, api::payments as payment_types}, + types::{self, api}, utils::{Encode, ValueExt}, }; pub fn populate_ip_into_browser_info( req: &actix_web::HttpRequest, - payload: &mut payment_types::PaymentsRequest, + payload: &mut api::PaymentsRequest, ) -> RouterResult<()> { let mut browser_info: types::BrowserInformation = payload .browser_info @@ -32,29 +32,46 @@ pub fn populate_ip_into_browser_info( 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 - }) - }); + // 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 + let ip_address_from_header = 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()); + + browser_info.ip_address = browser_info.ip_address.or_else(|| { + ip_address_from_header + .map(|ip| ip.parse()) + .transpose() + .unwrap_or_else(|e| { + logger::error!(error=?e, message="failed to parse ip address from X-Forwarded-For"); + 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::::encode_to_value(&browser_info) .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/types/api/mandates.rs b/crates/router/src/types/api/mandates.rs index d2d93a6397..22a96acf2b 100644 --- a/crates/router/src/types/api/mandates.rs +++ b/crates/router/src/types/api/mandates.rs @@ -73,7 +73,7 @@ impl MandateResponseExt for MandateResponse { }, accepted_at: mandate.customer_accepted_at, 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(), }), }), diff --git a/crates/router/src/types/api/payments.rs b/crates/router/src/types/api/payments.rs index 9a24f871db..067121d22b 100644 --- a/crates/router/src/types/api/payments.rs +++ b/crates/router/src/types/api/payments.rs @@ -43,7 +43,7 @@ impl CustomerAcceptanceExt for CustomerAcceptance { fn get_ip_address(&self) -> Option { self.online .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 {