mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	refactor: revert redis temp locker logic (#2670)
This commit is contained in:
		 Abhishek Marrivagu
					Abhishek Marrivagu
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							adad77f043
						
					
				
				
					commit
					eaa9720520
				
			| @ -115,7 +115,6 @@ host = ""                      # 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 | ||||
| redis_temp_locker_encryption_key = "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"  # encryption key for redis temp locker | ||||
|  | ||||
| [delayed_session_response] | ||||
| connectors_with_delayed_session_response = "trustpay,payme" # List of connectors which has delayed session response | ||||
|  | ||||
| @ -50,7 +50,6 @@ applepay_endpoint = "DOMAIN SPECIFIC ENDPOINT" | ||||
| host = "" | ||||
| mock_locker = true | ||||
| basilisk_host = "" | ||||
| redis_temp_locker_encryption_key = "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" | ||||
|  | ||||
| [jwekey] | ||||
| locker_key_identifier1 = "" | ||||
|  | ||||
| @ -46,7 +46,6 @@ recon_admin_api_key = "recon_test_admin" | ||||
| host = "" | ||||
| mock_locker = true | ||||
| basilisk_host = "" | ||||
| redis_temp_locker_encryption_key = "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" | ||||
|  | ||||
| [jwekey] | ||||
| locker_key_identifier1 = "" | ||||
|  | ||||
| @ -771,6 +771,13 @@ pub struct DeleteTokenizeByTokenRequest { | ||||
|     pub service_name: String, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, serde::Serialize)] // Blocked: Yet to be implemented by `basilisk` | ||||
| pub struct DeleteTokenizeByDateRequest { | ||||
|     pub buffer_minutes: i32, | ||||
|     pub service_name: String, | ||||
|     pub max_rows: i32, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, serde::Deserialize)] | ||||
| pub struct GetTokenizePayloadResponse { | ||||
|     pub lookup_key: String, | ||||
|  | ||||
| @ -120,14 +120,6 @@ pub enum KmsError { | ||||
|     /// The KMS client has not been initialized. | ||||
|     #[error("The KMS client has not been initialized")] | ||||
|     KmsClientNotInitialized, | ||||
|  | ||||
|     /// The KMS client has not been initialized. | ||||
|     #[error("Hex decode failed")] | ||||
|     HexDecodeFailed, | ||||
|  | ||||
|     /// The KMS client has not been initialized. | ||||
|     #[error("Utf8 decode failed")] | ||||
|     Utf8DecodeFailed, | ||||
| } | ||||
|  | ||||
| impl KmsConfig { | ||||
| @ -148,7 +140,7 @@ impl KmsConfig { | ||||
| /// A wrapper around a KMS value that can be decrypted. | ||||
| #[derive(Clone, Debug, Default, serde::Deserialize, Eq, PartialEq)] | ||||
| #[serde(transparent)] | ||||
| pub struct KmsValue(pub Secret<String>); | ||||
| pub struct KmsValue(Secret<String>); | ||||
|  | ||||
| impl common_utils::ext_traits::ConfigExt for KmsValue { | ||||
|     fn is_empty_after_trim(&self) -> bool { | ||||
|  | ||||
| @ -13,8 +13,9 @@ default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connec | ||||
| s3 = ["dep:aws-sdk-s3", "dep:aws-config"] | ||||
| kms = ["external_services/kms", "dep:aws-config"] | ||||
| email = ["external_services/email", "dep:aws-config"] | ||||
| basilisk = ["kms"] | ||||
| stripe = ["dep:serde_qs"] | ||||
| release = ["kms", "stripe", "s3", "email","accounts_cache"] | ||||
| release = ["kms", "stripe", "basilisk", "s3", "email","accounts_cache"] | ||||
| olap = ["data_models/olap", "storage_impl/olap", "scheduler/olap"] | ||||
| oltp = ["data_models/oltp", "storage_impl/oltp"] | ||||
| kv_store = ["scheduler/kv_store"] | ||||
|  | ||||
| @ -49,9 +49,8 @@ impl Default for super::settings::Locker { | ||||
|         Self { | ||||
|             host: "localhost".into(), | ||||
|             mock_locker: true, | ||||
|  | ||||
|             basilisk_host: "localhost".into(), | ||||
|             locker_signing_key_id: "1".into(), | ||||
|             redis_temp_locker_encryption_key: "".into(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| use common_utils::errors::CustomResult; | ||||
| use error_stack::{IntoReport, ResultExt}; | ||||
| use external_services::kms::{decrypt::KmsDecrypt, KmsClient, KmsError, KmsValue}; | ||||
| use external_services::kms::{decrypt::KmsDecrypt, KmsClient, KmsError}; | ||||
| use masking::ExposeInterface; | ||||
|  | ||||
| use crate::configs::settings; | ||||
| @ -42,19 +41,6 @@ impl KmsDecrypt for settings::ActiveKmsSecrets { | ||||
|         kms_client: &KmsClient, | ||||
|     ) -> CustomResult<Self::Output, KmsError> { | ||||
|         self.jwekey = self.jwekey.expose().decrypt_inner(kms_client).await?.into(); | ||||
|         self.redis_temp_locker_encryption_key = hex::decode( | ||||
|             KmsValue( | ||||
|                 String::from_utf8(self.redis_temp_locker_encryption_key.expose()) | ||||
|                     .into_report() | ||||
|                     .change_context(KmsError::Utf8DecodeFailed)? | ||||
|                     .into(), | ||||
|             ) | ||||
|             .decrypt_inner(kms_client) | ||||
|             .await?, | ||||
|         ) | ||||
|         .into_report() | ||||
|         .change_context(KmsError::HexDecodeFailed)? | ||||
|         .into(); | ||||
|         Ok(self) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -52,7 +52,6 @@ pub enum Subcommand { | ||||
| #[derive(Clone)] | ||||
| pub struct ActiveKmsSecrets { | ||||
|     pub jwekey: masking::Secret<Jwekey>, | ||||
|     pub redis_temp_locker_encryption_key: masking::Secret<Vec<u8>>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize, Clone, Default)] | ||||
| @ -411,8 +410,8 @@ pub struct Secrets { | ||||
| pub struct Locker { | ||||
|     pub host: String, | ||||
|     pub mock_locker: bool, | ||||
|     pub basilisk_host: String, | ||||
|     pub locker_signing_key_id: String, | ||||
|     pub redis_temp_locker_encryption_key: String, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize, Clone)] | ||||
|  | ||||
| @ -56,19 +56,10 @@ impl super::settings::Locker { | ||||
|         })?; | ||||
|  | ||||
|         when( | ||||
|             self.redis_temp_locker_encryption_key.is_default_or_empty(), | ||||
|             !self.mock_locker && self.basilisk_host.is_default_or_empty(), | ||||
|             || { | ||||
|                 Err(ApplicationError::InvalidConfigurationValueError( | ||||
|                     "redis_temp_locker_encryption_key must not be empty".into(), | ||||
|                 )) | ||||
|             }, | ||||
|         )?; | ||||
|  | ||||
|         when( | ||||
|             self.redis_temp_locker_encryption_key.is_default_or_empty(), | ||||
|             || { | ||||
|                 Err(ApplicationError::InvalidConfigurationValueError( | ||||
|                     "redis_temp_locker_encryption_key must not be empty".into(), | ||||
|                     "basilisk host must not be empty when mock locker is disabled".into(), | ||||
|                 )) | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
| @ -2010,13 +2010,8 @@ pub async fn get_lookup_key_from_locker( | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Get Card Details Failed")?; | ||||
|     let card = card_detail.clone(); | ||||
|  | ||||
|     let resp = TempLockerCardSupport::create_payment_method_data_in_temp_locker( | ||||
|         state, | ||||
|         payment_token, | ||||
|         card, | ||||
|         pm, | ||||
|     ) | ||||
|     let resp = | ||||
|         BasiliskCardSupport::create_payment_method_data_in_locker(state, payment_token, card, pm) | ||||
|             .await?; | ||||
|     Ok(resp) | ||||
| } | ||||
| @ -2063,11 +2058,106 @@ pub async fn get_lookup_key_for_payout_method( | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct TempLockerCardSupport; | ||||
| pub struct BasiliskCardSupport; | ||||
|  | ||||
| impl TempLockerCardSupport { | ||||
| #[cfg(not(feature = "basilisk"))] | ||||
| impl BasiliskCardSupport { | ||||
|     async fn create_payment_method_data_in_locker( | ||||
|         state: &routes::AppState, | ||||
|         payment_token: &str, | ||||
|         card: api::CardDetailFromLocker, | ||||
|         pm: &storage::PaymentMethod, | ||||
|     ) -> errors::RouterResult<api::CardDetailFromLocker> { | ||||
|         let card_number = card.card_number.clone().get_required_value("card_number")?; | ||||
|         let card_exp_month = card | ||||
|             .expiry_month | ||||
|             .clone() | ||||
|             .expose_option() | ||||
|             .get_required_value("expiry_month")?; | ||||
|         let card_exp_year = card | ||||
|             .expiry_year | ||||
|             .clone() | ||||
|             .expose_option() | ||||
|             .get_required_value("expiry_year")?; | ||||
|         let card_holder_name = card | ||||
|             .card_holder_name | ||||
|             .clone() | ||||
|             .expose_option() | ||||
|             .unwrap_or_default(); | ||||
|         let value1 = payment_methods::mk_card_value1( | ||||
|             card_number, | ||||
|             card_exp_year, | ||||
|             card_exp_month, | ||||
|             Some(card_holder_name), | ||||
|             None, | ||||
|             None, | ||||
|             None, | ||||
|         ) | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error getting Value1 for locker")?; | ||||
|         let value2 = payment_methods::mk_card_value2( | ||||
|             None, | ||||
|             None, | ||||
|             None, | ||||
|             Some(pm.customer_id.to_string()), | ||||
|             Some(pm.payment_method_id.to_string()), | ||||
|         ) | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error getting Value2 for locker")?; | ||||
|  | ||||
|         let value1 = vault::VaultPaymentMethod::Card(value1); | ||||
|         let value2 = vault::VaultPaymentMethod::Card(value2); | ||||
|  | ||||
|         let value1 = utils::Encode::<vault::VaultPaymentMethod>::encode_to_string_of_json(&value1) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Wrapped value1 construction failed when saving card to locker")?; | ||||
|  | ||||
|         let value2 = utils::Encode::<vault::VaultPaymentMethod>::encode_to_string_of_json(&value2) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Wrapped value2 construction failed when saving card to locker")?; | ||||
|  | ||||
|         let db_value = vault::MockTokenizeDBValue { value1, value2 }; | ||||
|  | ||||
|         let value_string = | ||||
|             utils::Encode::<vault::MockTokenizeDBValue>::encode_to_string_of_json(&db_value) | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable( | ||||
|                     "Mock tokenize value construction failed when saving card to locker", | ||||
|                 )?; | ||||
|  | ||||
|         let db = &*state.store; | ||||
|  | ||||
|         let already_present = db.find_config_by_key(payment_token).await; | ||||
|  | ||||
|         if already_present.is_err() { | ||||
|             let config = storage::ConfigNew { | ||||
|                 key: payment_token.to_string(), | ||||
|                 config: value_string, | ||||
|             }; | ||||
|  | ||||
|             db.insert_config(config) | ||||
|                 .await | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Mock tokenization save to db failed")?; | ||||
|         } else { | ||||
|             let config_update = storage::ConfigUpdate::Update { | ||||
|                 config: Some(value_string), | ||||
|             }; | ||||
|  | ||||
|             db.update_config_by_key(payment_token, config_update) | ||||
|                 .await | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Mock tokenization db update failed")?; | ||||
|         } | ||||
|  | ||||
|         Ok(card) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| impl BasiliskCardSupport { | ||||
|     #[instrument(skip_all)] | ||||
|     async fn create_payment_method_data_in_temp_locker( | ||||
|     async fn create_payment_method_data_in_locker( | ||||
|         state: &routes::AppState, | ||||
|         payment_token: &str, | ||||
|         card: api::CardDetailFromLocker, | ||||
|  | ||||
| @ -580,6 +580,21 @@ pub fn get_card_detail( | ||||
| } | ||||
|  | ||||
| //------------------------------------------------TokenizeService------------------------------------------------ | ||||
| pub fn mk_crud_locker_request( | ||||
|     locker: &settings::Locker, | ||||
|     path: &str, | ||||
|     req: api::TokenizePayloadEncrypted, | ||||
| ) -> CustomResult<services::Request, errors::VaultError> { | ||||
|     let body = utils::Encode::<api::TokenizePayloadEncrypted>::encode_to_value(&req) | ||||
|         .change_context(errors::VaultError::RequestEncodingFailed)?; | ||||
|     let mut url = locker.basilisk_host.to_owned(); | ||||
|     url.push_str(path); | ||||
|     let mut request = services::Request::new(services::Method::Post, &url); | ||||
|     request.add_default_headers(); | ||||
|     request.add_header(headers::CONTENT_TYPE, "application/json".into()); | ||||
|     request.set_body(body.to_string()); | ||||
|     Ok(request) | ||||
| } | ||||
|  | ||||
| pub fn mk_card_value1( | ||||
|     card_number: cards::CardNumber, | ||||
|  | ||||
| @ -1,31 +1,37 @@ | ||||
| use common_utils::{ | ||||
|     crypto::{DecodeMessage, EncodeMessage, GcmAes256}, | ||||
|     ext_traits::BytesExt, | ||||
|     generate_id_with_default_len, | ||||
| }; | ||||
| use error_stack::{report, IntoReport, ResultExt}; | ||||
| use common_utils::generate_id_with_default_len; | ||||
| #[cfg(feature = "basilisk")] | ||||
| use error_stack::report; | ||||
| use error_stack::{IntoReport, ResultExt}; | ||||
| #[cfg(feature = "basilisk")] | ||||
| use josekit::jwe; | ||||
| use masking::PeekInterface; | ||||
| use router_env::{instrument, tracing}; | ||||
| #[cfg(feature = "basilisk")] | ||||
| use scheduler::{types::process_data, utils as process_tracker_utils}; | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| use crate::routes::metrics; | ||||
| #[cfg(feature = "payouts")] | ||||
| use crate::types::api::payouts; | ||||
| use crate::{ | ||||
|     configs::settings, | ||||
|     core::errors::{self, CustomResult, RouterResult}, | ||||
|     db, logger, routes, | ||||
|     routes::metrics, | ||||
|     logger, routes, | ||||
|     types::{ | ||||
|         api, | ||||
|         storage::{self, enums, ProcessTrackerExt}, | ||||
|         storage::{self, enums}, | ||||
|     }, | ||||
|     utils::{self, StringExt}, | ||||
| }; | ||||
| #[cfg(feature = "basilisk")] | ||||
| use crate::{core::payment_methods::transformers as payment_methods, services, utils::BytesExt}; | ||||
| #[cfg(feature = "basilisk")] | ||||
| use crate::{db, types::storage::ProcessTrackerExt}; | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| const VAULT_SERVICE_NAME: &str = "CARD"; | ||||
|  | ||||
| const LOCKER_REDIS_PREFIX: &str = "LOCKER_TOKEN"; | ||||
|  | ||||
| const LOCKER_REDIS_EXPIRY_SECONDS: u32 = 60 * 15; // 15 minutes | ||||
| #[cfg(feature = "basilisk")] | ||||
| const VAULT_VERSION: &str = "0"; | ||||
|  | ||||
| pub struct SupplementaryVaultData { | ||||
|     pub customer_id: Option<String>, | ||||
| @ -616,6 +622,189 @@ pub struct MockTokenizeDBValue { | ||||
|  | ||||
| pub struct Vault; | ||||
|  | ||||
| #[cfg(not(feature = "basilisk"))] | ||||
| impl Vault { | ||||
|     #[instrument(skip_all)] | ||||
|     pub async fn get_payment_method_data_from_locker( | ||||
|         state: &routes::AppState, | ||||
|         lookup_key: &str, | ||||
|     ) -> RouterResult<(Option<api::PaymentMethodData>, SupplementaryVaultData)> { | ||||
|         let config = state | ||||
|             .store | ||||
|             .find_config_by_key(lookup_key) | ||||
|             .await | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Could not find payment method in vault")?; | ||||
|  | ||||
|         let tokenize_value: MockTokenizeDBValue = config | ||||
|             .config | ||||
|             .parse_struct("MockTokenizeDBValue") | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Unable to deserialize Mock tokenize db value")?; | ||||
|  | ||||
|         let (payment_method, supp_data) = | ||||
|             api::PaymentMethodData::from_values(tokenize_value.value1, tokenize_value.value2) | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Error parsing Payment Method from Values")?; | ||||
|  | ||||
|         Ok((Some(payment_method), supp_data)) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "payouts")] | ||||
|     #[instrument(skip_all)] | ||||
|     pub async fn get_payout_method_data_from_temporary_locker( | ||||
|         state: &routes::AppState, | ||||
|         lookup_key: &str, | ||||
|     ) -> RouterResult<(Option<api::PayoutMethodData>, SupplementaryVaultData)> { | ||||
|         let config = state | ||||
|             .store | ||||
|             .find_config_by_key(lookup_key) | ||||
|             .await | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Could not find payment method in vault")?; | ||||
|  | ||||
|         let tokenize_value: MockTokenizeDBValue = config | ||||
|             .config | ||||
|             .parse_struct("MockTokenizeDBValue") | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Unable to deserialize Mock tokenize db value")?; | ||||
|  | ||||
|         let (payout_method, supp_data) = | ||||
|             api::PayoutMethodData::from_values(tokenize_value.value1, tokenize_value.value2) | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Error parsing Payout Method from Values")?; | ||||
|  | ||||
|         Ok((Some(payout_method), supp_data)) | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "payouts")] | ||||
|     #[instrument(skip_all)] | ||||
|     pub async fn store_payout_method_data_in_locker( | ||||
|         state: &routes::AppState, | ||||
|         token_id: Option<String>, | ||||
|         payout_method: &api::PayoutMethodData, | ||||
|         customer_id: Option<String>, | ||||
|     ) -> RouterResult<String> { | ||||
|         let value1 = payout_method | ||||
|             .get_value1(customer_id.clone()) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Error getting Value1 for locker")?; | ||||
|  | ||||
|         let value2 = payout_method | ||||
|             .get_value2(customer_id) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Error getting Value2 for locker")?; | ||||
|  | ||||
|         let lookup_key = token_id.unwrap_or_else(|| generate_id_with_default_len("token")); | ||||
|  | ||||
|         let db_value = MockTokenizeDBValue { value1, value2 }; | ||||
|  | ||||
|         let value_string = | ||||
|             utils::Encode::<MockTokenizeDBValue>::encode_to_string_of_json(&db_value) | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Failed to encode payout method as mock tokenize db value")?; | ||||
|  | ||||
|         let already_present = state.store.find_config_by_key(&lookup_key).await; | ||||
|  | ||||
|         if already_present.is_err() { | ||||
|             let config = storage::ConfigNew { | ||||
|                 key: lookup_key.clone(), | ||||
|                 config: value_string, | ||||
|             }; | ||||
|  | ||||
|             state | ||||
|                 .store | ||||
|                 .insert_config(config) | ||||
|                 .await | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Mock tokenization save to db failed insert")?; | ||||
|         } else { | ||||
|             let config_update = storage::ConfigUpdate::Update { | ||||
|                 config: Some(value_string), | ||||
|             }; | ||||
|             state | ||||
|                 .store | ||||
|                 .update_config_by_key(&lookup_key, config_update) | ||||
|                 .await | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Mock tokenization save to db failed update")?; | ||||
|         } | ||||
|  | ||||
|         Ok(lookup_key) | ||||
|     } | ||||
|  | ||||
|     #[instrument(skip_all)] | ||||
|     pub async fn store_payment_method_data_in_locker( | ||||
|         state: &routes::AppState, | ||||
|         token_id: Option<String>, | ||||
|         payment_method: &api::PaymentMethodData, | ||||
|         customer_id: Option<String>, | ||||
|         _pm: enums::PaymentMethod, | ||||
|     ) -> RouterResult<String> { | ||||
|         let value1 = payment_method | ||||
|             .get_value1(customer_id.clone()) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Error getting Value1 for locker")?; | ||||
|  | ||||
|         let value2 = payment_method | ||||
|             .get_value2(customer_id) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("Error getting Value12 for locker")?; | ||||
|  | ||||
|         let lookup_key = token_id.unwrap_or_else(|| generate_id_with_default_len("token")); | ||||
|  | ||||
|         let db_value = MockTokenizeDBValue { value1, value2 }; | ||||
|  | ||||
|         let value_string = | ||||
|             utils::Encode::<MockTokenizeDBValue>::encode_to_string_of_json(&db_value) | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Failed to encode payment method as mock tokenize db value")?; | ||||
|  | ||||
|         let already_present = state.store.find_config_by_key(&lookup_key).await; | ||||
|  | ||||
|         if already_present.is_err() { | ||||
|             let config = storage::ConfigNew { | ||||
|                 key: lookup_key.clone(), | ||||
|                 config: value_string, | ||||
|             }; | ||||
|  | ||||
|             state | ||||
|                 .store | ||||
|                 .insert_config(config) | ||||
|                 .await | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Mock tokenization save to db failed insert")?; | ||||
|         } else { | ||||
|             let config_update = storage::ConfigUpdate::Update { | ||||
|                 config: Some(value_string), | ||||
|             }; | ||||
|             state | ||||
|                 .store | ||||
|                 .update_config_by_key(&lookup_key, config_update) | ||||
|                 .await | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Mock tokenization save to db failed update")?; | ||||
|         } | ||||
|  | ||||
|         Ok(lookup_key) | ||||
|     } | ||||
|  | ||||
|     #[instrument(skip_all)] | ||||
|     pub async fn delete_locker_payment_method_by_lookup_key( | ||||
|         state: &routes::AppState, | ||||
|         lookup_key: &Option<String>, | ||||
|     ) { | ||||
|         let db = &*state.store; | ||||
|         if let Some(id) = lookup_key { | ||||
|             match db.delete_config_by_key(id).await { | ||||
|                 Ok(_) => logger::info!("Card Deleted from locker mock up"), | ||||
|                 Err(err) => logger::error!("Err: Card Delete from locker Failed : {}", err), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| impl Vault { | ||||
|     #[instrument(skip_all)] | ||||
|     pub async fn get_payment_method_data_from_locker( | ||||
| @ -704,41 +893,49 @@ impl Vault { | ||||
|         lookup_key: &Option<String>, | ||||
|     ) { | ||||
|         if let Some(lookup_key) = lookup_key { | ||||
|             delete_tokenized_data(state, lookup_key) | ||||
|                 .await | ||||
|                 .map(|_| logger::info!("Card From locker deleted Successfully")) | ||||
|                 .map_err(|err| logger::error!("Error: Deleting Card From Redis Locker : {:?}", err)) | ||||
|                 .ok(); | ||||
|             let delete_resp = delete_tokenized_data(state, lookup_key).await; | ||||
|             match delete_resp { | ||||
|                 Ok(resp) => { | ||||
|                     if resp == "Ok" { | ||||
|                         logger::info!("Card From locker deleted Successfully") | ||||
|                     } else { | ||||
|                         logger::error!("Error: Deleting Card From Locker : {:?}", resp) | ||||
|                     } | ||||
|                 } | ||||
|                 Err(err) => logger::error!("Err: Deleting Card From Locker : {:?}", err), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| //------------------------------------------------TokenizeService------------------------------------------------ | ||||
|  | ||||
| fn get_redis_temp_locker_encryption_key(state: &routes::AppState) -> RouterResult<Vec<u8>> { | ||||
|     #[cfg(feature = "kms")] | ||||
|     let secret = state | ||||
|         .kms_secrets | ||||
|         .redis_temp_locker_encryption_key | ||||
|         .peek() | ||||
|         .to_owned(); | ||||
|  | ||||
|     #[cfg(not(feature = "kms"))] | ||||
|     let secret = hex::decode( | ||||
|         state | ||||
|             .conf | ||||
|             .locker | ||||
|             .redis_temp_locker_encryption_key | ||||
|             .to_owned(), | ||||
|     ) | ||||
|     .into_report() | ||||
|     .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|     .attach_printable("Failed to decode redis temp locker data")?; | ||||
|  | ||||
|     Ok(secret) | ||||
| pub fn get_key_id(keys: &settings::Jwekey) -> &str { | ||||
|     let key_identifier = "1"; // [#46]: Fetch this value from redis or external sources | ||||
|     if key_identifier == "1" { | ||||
|         &keys.locker_key_identifier1 | ||||
|     } else { | ||||
|         &keys.locker_key_identifier2 | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[instrument(skip(state, value1, value2))] | ||||
| #[cfg(feature = "basilisk")] | ||||
| async fn get_locker_jwe_keys( | ||||
|     keys: &settings::ActiveKmsSecrets, | ||||
| ) -> CustomResult<(String, String), errors::EncryptionError> { | ||||
|     let keys = keys.jwekey.peek(); | ||||
|     let key_id = get_key_id(keys); | ||||
|     let (public_key, private_key) = if key_id == keys.locker_key_identifier1 { | ||||
|         (&keys.locker_encryption_key1, &keys.locker_decryption_key1) | ||||
|     } else if key_id == keys.locker_key_identifier2 { | ||||
|         (&keys.locker_encryption_key2, &keys.locker_decryption_key2) | ||||
|     } else { | ||||
|         return Err(errors::EncryptionError.into()); | ||||
|     }; | ||||
|  | ||||
|     Ok((public_key.to_string(), private_key.to_string())) | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| pub async fn create_tokenize( | ||||
|     state: &routes::AppState, | ||||
|     value1: String, | ||||
| @ -746,125 +943,216 @@ pub async fn create_tokenize( | ||||
|     lookup_key: String, | ||||
| ) -> RouterResult<String> { | ||||
|     metrics::CREATED_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); | ||||
|  | ||||
|     let redis_key = format!("{}_{}", LOCKER_REDIS_PREFIX, lookup_key); | ||||
|  | ||||
|     let payload_to_be_encrypted = api::TokenizePayloadRequest { | ||||
|         value1, | ||||
|         value2: value2.unwrap_or_default(), | ||||
|         lookup_key: lookup_key.to_owned(), | ||||
|         lookup_key, | ||||
|         service_name: VAULT_SERVICE_NAME.to_string(), | ||||
|     }; | ||||
|  | ||||
|     let payload = utils::Encode::<api::TokenizePayloadRequest>::encode_to_string_of_json( | ||||
|         &payload_to_be_encrypted, | ||||
|     ) | ||||
|     .change_context(errors::ApiErrorResponse::InternalServerError)?; | ||||
|  | ||||
|     let secret = get_redis_temp_locker_encryption_key(state)?; | ||||
|  | ||||
|     let encrypted_payload = GcmAes256 | ||||
|         .encode_message(secret.as_ref(), payload.as_bytes()) | ||||
|     let (public_key, private_key) = get_locker_jwe_keys(&state.kms_secrets) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Failed to encode redis temp locker data")?; | ||||
|  | ||||
|     let redis_conn = state | ||||
|         .store | ||||
|         .get_redis_conn() | ||||
|         .attach_printable("Error getting Encryption key")?; | ||||
|     let encrypted_payload = services::encrypt_jwe(payload.as_bytes(), public_key) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Failed to get redis connection")?; | ||||
|         .attach_printable("Error getting Encrypt JWE response")?; | ||||
|  | ||||
|     redis_conn | ||||
|         .set_key_if_not_exists_with_expiry( | ||||
|             redis_key.as_str(), | ||||
|             bytes::Bytes::from(encrypted_payload), | ||||
|             Some(i64::from(LOCKER_REDIS_EXPIRY_SECONDS)), | ||||
|     let create_tokenize_request = api::TokenizePayloadEncrypted { | ||||
|         payload: encrypted_payload, | ||||
|         key_id: get_key_id(&state.conf.jwekey).to_string(), | ||||
|         version: Some(VAULT_VERSION.to_string()), | ||||
|     }; | ||||
|     let request = payment_methods::mk_crud_locker_request( | ||||
|         &state.conf.locker, | ||||
|         "/tokenize", | ||||
|         create_tokenize_request, | ||||
|     ) | ||||
|     .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|     .attach_printable("Making tokenize request failed")?; | ||||
|     let response = services::call_connector_api(state, request) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError)?; | ||||
|  | ||||
|     match response { | ||||
|         Ok(r) => { | ||||
|             let resp: api::TokenizePayloadEncrypted = r | ||||
|                 .response | ||||
|                 .parse_struct("TokenizePayloadEncrypted") | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Decoding Failed for TokenizePayloadEncrypted")?; | ||||
|             let alg = jwe::RSA_OAEP_256; | ||||
|             let decrypted_payload = services::decrypt_jwe( | ||||
|                 &resp.payload, | ||||
|                 services::KeyIdCheck::RequestResponseKeyId(( | ||||
|                     get_key_id(&state.conf.jwekey), | ||||
|                     &resp.key_id, | ||||
|                 )), | ||||
|                 private_key, | ||||
|                 alg, | ||||
|             ) | ||||
|             .await | ||||
|         .map(|_| lookup_key) | ||||
|         .map_err(|err| { | ||||
|             metrics::TEMP_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); | ||||
|             err | ||||
|         }) | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error from redis locker") | ||||
|             .attach_printable("Decrypt Jwe failed for TokenizePayloadEncrypted")?; | ||||
|             let get_response: api::GetTokenizePayloadResponse = decrypted_payload | ||||
|                 .parse_struct("GetTokenizePayloadResponse") | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable( | ||||
|                     "Error getting GetTokenizePayloadResponse from tokenize response", | ||||
|                 )?; | ||||
|             Ok(get_response.lookup_key) | ||||
|         } | ||||
|         Err(err) => { | ||||
|             metrics::TEMP_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); | ||||
|             Err(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .into_report() | ||||
|                 .attach_printable(format!("Got 4xx from the basilisk locker: {err:?}")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[instrument(skip(state))] | ||||
| #[cfg(feature = "basilisk")] | ||||
| pub async fn get_tokenized_data( | ||||
|     state: &routes::AppState, | ||||
|     lookup_key: &str, | ||||
|     _should_get_value2: bool, | ||||
|     should_get_value2: bool, | ||||
| ) -> RouterResult<api::TokenizePayloadRequest> { | ||||
|     metrics::GET_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); | ||||
|     let payload_to_be_encrypted = api::GetTokenizePayloadRequest { | ||||
|         lookup_key: lookup_key.to_string(), | ||||
|         get_value2: should_get_value2, | ||||
|         service_name: VAULT_SERVICE_NAME.to_string(), | ||||
|     }; | ||||
|     let payload = serde_json::to_string(&payload_to_be_encrypted) | ||||
|         .map_err(|_x| errors::ApiErrorResponse::InternalServerError)?; | ||||
|  | ||||
|     let redis_key = format!("{}_{}", LOCKER_REDIS_PREFIX, lookup_key); | ||||
|  | ||||
|     let redis_conn = state | ||||
|         .store | ||||
|         .get_redis_conn() | ||||
|     let (public_key, private_key) = get_locker_jwe_keys(&state.kms_secrets) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Failed to get redis connection")?; | ||||
|  | ||||
|     let response = redis_conn.get_key::<bytes::Bytes>(redis_key.as_str()).await; | ||||
|  | ||||
|         .attach_printable("Error getting Encryption key")?; | ||||
|     let encrypted_payload = services::encrypt_jwe(payload.as_bytes(), public_key) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error getting Encrypt JWE response")?; | ||||
|     let create_tokenize_request = api::TokenizePayloadEncrypted { | ||||
|         payload: encrypted_payload, | ||||
|         key_id: get_key_id(&state.conf.jwekey).to_string(), | ||||
|         version: Some("0".to_string()), | ||||
|     }; | ||||
|     let request = payment_methods::mk_crud_locker_request( | ||||
|         &state.conf.locker, | ||||
|         "/tokenize/get", | ||||
|         create_tokenize_request, | ||||
|     ) | ||||
|     .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|     .attach_printable("Making Get Tokenized request failed")?; | ||||
|     let response = services::call_connector_api(state, request) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError)?; | ||||
|     match response { | ||||
|         Ok(resp) => { | ||||
|             let secret = get_redis_temp_locker_encryption_key(state)?; | ||||
|  | ||||
|             let decrypted_payload = GcmAes256 | ||||
|                 .decode_message(secret.as_ref(), masking::Secret::new(resp.into())) | ||||
|         Ok(r) => { | ||||
|             let resp: api::TokenizePayloadEncrypted = r | ||||
|                 .response | ||||
|                 .parse_struct("TokenizePayloadEncrypted") | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Failed to decode redis temp locker data")?; | ||||
|  | ||||
|             let get_response: api::TokenizePayloadRequest = bytes::Bytes::from(decrypted_payload) | ||||
|                 .attach_printable("Decoding Failed for TokenizePayloadEncrypted")?; | ||||
|             let alg = jwe::RSA_OAEP_256; | ||||
|             let decrypted_payload = services::decrypt_jwe( | ||||
|                 &resp.payload, | ||||
|                 services::KeyIdCheck::RequestResponseKeyId(( | ||||
|                     get_key_id(&state.conf.jwekey), | ||||
|                     &resp.key_id, | ||||
|                 )), | ||||
|                 private_key, | ||||
|                 alg, | ||||
|             ) | ||||
|             .await | ||||
|             .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|             .attach_printable("GetTokenizedApi: Decrypt Jwe failed for TokenizePayloadEncrypted")?; | ||||
|             let get_response: api::TokenizePayloadRequest = decrypted_payload | ||||
|                 .parse_struct("TokenizePayloadRequest") | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Error getting TokenizePayloadRequest from tokenize response")?; | ||||
|  | ||||
|             Ok(get_response) | ||||
|         } | ||||
|         Err(err) => { | ||||
|             metrics::TEMP_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); | ||||
|             Err(err).change_context(errors::ApiErrorResponse::UnprocessableEntity { | ||||
|             match err.status_code { | ||||
|                 404 => Err(errors::ApiErrorResponse::UnprocessableEntity { | ||||
|                     message: "Token is invalid or expired".into(), | ||||
|             }) | ||||
|                 } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[instrument(skip(state))] | ||||
| pub async fn delete_tokenized_data(state: &routes::AppState, lookup_key: &str) -> RouterResult<()> { | ||||
|     metrics::DELETED_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); | ||||
|  | ||||
|     let redis_key = format!("{}_{}", LOCKER_REDIS_PREFIX, lookup_key); | ||||
|  | ||||
|     let redis_conn = state | ||||
|         .store | ||||
|         .get_redis_conn() | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Failed to get redis connection")?; | ||||
|  | ||||
|     let response = redis_conn.delete_key(redis_key.as_str()).await; | ||||
|  | ||||
|     match response { | ||||
|         Ok(redis_interface::DelReply::KeyDeleted) => Ok(()), | ||||
|         Ok(redis_interface::DelReply::KeyNotDeleted) => { | ||||
|             Err(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .into()), | ||||
|                 _ => Err(errors::ApiErrorResponse::InternalServerError) | ||||
|                     .into_report() | ||||
|                 .attach_printable("Token invalid or expired") | ||||
|                     .attach_printable(format!("Got error from the basilisk locker: {err:?}")), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| pub async fn delete_tokenized_data( | ||||
|     state: &routes::AppState, | ||||
|     lookup_key: &str, | ||||
| ) -> RouterResult<String> { | ||||
|     metrics::DELETED_TOKENIZED_CARD.add(&metrics::CONTEXT, 1, &[]); | ||||
|     let payload_to_be_encrypted = api::DeleteTokenizeByTokenRequest { | ||||
|         lookup_key: lookup_key.to_string(), | ||||
|         service_name: VAULT_SERVICE_NAME.to_string(), | ||||
|     }; | ||||
|     let payload = serde_json::to_string(&payload_to_be_encrypted) | ||||
|         .into_report() | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error serializing api::DeleteTokenizeByTokenRequest")?; | ||||
|  | ||||
|     let (public_key, _private_key) = get_locker_jwe_keys(&state.kms_secrets.clone()) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error getting Encryption key")?; | ||||
|     let encrypted_payload = services::encrypt_jwe(payload.as_bytes(), public_key) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error getting Encrypt JWE response")?; | ||||
|     let create_tokenize_request = api::TokenizePayloadEncrypted { | ||||
|         payload: encrypted_payload, | ||||
|         key_id: get_key_id(&state.conf.jwekey).to_string(), | ||||
|         version: Some("0".to_string()), | ||||
|     }; | ||||
|     let request = payment_methods::mk_crud_locker_request( | ||||
|         &state.conf.locker, | ||||
|         "/tokenize/delete/token", | ||||
|         create_tokenize_request, | ||||
|     ) | ||||
|     .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|     .attach_printable("Making Delete Tokenized request failed")?; | ||||
|     let response = services::call_connector_api(state, request) | ||||
|         .await | ||||
|         .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|         .attach_printable("Error while making /tokenize/delete/token call to the locker")?; | ||||
|     match response { | ||||
|         Ok(r) => { | ||||
|             let delete_response = std::str::from_utf8(&r.response) | ||||
|                 .into_report() | ||||
|                 .change_context(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .attach_printable("Decoding Failed for basilisk delete response")?; | ||||
|             Ok(delete_response.to_string()) | ||||
|         } | ||||
|         Err(err) => { | ||||
|             metrics::TEMP_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]); | ||||
|             Err(errors::ApiErrorResponse::InternalServerError) | ||||
|                 .into_report() | ||||
|                 .attach_printable_lazy(|| format!("Failed to delete from redis locker: {err:?}")) | ||||
|                 .attach_printable(format!("Got 4xx from the basilisk locker: {err:?}")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| // ********************************************** PROCESS TRACKER ********************************************** | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| pub async fn add_delete_tokenized_data_task( | ||||
|     db: &dyn db::StorageInterface, | ||||
|     lookup_key: &str, | ||||
| @ -907,6 +1195,7 @@ pub async fn add_delete_tokenized_data_task( | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| pub async fn start_tokenize_data_workflow( | ||||
|     state: &routes::AppState, | ||||
|     tokenize_tracker: &storage::ProcessTracker, | ||||
| @ -924,8 +1213,10 @@ pub async fn start_tokenize_data_workflow( | ||||
|         ) | ||||
|     })?; | ||||
|  | ||||
|     match delete_tokenized_data(state, &delete_tokenize_data.lookup_key).await { | ||||
|         Ok(()) => { | ||||
|     let delete_resp = delete_tokenized_data(state, &delete_tokenize_data.lookup_key).await; | ||||
|     match delete_resp { | ||||
|         Ok(resp) => { | ||||
|             if resp == "Ok" { | ||||
|                 logger::info!("Card From locker deleted Successfully"); | ||||
|                 //mark task as finished | ||||
|                 let id = tokenize_tracker.id.clone(); | ||||
| @ -933,6 +1224,12 @@ pub async fn start_tokenize_data_workflow( | ||||
|                     .clone() | ||||
|                     .finish_with_status(db.as_scheduler(), format!("COMPLETED_BY_PT_{id}")) | ||||
|                     .await?; | ||||
|             } else { | ||||
|                 logger::error!("Error: Deleting Card From Locker : {:?}", resp); | ||||
|                 retry_delete_tokenize(db, &delete_tokenize_data.pm, tokenize_tracker.to_owned()) | ||||
|                     .await?; | ||||
|                 metrics::RETRIED_DELETE_DATA_COUNT.add(&metrics::CONTEXT, 1, &[]); | ||||
|             } | ||||
|         } | ||||
|         Err(err) => { | ||||
|             logger::error!("Err: Deleting Card From Locker : {:?}", err); | ||||
| @ -944,6 +1241,7 @@ pub async fn start_tokenize_data_workflow( | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| pub async fn get_delete_tokenize_schedule_time( | ||||
|     db: &dyn db::StorageInterface, | ||||
|     pm: &enums::PaymentMethod, | ||||
| @ -967,6 +1265,7 @@ pub async fn get_delete_tokenize_schedule_time( | ||||
|     process_tracker_utils::get_time_from_delta(time_delta) | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "basilisk")] | ||||
| pub async fn retry_delete_tokenize( | ||||
|     db: &dyn db::StorageInterface, | ||||
|     pm: &enums::PaymentMethod, | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use async_trait::async_trait; | ||||
| use error_stack::{self, IntoReport, ResultExt}; | ||||
| use error_stack; | ||||
|  | ||||
| use super::{ConstructFlowSpecificData, Feature}; | ||||
| use crate::{ | ||||
| @ -95,8 +95,7 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu | ||||
|  | ||||
|             metrics::PAYMENT_COUNT.add(&metrics::CONTEXT, 1, &[]); // Metrics | ||||
|  | ||||
|             if resp.request.setup_mandate_details.clone().is_some() { | ||||
|                 let payment_method_id = tokenization::save_payment_method( | ||||
|             let save_payment_result = tokenization::save_payment_method( | ||||
|                 state, | ||||
|                 connector, | ||||
|                 resp.to_owned(), | ||||
| @ -105,57 +104,21 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu | ||||
|                 self.request.payment_method_type, | ||||
|                 key_store, | ||||
|             ) | ||||
|                 .await?; | ||||
|                 Ok( | ||||
|                     mandate::mandate_procedure(state, resp, maybe_customer, payment_method_id) | ||||
|                         .await?, | ||||
|                 ) | ||||
|             } else { | ||||
|                 let arbiter = actix::Arbiter::try_current() | ||||
|                     .ok_or(errors::ApiErrorResponse::InternalServerError) | ||||
|                     .into_report() | ||||
|                     .attach_printable("arbiter retrieval failure") | ||||
|                     .map_err(|err| { | ||||
|                         logger::error!(?err); | ||||
|                         err | ||||
|                     }) | ||||
|                     .ok(); | ||||
|  | ||||
|                 let connector = connector.clone(); | ||||
|                 let response = resp.clone(); | ||||
|                 let maybe_customer = maybe_customer.clone(); | ||||
|                 let merchant_account = merchant_account.clone(); | ||||
|                 let key_store = key_store.clone(); | ||||
|                 let state = state.clone(); | ||||
|  | ||||
|                 logger::info!("Initiating async call to save_payment_method in locker"); | ||||
|  | ||||
|                 arbiter.map(|arb| { | ||||
|                     arb.spawn(async move { | ||||
|                         logger::info!("Starting async call to save_payment_method in locker"); | ||||
|  | ||||
|                         let result = tokenization::save_payment_method( | ||||
|                             &state, | ||||
|                             &connector, | ||||
|                             response, | ||||
|                             &maybe_customer, | ||||
|                             &merchant_account, | ||||
|                             self.request.payment_method_type, | ||||
|                             &key_store, | ||||
|                         ) | ||||
|             .await; | ||||
|  | ||||
|                         if let Err(err) = result { | ||||
|                             logger::error!( | ||||
|                                 "Asynchronously saving card in locker failed : {:?}", | ||||
|                                 err | ||||
|                             ); | ||||
|             let pm_id = match save_payment_result { | ||||
|                 Ok(payment_method_id) => Ok(payment_method_id), | ||||
|                 Err(error) => { | ||||
|                     if resp.request.setup_mandate_details.clone().is_some() { | ||||
|                         Err(error) | ||||
|                     } else { | ||||
|                         logger::error!(save_payment_method_error=?error); | ||||
|                         Ok(None) | ||||
|                     } | ||||
|                     }) | ||||
|                 }); | ||||
|                 } | ||||
|             }?; | ||||
|  | ||||
|                 Ok(resp) | ||||
|             } | ||||
|             Ok(mandate::mandate_procedure(state, resp, maybe_customer, pm_id).await?) | ||||
|         } else { | ||||
|             Ok(self.clone()) | ||||
|         } | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| use common_utils::{ext_traits::ValueExt, pii}; | ||||
| use error_stack::{report, ResultExt}; | ||||
| use masking::ExposeInterface; | ||||
| use router_env::{instrument, tracing}; | ||||
|  | ||||
| use super::helpers; | ||||
| use crate::{ | ||||
| @ -21,7 +20,6 @@ use crate::{ | ||||
|     utils::OptionExt, | ||||
| }; | ||||
|  | ||||
| #[instrument(skip_all)] | ||||
| pub async fn save_payment_method<F: Clone, FData>( | ||||
|     state: &AppState, | ||||
|     connector: &api::ConnectorData, | ||||
|  | ||||
| @ -128,12 +128,6 @@ impl AppState { | ||||
|         #[allow(clippy::expect_used)] | ||||
|         let kms_secrets = settings::ActiveKmsSecrets { | ||||
|             jwekey: conf.jwekey.clone().into(), | ||||
|             redis_temp_locker_encryption_key: conf | ||||
|                 .locker | ||||
|                 .redis_temp_locker_encryption_key | ||||
|                 .clone() | ||||
|                 .into_bytes() | ||||
|                 .into(), | ||||
|         } | ||||
|         .decrypt_inner(kms_client) | ||||
|         .await | ||||
| @ -141,7 +135,6 @@ impl AppState { | ||||
|  | ||||
|         #[cfg(feature = "email")] | ||||
|         let email_client = Arc::new(AwsSes::new(&conf.email).await); | ||||
|  | ||||
|         Self { | ||||
|             flow_name: String::from("default"), | ||||
|             store, | ||||
|  | ||||
| @ -110,6 +110,7 @@ pub(super) fn create_client( | ||||
|  | ||||
| pub fn proxy_bypass_urls(locker: &Locker) -> Vec<String> { | ||||
|     let locker_host = locker.host.to_owned(); | ||||
|     let basilisk_host = locker.basilisk_host.to_owned(); | ||||
|     vec![ | ||||
|         format!("{locker_host}/cards/add"), | ||||
|         format!("{locker_host}/cards/retrieve"), | ||||
| @ -117,6 +118,10 @@ pub fn proxy_bypass_urls(locker: &Locker) -> Vec<String> { | ||||
|         format!("{locker_host}/card/addCard"), | ||||
|         format!("{locker_host}/card/getCard"), | ||||
|         format!("{locker_host}/card/deleteCard"), | ||||
|         format!("{basilisk_host}/tokenize"), | ||||
|         format!("{basilisk_host}/tokenize/get"), | ||||
|         format!("{basilisk_host}/tokenize/delete"), | ||||
|         format!("{basilisk_host}/tokenize/delete/token"), | ||||
|     ] | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -1,11 +1,12 @@ | ||||
| use api_models::enums as api_enums; | ||||
| pub use api_models::payment_methods::{ | ||||
|     CardDetail, CardDetailFromLocker, CardDetailsPaymentMethod, CustomerPaymentMethod, | ||||
|     CustomerPaymentMethodsListResponse, GetTokenizePayloadRequest, GetTokenizePayloadResponse, | ||||
|     PaymentMethodCreate, PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodList, | ||||
|     PaymentMethodListRequest, PaymentMethodListResponse, PaymentMethodResponse, | ||||
|     PaymentMethodUpdate, PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest, | ||||
|     TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2, | ||||
|     CustomerPaymentMethodsListResponse, DeleteTokenizeByDateRequest, DeleteTokenizeByTokenRequest, | ||||
|     GetTokenizePayloadRequest, GetTokenizePayloadResponse, PaymentMethodCreate, | ||||
|     PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodList, PaymentMethodListRequest, | ||||
|     PaymentMethodListResponse, PaymentMethodResponse, PaymentMethodUpdate, PaymentMethodsData, | ||||
|     TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2, | ||||
|     TokenizedWalletValue1, TokenizedWalletValue2, | ||||
| }; | ||||
| use error_stack::report; | ||||
|  | ||||
|  | ||||
| @ -1,13 +1,14 @@ | ||||
| use scheduler::consumer::workflows::ProcessTrackerWorkflow; | ||||
|  | ||||
| use crate::{ | ||||
|     core::payment_methods::vault, errors, logger::error, routes::AppState, types::storage, | ||||
| }; | ||||
| #[cfg(feature = "basilisk")] | ||||
| use crate::core::payment_methods::vault; | ||||
| use crate::{errors, logger::error, routes::AppState, types::storage}; | ||||
|  | ||||
| pub struct DeleteTokenizeDataWorkflow; | ||||
|  | ||||
| #[async_trait::async_trait] | ||||
| impl ProcessTrackerWorkflow<AppState> for DeleteTokenizeDataWorkflow { | ||||
|     #[cfg(feature = "basilisk")] | ||||
|     async fn execute_workflow<'a>( | ||||
|         &'a self, | ||||
|         state: &'a AppState, | ||||
| @ -16,6 +17,15 @@ impl ProcessTrackerWorkflow<AppState> for DeleteTokenizeDataWorkflow { | ||||
|         Ok(vault::start_tokenize_data_workflow(state, &process).await?) | ||||
|     } | ||||
|  | ||||
|     #[cfg(not(feature = "basilisk"))] | ||||
|     async fn execute_workflow<'a>( | ||||
|         &'a self, | ||||
|         _state: &'a AppState, | ||||
|         _process: storage::ProcessTracker, | ||||
|     ) -> Result<(), errors::ProcessTrackerError> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     async fn error_handler<'a>( | ||||
|         &'a self, | ||||
|         _state: &'a AppState, | ||||
|  | ||||
| @ -32,7 +32,6 @@ jwt_secret = "secret" | ||||
| host = "" | ||||
| mock_locker = true | ||||
| basilisk_host = "" | ||||
| redis_temp_locker_encryption_key = "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" | ||||
|  | ||||
| [eph_key] | ||||
| validity = 1 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user