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 locker config to enable or disable locker #3352

Merged
merged 33 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ba6da85
add locker config
Aprabhat19 Jan 15, 2024
4f1fa0d
fix failing spell check
Aprabhat19 Jan 15, 2024
17c7180
add config for lsit mandate flow
Aprabhat19 Jan 15, 2024
44acd44
Merge branch 'main' into locker-enable-config
Aprabhat19 Jan 16, 2024
391ce0a
not list customer paymnet methods when the locker is disabled:
Aprabhat19 Jan 16, 2024
bc80cb6
Merge branch 'locker-enable-config' of https://github.com/juspay/hype…
Aprabhat19 Jan 16, 2024
0e752e9
validate openapi spec
Aprabhat19 Jan 16, 2024
558c186
address comments
Aprabhat19 Jan 16, 2024
4d6a6d3
change cofnig to false
Aprabhat19 Jan 16, 2024
42c6a48
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Jan 16, 2024
cbcb0c7
add default implementation for save in locker
Aprabhat19 Jan 16, 2024
3e209ba
Merge branch 'locker-enable-config' of https://github.com/juspay/hype…
Aprabhat19 Jan 16, 2024
8a634dc
address comments
Aprabhat19 Jan 16, 2024
00766b1
minor changes
Aprabhat19 Jan 16, 2024
90e34ba
address clippy fails
Aprabhat19 Jan 16, 2024
1f82243
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Jan 16, 2024
7da7596
change config to true
Aprabhat19 Jan 16, 2024
94618c3
Merge branch 'locker-enable-config' of https://github.com/juspay/hype…
Aprabhat19 Jan 16, 2024
7781d01
Merge branch 'main' of https://github.com/juspay/hyperswitch into loc…
Aprabhat19 Jan 16, 2024
69a296e
remove the card bin db call
Aprabhat19 Jan 17, 2024
041a67a
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Jan 17, 2024
a860371
address spell check
Aprabhat19 Jan 17, 2024
bdb4c57
Merge branch 'locker-enable-config' of https://github.com/juspay/hype…
Aprabhat19 Jan 17, 2024
344e178
add the config for retrieve payment method api
Aprabhat19 Jan 17, 2024
80160b4
resolve conflict
Aprabhat19 Jan 17, 2024
4041cd2
make config as true:'
Aprabhat19 Jan 17, 2024
10de26b
add bank transfers in response
Aprabhat19 Jan 17, 2024
33f4f57
address comments
Aprabhat19 Jan 18, 2024
8a1413d
Merge branch 'main' into locker-enable-config
Aprabhat19 Jan 18, 2024
c490d7b
chnage config to true
Aprabhat19 Jan 18, 2024
a59f377
Merge branch 'locker-enable-config' of https://github.com/juspay/hype…
Aprabhat19 Jan 18, 2024
c9d4467
list mandates add field pmt
Aprabhat19 Jan 18, 2024
0d7f986
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Jan 18, 2024
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
1 change: 1 addition & 0 deletions config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ host_rs = "" # Rust Locker host
mock_locker = true # Emulate a locker locally using Postgres
basilisk_host = "" # Basilisk host
locker_signing_key_id = "1" # Key_id to sign basilisk hs locker
locker_enabled = false # Boolean to enable or disable saving cards in locker

[delayed_session_response]
connectors_with_delayed_session_response = "trustpay,payme" # List of connectors which has delayed session response
Expand Down
2 changes: 2 additions & 0 deletions config/development.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ host = ""
host_rs = ""
mock_locker = true
basilisk_host = ""
locker_enabled = true


[forex_api]
call_delay = 21600
Expand Down
1 change: 1 addition & 0 deletions config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ host = ""
host_rs = ""
mock_locker = true
basilisk_host = ""
locker_enabled = false

[jwekey]
vault_encryption_key = ""
Expand Down
9 changes: 9 additions & 0 deletions crates/api_models/src/mandates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ pub struct MandateCardDetails {
#[schema(value_type = Option<String>)]
/// A unique identifier alias to identify a particular card
pub card_fingerprint: Option<Secret<String>>,
/// The first 6 digits of card
pub card_isin: Option<String>,
/// The bank that issued the card
pub card_issuer: Option<String>,
/// The network that facilitates payment card transactions
#[schema(value_type = Option<CardNetwork>)]
pub card_network: Option<api_enums::CardNetwork>,
/// The type of the payment card
pub card_type: Option<String>,
}

#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
Expand Down
41 changes: 41 additions & 0 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ pub struct CardDetail {
/// Card Holder's Nick Name
#[schema(value_type = Option<String>,example = "John Doe")]
pub nick_name: Option<masking::Secret<String>>,

/// Card Issuing Country
pub card_issuing_country: Option<String>,

/// Card's Network
#[schema(value_type = Option<CardNetwork>)]
pub card_network: Option<api_enums::CardNetwork>,

/// Issuer Bank for Card
pub card_issuer: Option<String>,

/// Card Type
pub card_type: Option<String>,
}

#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
Expand Down Expand Up @@ -177,6 +190,12 @@ pub struct CardDetailsPaymentMethod {
pub expiry_year: Option<masking::Secret<String>>,
pub nick_name: Option<masking::Secret<String>>,
pub card_holder_name: Option<masking::Secret<String>>,
pub card_isin: Option<String>,
pub card_issuer: Option<String>,
pub card_network: Option<api_enums::CardNetwork>,
pub card_type: Option<String>,
#[serde(default = "saved_in_locker_default")]
pub saved_to_locker: bool,
}

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
Expand Down Expand Up @@ -227,6 +246,18 @@ pub struct CardDetailFromLocker {

#[schema(value_type=Option<String>)]
pub nick_name: Option<masking::Secret<String>>,

#[schema(value_type = Option<CardNetwork>)]
pub card_network: Option<api_enums::CardNetwork>,

pub card_isin: Option<String>,
pub card_issuer: Option<String>,
pub card_type: Option<String>,
pub saved_to_locker: bool,
}

fn saved_in_locker_default() -> bool {
true
}

impl From<CardDetailsPaymentMethod> for CardDetailFromLocker {
Expand All @@ -242,6 +273,11 @@ impl From<CardDetailsPaymentMethod> for CardDetailFromLocker {
card_holder_name: item.card_holder_name,
card_fingerprint: None,
nick_name: item.nick_name,
card_isin: item.card_isin,
card_issuer: item.card_issuer,
card_network: item.card_network,
card_type: item.card_type,
saved_to_locker: item.saved_to_locker,
}
}
}
Expand All @@ -255,6 +291,11 @@ impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
expiry_year: item.expiry_year,
nick_name: item.nick_name,
card_holder_name: item.card_holder_name,
card_isin: item.card_isin,
card_issuer: item.card_issuer,
card_network: item.card_network,
card_type: item.card_type,
saved_to_locker: item.saved_to_locker,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions crates/router/src/configs/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ impl Default for super::settings::Locker {
mock_locker: true,
basilisk_host: "localhost".into(),
locker_signing_key_id: "1".into(),
//true or false
locker_enabled: true,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/configs/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ pub struct Locker {
pub mock_locker: bool,
pub basilisk_host: String,
pub locker_signing_key_id: String,
pub locker_enabled: bool,
}

#[derive(Debug, Deserialize, Clone)]
Expand Down
4 changes: 4 additions & 0 deletions crates/router/src/core/locker_migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ pub async fn call_to_locker(
card_exp_year: card.card_exp_year,
card_holder_name: card.name_on_card,
nick_name: card.nick_name.map(masking::Secret::new),
card_issuing_country: None,
card_network: None,
card_issuer: None,
card_type: None,
};

let pm_create = api::PaymentMethodCreate {
Expand Down
18 changes: 11 additions & 7 deletions crates/router/src/core/mandate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::{
pub async fn get_mandate(
state: AppState,
merchant_account: domain::MerchantAccount,
key_store: domain::MerchantKeyStore,
req: mandates::MandateId,
) -> RouterResponse<mandates::MandateResponse> {
let mandate = state
Expand All @@ -42,7 +43,7 @@ pub async fn get_mandate(
.await
.to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?;
Ok(services::ApplicationResponse::Json(
mandates::MandateResponse::from_db_mandate(&state, mandate).await?,
mandates::MandateResponse::from_db_mandate(&state, key_store, mandate).await?,
))
}

Expand Down Expand Up @@ -202,6 +203,7 @@ pub async fn update_connector_mandate_id(
pub async fn get_customer_mandates(
state: AppState,
merchant_account: domain::MerchantAccount,
key_store: domain::MerchantKeyStore,
req: customers::CustomerId,
) -> RouterResponse<Vec<mandates::MandateResponse>> {
let mandates = state
Expand All @@ -221,7 +223,10 @@ pub async fn get_customer_mandates(
} else {
let mut response_vec = Vec::with_capacity(mandates.len());
for mandate in mandates {
response_vec.push(mandates::MandateResponse::from_db_mandate(&state, mandate).await?);
response_vec.push(
mandates::MandateResponse::from_db_mandate(&state, key_store.clone(), mandate)
.await?,
);
}
Ok(services::ApplicationResponse::Json(response_vec))
}
Expand Down Expand Up @@ -383,6 +388,7 @@ where
pub async fn retrieve_mandates_list(
state: AppState,
merchant_account: domain::MerchantAccount,
key_store: domain::MerchantKeyStore,
constraints: api_models::mandates::MandateListConstraints,
) -> RouterResponse<Vec<api_models::mandates::MandateResponse>> {
let mandates = state
Expand All @@ -392,11 +398,9 @@ pub async fn retrieve_mandates_list(
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to retrieve mandates")?;
let mandates_list = future::try_join_all(
mandates
.into_iter()
.map(|mandate| mandates::MandateResponse::from_db_mandate(&state, mandate)),
)
let mandates_list = future::try_join_all(mandates.into_iter().map(|mandate| {
mandates::MandateResponse::from_db_mandate(&state, key_store.clone(), mandate)
}))
.await?;
Ok(services::ApplicationResponse::Json(mandates_list))
}
Expand Down
82 changes: 65 additions & 17 deletions crates/router/src/core/payment_methods/cards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,7 @@ pub async fn add_card_hs(
req,
&merchant_account.merchant_id,
);

Ok((
payment_method_resp,
store_card_payload.duplicate.unwrap_or(false),
Expand Down Expand Up @@ -2508,11 +2509,19 @@ pub async fn list_customer_payment_method(
let parent_payment_method_token = generate_id(consts::ID_LENGTH, "token");

let (card, pmd, hyperswitch_token_data) = match pm.payment_method {
enums::PaymentMethod::Card => (
Some(get_card_details(&pm, key, state).await?),
None,
PaymentTokenData::permanent_card(pm.payment_method_id.clone()),
),
enums::PaymentMethod::Card => {
let card_details = get_card_details_with_locker_fallback(&pm, key, state).await?;

if card_details.is_some() {
(
card_details,
None,
PaymentTokenData::permanent_card(pm.payment_method_id.clone()),
)
} else {
continue;
}
}

#[cfg(feature = "payouts")]
enums::PaymentMethod::BankTransfer => {
Expand Down Expand Up @@ -2571,6 +2580,7 @@ pub async fn list_customer_payment_method(
};

//Need validation for enabled payment method ,querying MCA

let pma = api::CustomerPaymentMethod {
payment_token: parent_payment_method_token.to_owned(),
customer_id: pm.customer_id,
Expand Down Expand Up @@ -2700,7 +2710,38 @@ pub async fn list_customer_payment_method(
Ok(services::ApplicationResponse::Json(response))
}

async fn get_card_details(
pub async fn get_card_details_with_locker_fallback(
pm: &payment_method::PaymentMethod,
key: &[u8],
state: &routes::AppState,
) -> errors::RouterResult<Option<api::CardDetailFromLocker>> {
let card_decrypted =
decrypt::<serde_json::Value, masking::WithType>(pm.payment_method_data.clone(), key)
.await
.change_context(errors::StorageError::DecryptionError)
.attach_printable("unable to decrypt card details")
.ok()
.flatten()
.map(|x| x.into_inner().expose())
.and_then(|v| serde_json::from_value::<PaymentMethodsData>(v).ok())
.and_then(|pmd| match pmd {
PaymentMethodsData::Card(crd) => Some(api::CardDetailFromLocker::from(crd)),
_ => None,
});

Ok(if let Some(mut crd) = card_decrypted {
if crd.saved_to_locker {
crd.scheme = pm.scheme.clone();
Some(crd)
} else {
None
}
} else {
Some(get_card_details_from_locker(state, pm).await?)
})
}

pub async fn get_card_details_without_locker_fallback(
pm: &payment_method::PaymentMethod,
key: &[u8],
state: &routes::AppState,
Expand Down Expand Up @@ -2971,25 +3012,32 @@ impl TempLockerCardSupport {
pub async fn retrieve_payment_method(
state: routes::AppState,
pm: api::PaymentMethodId,
key_store: domain::MerchantKeyStore,
) -> errors::RouterResponse<api::PaymentMethodResponse> {
let db = state.store.as_ref();
let pm = db
.find_payment_method(&pm.payment_method_id)
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;

let key = key_store.key.peek();
let card = if pm.payment_method == enums::PaymentMethod::Card {
let card = get_card_from_locker(
&state,
&pm.customer_id,
&pm.merchant_id,
&pm.payment_method_id,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Error getting card from card vault")?;
let card_detail = payment_methods::get_card_detail(&pm, card)
let card_detail = if state.conf.locker.locker_enabled {
let card = get_card_from_locker(
&state,
&pm.customer_id,
&pm.merchant_id,
&pm.payment_method_id,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed while getting card details from locker")?;
.attach_printable("Error getting card from card vault")?;
payment_methods::get_card_detail(&pm, card)
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed while getting card details from locker")?
} else {
get_card_details_without_locker_fallback(&pm, key, &state).await?
};
Some(card_detail)
} else {
None
Expand Down
40 changes: 30 additions & 10 deletions crates/router/src/core/payment_methods/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,18 +352,26 @@ pub fn mk_add_card_response_hs(
req: api::PaymentMethodCreate,
merchant_id: &str,
) -> api::PaymentMethodResponse {
let mut card_number = card.card_number.peek().to_owned();
let card_number = card.card_number.clone();
let last4_digits = card_number.clone().get_last4();
let card_isin = card_number.get_card_isin();

let card = api::CardDetailFromLocker {
scheme: None,
last4_digits: Some(card_number.split_off(card_number.len() - 4)),
issuer_country: None, // [#256] bin mapping
card_number: Some(card.card_number),
expiry_month: Some(card.card_exp_month),
expiry_year: Some(card.card_exp_year),
card_token: None, // [#256]
card_fingerprint: None, // fingerprint not send by basilisk-hs need to have this feature in case we need it in future
card_holder_name: card.card_holder_name,
nick_name: card.nick_name,
last4_digits: Some(last4_digits),
issuer_country: None,
card_number: Some(card.card_number.clone()),
expiry_month: Some(card.card_exp_month.clone()),
expiry_year: Some(card.card_exp_year.clone()),
card_token: None,
card_fingerprint: None,
card_holder_name: card.card_holder_name.clone(),
nick_name: card.nick_name.clone(),
card_isin: Some(card_isin),
card_issuer: card.card_issuer,
card_network: card.card_network,
card_type: card.card_type,
saved_to_locker: true,
};
api::PaymentMethodResponse {
merchant_id: merchant_id.to_owned(),
Expand Down Expand Up @@ -399,6 +407,11 @@ pub fn mk_add_card_response(
card_fingerprint: Some(response.card_fingerprint),
card_holder_name: card.card_holder_name,
nick_name: card.nick_name,
card_isin: None,
card_issuer: None,
card_network: None,
card_type: None,
saved_to_locker: true,
};
api::PaymentMethodResponse {
merchant_id: merchant_id.to_owned(),
Expand Down Expand Up @@ -597,6 +610,8 @@ pub fn get_card_detail(
) -> CustomResult<api::CardDetailFromLocker, errors::VaultError> {
let card_number = response.card_number;
let mut last4_digits = card_number.peek().to_owned();
//fetch form card bin

let card_detail = api::CardDetailFromLocker {
scheme: pm.scheme.to_owned(),
issuer_country: pm.issuer_country.clone(),
Expand All @@ -608,6 +623,11 @@ pub fn get_card_detail(
card_fingerprint: None,
card_holder_name: response.name_on_card,
nick_name: response.nick_name.map(masking::Secret::new),
card_isin: None,
card_issuer: None,
card_network: None,
card_type: None,
saved_to_locker: true,
};
Ok(card_detail)
}
Expand Down
Loading
Loading