Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core): Add killswitch for blocklist feature #3459

Merged
Merged
Changes from 2 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
281 changes: 146 additions & 135 deletions crates/router/src/core/payments/operations/payment_confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,156 +719,167 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
let m_db = state.clone().store;

// Validate Blocklist
let merchant_id = payment_data.payment_attempt.merchant_id;
let merchant_fingerprint_secret =
blocklist_utils::get_merchant_fingerprint_secret(state, &merchant_id).await?;

// Hashed Fingerprint to check whether or not this payment should be blocked.
let card_number_fingerprint = payment_data
.payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
api_models::payments::PaymentMethodData::Card(card) => {
crypto::HmacSha512::sign_message(
&crypto::HmacSha512,
merchant_fingerprint_secret.as_bytes(),
card.card_number.clone().get_card_no().as_bytes(),
)
.attach_printable("error in pm fingerprint creation")
.map_or_else(
|err| {
logger::error!(error=?err);
None
},
Some,
)
}
_ => None,
})
.map(hex::encode);

// Hashed Cardbin to check whether or not this payment should be blocked.
let card_bin_fingerprint = payment_data
.payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
api_models::payments::PaymentMethodData::Card(card) => {
crypto::HmacSha512::sign_message(
&crypto::HmacSha512,
merchant_fingerprint_secret.as_bytes(),
card.card_number.clone().get_card_isin().as_bytes(),
)
.attach_printable("error in card bin hash creation")
.map_or_else(
|err| {
logger::error!(error=?err);
None
},
Some,
)
}
_ => None,
})
.map(hex::encode);

// Hashed Extended Cardbin to check whether or not this payment should be blocked.
let extended_card_bin_fingerprint = payment_data
.payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
api_models::payments::PaymentMethodData::Card(card) => {
crypto::HmacSha512::sign_message(
&crypto::HmacSha512,
merchant_fingerprint_secret.as_bytes(),
card.card_number.clone().get_extended_card_bin().as_bytes(),
)
.attach_printable("error in extended card bin hash creation")
.map_or_else(
|err| {
logger::error!(error=?err);
None
},
Some,
)
}
_ => None,
})
.map(hex::encode);

let mut fingerprint_id = None;

//validating the payment method.
let mut is_pm_blocklisted = false;
let merchant_id = payment_data.payment_attempt.merchant_id;
let blocklist_enabled_key = format!("guard_blocklist_for_{merchant_id}");
let blocklist_guard_enabled = state
.store
.find_config_by_key_unwrap_or(&blocklist_enabled_key, Some("false".to_string()))
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to fetch guard blocklist enabled config")?;

let blocklist_guard_enabled = blocklist_guard_enabled.config != "false";
prajjwalkumar17 marked this conversation as resolved.
Show resolved Hide resolved

if blocklist_guard_enabled {
let merchant_fingerprint_secret =
blocklist_utils::get_merchant_fingerprint_secret(state, &merchant_id).await?;
// Hashed Fingerprint to check whether or not this payment should be blocked.
let card_number_fingerprint = payment_data
.payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
api_models::payments::PaymentMethodData::Card(card) => {
crypto::HmacSha512::sign_message(
&crypto::HmacSha512,
merchant_fingerprint_secret.as_bytes(),
card.card_number.clone().get_card_no().as_bytes(),
)
.attach_printable("error in pm fingerprint creation")
.map_or_else(
|err| {
logger::error!(error=?err);
None
},
Some,
)
}
_ => None,
})
.map(hex::encode);

// Hashed Cardbin to check whether or not this payment should be blocked.
let card_bin_fingerprint = payment_data
.payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
api_models::payments::PaymentMethodData::Card(card) => {
crypto::HmacSha512::sign_message(
&crypto::HmacSha512,
merchant_fingerprint_secret.as_bytes(),
card.card_number.clone().get_card_isin().as_bytes(),
)
.attach_printable("error in card bin hash creation")
.map_or_else(
|err| {
logger::error!(error=?err);
None
},
Some,
)
}
_ => None,
})
.map(hex::encode);

// Hashed Extended Cardbin to check whether or not this payment should be blocked.
let extended_card_bin_fingerprint = payment_data
.payment_method_data
.as_ref()
.and_then(|pm_data| match pm_data {
api_models::payments::PaymentMethodData::Card(card) => {
crypto::HmacSha512::sign_message(
&crypto::HmacSha512,
merchant_fingerprint_secret.as_bytes(),
card.card_number.clone().get_extended_card_bin().as_bytes(),
)
.attach_printable("error in extended card bin hash creation")
.map_or_else(
|err| {
logger::error!(error=?err);
None
},
Some,
)
}
_ => None,
})
.map(hex::encode);

//validating the payment method.
let mut blocklist_futures = Vec::new();
if let Some(card_number_fingerprint) = card_number_fingerprint.as_ref() {
blocklist_futures.push(db.find_blocklist_lookup_entry_by_merchant_id_fingerprint(
&merchant_id,
card_number_fingerprint,
));
}

let mut blocklist_futures = Vec::new();
if let Some(card_number_fingerprint) = card_number_fingerprint.as_ref() {
blocklist_futures.push(db.find_blocklist_lookup_entry_by_merchant_id_fingerprint(
&merchant_id,
card_number_fingerprint,
));
}

if let Some(card_bin_fingerprint) = card_bin_fingerprint.as_ref() {
blocklist_futures.push(db.find_blocklist_lookup_entry_by_merchant_id_fingerprint(
&merchant_id,
card_bin_fingerprint,
));
}
if let Some(card_bin_fingerprint) = card_bin_fingerprint.as_ref() {
blocklist_futures.push(db.find_blocklist_lookup_entry_by_merchant_id_fingerprint(
&merchant_id,
card_bin_fingerprint,
));
}

if let Some(extended_card_bin_fingerprint) = extended_card_bin_fingerprint.as_ref() {
blocklist_futures.push(db.find_blocklist_lookup_entry_by_merchant_id_fingerprint(
&merchant_id,
extended_card_bin_fingerprint,
));
}
if let Some(extended_card_bin_fingerprint) = extended_card_bin_fingerprint.as_ref() {
blocklist_futures.push(db.find_blocklist_lookup_entry_by_merchant_id_fingerprint(
&merchant_id,
extended_card_bin_fingerprint,
));
}

let blocklist_lookups = futures::future::join_all(blocklist_futures).await;
let blocklist_lookups = futures::future::join_all(blocklist_futures).await;

if blocklist_lookups.iter().any(|x| x.is_ok()) {
intent_status = storage_enums::IntentStatus::Failed;
attempt_status = storage_enums::AttemptStatus::Failure;
is_pm_blocklisted = true;
}
if blocklist_lookups.iter().any(|x| x.is_ok()) {
intent_status = storage_enums::IntentStatus::Failed;
attempt_status = storage_enums::AttemptStatus::Failure;
is_pm_blocklisted = true;
}

if let Some(encoded_hash) = card_number_fingerprint {
#[cfg(feature = "kms")]
let encrypted_fingerprint = kms::get_kms_client(&state.conf.kms)
.await
.encrypt(encoded_hash)
.await
.map_or_else(
|e| {
logger::error!(error=?e, "failed kms encryption of card fingerprint");
None
},
Some,
);

#[cfg(not(feature = "kms"))]
let encrypted_fingerprint = Some(encoded_hash);

if let Some(encrypted_fingerprint) = encrypted_fingerprint {
fingerprint_id = db
.insert_blocklist_fingerprint_entry(
diesel_models::blocklist_fingerprint::BlocklistFingerprintNew {
merchant_id,
fingerprint_id: utils::generate_id(consts::ID_LENGTH, "fingerprint"),
encrypted_fingerprint,
data_kind: common_enums::BlocklistDataKind::PaymentMethod,
created_at: common_utils::date_time::now(),
},
)
if let Some(encoded_hash) = card_number_fingerprint {
#[cfg(feature = "kms")]
let encrypted_fingerprint = kms::get_kms_client(&state.conf.kms)
.await
.encrypt(encoded_hash)
.await
.map_or_else(
|e| {
logger::error!(error=?e, "failed storing card fingerprint in db");
logger::error!(error=?e, "failed kms encryption of card fingerprint");
None
},
|fp| Some(fp.fingerprint_id),
Some,
);

#[cfg(not(feature = "kms"))]
let encrypted_fingerprint = Some(encoded_hash);

if let Some(encrypted_fingerprint) = encrypted_fingerprint {
fingerprint_id = db
.insert_blocklist_fingerprint_entry(
diesel_models::blocklist_fingerprint::BlocklistFingerprintNew {
merchant_id,
fingerprint_id: utils::generate_id(
consts::ID_LENGTH,
"fingerprint",
),
encrypted_fingerprint,
data_kind: common_enums::BlocklistDataKind::PaymentMethod,
created_at: common_utils::date_time::now(),
},
)
.await
.map_or_else(
|e| {
logger::error!(error=?e, "failed storing card fingerprint in db");
None
},
|fp| Some(fp.fingerprint_id),
);
}
}
}

let surcharge_amount = payment_data
.surcharge_details
.as_ref()
Expand Down
Loading