Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 65 additions & 13 deletions api-reference/v1/openapi_spec_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -19542,13 +19542,62 @@
}
},
"NextActionCall": {
"type": "string",
"enum": [
"post_session_tokens",
"confirm",
"sync",
"complete_authorize",
"await_merchant_callback"
"oneOf": [
{
"type": "string",
"description": "The next action call is Post Session Tokens",
"enum": [
"post_session_tokens"
]
},
{
"type": "string",
"description": "The next action call is confirm",
"enum": [
"confirm"
]
},
{
"type": "string",
"description": "The next action call is sync",
"enum": [
"sync"
]
},
{
"type": "string",
"description": "The next action call is Complete Authorize",
"enum": [
"complete_authorize"
]
},
{
"type": "string",
"description": "The next action is to await for a merchant callback",
"enum": [
"await_merchant_callback"
]
},
{
"type": "object",
"required": [
"deny"
],
"properties": {
"deny": {
"type": "object",
"description": "The next action is to deny the payment with an error message",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
},
"NextActionData": {
Expand Down Expand Up @@ -24532,14 +24581,17 @@
},
"PaymentsEligibilityResponse": {
"type": "object",
"required": [
"payment_id",
"sdk_next_action"
],
"properties": {
"payment_id": {
"type": "string",
"description": "The identifier for the payment"
},
"sdk_next_action": {
"allOf": [
{
"$ref": "#/components/schemas/SdkNextAction"
}
],
"nullable": true
"$ref": "#/components/schemas/SdkNextAction"
}
}
},
Expand Down
63 changes: 56 additions & 7 deletions api-reference/v2/openapi_spec_v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -15397,13 +15397,62 @@
}
},
"NextActionCall": {
"type": "string",
"enum": [
"post_session_tokens",
"confirm",
"sync",
"complete_authorize",
"await_merchant_callback"
"oneOf": [
{
"type": "string",
"description": "The next action call is Post Session Tokens",
"enum": [
"post_session_tokens"
]
},
{
"type": "string",
"description": "The next action call is confirm",
"enum": [
"confirm"
]
},
{
"type": "string",
"description": "The next action call is sync",
"enum": [
"sync"
]
},
{
"type": "string",
"description": "The next action call is Complete Authorize",
"enum": [
"complete_authorize"
]
},
{
"type": "string",
"description": "The next action is to await for a merchant callback",
"enum": [
"await_merchant_callback"
]
},
{
"type": "object",
"required": [
"deny"
],
"properties": {
"deny": {
"type": "object",
"description": "The next action is to deny the payment with an error message",
"required": [
"message"
],
"properties": {
"message": {
"type": "string"
}
}
}
}
}
]
},
"NextActionData": {
Expand Down
18 changes: 18 additions & 0 deletions crates/api_models/src/events/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,24 @@ impl ApiEventMetric for payments::PaymentsRequest {
}
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payments::PaymentsEligibilityRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
payment_id: self.payment_id.clone(),
})
}
}

#[cfg(feature = "v1")]
impl ApiEventMetric for payments::PaymentsEligibilityResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Payment {
payment_id: self.payment_id.clone(),
})
}
}

#[cfg(feature = "v2")]
impl ApiEventMetric for PaymentsCreateIntentRequest {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Expand Down
14 changes: 12 additions & 2 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8026,6 +8026,8 @@ pub enum NextActionCall {
CompleteAuthorize,
/// The next action is to await for a merchant callback
AwaitMerchantCallback,
/// The next action is to deny the payment with an error message
Deny { message: String },
}

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
Expand Down Expand Up @@ -9296,9 +9298,13 @@ pub struct ClickToPaySessionResponse {

#[derive(Debug, serde::Deserialize, Clone, ToSchema)]
pub struct PaymentsEligibilityRequest {
/// The identifier for the payment
/// Added in the payload for ApiEventMetrics, populated from the path param
#[serde(skip)]
pub payment_id: id_type::PaymentId,
/// Token used for client side verification
#[schema(value_type = String, example = "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo")]
pub client_secret: Secret<String>,
pub client_secret: Option<Secret<String>>,
/// The payment method to be used for the payment
#[schema(value_type = PaymentMethod, example = "wallet")]
pub payment_method_type: api_enums::PaymentMethod,
Expand All @@ -9311,7 +9317,11 @@ pub struct PaymentsEligibilityRequest {

#[derive(Debug, serde::Serialize, Clone, ToSchema)]
pub struct PaymentsEligibilityResponse {
pub sdk_next_action: Option<SdkNextAction>,
/// The identifier for the payment
#[schema(value_type = String)]
pub payment_id: id_type::PaymentId,
/// Next action to be performed by the SDK
pub sdk_next_action: SdkNextAction,
}

#[cfg(feature = "v1")]
Expand Down
73 changes: 41 additions & 32 deletions crates/router/src/core/blocklist/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,45 +290,40 @@ async fn delete_card_bin_blocklist_entry(
})
}

pub async fn validate_data_for_blocklist<F>(
pub async fn should_payment_be_blocked(
state: &SessionState,
merchant_context: &domain::MerchantContext,
payment_data: &mut PaymentData<F>,
) -> CustomResult<bool, errors::ApiErrorResponse>
where
F: Send + Clone,
{
payment_method_data: &Option<domain::PaymentMethodData>,
) -> CustomResult<bool, errors::ApiErrorResponse> {
let db = &state.store;
let merchant_id = merchant_context.get_merchant_account().get_id();
let merchant_fingerprint_secret = get_merchant_fingerprint_secret(state, merchant_id).await?;

// Hashed Fingerprint to check whether or not this payment should be blocked.
let card_number_fingerprint = if let Some(domain::PaymentMethodData::Card(card)) =
payment_data.payment_method_data.as_ref()
{
generate_fingerprint(
state,
StrongSecret::new(card.card_number.get_card_no()),
StrongSecret::new(merchant_fingerprint_secret.clone()),
api_models::enums::LockerChoice::HyperswitchCardVault,
)
.await
.attach_printable("error in pm fingerprint creation")
.map_or_else(
|error| {
logger::error!(?error);
None
},
Some,
)
.map(|payload| payload.card_fingerprint)
} else {
None
};
let card_number_fingerprint =
if let Some(domain::PaymentMethodData::Card(card)) = payment_method_data {
generate_fingerprint(
state,
StrongSecret::new(card.card_number.get_card_no()),
StrongSecret::new(merchant_fingerprint_secret.clone()),
api_models::enums::LockerChoice::HyperswitchCardVault,
)
.await
.attach_printable("error in pm fingerprint creation")
.map_or_else(
|error| {
logger::error!(?error);
None
},
Some,
)
.map(|payload| payload.card_fingerprint)
} else {
None
};

// Hashed Cardbin to check whether or not this payment should be blocked.
let card_bin_fingerprint = payment_data
.payment_method_data
let card_bin_fingerprint = payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
domain::PaymentMethodData::Card(card) => Some(card.card_number.get_card_isin()),
Expand All @@ -337,8 +332,7 @@ where

// Hashed Extended Cardbin to check whether or not this payment should be blocked.
let extended_card_bin_fingerprint =
payment_data
.payment_method_data
payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
domain::PaymentMethodData::Card(card) => {
Expand Down Expand Up @@ -385,6 +379,21 @@ where
}
}
}
Ok(should_payment_be_blocked)
}

pub async fn validate_data_for_blocklist<F>(
state: &SessionState,
merchant_context: &domain::MerchantContext,
payment_data: &mut PaymentData<F>,
) -> CustomResult<bool, errors::ApiErrorResponse>
where
F: Send + Clone,
{
let db = &state.store;
let should_payment_be_blocked =
should_payment_be_blocked(state, merchant_context, &payment_data.payment_method_data)
.await?;
if should_payment_be_blocked {
// Update db for attempt and intent status.
db.update_payment_intent(
Expand Down
Loading
Loading