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 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
283 changes: 151 additions & 132 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,175 @@ impl<F: Clone, Ctx: PaymentMethodRetrieve>
let m_db = state.clone().store;

// Validate Blocklist
let mut fingerprint_id = None;
let mut is_pm_blocklisted = false;
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);
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;

// 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);
let blocklist_guard_enabled: bool = match blocklist_guard_enabled {
Ok(config) => serde_json::from_str(&config.config).unwrap_or(false),

// 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,
)
// If it is not present in db we are defaulting it to false
Err(inner) => {
if !inner.current_context().is_db_not_found() {
logger::error!("Error fetching guard blocklist enabled config {:?}", inner);
}
_ => None,
})
.map(hex::encode);

let mut fingerprint_id = None;

//validating the payment method.
let mut is_pm_blocklisted = false;
false
}
};

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 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,
));
}

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