mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
fix(connector): [NEXIXPAY] Add Validation Checks for Request Fields (#8345)
Co-authored-by: Sayak Bhattacharya <sayak.b@Sayak-Bhattacharya-G092THXJ34.local>
This commit is contained in:
committed by
GitHub
parent
7338a8db85
commit
6fd7626c99
@ -27,6 +27,7 @@ use hyperswitch_domain_models::{
|
|||||||
};
|
};
|
||||||
use hyperswitch_interfaces::{consts::NO_ERROR_CODE, errors};
|
use hyperswitch_interfaces::{consts::NO_ERROR_CODE, errors};
|
||||||
use masking::{ExposeInterface, Secret};
|
use masking::{ExposeInterface, Secret};
|
||||||
|
use rand::distributions::{Alphanumeric, DistString};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum::Display;
|
use strum::Display;
|
||||||
|
|
||||||
@ -40,6 +41,224 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn get_random_string() -> String {
|
||||||
|
Alphanumeric.sample_string(&mut rand::thread_rng(), MAX_ORDER_ID_LENGTH)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum AddressKind {
|
||||||
|
Billing,
|
||||||
|
Shipping,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait AddressConstructor {
|
||||||
|
fn new(
|
||||||
|
name: Option<Secret<String>>,
|
||||||
|
street: Option<Secret<String>>,
|
||||||
|
city: Option<String>,
|
||||||
|
post_code: Option<Secret<String>>,
|
||||||
|
country: Option<enums::CountryAlpha2>,
|
||||||
|
) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressConstructor for BillingAddress {
|
||||||
|
fn new(
|
||||||
|
name: Option<Secret<String>>,
|
||||||
|
street: Option<Secret<String>>,
|
||||||
|
city: Option<String>,
|
||||||
|
post_code: Option<Secret<String>>,
|
||||||
|
country: Option<enums::CountryAlpha2>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
street,
|
||||||
|
city,
|
||||||
|
post_code,
|
||||||
|
country,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressConstructor for ShippingAddress {
|
||||||
|
fn new(
|
||||||
|
name: Option<Secret<String>>,
|
||||||
|
street: Option<Secret<String>>,
|
||||||
|
city: Option<String>,
|
||||||
|
post_code: Option<Secret<String>>,
|
||||||
|
country: Option<enums::CountryAlpha2>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
street,
|
||||||
|
city,
|
||||||
|
post_code,
|
||||||
|
country,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_validated_address_details_generic<RouterContextDataAlias, AddressOutput>(
|
||||||
|
data: &RouterContextDataAlias,
|
||||||
|
address_kind: AddressKind,
|
||||||
|
) -> Result<Option<AddressOutput>, error_stack::Report<errors::ConnectorError>>
|
||||||
|
where
|
||||||
|
RouterContextDataAlias: crate::utils::RouterData,
|
||||||
|
AddressOutput: AddressConstructor + Sized,
|
||||||
|
{
|
||||||
|
let (
|
||||||
|
opt_line1,
|
||||||
|
opt_line2,
|
||||||
|
opt_full_name,
|
||||||
|
opt_city,
|
||||||
|
opt_zip,
|
||||||
|
opt_country,
|
||||||
|
has_address_details_check,
|
||||||
|
address_type_str,
|
||||||
|
max_name_len,
|
||||||
|
max_street_len,
|
||||||
|
max_city_len,
|
||||||
|
max_post_code_len,
|
||||||
|
max_country_len,
|
||||||
|
) = match address_kind {
|
||||||
|
AddressKind::Billing => (
|
||||||
|
data.get_optional_billing_line1(),
|
||||||
|
data.get_optional_billing_line2(),
|
||||||
|
data.get_optional_billing_full_name(),
|
||||||
|
data.get_optional_billing_city(),
|
||||||
|
data.get_optional_billing_zip(),
|
||||||
|
data.get_optional_billing_country(),
|
||||||
|
data.get_optional_billing().is_some(),
|
||||||
|
"billing",
|
||||||
|
MAX_BILLING_ADDRESS_NAME_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_STREET_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_CITY_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_POST_CODE_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_COUNTRY_LENGTH,
|
||||||
|
),
|
||||||
|
AddressKind::Shipping => (
|
||||||
|
data.get_optional_shipping_line1(),
|
||||||
|
data.get_optional_shipping_line2(),
|
||||||
|
data.get_optional_shipping_full_name(),
|
||||||
|
data.get_optional_shipping_city(),
|
||||||
|
data.get_optional_shipping_zip(),
|
||||||
|
data.get_optional_shipping_country(),
|
||||||
|
data.get_optional_shipping().is_some(),
|
||||||
|
"shipping",
|
||||||
|
MAX_BILLING_ADDRESS_NAME_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_STREET_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_CITY_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_POST_CODE_LENGTH,
|
||||||
|
MAX_BILLING_ADDRESS_COUNTRY_LENGTH,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let street_val = match (opt_line1.clone(), opt_line2.clone()) {
|
||||||
|
(Some(l1), Some(l2)) => Some(Secret::new(format!("{}, {}", l1.expose(), l2.expose()))),
|
||||||
|
(Some(l1), None) => Some(l1),
|
||||||
|
(None, Some(l2)) => Some(l2),
|
||||||
|
(None, None) => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if has_address_details_check {
|
||||||
|
let name_val = opt_full_name;
|
||||||
|
if let Some(ref val) = name_val {
|
||||||
|
let length = val.clone().expose().len();
|
||||||
|
if length > max_name_len {
|
||||||
|
return Err(error_stack::Report::from(
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
|
field_name: format!(
|
||||||
|
"{0}.address.first_name & {0}.address.last_name",
|
||||||
|
address_type_str
|
||||||
|
),
|
||||||
|
connector: "Nexixpay".to_string(),
|
||||||
|
max_length: max_name_len,
|
||||||
|
received_length: length,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref val) = street_val {
|
||||||
|
let length = val.clone().expose().len();
|
||||||
|
if length > max_street_len {
|
||||||
|
return Err(error_stack::Report::from(
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
|
field_name: format!(
|
||||||
|
"{0}.address.line1 & {0}.address.line2",
|
||||||
|
address_type_str
|
||||||
|
),
|
||||||
|
connector: "Nexixpay".to_string(),
|
||||||
|
max_length: max_street_len,
|
||||||
|
received_length: length,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let city_val = opt_city;
|
||||||
|
if let Some(ref val) = city_val {
|
||||||
|
let length = val.len();
|
||||||
|
if length > max_city_len {
|
||||||
|
return Err(error_stack::Report::from(
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
|
field_name: format!("{}.address.city", address_type_str),
|
||||||
|
connector: "Nexixpay".to_string(),
|
||||||
|
max_length: max_city_len,
|
||||||
|
received_length: length,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let post_code_val = opt_zip;
|
||||||
|
if let Some(ref val) = post_code_val {
|
||||||
|
let length = val.clone().expose().len();
|
||||||
|
if length > max_post_code_len {
|
||||||
|
return Err(error_stack::Report::from(
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
|
field_name: format!("{}.address.zip", address_type_str),
|
||||||
|
connector: "Nexixpay".to_string(),
|
||||||
|
max_length: max_post_code_len,
|
||||||
|
received_length: length,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let country_val = opt_country;
|
||||||
|
if let Some(ref val) = country_val {
|
||||||
|
let length = val.to_string().len();
|
||||||
|
if length > max_country_len {
|
||||||
|
return Err(error_stack::Report::from(
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
|
field_name: format!("{}.address.country", address_type_str),
|
||||||
|
connector: "Nexixpay".to_string(),
|
||||||
|
max_length: max_country_len,
|
||||||
|
received_length: length,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Some(AddressOutput::new(
|
||||||
|
name_val,
|
||||||
|
street_val,
|
||||||
|
city_val,
|
||||||
|
post_code_val,
|
||||||
|
country_val,
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_ORDER_ID_LENGTH: usize = 18;
|
||||||
|
const MAX_CARD_HOLDER_LENGTH: usize = 255;
|
||||||
|
const MAX_BILLING_ADDRESS_NAME_LENGTH: usize = 50;
|
||||||
|
const MAX_BILLING_ADDRESS_STREET_LENGTH: usize = 50;
|
||||||
|
const MAX_BILLING_ADDRESS_CITY_LENGTH: usize = 40;
|
||||||
|
const MAX_BILLING_ADDRESS_POST_CODE_LENGTH: usize = 16;
|
||||||
|
const MAX_BILLING_ADDRESS_COUNTRY_LENGTH: usize = 3;
|
||||||
|
|
||||||
pub struct NexixpayRouterData<T> {
|
pub struct NexixpayRouterData<T> {
|
||||||
pub amount: StringMinorUnit,
|
pub amount: StringMinorUnit,
|
||||||
pub router_data: T,
|
pub router_data: T,
|
||||||
@ -480,60 +699,50 @@ impl TryFrom<&NexixpayRouterData<&PaymentsAuthorizeRouterData>> for NexixpayPaym
|
|||||||
fn try_from(
|
fn try_from(
|
||||||
item: &NexixpayRouterData<&PaymentsAuthorizeRouterData>,
|
item: &NexixpayRouterData<&PaymentsAuthorizeRouterData>,
|
||||||
) -> Result<Self, Self::Error> {
|
) -> Result<Self, Self::Error> {
|
||||||
let billing_address_street = match (
|
let order_id = if item.router_data.payment_id.len() > MAX_ORDER_ID_LENGTH {
|
||||||
item.router_data.get_optional_billing_line1(),
|
if item.router_data.payment_id.starts_with("pay_") {
|
||||||
item.router_data.get_optional_billing_line2(),
|
get_random_string()
|
||||||
) {
|
} else {
|
||||||
(Some(line1), Some(line2)) => Some(Secret::new(format!(
|
return Err(error_stack::Report::from(
|
||||||
"{}, {}",
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
line1.expose(),
|
field_name: "payment_id".to_string(),
|
||||||
line2.expose()
|
connector: "Nexixpay".to_string(),
|
||||||
))),
|
max_length: MAX_ORDER_ID_LENGTH,
|
||||||
(Some(line1), None) => Some(line1),
|
received_length: item.router_data.payment_id.len(),
|
||||||
(None, Some(line2)) => Some(line2),
|
},
|
||||||
(None, None) => None,
|
));
|
||||||
};
|
}
|
||||||
let billing_address = item
|
} else {
|
||||||
.router_data
|
item.router_data.payment_id.clone()
|
||||||
.get_optional_billing()
|
|
||||||
.map(|_| BillingAddress {
|
|
||||||
name: item.router_data.get_optional_billing_full_name(),
|
|
||||||
street: billing_address_street,
|
|
||||||
city: item.router_data.get_optional_billing_city(),
|
|
||||||
post_code: item.router_data.get_optional_billing_zip(),
|
|
||||||
country: item.router_data.get_optional_billing_country(),
|
|
||||||
});
|
|
||||||
let shipping_address_street = match (
|
|
||||||
item.router_data.get_optional_shipping_line1(),
|
|
||||||
item.router_data.get_optional_shipping_line2(),
|
|
||||||
) {
|
|
||||||
(Some(line1), Some(line2)) => Some(Secret::new(format!(
|
|
||||||
"{}, {}",
|
|
||||||
line1.expose(),
|
|
||||||
line2.expose()
|
|
||||||
))),
|
|
||||||
(Some(line1), None) => Some(Secret::new(line1.expose())),
|
|
||||||
(None, Some(line2)) => Some(Secret::new(line2.expose())),
|
|
||||||
(None, None) => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let shipping_address = item
|
let billing_address = get_validated_billing_address(item.router_data)?;
|
||||||
.router_data
|
let shipping_address = get_validated_shipping_address(item.router_data)?;
|
||||||
.get_optional_shipping()
|
|
||||||
.map(|_| ShippingAddress {
|
|
||||||
name: item.router_data.get_optional_shipping_full_name(),
|
|
||||||
street: shipping_address_street,
|
|
||||||
city: item.router_data.get_optional_shipping_city(),
|
|
||||||
post_code: item.router_data.get_optional_shipping_zip(),
|
|
||||||
country: item.router_data.get_optional_shipping_country(),
|
|
||||||
});
|
|
||||||
let customer_info = CustomerInfo {
|
let customer_info = CustomerInfo {
|
||||||
card_holder_name: item.router_data.get_billing_full_name()?,
|
card_holder_name: match item.router_data.get_billing_full_name()? {
|
||||||
|
name if name.clone().expose().len() <= MAX_CARD_HOLDER_LENGTH => name,
|
||||||
|
_ => {
|
||||||
|
return Err(error_stack::Report::from(
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
|
field_name: "billing.address.first_name & billing.address.last_name"
|
||||||
|
.to_string(),
|
||||||
|
connector: "Nexixpay".to_string(),
|
||||||
|
max_length: MAX_CARD_HOLDER_LENGTH,
|
||||||
|
received_length: item
|
||||||
|
.router_data
|
||||||
|
.get_billing_full_name()?
|
||||||
|
.expose()
|
||||||
|
.len(),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
},
|
||||||
billing_address: billing_address.clone(),
|
billing_address: billing_address.clone(),
|
||||||
shipping_address: shipping_address.clone(),
|
shipping_address: shipping_address.clone(),
|
||||||
};
|
};
|
||||||
let order = Order {
|
let order = Order {
|
||||||
order_id: item.router_data.connector_request_reference_id.clone(),
|
order_id,
|
||||||
amount: item.amount.clone(),
|
amount: item.amount.clone(),
|
||||||
currency: item.router_data.request.currency,
|
currency: item.router_data.request.currency,
|
||||||
description: item.router_data.description.clone(),
|
description: item.router_data.description.clone(),
|
||||||
@ -1089,55 +1298,27 @@ impl TryFrom<&NexixpayRouterData<&PaymentsCompleteAuthorizeRouterData>>
|
|||||||
)?;
|
)?;
|
||||||
let capture_type = get_nexixpay_capture_type(item.router_data.request.capture_method)?;
|
let capture_type = get_nexixpay_capture_type(item.router_data.request.capture_method)?;
|
||||||
|
|
||||||
let order_id = item.router_data.connector_request_reference_id.clone();
|
let order_id = if item.router_data.payment_id.len() > MAX_ORDER_ID_LENGTH {
|
||||||
|
if item.router_data.payment_id.starts_with("pay_") {
|
||||||
|
get_random_string()
|
||||||
|
} else {
|
||||||
|
return Err(error_stack::Report::from(
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated {
|
||||||
|
field_name: "payment_id".to_string(),
|
||||||
|
connector: "Nexixpay".to_string(),
|
||||||
|
max_length: MAX_ORDER_ID_LENGTH,
|
||||||
|
received_length: item.router_data.payment_id.len(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.router_data.payment_id.clone()
|
||||||
|
};
|
||||||
let amount = item.amount.clone();
|
let amount = item.amount.clone();
|
||||||
let billing_address_street = match (
|
|
||||||
item.router_data.get_optional_billing_line1(),
|
|
||||||
item.router_data.get_optional_billing_line2(),
|
|
||||||
) {
|
|
||||||
(Some(line1), Some(line2)) => Some(Secret::new(format!(
|
|
||||||
"{}, {}",
|
|
||||||
line1.expose(),
|
|
||||||
line2.expose()
|
|
||||||
))),
|
|
||||||
(Some(line1), None) => Some(line1),
|
|
||||||
(None, Some(line2)) => Some(line2),
|
|
||||||
(None, None) => None,
|
|
||||||
};
|
|
||||||
let billing_address = item
|
|
||||||
.router_data
|
|
||||||
.get_optional_billing()
|
|
||||||
.map(|_| BillingAddress {
|
|
||||||
name: item.router_data.get_optional_billing_full_name(),
|
|
||||||
street: billing_address_street,
|
|
||||||
city: item.router_data.get_optional_billing_city(),
|
|
||||||
post_code: item.router_data.get_optional_billing_zip(),
|
|
||||||
country: item.router_data.get_optional_billing_country(),
|
|
||||||
});
|
|
||||||
let shipping_address_street = match (
|
|
||||||
item.router_data.get_optional_shipping_line1(),
|
|
||||||
item.router_data.get_optional_shipping_line2(),
|
|
||||||
) {
|
|
||||||
(Some(line1), Some(line2)) => Some(Secret::new(format!(
|
|
||||||
"{}, {}",
|
|
||||||
line1.expose(),
|
|
||||||
line2.expose()
|
|
||||||
))),
|
|
||||||
(Some(line1), None) => Some(Secret::new(line1.expose())),
|
|
||||||
(None, Some(line2)) => Some(Secret::new(line2.expose())),
|
|
||||||
(None, None) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let shipping_address = item
|
let billing_address = get_validated_billing_address(item.router_data)?;
|
||||||
.router_data
|
let shipping_address = get_validated_shipping_address(item.router_data)?;
|
||||||
.get_optional_shipping()
|
|
||||||
.map(|_| ShippingAddress {
|
|
||||||
name: item.router_data.get_optional_shipping_full_name(),
|
|
||||||
street: shipping_address_street,
|
|
||||||
city: item.router_data.get_optional_shipping_city(),
|
|
||||||
post_code: item.router_data.get_optional_shipping_zip(),
|
|
||||||
country: item.router_data.get_optional_shipping_country(),
|
|
||||||
});
|
|
||||||
let customer_info = CustomerInfo {
|
let customer_info = CustomerInfo {
|
||||||
card_holder_name: item.router_data.get_billing_full_name()?,
|
card_holder_name: item.router_data.get_billing_full_name()?,
|
||||||
billing_address: billing_address.clone(),
|
billing_address: billing_address.clone(),
|
||||||
@ -1227,6 +1408,24 @@ impl TryFrom<&NexixpayRouterData<&PaymentsCompleteAuthorizeRouterData>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_validated_shipping_address<RouterContextDataAlias>(
|
||||||
|
data: &RouterContextDataAlias,
|
||||||
|
) -> Result<Option<ShippingAddress>, error_stack::Report<errors::ConnectorError>>
|
||||||
|
where
|
||||||
|
RouterContextDataAlias: crate::utils::RouterData,
|
||||||
|
{
|
||||||
|
get_validated_address_details_generic(data, AddressKind::Shipping)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_validated_billing_address<RouterContextDataAlias>(
|
||||||
|
data: &RouterContextDataAlias,
|
||||||
|
) -> Result<Option<BillingAddress>, error_stack::Report<errors::ConnectorError>>
|
||||||
|
where
|
||||||
|
RouterContextDataAlias: crate::utils::RouterData,
|
||||||
|
{
|
||||||
|
get_validated_address_details_generic(data, AddressKind::Billing)
|
||||||
|
}
|
||||||
|
|
||||||
impl<F>
|
impl<F>
|
||||||
TryFrom<
|
TryFrom<
|
||||||
ResponseRouterData<F, NexixpayTransactionResponse, PaymentsSyncData, PaymentsResponseData>,
|
ResponseRouterData<F, NexixpayTransactionResponse, PaymentsSyncData, PaymentsResponseData>,
|
||||||
|
|||||||
@ -292,6 +292,13 @@ pub enum ApiErrorResponse {
|
|||||||
ExternalVaultFailed,
|
ExternalVaultFailed,
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_46", message = "Field {fields} doesn't match with the ones used during mandate creation")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_46", message = "Field {fields} doesn't match with the ones used during mandate creation")]
|
||||||
MandatePaymentDataMismatch { fields: String },
|
MandatePaymentDataMismatch { fields: String },
|
||||||
|
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_47", message = "Connector '{connector}' rejected field '{field_name}': length {received_length} exceeds maximum of {max_length}")]
|
||||||
|
MaxFieldLengthViolated {
|
||||||
|
connector: String,
|
||||||
|
field_name: String,
|
||||||
|
max_length: usize,
|
||||||
|
received_length: usize,
|
||||||
|
},
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_01", message = "Failed to authenticate the webhook")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_01", message = "Failed to authenticate the webhook")]
|
||||||
WebhookAuthenticationFailed,
|
WebhookAuthenticationFailed,
|
||||||
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_02", message = "Bad request received in webhook")]
|
#[error(error_type = ErrorType::InvalidRequestError, code = "WE_02", message = "Bad request received in webhook")]
|
||||||
@ -656,7 +663,9 @@ impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorRespon
|
|||||||
Self::MandatePaymentDataMismatch { fields} => {
|
Self::MandatePaymentDataMismatch { fields} => {
|
||||||
AER::BadRequest(ApiError::new("IR", 46, format!("Field {fields} doesn't match with the ones used during mandate creation"), Some(Extra {fields: Some(fields.to_owned()), ..Default::default()}))) //FIXME: error message
|
AER::BadRequest(ApiError::new("IR", 46, format!("Field {fields} doesn't match with the ones used during mandate creation"), Some(Extra {fields: Some(fields.to_owned()), ..Default::default()}))) //FIXME: error message
|
||||||
}
|
}
|
||||||
|
Self::MaxFieldLengthViolated { connector, field_name, max_length, received_length} => {
|
||||||
|
AER::BadRequest(ApiError::new("IR", 47, format!("Connector '{connector}' rejected field '{field_name}': length {received_length} exceeds maximum of {max_length}"), Some(Extra {connector: Some(connector.to_string()), ..Default::default()})))
|
||||||
|
}
|
||||||
Self::WebhookAuthenticationFailed => {
|
Self::WebhookAuthenticationFailed => {
|
||||||
AER::Unauthorized(ApiError::new("WE", 1, "Webhook authentication failed", None))
|
AER::Unauthorized(ApiError::new("WE", 1, "Webhook authentication failed", None))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -127,6 +127,13 @@ pub enum ConnectorError {
|
|||||||
},
|
},
|
||||||
#[error("Field {fields} doesn't match with the ones used during mandate creation")]
|
#[error("Field {fields} doesn't match with the ones used during mandate creation")]
|
||||||
MandatePaymentDataMismatch { fields: String },
|
MandatePaymentDataMismatch { fields: String },
|
||||||
|
#[error("Field '{field_name}' is too long for connector '{connector}'")]
|
||||||
|
MaxFieldLengthViolated {
|
||||||
|
connector: String,
|
||||||
|
field_name: String,
|
||||||
|
max_length: usize,
|
||||||
|
received_length: usize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectorError {
|
impl ConnectorError {
|
||||||
|
|||||||
@ -601,6 +601,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
|
|||||||
errors::ApiErrorResponse::NotImplemented { .. } => Self::Unauthorized,
|
errors::ApiErrorResponse::NotImplemented { .. } => Self::Unauthorized,
|
||||||
errors::ApiErrorResponse::FlowNotSupported { .. } => Self::InternalServerError,
|
errors::ApiErrorResponse::FlowNotSupported { .. } => Self::InternalServerError,
|
||||||
errors::ApiErrorResponse::MandatePaymentDataMismatch { .. } => Self::PlatformBadRequest,
|
errors::ApiErrorResponse::MandatePaymentDataMismatch { .. } => Self::PlatformBadRequest,
|
||||||
|
errors::ApiErrorResponse::MaxFieldLengthViolated { .. } => Self::PlatformBadRequest,
|
||||||
errors::ApiErrorResponse::PaymentUnexpectedState {
|
errors::ApiErrorResponse::PaymentUnexpectedState {
|
||||||
current_flow,
|
current_flow,
|
||||||
field_name,
|
field_name,
|
||||||
|
|||||||
@ -156,6 +156,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
|
|||||||
| errors::ConnectorError::NoConnectorMetaData
|
| errors::ConnectorError::NoConnectorMetaData
|
||||||
| errors::ConnectorError::NoConnectorWalletDetails
|
| errors::ConnectorError::NoConnectorWalletDetails
|
||||||
| errors::ConnectorError::FailedToObtainCertificateKey
|
| errors::ConnectorError::FailedToObtainCertificateKey
|
||||||
|
| errors::ConnectorError::MaxFieldLengthViolated { .. }
|
||||||
| errors::ConnectorError::FlowNotSupported { .. }
|
| errors::ConnectorError::FlowNotSupported { .. }
|
||||||
| errors::ConnectorError::MissingConnectorMandateID
|
| errors::ConnectorError::MissingConnectorMandateID
|
||||||
| errors::ConnectorError::MissingConnectorMandateMetadata
|
| errors::ConnectorError::MissingConnectorMandateMetadata
|
||||||
@ -242,6 +243,9 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
|
|||||||
errors::ConnectorError::FlowNotSupported{ flow, connector } => {
|
errors::ConnectorError::FlowNotSupported{ flow, connector } => {
|
||||||
errors::ApiErrorResponse::FlowNotSupported { flow: flow.to_owned(), connector: connector.to_owned() }
|
errors::ApiErrorResponse::FlowNotSupported { flow: flow.to_owned(), connector: connector.to_owned() }
|
||||||
},
|
},
|
||||||
|
errors::ConnectorError::MaxFieldLengthViolated{ connector, field_name, max_length, received_length} => {
|
||||||
|
errors::ApiErrorResponse::MaxFieldLengthViolated { connector: connector.to_string(), field_name: field_name.to_string(), max_length: *max_length, received_length: *received_length }
|
||||||
|
},
|
||||||
errors::ConnectorError::InvalidDataFormat { field_name } => {
|
errors::ConnectorError::InvalidDataFormat { field_name } => {
|
||||||
errors::ApiErrorResponse::InvalidDataValue { field_name }
|
errors::ApiErrorResponse::InvalidDataValue { field_name }
|
||||||
},
|
},
|
||||||
@ -362,6 +366,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
|
|||||||
| errors::ConnectorError::FailedToObtainCertificateKey
|
| errors::ConnectorError::FailedToObtainCertificateKey
|
||||||
| errors::ConnectorError::NotImplemented(_)
|
| errors::ConnectorError::NotImplemented(_)
|
||||||
| errors::ConnectorError::NotSupported { .. }
|
| errors::ConnectorError::NotSupported { .. }
|
||||||
|
| errors::ConnectorError::MaxFieldLengthViolated { .. }
|
||||||
| errors::ConnectorError::FlowNotSupported { .. }
|
| errors::ConnectorError::FlowNotSupported { .. }
|
||||||
| errors::ConnectorError::MissingConnectorMandateID
|
| errors::ConnectorError::MissingConnectorMandateID
|
||||||
| errors::ConnectorError::MissingConnectorMandateMetadata
|
| errors::ConnectorError::MissingConnectorMandateMetadata
|
||||||
|
|||||||
@ -161,6 +161,13 @@ pub enum ConnectorError {
|
|||||||
},
|
},
|
||||||
#[error("{flow} flow not supported by {connector} connector")]
|
#[error("{flow} flow not supported by {connector} connector")]
|
||||||
FlowNotSupported { flow: String, connector: String },
|
FlowNotSupported { flow: String, connector: String },
|
||||||
|
#[error("Connector '{connector}' rejected field '{field_name}': length {received_length} exceeds maximum of {max_length}'")]
|
||||||
|
MaxFieldLengthViolated {
|
||||||
|
connector: String,
|
||||||
|
field_name: String,
|
||||||
|
max_length: usize,
|
||||||
|
received_length: usize,
|
||||||
|
},
|
||||||
#[error("Capture method not supported")]
|
#[error("Capture method not supported")]
|
||||||
CaptureMethodNotSupported,
|
CaptureMethodNotSupported,
|
||||||
#[error("Missing connector transaction ID")]
|
#[error("Missing connector transaction ID")]
|
||||||
|
|||||||
Reference in New Issue
Block a user