diff --git a/.typos.toml b/.typos.toml index 1ac38a005c9e..4ce21526604b 100644 --- a/.typos.toml +++ b/.typos.toml @@ -24,6 +24,7 @@ optin = "optin" # Boku preflow name optin_id = "optin_id" # Boku's id for optin flow deriver = "deriver" Deriver = "Deriver" +requestor_card_reference = "requestor_card_reference" [default.extend-words] aci = "aci" # Name of a connector diff --git a/config/config.example.toml b/config/config.example.toml index 02eff1d42979..7815f2400d04 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -21,25 +21,25 @@ idle_pool_connection_timeout = 90 # Timeout for idle pool connections (defaults # Main SQL data store credentials [master_database] -username = "db_user" # DB Username -password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled -host = "localhost" # DB Host -port = 5432 # DB Port -dbname = "hyperswitch_db" # Name of Database -pool_size = 5 # Number of connections to keep open -connection_timeout = 10 # Timeout for database connection in seconds -queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client +username = "db_user" # DB Username +password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled +host = "localhost" # DB Host +port = 5432 # DB Port +dbname = "hyperswitch_db" # Name of Database +pool_size = 5 # Number of connections to keep open +connection_timeout = 10 # Timeout for database connection in seconds +queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client # Replica SQL data store credentials [replica_database] -username = "replica_user" # DB Username -password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled -host = "localhost" # DB Host -port = 5432 # DB Port -dbname = "hyperswitch_db" # Name of Database -pool_size = 5 # Number of connections to keep open -connection_timeout = 10 # Timeout for database connection in seconds -queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client +username = "replica_user" # DB Username +password = "db_pass" # DB Password. Use base-64 encoded kms encrypted value here when kms is enabled +host = "localhost" # DB Host +port = 5432 # DB Port +dbname = "hyperswitch_db" # Name of Database +pool_size = 5 # Number of connections to keep open +connection_timeout = 10 # Timeout for database connection in seconds +queue_strategy = "Fifo" # Add the queue strategy used by the database bb8 client # Redis credentials [redis] @@ -95,17 +95,17 @@ sampling_rate = 0.1 # decimal rate between 0.0 otel_exporter_otlp_endpoint = "http://localhost:4317" # endpoint to send metrics and traces to, can include port number otel_exporter_otlp_timeout = 5000 # timeout (in milliseconds) for sending metrics and traces use_xray_generator = false # Set this to true for AWS X-ray compatible traces -route_to_trace = [ "*/confirm" ] +route_to_trace = ["*/confirm"] # This section provides some secret values. [secrets] -master_enc_key = "sample_key" # Master Encryption key used to encrypt merchant wise encryption key. Should be 32-byte long. -admin_api_key = "test_admin" # admin API key for admin authentication. Only applicable when KMS is disabled. -kms_encrypted_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the admin_api_key. Only applicable when KMS is enabled. -jwt_secret = "secret" # JWT secret used for user authentication. Only applicable when KMS is disabled. -kms_encrypted_jwt_secret = "" # Base64-encoded (KMS encrypted) ciphertext of the jwt_secret. Only applicable when KMS is enabled. -recon_admin_api_key = "recon_test_admin" # recon_admin API key for recon authentication. Only applicable when KMS is disabled. -kms_encrypted_recon_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the recon_admin_api_key. Only applicable when KMS is enabled +master_enc_key = "sample_key" # Master Encryption key used to encrypt merchant wise encryption key. Should be 32-byte long. +admin_api_key = "test_admin" # admin API key for admin authentication. Only applicable when KMS is disabled. +kms_encrypted_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the admin_api_key. Only applicable when KMS is enabled. +jwt_secret = "secret" # JWT secret used for user authentication. Only applicable when KMS is disabled. +kms_encrypted_jwt_secret = "" # Base64-encoded (KMS encrypted) ciphertext of the jwt_secret. Only applicable when KMS is enabled. +recon_admin_api_key = "recon_test_admin" # recon_admin API key for recon authentication. Only applicable when KMS is disabled. +kms_encrypted_recon_admin_api_key = "" # Base64-encoded (KMS encrypted) ciphertext of the recon_admin_api_key. Only applicable when KMS is enabled # Locker settings contain details for accessing a card locker, a # PCI Compliant storage entity which stores payment method information @@ -124,15 +124,15 @@ connectors_with_delayed_session_response = "trustpay,payme" # List of connectors connectors_with_webhook_source_verification_call = "paypal" # List of connectors which has additional source verification api-call [jwekey] # 4 priv/pub key pair -locker_key_identifier1 = "" # key identifier for key rotation , should be same as basilisk -locker_key_identifier2 = "" # key identifier for key rotation , should be same as basilisk -locker_encryption_key1 = "" # public key 1 in pem format, corresponding private key in basilisk -locker_encryption_key2 = "" # public key 2 in pem format, corresponding private key in basilisk -locker_decryption_key1 = "" # private key 1 in pem format, corresponding public key in basilisk -locker_decryption_key2 = "" # private key 2 in pem format, corresponding public key in basilisk -vault_encryption_key = "" # public key in pem format, corresponding private key in basilisk-hs +locker_key_identifier1 = "" # key identifier for key rotation , should be same as basilisk +locker_key_identifier2 = "" # key identifier for key rotation , should be same as basilisk +locker_encryption_key1 = "" # public key 1 in pem format, corresponding private key in basilisk +locker_encryption_key2 = "" # public key 2 in pem format, corresponding private key in basilisk +locker_decryption_key1 = "" # private key 1 in pem format, corresponding public key in basilisk +locker_decryption_key2 = "" # private key 2 in pem format, corresponding public key in basilisk +vault_encryption_key = "" # public key in pem format, corresponding private key in basilisk-hs rust_locker_encryption_key = "" # public key in pem format, corresponding private key in rust locker -vault_private_key = "" # private key in pem format, corresponding public key in basilisk-hs +vault_private_key = "" # private key in pem format, corresponding public key in basilisk-hs # Refund configuration @@ -234,11 +234,11 @@ adyen = { banks = "e_platby_vub,postova_banka,sporo_pay,tatra_pay,viamo" } # Bank redirect configs for allowed banks through online_banking_poland payment method [bank_config.online_banking_poland] -adyen = { banks = "blik_psp,place_zipko,m_bank,pay_with_ing,santander_przelew24,bank_pekaosa,bank_millennium,pay_with_alior_bank,banki_spoldzielcze,pay_with_inteligo,bnp_paribas_poland,bank_nowy_sa,credit_agricole,pay_with_bos,pay_with_citi_handlowy,pay_with_plus_bank,toyota_bank,velo_bank,e_transfer_pocztowy24"} +adyen = { banks = "blik_psp,place_zipko,m_bank,pay_with_ing,santander_przelew24,bank_pekaosa,bank_millennium,pay_with_alior_bank,banki_spoldzielcze,pay_with_inteligo,bnp_paribas_poland,bank_nowy_sa,credit_agricole,pay_with_bos,pay_with_citi_handlowy,pay_with_plus_bank,toyota_bank,velo_bank,e_transfer_pocztowy24" } # Bank redirect configs for allowed banks through open_banking_uk payment method [bank_config.open_banking_uk] -adyen = { banks = "aib,bank_of_scotland,danske_bank,first_direct,first_trust,halifax,lloyds,monzo,nat_west,nationwide_bank,royal_bank_of_scotland,starling,tsb_bank,tesco_bank,ulster_bank,barclays,hsbc_bank,revolut,santander_przelew24,open_bank_success,open_bank_failure,open_bank_cancelled"} +adyen = { banks = "aib,bank_of_scotland,danske_bank,first_direct,first_trust,halifax,lloyds,monzo,nat_west,nationwide_bank,royal_bank_of_scotland,starling,tsb_bank,tesco_bank,ulster_bank,barclays,hsbc_bank,revolut,santander_przelew24,open_bank_success,open_bank_failure,open_bank_cancelled" } # Bank redirect configs for allowed banks through przelewy24 payment method [bank_config.przelewy24] @@ -313,89 +313,92 @@ region = "" # The AWS region used by the KMS SDK for decrypting data. # EmailClient configuration. Only applicable when the `email` feature flag is enabled. [email] from_email = "notify@example.com" # Sender email -aws_region = "" # AWS region used by AWS SES -base_url = "" # Base url used when adding links that should redirect to self +aws_region = "" # AWS region used by AWS SES +base_url = "" # Base url used when adding links that should redirect to self #tokenization configuration which describe token lifetime and payment method for specific connector [tokenization] stripe = { long_lived_token = false, payment_method = "wallet", payment_method_type = { type = "disable_only", list = "google_pay" } } checkout = { long_lived_token = false, payment_method = "wallet" } -mollie = {long_lived_token = false, payment_method = "card"} +mollie = { long_lived_token = false, payment_method = "card" } stax = { long_lived_token = true, payment_method = "card,bank_debit" } -square = {long_lived_token = false, payment_method = "card"} +square = { long_lived_token = false, payment_method = "card" } braintree = { long_lived_token = false, payment_method = "card" } -gocardless = {long_lived_token = true, payment_method = "bank_debit"} +gocardless = { long_lived_token = true, payment_method = "bank_debit" } [temp_locker_enable_config] -stripe = {payment_method = "bank_transfer"} -nuvei = {payment_method = "card"} -shift4 = {payment_method = "card"} -bluesnap = {payment_method = "card"} +stripe = { payment_method = "bank_transfer" } +nuvei = { payment_method = "card" } +shift4 = { payment_method = "card" } +bluesnap = { payment_method = "card" } [dummy_connector] -enabled = true # Whether dummy connector is enabled or not -payment_ttl = 172800 # Time to live for dummy connector payment in redis -payment_duration = 1000 # Fake delay duration for dummy connector payment -payment_tolerance = 100 # Fake delay tolerance for dummy connector payment -payment_retrieve_duration = 500 # Fake delay duration for dummy connector payment sync -payment_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector payment sync -payment_complete_duration = 500 # Fake delay duration for dummy connector payment complete -payment_complete_tolerance = 100 # Fake delay tolerance for dummy connector payment complete -refund_ttl = 172800 # Time to live for dummy connector refund in redis -refund_duration = 1000 # Fake delay duration for dummy connector refund -refund_tolerance = 100 # Fake delay tolerance for dummy connector refund -refund_retrieve_duration = 500 # Fake delay duration for dummy connector refund sync -refund_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector refund sync -authorize_ttl = 36000 # Time to live for dummy connector authorize request in redis +enabled = true # Whether dummy connector is enabled or not +payment_ttl = 172800 # Time to live for dummy connector payment in redis +payment_duration = 1000 # Fake delay duration for dummy connector payment +payment_tolerance = 100 # Fake delay tolerance for dummy connector payment +payment_retrieve_duration = 500 # Fake delay duration for dummy connector payment sync +payment_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector payment sync +payment_complete_duration = 500 # Fake delay duration for dummy connector payment complete +payment_complete_tolerance = 100 # Fake delay tolerance for dummy connector payment complete +refund_ttl = 172800 # Time to live for dummy connector refund in redis +refund_duration = 1000 # Fake delay duration for dummy connector refund +refund_tolerance = 100 # Fake delay tolerance for dummy connector refund +refund_retrieve_duration = 500 # Fake delay duration for dummy connector refund sync +refund_retrieve_tolerance = 100 # Fake delay tolerance for dummy connector refund sync +authorize_ttl = 36000 # Time to live for dummy connector authorize request in redis assets_base_url = "https://www.example.com/" # Base url for dummy connector assets default_return_url = "https://www.example.com/" # Default return url when no return url is passed while payment slack_invite_url = "https://www.example.com/" # Slack invite url for hyperswitch discord_invite_url = "https://www.example.com/" # Discord invite url for hyperswitch [mandates.supported_payment_methods] -card.credit = {connector_list = "stripe,adyen"} # Mandate supported payment method type and connector for card -wallet.paypal = {connector_list = "adyen"} # Mandate supported payment method type and connector for wallets -pay_later.klarna = {connector_list = "adyen"} # Mandate supported payment method type and connector for pay_later -bank_debit.ach = { connector_list = "gocardless"} # Mandate supported payment method type and connector for bank_debit -bank_debit.becs = { connector_list = "gocardless"} # Mandate supported payment method type and connector for bank_debit -bank_debit.sepa = { connector_list = "gocardless"} # Mandate supported payment method type and connector for bank_debit +card.credit = { connector_list = "stripe,adyen" } # Mandate supported payment method type and connector for card +wallet.paypal = { connector_list = "adyen" } # Mandate supported payment method type and connector for wallets +pay_later.klarna = { connector_list = "adyen" } # Mandate supported payment method type and connector for pay_later +bank_debit.ach = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit +bank_debit.becs = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit +bank_debit.sepa = { connector_list = "gocardless" } # Mandate supported payment method type and connector for bank_debit # Required fields info used while listing the payment_method_data [required_fields.pay_later] # payment_method = "pay_later" -afterpay_clearpay = {fields = {stripe = [ # payment_method_type = afterpay_clearpay, connector = "stripe" - # Required fields vector with its respective display name in front-end and field_type - { required_field = "shipping.address.first_name", display_name = "first_name", field_type = "text" }, - { required_field = "shipping.address.last_name", display_name = "last_name", field_type = "text" }, - { required_field = "shipping.address.country", display_name = "country", field_type = { drop_down = { options = [ "US", "IN" ] } } }, - ] } } +afterpay_clearpay = { fields = { stripe = [ # payment_method_type = afterpay_clearpay, connector = "stripe" + # Required fields vector with its respective display name in front-end and field_type + { required_field = "shipping.address.first_name", display_name = "first_name", field_type = "text" }, + { required_field = "shipping.address.last_name", display_name = "last_name", field_type = "text" }, + { required_field = "shipping.address.country", display_name = "country", field_type = { drop_down = { options = [ + "US", + "IN", + ] } } }, +] } } [payouts] -payout_eligibility = true # Defaults the eligibility of a payout method to true in case connector does not provide checks for payout eligibility +payout_eligibility = true # Defaults the eligibility of a payout method to true in case connector does not provide checks for payout eligibility [pm_filters.adyen] -online_banking_fpx = {country = "MY", currency = "MYR"} -online_banking_thailand = {country = "TH", currency = "THB"} -touch_n_go = {country = "MY", currency = "MYR"} -atome = {country = "MY,SG", currency = "MYR,SGD"} -swish = {country = "SE", currency = "SEK"} -permata_bank_transfer = {country = "ID", currency = "IDR"} -bca_bank_transfer = {country = "ID", currency = "IDR"} -bni_va = {country = "ID", currency = "IDR"} -bri_va = {country = "ID", currency = "IDR"} -cimb_va = {country = "ID", currency = "IDR"} -danamon_va = {country = "ID", currency = "IDR"} -mandiri_va = {country = "ID", currency = "IDR"} -alfamart = {country = "ID", currency = "IDR"} -indomaret = {country = "ID", currency = "IDR"} -open_banking_uk = {country = "GB", currency = "GBP"} -oxxo = {country = "MX", currency = "MXN"} -pay_safe_card = {country = "AT,AU,BE,BR,BE,CA,HR,CY,CZ,DK,FI,FR,GE,DE,GI,HU,IS,IE,KW,LV,IE,LI,LT,LU,MT,MX,MD,ME,NL,NZ,NO,PY,PE,PL,PT,RO,SA,RS,SK,SI,ES,SE,CH,TR,UAE,UK,US,UY", currency = "EUR,AUD,BRL,CAD,CZK,DKK,GEL,GIP,HUF,ISK,KWD,CHF,MXN,MDL,NZD,NOK,PYG,PEN,PLN,RON,SAR,RSD,SEK,TRY,AED,GBP,USD,UYU"} -seven_eleven = {country = "JP", currency = "JPY"} -lawson = {country = "JP", currency = "JPY"} -mini_stop = {country = "JP", currency = "JPY"} -family_mart = {country = "JP", currency = "JPY"} -seicomart = {country = "JP", currency = "JPY"} -pay_easy = {country = "JP", currency = "JPY"} +online_banking_fpx = { country = "MY", currency = "MYR" } +online_banking_thailand = { country = "TH", currency = "THB" } +touch_n_go = { country = "MY", currency = "MYR" } +atome = { country = "MY,SG", currency = "MYR,SGD" } +swish = { country = "SE", currency = "SEK" } +permata_bank_transfer = { country = "ID", currency = "IDR" } +bca_bank_transfer = { country = "ID", currency = "IDR" } +bni_va = { country = "ID", currency = "IDR" } +bri_va = { country = "ID", currency = "IDR" } +cimb_va = { country = "ID", currency = "IDR" } +danamon_va = { country = "ID", currency = "IDR" } +mandiri_va = { country = "ID", currency = "IDR" } +alfamart = { country = "ID", currency = "IDR" } +indomaret = { country = "ID", currency = "IDR" } +open_banking_uk = { country = "GB", currency = "GBP" } +oxxo = { country = "MX", currency = "MXN" } +pay_safe_card = { country = "AT,AU,BE,BR,BE,CA,HR,CY,CZ,DK,FI,FR,GE,DE,GI,HU,IS,IE,KW,LV,IE,LI,LT,LU,MT,MX,MD,ME,NL,NZ,NO,PY,PE,PL,PT,RO,SA,RS,SK,SI,ES,SE,CH,TR,UAE,UK,US,UY", currency = "EUR,AUD,BRL,CAD,CZK,DKK,GEL,GIP,HUF,ISK,KWD,CHF,MXN,MDL,NZD,NOK,PYG,PEN,PLN,RON,SAR,RSD,SEK,TRY,AED,GBP,USD,UYU" } +seven_eleven = { country = "JP", currency = "JPY" } +lawson = { country = "JP", currency = "JPY" } +mini_stop = { country = "JP", currency = "JPY" } +family_mart = { country = "JP", currency = "JPY" } +seicomart = { country = "JP", currency = "JPY" } +pay_easy = { country = "JP", currency = "JPY" } [pm_filters.zen] credit = { not_available_flows = { capture_method = "manual" } } @@ -415,7 +418,7 @@ debit = { currency = "USD" } ach = { currency = "USD" } [pm_filters.stripe] -cashapp = {country = "US", currency = "USD"} +cashapp = { country = "US", currency = "USD" } [pm_filters.prophetpay] card_redirect = { currency = "USD" } @@ -434,10 +437,10 @@ adyen.banks = "bangkok_bank,krungsri_bank,krung_thai_bank,the_siam_commercial_ba supported_connectors = "braintree" [applepay_decrypt_keys] -apple_pay_ppc = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE" #Payment Processing Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Payment Processing Certificate -apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" #Private key generate by Elliptic-curve prime256v1 curve -apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" #Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate -apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" #Private key generate by RSA:2048 algorithm +apple_pay_ppc = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE" #Payment Processing Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Payment Processing Certificate +apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" #Private key generate by Elliptic-curve prime256v1 curve +apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" #Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate +apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" #Private key generate by RSA:2048 algorithm [payment_link] sdk_url = "http://localhost:9090/dist/HyperLoader.js" diff --git a/crates/router/src/core/locker_migration.rs b/crates/router/src/core/locker_migration.rs index aa82b4a3a636..f036a03a2f0e 100644 --- a/crates/router/src/core/locker_migration.rs +++ b/crates/router/src/core/locker_migration.rs @@ -106,7 +106,7 @@ pub async fn call_to_locker( let (_add_card_rs_resp, _is_duplicate) = cards::add_card_hs( state, pm_create, - card_details, + &card_details, customer_id.to_string(), merchant_account, api_enums::LockerChoice::Tartarus, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index f9c666cbb954..4ab7d334f883 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -103,16 +103,12 @@ pub async fn add_payment_method( let merchant_id = &merchant_account.merchant_id; let customer_id = req.customer_id.clone().get_required_value("customer_id")?; let response = match req.card.clone() { - Some(card) => add_card_to_locker( - &state, - req.clone(), - card, - customer_id.clone(), - merchant_account, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Add Card Failed"), + Some(card) => { + add_card_to_locker(&state, req.clone(), &card, &customer_id, merchant_account) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Add Card Failed") + } None => { let pm_id = generate_id(consts::ID_LENGTH, "pm"); let payment_method_response = api::PaymentMethodResponse { @@ -207,18 +203,18 @@ pub async fn update_customer_payment_method( pub async fn add_card_to_locker( state: &routes::AppState, req: api::PaymentMethodCreate, - card: api::CardDetail, - customer_id: String, + card: &api::CardDetail, + customer_id: &String, merchant_account: &domain::MerchantAccount, ) -> errors::CustomResult<(api::PaymentMethodResponse, bool), errors::VaultError> { metrics::STORED_TO_LOCKER.add(&metrics::CONTEXT, 1, &[]); - request::record_operation_time( + let add_card_to_hs_resp = request::record_operation_time( async { add_card_hs( state, - req, + req.clone(), card, - customer_id, + customer_id.to_string(), merchant_account, api_enums::LockerChoice::Basilisk, None, @@ -232,7 +228,34 @@ pub async fn add_card_to_locker( &metrics::CARD_ADD_TIME, &[], ) - .await + .await?; + logger::debug!("card added to basilisk locker"); + + let add_card_to_rs_resp = request::record_operation_time( + async { + add_card_hs( + state, + req, + card, + customer_id.to_string(), + merchant_account, + api_enums::LockerChoice::Tartarus, + Some(&add_card_to_hs_resp.0.payment_method_id), + ) + .await + .map_err(|error| { + metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + error + }) + }, + &metrics::CARD_ADD_TIME, + &[], + ) + .await?; + + logger::debug!("card added to rust locker"); + + Ok(add_card_to_rs_resp) } pub async fn get_card_from_locker( @@ -243,9 +266,38 @@ pub async fn get_card_from_locker( ) -> errors::RouterResult { metrics::GET_FROM_LOCKER.add(&metrics::CONTEXT, 1, &[]); - request::record_operation_time( + let get_card_from_rs_locker_resp = request::record_operation_time( async { - get_card_from_hs_locker(state, customer_id, merchant_id, card_reference) + get_card_from_hs_locker( + state, + customer_id, + merchant_id, + card_reference, + api_enums::LockerChoice::Tartarus, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while getting card from basilisk_hs") + .map_err(|error| { + metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); + error + }) + }, + &metrics::CARD_GET_TIME, + &[], + ) + .await; + + match get_card_from_rs_locker_resp { + Err(_) => request::record_operation_time( + async { + get_card_from_hs_locker( + state, + customer_id, + merchant_id, + card_reference, + api_enums::LockerChoice::Basilisk, + ) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed while getting card from basilisk_hs") @@ -253,11 +305,20 @@ pub async fn get_card_from_locker( metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); error }) - }, - &metrics::CARD_GET_TIME, - &[], - ) - .await + }, + &metrics::CARD_GET_TIME, + &[], + ) + .await + .map(|inner_card| { + logger::debug!("card retrieved from basilisk locker"); + inner_card + }), + Ok(_) => { + logger::debug!("card retrieved from rust locker"); + get_card_from_rs_locker_resp + } + } } pub async fn delete_card_from_locker( @@ -287,7 +348,7 @@ pub async fn delete_card_from_locker( pub async fn add_card_hs( state: &routes::AppState, req: api::PaymentMethodCreate, - card: api::CardDetail, + card: &api::CardDetail, customer_id: String, merchant_account: &domain::MerchantAccount, locker_choice: api_enums::LockerChoice, @@ -296,7 +357,7 @@ pub async fn add_card_hs( let payload = payment_methods::StoreLockerReq::LockerCard(payment_methods::StoreCardReq { merchant_id: &merchant_account.merchant_id, merchant_customer_id: customer_id.to_owned(), - card_reference: card_reference.map(str::to_string), + requestor_card_reference: card_reference.map(str::to_string), card: payment_methods::Card { card_number: card.card_number.to_owned(), name_on_card: card.card_holder_name.to_owned(), @@ -307,11 +368,12 @@ pub async fn add_card_hs( nick_name: card.nick_name.as_ref().map(masking::Secret::peek).cloned(), }, }); + let store_card_payload = call_to_locker_hs(state, &payload, &customer_id, locker_choice).await?; let payment_method_resp = payment_methods::mk_add_card_response_hs( - card, + card.clone(), store_card_payload.card_reference, req, &merchant_account.merchant_id, @@ -351,6 +413,7 @@ pub async fn get_payment_method_from_hs_locker<'a>( customer_id: &str, merchant_id: &str, payment_method_reference: &'a str, + locker_choice: Option, ) -> errors::CustomResult, errors::VaultError> { let locker = &state.conf.locker; #[cfg(not(feature = "kms"))] @@ -365,6 +428,7 @@ pub async fn get_payment_method_from_hs_locker<'a>( customer_id, merchant_id, payment_method_reference, + locker_choice, ) .await .change_context(errors::VaultError::FetchPaymentMethodFailed) @@ -466,6 +530,7 @@ pub async fn get_card_from_hs_locker<'a>( customer_id: &str, merchant_id: &str, card_reference: &'a str, + locker_choice: api_enums::LockerChoice, ) -> errors::CustomResult { let locker = &state.conf.locker; #[cfg(not(feature = "kms"))] @@ -480,6 +545,7 @@ pub async fn get_card_from_hs_locker<'a>( customer_id, merchant_id, card_reference, + Some(locker_choice), ) .await .change_context(errors::VaultError::FetchCardFailed) @@ -2193,6 +2259,7 @@ pub async fn get_lookup_key_for_payout_method( &pm.customer_id, &pm.merchant_id, &pm.payment_method_id, + None, ) .await .change_context(errors::ApiErrorResponse::InternalServerError) diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs index 63a0479375e8..45182411c28c 100644 --- a/crates/router/src/core/payment_methods/transformers.rs +++ b/crates/router/src/core/payment_methods/transformers.rs @@ -28,7 +28,7 @@ pub struct StoreCardReq<'a> { pub merchant_id: &'a str, pub merchant_customer_id: String, #[serde(skip_serializing_if = "Option::is_none")] - pub card_reference: Option, + pub requestor_card_reference: Option, pub card: Card, } @@ -428,6 +428,7 @@ pub async fn mk_get_card_request_hs( customer_id: &str, merchant_id: &str, card_reference: &str, + locker_choice: Option, ) -> CustomResult { let merchant_customer_id = customer_id.to_owned(); let card_req_body = CardReqBody { @@ -448,11 +449,16 @@ pub async fn mk_get_card_request_hs( .await .change_context(errors::VaultError::RequestEncodingFailed)?; - let jwe_payload = mk_basilisk_req(jwekey, &jws, api_enums::LockerChoice::Basilisk).await?; + let target_locker = locker_choice.unwrap_or(api_enums::LockerChoice::Basilisk); + + let jwe_payload = mk_basilisk_req(jwekey, &jws, target_locker).await?; let body = utils::Encode::::encode_to_value(&jwe_payload) .change_context(errors::VaultError::RequestEncodingFailed)?; - let mut url = locker.host.to_owned(); + let mut url = match target_locker { + api_enums::LockerChoice::Basilisk => locker.host.to_owned(), + api_enums::LockerChoice::Tartarus => locker.host_rs.to_owned(), + }; url.push_str("/cards/retrieve"); let mut request = services::Request::new(services::Method::Post, &url); request.add_header(headers::CONTENT_TYPE, "application/json".into()); diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 794180e2112e..551d1c8abb9a 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -183,8 +183,8 @@ pub async fn save_in_locker( Some(card) => payment_methods::cards::add_card_to_locker( state, payment_method_request, - card, - customer_id, + &card, + &customer_id, merchant_account, ) .await diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs index c1e00b9b8000..9ddc8395738e 100644 --- a/crates/router/src/core/payouts/helpers.rs +++ b/crates/router/src/core/payouts/helpers.rs @@ -152,7 +152,7 @@ pub async fn save_payout_data_to_locker( card_isin: None, nick_name: None, }, - card_reference: None, + requestor_card_reference: None, }); ( payload,