From 98715e8fd740fb787c7f764137d61f1cd3a715f6 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 4 Jun 2024 06:46:26 +0530 Subject: [PATCH 01/12] refactor: remove id column from intent and attempt --- crates/diesel_models/src/payment_attempt.rs | 3 +-- crates/diesel_models/src/payment_intent.rs | 3 +-- crates/diesel_models/src/schema.rs | 6 ++---- crates/hyperswitch_domain_models/src/lib.rs | 2 ++ .../hyperswitch_domain_models/src/payments.rs | 1 - .../src/mock_db/payment_attempt.rs | 3 --- .../src/payments/payment_attempt.rs | 3 --- .../down.sql | 1 + .../up.sql | 19 +++++++++++++++++++ .../down.sql | 1 + .../up.sql | 6 ++++++ 11 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql create mode 100644 migrations/2024-06-03-090859_make_id_as_optional_for_payments/up.sql create mode 100644 migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql create mode 100644 migrations/2024-06-03-133421_remove_id_from_payment_table/up.sql diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index 6bb286b42a95..fbafd889618a 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -8,9 +8,8 @@ use crate::{ }; #[derive(Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Serialize, Deserialize)] -#[diesel(table_name = payment_attempt)] +#[diesel(table_name = payment_attempt, primary_key(attempt_id, merchant_id))] pub struct PaymentAttempt { - pub id: i32, pub payment_id: String, pub merchant_id: String, pub attempt_id: String, diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index c54ff2a429e1..ecdddd8434c3 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -7,9 +7,8 @@ use time::PrimitiveDateTime; use crate::{enums as storage_enums, schema::payment_intent}; #[derive(Clone, Debug, Eq, PartialEq, Identifiable, Queryable, Serialize, Deserialize)] -#[diesel(table_name = payment_intent)] +#[diesel(table_name = payment_intent, primary_key(payment_id, merchant_id))] pub struct PaymentIntent { - pub id: i32, pub payment_id: String, pub merchant_id: String, pub status: storage_enums::IntentStatus, diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 6074fdc10b77..dd017e5ba862 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -709,8 +709,7 @@ diesel::table! { use diesel::sql_types::*; use crate::enums::diesel_exports::*; - payment_attempt (id) { - id -> Int4, + payment_attempt (attempt_id, merchant_id) { #[max_length = 64] payment_id -> Varchar, #[max_length = 64] @@ -799,8 +798,7 @@ diesel::table! { use diesel::sql_types::*; use crate::enums::diesel_exports::*; - payment_intent (id) { - id -> Int4, + payment_intent (payment_id, merchant_id) { #[max_length = 64] payment_id -> Varchar, #[max_length = 64] diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index d9778353cdaa..45a67178204f 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -10,6 +10,8 @@ pub mod router_flow_types; pub mod router_request_types; pub mod router_response_types; +pub mod behaviour; + #[cfg(not(feature = "payouts"))] pub trait PayoutAttemptInterface {} diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 089cb29aec5e..c09df82f87c9 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -11,7 +11,6 @@ use crate::RemoteStorageObject; #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] pub struct PaymentIntent { - pub id: i32, pub payment_id: String, pub merchant_id: String, pub status: storage_enums::IntentStatus, diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs index 0e8df898f126..547fc9f7d719 100644 --- a/crates/storage_impl/src/mock_db/payment_attempt.rs +++ b/crates/storage_impl/src/mock_db/payment_attempt.rs @@ -97,12 +97,9 @@ impl PaymentAttemptInterface for MockDb { storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { let mut payment_attempts = self.payment_attempts.lock().await; - #[allow(clippy::as_conversions)] - let id = payment_attempts.len() as i32; let time = common_utils::date_time::now(); let payment_attempt = payment_attempt.populate_derived_fields(); let payment_attempt = PaymentAttempt { - id, payment_id: payment_attempt.payment_id, merchant_id: payment_attempt.merchant_id, attempt_id: payment_attempt.attempt_id, diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 1e60c3e02f22..e5e3a487f508 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -352,7 +352,6 @@ impl PaymentAttemptInterface for KVRouterStore { }; let key_str = key.to_string(); let created_attempt = PaymentAttempt { - id: Default::default(), payment_id: payment_attempt.payment_id.clone(), merchant_id: payment_attempt.merchant_id.clone(), attempt_id: payment_attempt.attempt_id.clone(), @@ -1137,7 +1136,6 @@ impl DataModelExt for PaymentAttempt { fn to_storage_model(self) -> Self::StorageModel { DieselPaymentAttempt { - id: self.id, payment_id: self.payment_id, merchant_id: self.merchant_id, attempt_id: self.attempt_id, @@ -1207,7 +1205,6 @@ impl DataModelExt for PaymentAttempt { fn from_storage_model(storage_model: Self::StorageModel) -> Self { Self { net_amount: MinorUnit::new(storage_model.get_or_calculate_net_amount()), - id: storage_model.id, payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, attempt_id: storage_model.attempt_id, diff --git a/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql new file mode 100644 index 000000000000..d9a93fe9a1a1 --- /dev/null +++ b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` diff --git a/migrations/2024-06-03-090859_make_id_as_optional_for_payments/up.sql b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/up.sql new file mode 100644 index 000000000000..3c050d6e9671 --- /dev/null +++ b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/up.sql @@ -0,0 +1,19 @@ +-- First drop the primary key of payment_intent +ALTER TABLE payment_intent DROP CONSTRAINT payment_intent_pkey; + +-- Create new primary key +ALTER TABLE payment_intent +ADD PRIMARY KEY (payment_id, merchant_id); + +-- Make the previous primary key as optional +ALTER TABLE payment_intent +ALTER COLUMN id DROP NOT NULL; + +-- Follow the same steps for payment attempt as well +ALTER TABLE payment_attempt DROP CONSTRAINT payment_attempt_pkey; + +ALTER TABLE payment_attempt +ADD PRIMARY KEY (attempt_id, merchant_id); + +ALTER TABLE payment_attempt +ALTER COLUMN id DROP NOT NULL; diff --git a/migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql b/migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql new file mode 100644 index 000000000000..d9a93fe9a1a1 --- /dev/null +++ b/migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql @@ -0,0 +1 @@ +-- This file should undo anything in `up.sql` diff --git a/migrations/2024-06-03-133421_remove_id_from_payment_table/up.sql b/migrations/2024-06-03-133421_remove_id_from_payment_table/up.sql new file mode 100644 index 000000000000..221ab4e9ae24 --- /dev/null +++ b/migrations/2024-06-03-133421_remove_id_from_payment_table/up.sql @@ -0,0 +1,6 @@ +-- The following queries must be run after the newer version of the application is deployed. +-- Running these queries can even be deferred for some time (a couple of weeks or even a month) until the +-- new version being deployed is considered stable +ALTER TABLE payment_intent DROP COLUMN id; + +ALTER TABLE payment_attempt DROP COLUMN id; From c4f0470b19194cd03ce2cd12553e759259f2ad33 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 4 Jun 2024 10:19:46 +0530 Subject: [PATCH 02/12] feat: impl behaviour for payment_intent insert --- .../src/behaviour.rs | 31 ++++ .../src/payments/payment_attempt.rs | 171 +++++++++++++++++- .../src/payments/payment_intent.rs | 2 +- crates/router/src/core/payments/helpers.rs | 3 - .../payments/operations/payment_create.rs | 8 +- crates/router/src/db/kafka_store.rs | 2 +- crates/router/src/types/domain/behaviour.rs | 33 +--- .../src/mock_db/payment_intent.rs | 61 +------ .../src/payments/payment_intent.rs | 88 +++------ .../down.sql | 15 ++ .../down.sql | 5 + 11 files changed, 259 insertions(+), 160 deletions(-) create mode 100644 crates/hyperswitch_domain_models/src/behaviour.rs diff --git a/crates/hyperswitch_domain_models/src/behaviour.rs b/crates/hyperswitch_domain_models/src/behaviour.rs new file mode 100644 index 000000000000..9976dd25a985 --- /dev/null +++ b/crates/hyperswitch_domain_models/src/behaviour.rs @@ -0,0 +1,31 @@ +use common_utils::errors::{CustomResult, ValidationError}; +use masking::Secret; + +/// Trait for converting domain types to storage models +#[async_trait::async_trait] +pub trait Conversion { + type DstType; + type NewDstType; + async fn convert(self) -> CustomResult; + + async fn convert_back( + item: Self::DstType, + key: &Secret>, + ) -> CustomResult + where + Self: Sized; + + async fn construct_new(self) -> CustomResult; +} + +#[async_trait::async_trait] +pub trait ReverseConversion { + async fn convert(self, key: &Secret>) -> CustomResult; +} + +#[async_trait::async_trait] +impl> ReverseConversion for T { + async fn convert(self, key: &Secret>) -> CustomResult { + U::convert_back(self, key).await + } +} diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index ac0c74ea9134..52872efc1971 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -1,14 +1,17 @@ use api_models::enums::Connector; use common_enums as storage_enums; -use common_utils::types::MinorUnit; +use common_utils::{ + errors::{CustomResult, ValidationError}, + types::MinorUnit, +}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use super::PaymentIntent; use crate::{ - errors, + behaviour, errors, mandates::{MandateDataType, MandateDetails}, - ForeignIDRef, + ForeignIDRef, RemoteStorageObject, }; #[async_trait::async_trait] @@ -107,7 +110,6 @@ pub trait PaymentAttemptInterface { #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct PaymentAttempt { - pub id: i32, pub payment_id: String, pub merchant_id: String, pub attempt_id: String, @@ -458,3 +460,164 @@ impl ForeignIDRef for PaymentAttempt { self.attempt_id.clone() } } + +use diesel_models::{ + PaymentIntent as DieselPaymentIntent, PaymentIntentNew as DieselPaymentIntentNew, +}; + +#[async_trait::async_trait] +impl behaviour::Conversion for PaymentIntent { + type DstType = DieselPaymentIntent; + type NewDstType = DieselPaymentIntentNew; + + async fn convert(self) -> CustomResult { + Ok(DieselPaymentIntent { + payment_id: self.payment_id, + merchant_id: self.merchant_id, + status: self.status, + amount: self.amount, + currency: self.currency, + amount_captured: self.amount_captured, + customer_id: self.customer_id, + description: self.description, + return_url: self.return_url, + metadata: self.metadata, + connector_id: self.connector_id, + shipping_address_id: self.shipping_address_id, + billing_address_id: self.billing_address_id, + statement_descriptor_name: self.statement_descriptor_name, + statement_descriptor_suffix: self.statement_descriptor_suffix, + created_at: self.created_at, + modified_at: self.modified_at, + last_synced: self.last_synced, + setup_future_usage: self.setup_future_usage, + off_session: self.off_session, + client_secret: self.client_secret, + active_attempt_id: self.active_attempt.get_id(), + business_country: self.business_country, + business_label: self.business_label, + order_details: self.order_details, + allowed_payment_method_types: self.allowed_payment_method_types, + connector_metadata: self.connector_metadata, + feature_metadata: self.feature_metadata, + attempt_count: self.attempt_count, + profile_id: self.profile_id, + merchant_decision: self.merchant_decision, + payment_link_id: self.payment_link_id, + payment_confirm_source: self.payment_confirm_source, + updated_by: self.updated_by, + surcharge_applicable: self.surcharge_applicable, + request_incremental_authorization: self.request_incremental_authorization, + incremental_authorization_allowed: self.incremental_authorization_allowed, + authorization_count: self.authorization_count, + fingerprint_id: self.fingerprint_id, + session_expiry: self.session_expiry, + request_external_three_ds_authentication: self.request_external_three_ds_authentication, + charges: self.charges, + frm_metadata: self.frm_metadata, + }) + } + + async fn convert_back( + storage_model: Self::DstType, + _key: &masking::Secret>, + ) -> CustomResult + where + Self: Sized, + { + Ok(PaymentIntent { + payment_id: storage_model.payment_id, + merchant_id: storage_model.merchant_id, + status: storage_model.status, + amount: storage_model.amount, + currency: storage_model.currency, + amount_captured: storage_model.amount_captured, + customer_id: storage_model.customer_id, + description: storage_model.description, + return_url: storage_model.return_url, + metadata: storage_model.metadata, + connector_id: storage_model.connector_id, + shipping_address_id: storage_model.shipping_address_id, + billing_address_id: storage_model.billing_address_id, + statement_descriptor_name: storage_model.statement_descriptor_name, + statement_descriptor_suffix: storage_model.statement_descriptor_suffix, + created_at: storage_model.created_at, + modified_at: storage_model.modified_at, + last_synced: storage_model.last_synced, + setup_future_usage: storage_model.setup_future_usage, + off_session: storage_model.off_session, + client_secret: storage_model.client_secret, + active_attempt: RemoteStorageObject::ForeignID(storage_model.active_attempt_id), + business_country: storage_model.business_country, + business_label: storage_model.business_label, + order_details: storage_model.order_details, + allowed_payment_method_types: storage_model.allowed_payment_method_types, + connector_metadata: storage_model.connector_metadata, + feature_metadata: storage_model.feature_metadata, + attempt_count: storage_model.attempt_count, + profile_id: storage_model.profile_id, + merchant_decision: storage_model.merchant_decision, + payment_link_id: storage_model.payment_link_id, + payment_confirm_source: storage_model.payment_confirm_source, + updated_by: storage_model.updated_by, + surcharge_applicable: storage_model.surcharge_applicable, + request_incremental_authorization: storage_model.request_incremental_authorization, + incremental_authorization_allowed: storage_model.incremental_authorization_allowed, + authorization_count: storage_model.authorization_count, + fingerprint_id: storage_model.fingerprint_id, + session_expiry: storage_model.session_expiry, + request_external_three_ds_authentication: storage_model + .request_external_three_ds_authentication, + charges: storage_model.charges, + frm_metadata: storage_model.frm_metadata, + }) + } + + async fn construct_new(self) -> CustomResult { + Ok(DieselPaymentIntentNew { + payment_id: self.payment_id, + merchant_id: self.merchant_id, + status: self.status, + amount: self.amount, + currency: self.currency, + amount_captured: self.amount_captured, + customer_id: self.customer_id, + description: self.description, + return_url: self.return_url, + metadata: self.metadata, + connector_id: self.connector_id, + shipping_address_id: self.shipping_address_id, + billing_address_id: self.billing_address_id, + statement_descriptor_name: self.statement_descriptor_name, + statement_descriptor_suffix: self.statement_descriptor_suffix, + created_at: Some(self.created_at), + modified_at: Some(self.modified_at), + last_synced: self.last_synced, + setup_future_usage: self.setup_future_usage, + off_session: self.off_session, + client_secret: self.client_secret, + active_attempt_id: self.active_attempt.get_id(), + business_country: self.business_country, + business_label: self.business_label, + order_details: self.order_details, + allowed_payment_method_types: self.allowed_payment_method_types, + connector_metadata: self.connector_metadata, + feature_metadata: self.feature_metadata, + attempt_count: self.attempt_count, + profile_id: self.profile_id, + merchant_decision: self.merchant_decision, + payment_link_id: self.payment_link_id, + payment_confirm_source: self.payment_confirm_source, + updated_by: self.updated_by, + surcharge_applicable: self.surcharge_applicable, + request_incremental_authorization: self.request_incremental_authorization, + incremental_authorization_allowed: self.incremental_authorization_allowed, + authorization_count: self.authorization_count, + fingerprint_id: self.fingerprint_id, + session_expiry: self.session_expiry, + request_external_three_ds_authentication: self.request_external_three_ds_authentication, + charges: self.charges, + frm_metadata: self.frm_metadata, + }) + } +} diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index d413e97289af..e23c92508a15 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -20,7 +20,7 @@ pub trait PaymentIntentInterface { async fn insert_payment_intent( &self, - new: PaymentIntentNew, + new: PaymentIntent, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 8f7ed4da2565..0bc8697eed8b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2937,7 +2937,6 @@ mod tests { #[test] fn test_authenticate_client_secret_fulfillment_time_not_expired() { let payment_intent = PaymentIntent { - id: 21, payment_id: "23".to_string(), merchant_id: "22".to_string(), status: storage_enums::IntentStatus::RequiresCapture, @@ -2997,7 +2996,6 @@ mod tests { #[test] fn test_authenticate_client_secret_fulfillment_time_expired() { let payment_intent = PaymentIntent { - id: 21, payment_id: "23".to_string(), merchant_id: "22".to_string(), status: storage_enums::IntentStatus::RequiresCapture, @@ -3056,7 +3054,6 @@ mod tests { #[test] fn test_authenticate_client_secret_expired() { let payment_intent = PaymentIntent { - id: 21, payment_id: "23".to_string(), merchant_id: "22".to_string(), status: storage_enums::IntentStatus::RequiresCapture, diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 9a4e87890582..f77760fa46cc 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -964,8 +964,8 @@ impl PaymentCreate { active_attempt_id: String, profile_id: String, session_expiry: PrimitiveDateTime, - ) -> RouterResult { - let created_at @ modified_at @ last_synced = Some(common_utils::date_time::now()); + ) -> RouterResult { + let created_at @ modified_at @ last_synced = common_utils::date_time::now(); let status = helpers::payment_intent_status_fsm( request @@ -1021,7 +1021,7 @@ impl PaymentCreate { .change_context(errors::ApiErrorResponse::InternalServerError)? .map(Secret::new); - Ok(storage::PaymentIntentNew { + Ok(storage::PaymentIntent { payment_id: payment_id.to_string(), merchant_id: merchant_account.merchant_id.to_string(), status, @@ -1030,7 +1030,7 @@ impl PaymentCreate { description: request.description.clone(), created_at, modified_at, - last_synced, + last_synced: Some(last_synced), client_secret: Some(client_secret), setup_future_usage: request.setup_future_usage, off_session: request.off_session, diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 0e3b365ae075..0d3bec40f40b 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1335,7 +1335,7 @@ impl PaymentIntentInterface for KafkaStore { async fn insert_payment_intent( &self, - new: storage::PaymentIntentNew, + new: storage::PaymentIntent, storage_scheme: MerchantStorageScheme, ) -> CustomResult { logger::debug!("Inserting PaymentIntent Via KafkaStore"); diff --git a/crates/router/src/types/domain/behaviour.rs b/crates/router/src/types/domain/behaviour.rs index db7159fad5aa..87ab7feab9c9 100644 --- a/crates/router/src/types/domain/behaviour.rs +++ b/crates/router/src/types/domain/behaviour.rs @@ -1,32 +1 @@ -use common_utils::errors::{CustomResult, ValidationError}; - -use crate::pii::Secret; - -/// Trait for converting domain types to storage models -#[async_trait::async_trait] -pub trait Conversion { - type DstType; - type NewDstType; - async fn convert(self) -> CustomResult; - - async fn convert_back( - item: Self::DstType, - key: &Secret>, - ) -> CustomResult - where - Self: Sized; - - async fn construct_new(self) -> CustomResult; -} - -#[async_trait::async_trait] -pub trait ReverseConversion { - async fn convert(self, key: &Secret>) -> CustomResult; -} - -#[async_trait::async_trait] -impl> ReverseConversion for T { - async fn convert(self, key: &Secret>) -> CustomResult { - U::convert_back(self, key).await - } -} +pub use hyperswitch_domain_models::behaviour::{Conversion, ReverseConversion}; diff --git a/crates/storage_impl/src/mock_db/payment_intent.rs b/crates/storage_impl/src/mock_db/payment_intent.rs index a12b06b29144..6aa0121340e0 100644 --- a/crates/storage_impl/src/mock_db/payment_intent.rs +++ b/crates/storage_impl/src/mock_db/payment_intent.rs @@ -1,11 +1,10 @@ use common_utils::errors::CustomResult; use diesel_models::enums as storage_enums; -use error_stack::ResultExt; use hyperswitch_domain_models::{ errors::StorageError, payments::{ payment_attempt::PaymentAttempt, - payment_intent::{PaymentIntentInterface, PaymentIntentNew, PaymentIntentUpdate}, + payment_intent::{PaymentIntentInterface, PaymentIntentUpdate}, PaymentIntent, }, }; @@ -59,60 +58,12 @@ impl PaymentIntentInterface for MockDb { #[allow(clippy::panic)] async fn insert_payment_intent( &self, - new: PaymentIntentNew, - storage_scheme: storage_enums::MerchantStorageScheme, + new: PaymentIntent, + _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { let mut payment_intents = self.payment_intents.lock().await; - let time = common_utils::date_time::now(); - let payment_intent = PaymentIntent { - #[allow(clippy::as_conversions)] - id: i32::try_from(payment_intents.len()).change_context(StorageError::MockDbError)?, - payment_id: new.payment_id, - merchant_id: new.merchant_id, - status: new.status, - amount: new.amount, - currency: new.currency, - amount_captured: new.amount_captured, - customer_id: new.customer_id, - description: new.description, - return_url: new.return_url, - metadata: new.metadata, - connector_id: new.connector_id, - shipping_address_id: new.shipping_address_id, - billing_address_id: new.billing_address_id, - statement_descriptor_name: new.statement_descriptor_name, - statement_descriptor_suffix: new.statement_descriptor_suffix, - created_at: new.created_at.unwrap_or(time), - modified_at: new.modified_at.unwrap_or(time), - last_synced: new.last_synced, - setup_future_usage: new.setup_future_usage, - off_session: new.off_session, - client_secret: new.client_secret, - business_country: new.business_country, - business_label: new.business_label, - active_attempt: new.active_attempt, - order_details: new.order_details, - allowed_payment_method_types: new.allowed_payment_method_types, - connector_metadata: new.connector_metadata, - feature_metadata: new.feature_metadata, - attempt_count: new.attempt_count, - profile_id: new.profile_id, - merchant_decision: new.merchant_decision, - payment_link_id: new.payment_link_id, - payment_confirm_source: new.payment_confirm_source, - updated_by: storage_scheme.to_string(), - surcharge_applicable: new.surcharge_applicable, - request_incremental_authorization: new.request_incremental_authorization, - incremental_authorization_allowed: new.incremental_authorization_allowed, - authorization_count: new.authorization_count, - fingerprint_id: new.fingerprint_id, - session_expiry: new.session_expiry, - request_external_three_ds_authentication: new.request_external_three_ds_authentication, - charges: new.charges, - frm_metadata: new.frm_metadata, - }; - payment_intents.push(payment_intent.clone()); - Ok(payment_intent) + payment_intents.push(new.clone()); + Ok(new) } // safety: only used for testing @@ -126,7 +77,7 @@ impl PaymentIntentInterface for MockDb { let mut payment_intents = self.payment_intents.lock().await; let payment_intent = payment_intents .iter_mut() - .find(|item| item.id == this.id) + .find(|item| item.payment_id == this.payment_id && item.merchant_id == this.merchant_id) .unwrap(); *payment_intent = PaymentIntent::from_storage_model( update diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index f40a9c3e2d4d..e1cb5af00359 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -4,7 +4,7 @@ use api_models::payments::AmountFilter; use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl}; #[cfg(feature = "olap")] use common_utils::errors::ReportSwitchExt; -use common_utils::{date_time, ext_traits::Encode}; +use common_utils::ext_traits::Encode; #[cfg(feature = "olap")] use diesel::{associations::HasTable, ExpressionMethods, JoinOnDsl, QueryDsl}; use diesel_models::{ @@ -24,7 +24,9 @@ use diesel_models::{ use error_stack::ResultExt; #[cfg(feature = "olap")] use hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints; + use hyperswitch_domain_models::{ + behaviour::Conversion, errors::StorageError, payments::{ payment_attempt::PaymentAttempt, @@ -52,12 +54,12 @@ use crate::{ impl PaymentIntentInterface for KVRouterStore { async fn insert_payment_intent( &self, - new: PaymentIntentNew, + payment_intent: PaymentIntent, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { - let merchant_id = new.merchant_id.clone(); - let payment_id = new.payment_id.clone(); - let field = format!("pi_{}", new.payment_id); + let merchant_id = payment_intent.merchant_id.clone(); + let payment_id = payment_intent.payment_id.clone(); + let field = format!("pi_{}", payment_intent.payment_id); let key = PartitionKey::MerchantIdPaymentId { merchant_id: &merchant_id, payment_id: &payment_id, @@ -67,70 +69,35 @@ impl PaymentIntentInterface for KVRouterStore { match storage_scheme { MerchantStorageScheme::PostgresOnly => { self.router_store - .insert_payment_intent(new, storage_scheme) + .insert_payment_intent(payment_intent, storage_scheme) .await } MerchantStorageScheme::RedisKv => { let key_str = key.to_string(); - let created_intent = PaymentIntent { - id: 0i32, - payment_id: new.payment_id.clone(), - merchant_id: new.merchant_id.clone(), - status: new.status, - amount: new.amount, - currency: new.currency, - amount_captured: new.amount_captured, - customer_id: new.customer_id.clone(), - description: new.description.clone(), - return_url: new.return_url.clone(), - metadata: new.metadata.clone(), - frm_metadata: new.frm_metadata.clone(), - connector_id: new.connector_id.clone(), - shipping_address_id: new.shipping_address_id.clone(), - billing_address_id: new.billing_address_id.clone(), - statement_descriptor_name: new.statement_descriptor_name.clone(), - statement_descriptor_suffix: new.statement_descriptor_suffix.clone(), - created_at: new.created_at.unwrap_or_else(date_time::now), - modified_at: new.created_at.unwrap_or_else(date_time::now), - last_synced: new.last_synced, - setup_future_usage: new.setup_future_usage, - off_session: new.off_session, - client_secret: new.client_secret.clone(), - business_country: new.business_country, - business_label: new.business_label.clone(), - active_attempt: new.active_attempt.clone(), - order_details: new.order_details.clone(), - allowed_payment_method_types: new.allowed_payment_method_types.clone(), - connector_metadata: new.connector_metadata.clone(), - feature_metadata: new.feature_metadata.clone(), - attempt_count: new.attempt_count, - profile_id: new.profile_id.clone(), - merchant_decision: new.merchant_decision.clone(), - payment_link_id: new.payment_link_id.clone(), - payment_confirm_source: new.payment_confirm_source, - updated_by: storage_scheme.to_string(), - surcharge_applicable: new.surcharge_applicable, - request_incremental_authorization: new.request_incremental_authorization, - incremental_authorization_allowed: new.incremental_authorization_allowed, - authorization_count: new.authorization_count, - fingerprint_id: new.fingerprint_id.clone(), - session_expiry: new.session_expiry, - request_external_three_ds_authentication: new - .request_external_three_ds_authentication, - charges: new.charges.clone(), - }; + let new_payment_intent = payment_intent + .clone() + .construct_new() + .await + .change_context(StorageError::EncryptionError)?; + let redis_entry = kv::TypedSql { op: kv::DBOperation::Insert { - insertable: kv::Insertable::PaymentIntent(new.to_storage_model()), + insertable: kv::Insertable::PaymentIntent(new_payment_intent), }, }; + let diesel_payment_intent = payment_intent + .clone() + .convert() + .await + .change_context(StorageError::EncryptionError)?; + match kv_wrapper::( self, KvOperation::::HSetNx( &field, - &created_intent.clone().to_storage_model(), + &diesel_payment_intent, redis_entry, ), key, @@ -144,7 +111,7 @@ impl PaymentIntentInterface for KVRouterStore { key: Some(key_str), } .into()), - Ok(HsetnxReply::KeySet) => Ok(created_intent), + Ok(HsetnxReply::KeySet) => Ok(payment_intent), Err(error) => Err(error.change_context(StorageError::KVError)), } } @@ -352,11 +319,14 @@ impl PaymentIntentInterface for crate::RouterStore { #[instrument(skip_all)] async fn insert_payment_intent( &self, - new: PaymentIntentNew, + payment_intent: PaymentIntent, _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let conn = pg_connection_write(self).await?; - new.to_storage_model() + payment_intent + .construct_new() + .await + .change_context(StorageError::EncryptionError)? .insert(&conn) .await .map_err(|er| { @@ -909,7 +879,6 @@ impl DataModelExt for PaymentIntent { fn to_storage_model(self) -> Self::StorageModel { DieselPaymentIntent { - id: self.id, payment_id: self.payment_id, merchant_id: self.merchant_id, status: self.status, @@ -958,7 +927,6 @@ impl DataModelExt for PaymentIntent { fn from_storage_model(storage_model: Self::StorageModel) -> Self { Self { - id: storage_model.id, payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, status: storage_model.status, diff --git a/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql index d9a93fe9a1a1..899b595105fa 100644 --- a/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql +++ b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql @@ -1 +1,16 @@ -- This file should undo anything in `up.sql` +ALTER TABLE payment_attempt +ALTER COLUMN id +SET NOT NULL: +ALTER TABLE payment_attempt DROP payment_attempt_pkey; + +ALTER TABLE payment_attempt +ADD PRIMARY KEY (id); + +ALTER TABLE payment_intent +ALTER COLUMN id +SET NOT NULL: +ALTER TABLE payment_intent DROP payment_intent_pkey; + +ALTER TABLE payment_intent +ADD PRIMARY KEY (id); diff --git a/migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql b/migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql index d9a93fe9a1a1..5b704469b9cc 100644 --- a/migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql +++ b/migrations/2024-06-03-133421_remove_id_from_payment_table/down.sql @@ -1 +1,6 @@ -- This file should undo anything in `up.sql` +ALTER TABLE payment_intent +ADD id SERIAL; + +ALTER TABLE payment_attempt +ADD id SERIAL; From b4039d9634d0e8fc3496dde7dae25b1b4479daf9 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Thu, 6 Jun 2024 19:19:00 +0530 Subject: [PATCH 03/12] implement encryption for find and update --- Cargo.lock | 2 + crates/common_utils/Cargo.toml | 10 +- crates/common_utils/src/lib.rs | 2 + crates/common_utils/src/metrics.rs | 2 + crates/common_utils/src/metrics/utils.rs | 32 ++ crates/diesel_models/src/payment_intent.rs | 12 +- crates/hyperswitch_domain_models/Cargo.toml | 9 +- crates/hyperswitch_domain_models/src/lib.rs | 2 + .../src/merchant_key_store.rs | 57 +++ .../src/payments/payment_intent.rs | 248 ++++++++++ .../src/type_encryption.rs | 237 +++++++++ .../compatibility/stripe/payment_intents.rs | 4 +- crates/router/src/core/blocklist/utils.rs | 2 + crates/router/src/core/cards_info.rs | 2 + crates/router/src/core/disputes.rs | 2 + crates/router/src/core/files/helpers.rs | 1 + crates/router/src/core/fraud_check.rs | 6 +- .../router/src/core/fraud_check/operation.rs | 1 + .../fraud_check/operation/fraud_check_post.rs | 2 + .../fraud_check/operation/fraud_check_pre.rs | 1 + crates/router/src/core/mandate.rs | 10 +- crates/router/src/core/mandate/helpers.rs | 2 + crates/router/src/core/payment_link.rs | 4 + .../router/src/core/payment_methods/cards.rs | 17 +- crates/router/src/core/payments.rs | 33 +- crates/router/src/core/payments/helpers.rs | 7 + crates/router/src/core/payments/operations.rs | 6 + .../payments/operations/payment_approve.rs | 10 +- .../payments/operations/payment_cancel.rs | 10 +- .../payments/operations/payment_capture.rs | 7 +- .../operations/payment_complete_authorize.rs | 17 +- .../payments/operations/payment_confirm.rs | 13 +- .../payments/operations/payment_create.rs | 6 +- .../payments/operations/payment_reject.rs | 10 +- .../payments/operations/payment_response.rs | 27 +- .../payments/operations/payment_session.rs | 11 +- .../core/payments/operations/payment_start.rs | 8 +- .../payments/operations/payment_status.rs | 22 +- .../payments/operations/payment_update.rs | 11 +- .../payments_incremental_authorization.rs | 13 +- crates/router/src/core/payments/retry.rs | 3 + crates/router/src/core/pm_auth.rs | 2 + crates/router/src/core/refunds.rs | 3 + crates/router/src/db/kafka_store.rs | 27 +- crates/router/src/routes/cards_info.rs | 4 +- crates/router/src/routes/metrics.rs | 4 - crates/router/src/routes/metrics/request.rs | 14 - crates/router/src/routes/payment_link.rs | 2 + crates/router/src/routes/payments.rs | 8 +- crates/router/src/services/api.rs | 9 +- .../src/types/domain/merchant_key_store.rs | 60 +-- crates/router/src/types/domain/types.rs | 452 +++++++++--------- crates/router/src/utils.rs | 27 +- crates/router/src/workflows/payment_sync.rs | 1 + .../src/mock_db/payment_intent.rs | 7 + .../src/payments/payment_intent.rs | 112 ++++- 56 files changed, 1209 insertions(+), 404 deletions(-) create mode 100644 crates/common_utils/src/metrics.rs create mode 100644 crates/common_utils/src/metrics/utils.rs create mode 100644 crates/hyperswitch_domain_models/src/merchant_key_store.rs create mode 100644 crates/hyperswitch_domain_models/src/type_encryption.rs diff --git a/Cargo.lock b/Cargo.lock index d814cb1e5107..cd9204f68cde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3677,10 +3677,12 @@ dependencies = [ "common_utils", "diesel_models", "error-stack", + "futures 0.3.30", "http 0.2.12", "masking", "mime", "router_derive", + "router_env", "serde", "serde_json", "serde_with", diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index def64e35db07..365bc9436629 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -8,16 +8,16 @@ readme = "README.md" license.workspace = true [features] -signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env", "dep:futures"] -async_ext = ["dep:futures", "dep:async-trait"] -logs = ["dep:router_env"] +signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio"] +async_ext = ["dep:async-trait"] +logs = [] [dependencies] async-trait = { version = "0.1.79", optional = true } bytes = "1.6.0" diesel = "2.1.5" error-stack = "0.4.1" -futures = { version = "0.3.30", optional = true } +futures = { version = "0.3.30" } hex = "0.4.3" http = "0.2.12" md5 = "0.7.0" @@ -47,7 +47,7 @@ rust_decimal = "1.35" rusty-money = { git = "https://github.com/varunsrin/rusty_money", rev = "bbc0150742a0fff905225ff11ee09388e9babdcc", features = ["iso", "crypto"] } common_enums = { version = "0.1.0", path = "../common_enums" } masking = { version = "0.1.0", path = "../masking" } -router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"], optional = true } +router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] } [target.'cfg(not(target_os = "windows"))'.dependencies] signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"], optional = true } diff --git a/crates/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs index d77442ad40f1..7272ad9c90ff 100644 --- a/crates/common_utils/src/lib.rs +++ b/crates/common_utils/src/lib.rs @@ -28,6 +28,8 @@ pub mod static_cache; pub mod types; pub mod validation; +pub mod metrics; + /// Date-time utilities. pub mod date_time { #[cfg(feature = "async_ext")] diff --git a/crates/common_utils/src/metrics.rs b/crates/common_utils/src/metrics.rs new file mode 100644 index 000000000000..36e531c8556a --- /dev/null +++ b/crates/common_utils/src/metrics.rs @@ -0,0 +1,2 @@ +//! Utilities for metrics +pub mod utils; diff --git a/crates/common_utils/src/metrics/utils.rs b/crates/common_utils/src/metrics/utils.rs new file mode 100644 index 000000000000..9a40339bb49b --- /dev/null +++ b/crates/common_utils/src/metrics/utils.rs @@ -0,0 +1,32 @@ +//! metric utility functions + +use router_env::opentelemetry; +use std::time; + +/// Record the time taken by the future to execute +#[inline] +pub async fn time_future(future: F) -> (R, time::Duration) +where + F: futures::Future, +{ + let start = time::Instant::now(); + let result = future.await; + let time_spent = start.elapsed(); + (result, time_spent) +} + +/// Record the time taken by the operation for the given context +#[inline] +pub async fn record_operation_time( + future: F, + metric: &opentelemetry::metrics::Histogram, + metric_context: &opentelemetry::Context, + key_value: &[opentelemetry::KeyValue], +) -> R +where + F: futures::Future, +{ + let (result, time) = time_future(future).await; + metric.record(metric_context, time.as_secs_f64(), key_value); + result +} diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index ecdddd8434c3..7fad83e7a0f1 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -232,10 +232,8 @@ pub struct PaymentIntentUpdateInternal { #[diesel(deserialize_as = super::OptionalDieselArray)] pub order_details: Option>, pub attempt_count: Option, - pub profile_id: Option, - merchant_decision: Option, - payment_confirm_source: Option, - + pub merchant_decision: Option, + pub payment_confirm_source: Option, pub updated_by: String, pub surcharge_applicable: Option, pub incremental_authorization_allowed: Option, @@ -243,7 +241,6 @@ pub struct PaymentIntentUpdateInternal { pub session_expiry: Option, pub fingerprint_id: Option, pub request_external_three_ds_authentication: Option, - pub charges: Option, pub frm_metadata: Option, } @@ -270,7 +267,6 @@ impl PaymentIntentUpdate { statement_descriptor_suffix, order_details, attempt_count, - profile_id, merchant_decision, payment_confirm_source, updated_by, @@ -280,7 +276,6 @@ impl PaymentIntentUpdate { session_expiry, fingerprint_id, request_external_three_ds_authentication, - charges, frm_metadata, } = self.into(); PaymentIntent { @@ -306,7 +301,6 @@ impl PaymentIntentUpdate { .or(source.statement_descriptor_suffix), order_details: order_details.or(source.order_details), attempt_count: attempt_count.unwrap_or(source.attempt_count), - profile_id: profile_id.or(source.profile_id), merchant_decision: merchant_decision.or(source.merchant_decision), payment_confirm_source: payment_confirm_source.or(source.payment_confirm_source), updated_by, @@ -319,8 +313,6 @@ impl PaymentIntentUpdate { session_expiry: session_expiry.or(source.session_expiry), request_external_three_ds_authentication: request_external_three_ds_authentication .or(source.request_external_three_ds_authentication), - charges: charges.or(source.charges), - frm_metadata: frm_metadata.or(source.frm_metadata), ..source } diff --git a/crates/hyperswitch_domain_models/Cargo.toml b/crates/hyperswitch_domain_models/Cargo.toml index c1db2a4fb995..a64770f3eeaa 100644 --- a/crates/hyperswitch_domain_models/Cargo.toml +++ b/crates/hyperswitch_domain_models/Cargo.toml @@ -16,11 +16,12 @@ payouts = ["api_models/payouts"] # First party deps api_models = { version = "0.1.0", path = "../api_models", features = ["errors"] } common_enums = { version = "0.1.0", path = "../common_enums" } -common_utils = { version = "0.1.0", path = "../common_utils" } +common_utils = { version = "0.1.0", path = "../common_utils", features = ["async_ext"] } masking = { version = "0.1.0", path = "../masking" } diesel_models = { version = "0.1.0", path = "../diesel_models", features = ["kv_store"] } -cards = {version = "0.1.0", path = "../cards"} -router_derive = {version = "0.1.0", path = "../router_derive"} +cards = { version = "0.1.0", path = "../cards" } +router_derive = { version = "0.1.0", path = "../router_derive" } +router_env = { version = "0.1.0", path = "../router_env" } # Third party deps actix-web = "4.5.1" @@ -35,4 +36,4 @@ thiserror = "1.0.58" time = { version = "0.3.35", features = ["serde", "serde-well-known", "std"] } url = { version = "2.5.0", features = ["serde"] } utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order", "time"] } - +futures = "0.3.30" diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index 45a67178204f..a98d9b5af6ec 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -11,6 +11,8 @@ pub mod router_request_types; pub mod router_response_types; pub mod behaviour; +pub mod merchant_key_store; +pub mod type_encryption; #[cfg(not(feature = "payouts"))] pub trait PayoutAttemptInterface {} diff --git a/crates/hyperswitch_domain_models/src/merchant_key_store.rs b/crates/hyperswitch_domain_models/src/merchant_key_store.rs new file mode 100644 index 000000000000..29050b7eb496 --- /dev/null +++ b/crates/hyperswitch_domain_models/src/merchant_key_store.rs @@ -0,0 +1,57 @@ +use common_utils::{ + crypto::{Encryptable, GcmAes256}, + custom_serde, date_time, + errors::{CustomResult, ValidationError}, +}; +use error_stack::ResultExt; +use masking::{PeekInterface, Secret}; +use time::PrimitiveDateTime; + +use crate::type_encryption::TypeEncryption; + +#[derive(Clone, Debug, serde::Serialize)] +pub struct MerchantKeyStore { + pub merchant_id: String, + pub key: Encryptable>>, + #[serde(with = "custom_serde::iso8601")] + pub created_at: PrimitiveDateTime, +} + +#[async_trait::async_trait] +impl super::behaviour::Conversion for MerchantKeyStore { + type DstType = diesel_models::merchant_key_store::MerchantKeyStore; + type NewDstType = diesel_models::merchant_key_store::MerchantKeyStoreNew; + async fn convert(self) -> CustomResult { + Ok(diesel_models::merchant_key_store::MerchantKeyStore { + key: self.key.into(), + merchant_id: self.merchant_id, + created_at: self.created_at, + }) + } + + async fn convert_back( + item: Self::DstType, + key: &Secret>, + ) -> CustomResult + where + Self: Sized, + { + Ok(Self { + key: Encryptable::decrypt(item.key, key.peek(), GcmAes256) + .await + .change_context(ValidationError::InvalidValue { + message: "Failed while decrypting customer data".to_string(), + })?, + merchant_id: item.merchant_id, + created_at: item.created_at, + }) + } + + async fn construct_new(self) -> CustomResult { + Ok(diesel_models::merchant_key_store::MerchantKeyStoreNew { + merchant_id: self.merchant_id, + key: self.key.into(), + created_at: date_time::now(), + }) + } +} diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index e23c92508a15..a7350c5fa28b 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -1,3 +1,4 @@ +use crate::merchant_key_store::MerchantKeyStore; use common_enums as storage_enums; use common_utils::{ consts::{PAYMENTS_LIST_MAX_LIMIT_V1, PAYMENTS_LIST_MAX_LIMIT_V2}, @@ -15,12 +16,14 @@ pub trait PaymentIntentInterface { &self, this: PaymentIntent, payment_intent: PaymentIntentUpdate, + merchant_key_store: &MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; async fn insert_payment_intent( &self, new: PaymentIntent, + merchant_key_store: &MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; @@ -28,6 +31,7 @@ pub trait PaymentIntentInterface { &self, payment_id: &str, merchant_id: &str, + merchant_key_store: &MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; @@ -42,6 +46,7 @@ pub trait PaymentIntentInterface { &self, merchant_id: &str, filters: &PaymentIntentFetchConstraints, + merchant_key_store: &MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, errors::StorageError>; @@ -50,6 +55,7 @@ pub trait PaymentIntentInterface { &self, merchant_id: &str, time_range: &api_models::payments::TimeRange, + merchant_key_store: &MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, errors::StorageError>; @@ -58,6 +64,7 @@ pub trait PaymentIntentInterface { &self, merchant_id: &str, constraints: &PaymentIntentFetchConstraints, + merchant_key_store: &MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, errors::StorageError>; @@ -440,6 +447,247 @@ impl From for PaymentIntentUpdateInternal { } } +use diesel_models::PaymentIntentUpdate as DieselPaymentIntentUpdate; + +impl From for DieselPaymentIntentUpdate { + fn from(value: PaymentIntentUpdate) -> Self { + match value { + PaymentIntentUpdate::ResponseUpdate { + status, + amount_captured, + fingerprint_id, + return_url, + updated_by, + incremental_authorization_allowed, + } => DieselPaymentIntentUpdate::ResponseUpdate { + status, + amount_captured, + fingerprint_id, + return_url, + updated_by, + incremental_authorization_allowed, + }, + PaymentIntentUpdate::MetadataUpdate { + metadata, + updated_by, + } => DieselPaymentIntentUpdate::MetadataUpdate { + metadata, + updated_by, + }, + PaymentIntentUpdate::ReturnUrlUpdate { + return_url, + status, + customer_id, + shipping_address_id, + billing_address_id, + updated_by, + } => DieselPaymentIntentUpdate::ReturnUrlUpdate { + return_url, + status, + customer_id, + shipping_address_id, + billing_address_id, + updated_by, + }, + PaymentIntentUpdate::MerchantStatusUpdate { + status, + shipping_address_id, + billing_address_id, + updated_by, + } => DieselPaymentIntentUpdate::MerchantStatusUpdate { + status, + shipping_address_id, + billing_address_id, + updated_by, + }, + PaymentIntentUpdate::PGStatusUpdate { + status, + updated_by, + incremental_authorization_allowed, + } => DieselPaymentIntentUpdate::PGStatusUpdate { + status, + updated_by, + incremental_authorization_allowed, + }, + PaymentIntentUpdate::Update { + amount, + currency, + setup_future_usage, + status, + customer_id, + shipping_address_id, + billing_address_id, + return_url, + business_country, + business_label, + description, + statement_descriptor_name, + statement_descriptor_suffix, + order_details, + metadata, + payment_confirm_source, + updated_by, + fingerprint_id, + session_expiry, + request_external_three_ds_authentication, + frm_metadata, + } => DieselPaymentIntentUpdate::Update { + amount, + currency, + setup_future_usage, + status, + customer_id, + shipping_address_id, + billing_address_id, + return_url, + business_country, + business_label, + description, + statement_descriptor_name, + statement_descriptor_suffix, + order_details, + metadata, + payment_confirm_source, + updated_by, + fingerprint_id, + session_expiry, + request_external_three_ds_authentication, + frm_metadata, + }, + PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { + active_attempt_id, + attempt_count, + updated_by, + } => DieselPaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { + active_attempt_id, + attempt_count, + updated_by, + }, + PaymentIntentUpdate::StatusAndAttemptUpdate { + status, + active_attempt_id, + attempt_count, + updated_by, + } => DieselPaymentIntentUpdate::StatusAndAttemptUpdate { + status, + active_attempt_id, + attempt_count, + updated_by, + }, + PaymentIntentUpdate::ApproveUpdate { + status, + merchant_decision, + updated_by, + } => DieselPaymentIntentUpdate::ApproveUpdate { + status, + merchant_decision, + updated_by, + }, + PaymentIntentUpdate::RejectUpdate { + status, + merchant_decision, + updated_by, + } => DieselPaymentIntentUpdate::RejectUpdate { + status, + merchant_decision, + updated_by, + }, + PaymentIntentUpdate::SurchargeApplicableUpdate { + surcharge_applicable, + updated_by, + } => DieselPaymentIntentUpdate::SurchargeApplicableUpdate { + surcharge_applicable: Some(surcharge_applicable), + updated_by, + }, + PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => { + DieselPaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } + } + PaymentIntentUpdate::AuthorizationCountUpdate { + authorization_count, + } => DieselPaymentIntentUpdate::AuthorizationCountUpdate { + authorization_count, + }, + PaymentIntentUpdate::CompleteAuthorizeUpdate { + shipping_address_id, + } => DieselPaymentIntentUpdate::CompleteAuthorizeUpdate { + shipping_address_id, + }, + } + } +} + +impl From for diesel_models::PaymentIntentUpdateInternal { + fn from(value: PaymentIntentUpdateInternal) -> Self { + let modified_at = Some(common_utils::date_time::now()); + + let PaymentIntentUpdateInternal { + amount, + currency, + status, + amount_captured, + customer_id, + return_url, + setup_future_usage, + off_session, + metadata, + billing_address_id, + shipping_address_id, + modified_at: _, + active_attempt_id, + business_country, + business_label, + description, + statement_descriptor_name, + statement_descriptor_suffix, + order_details, + attempt_count, + merchant_decision, + payment_confirm_source, + updated_by, + surcharge_applicable, + incremental_authorization_allowed, + authorization_count, + session_expiry, + fingerprint_id, + request_external_three_ds_authentication, + frm_metadata, + } = value; + + Self { + amount, + currency, + status, + amount_captured, + customer_id, + return_url, + setup_future_usage, + off_session, + metadata, + billing_address_id, + shipping_address_id, + modified_at, + active_attempt_id, + business_country, + business_label, + description, + statement_descriptor_name, + statement_descriptor_suffix, + order_details, + attempt_count, + merchant_decision, + payment_confirm_source, + updated_by, + surcharge_applicable, + incremental_authorization_allowed, + authorization_count, + session_expiry, + fingerprint_id, + request_external_three_ds_authentication, + frm_metadata, + } + } +} + pub enum PaymentIntentFetchConstraints { Single { payment_intent_id: String }, List(Box), diff --git a/crates/hyperswitch_domain_models/src/type_encryption.rs b/crates/hyperswitch_domain_models/src/type_encryption.rs new file mode 100644 index 000000000000..82d904ccf49f --- /dev/null +++ b/crates/hyperswitch_domain_models/src/type_encryption.rs @@ -0,0 +1,237 @@ +use async_trait::async_trait; +use common_utils::{ + crypto, + errors::{self, CustomResult}, + ext_traits::AsyncExt, + metrics::utils::record_operation_time, +}; +use diesel_models::encryption::Encryption; +use error_stack::ResultExt; +use masking::{PeekInterface, Secret}; +use router_env::{instrument, tracing}; + +#[async_trait] +pub trait TypeEncryption< + T, + V: crypto::EncodeMessage + crypto::DecodeMessage, + S: masking::Strategy, +>: Sized +{ + async fn encrypt( + masked_data: Secret, + key: &[u8], + crypt_algo: V, + ) -> CustomResult; + + async fn decrypt( + encrypted_data: Encryption, + key: &[u8], + crypt_algo: V, + ) -> CustomResult; +} + +#[async_trait] +impl< + V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, + S: masking::Strategy + Send, + > TypeEncryption for crypto::Encryptable> +{ + #[instrument(skip_all)] + async fn encrypt( + masked_data: Secret, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let encrypted_data = crypt_algo.encode_message(key, masked_data.peek().as_bytes())?; + + Ok(Self::new(masked_data, encrypted_data.into())) + } + + #[instrument(skip_all)] + async fn decrypt( + encrypted_data: Encryption, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let encrypted = encrypted_data.into_inner(); + let data = crypt_algo.decode_message(key, encrypted.clone())?; + + let value: String = std::str::from_utf8(&data) + .change_context(errors::CryptoError::DecodingFailed)? + .to_string(); + + Ok(Self::new(value.into(), encrypted)) + } +} + +#[async_trait] +impl< + V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, + S: masking::Strategy + Send, + > TypeEncryption + for crypto::Encryptable> +{ + #[instrument(skip_all)] + async fn encrypt( + masked_data: Secret, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let data = serde_json::to_vec(&masked_data.peek()) + .change_context(errors::CryptoError::DecodingFailed)?; + let encrypted_data = crypt_algo.encode_message(key, &data)?; + + Ok(Self::new(masked_data, encrypted_data.into())) + } + + #[instrument(skip_all)] + async fn decrypt( + encrypted_data: Encryption, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let encrypted = encrypted_data.into_inner(); + let data = crypt_algo.decode_message(key, encrypted.clone())?; + + let value: serde_json::Value = + serde_json::from_slice(&data).change_context(errors::CryptoError::DecodingFailed)?; + + Ok(Self::new(value.into(), encrypted)) + } +} + +#[async_trait] +impl< + V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, + S: masking::Strategy> + Send, + > TypeEncryption, V, S> for crypto::Encryptable, S>> +{ + #[instrument(skip_all)] + async fn encrypt( + masked_data: Secret, S>, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let encrypted_data = crypt_algo.encode_message(key, masked_data.peek())?; + + Ok(Self::new(masked_data, encrypted_data.into())) + } + + #[instrument(skip_all)] + async fn decrypt( + encrypted_data: Encryption, + key: &[u8], + crypt_algo: V, + ) -> CustomResult { + let encrypted = encrypted_data.into_inner(); + let data = crypt_algo.decode_message(key, encrypted.clone())?; + + Ok(Self::new(data.into(), encrypted)) + } +} + +pub trait Lift { + type SelfWrapper; + type OtherWrapper; + + fn lift(self, func: Func) -> Self::OtherWrapper + where + Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper; +} + +impl Lift for Option { + type SelfWrapper = Option; + type OtherWrapper = CustomResult, E>; + + fn lift(self, func: Func) -> Self::OtherWrapper + where + Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper, + { + func(self) + } +} + +#[async_trait] +pub trait AsyncLift { + type SelfWrapper; + type OtherWrapper; + + async fn async_lift(self, func: Func) -> Self::OtherWrapper + where + Func: Fn(Self::SelfWrapper) -> F + Send + Sync, + F: futures::Future> + Send; +} + +#[async_trait] +impl + Lift = V> + Send> AsyncLift for V { + type SelfWrapper = >::SelfWrapper; + type OtherWrapper = >::OtherWrapper; + + async fn async_lift(self, func: Func) -> Self::OtherWrapper + where + Func: Fn(Self::SelfWrapper) -> F + Send + Sync, + F: futures::Future> + Send, + { + func(self).await + } +} + +#[inline] +pub async fn encrypt( + inner: Secret, + key: &[u8], +) -> CustomResult>, errors::CryptoError> +where + S: masking::Strategy, + crypto::Encryptable>: TypeEncryption, +{ + record_operation_time( + crypto::Encryptable::encrypt(inner, key, crypto::GcmAes256), + &metrics::ENCRYPTION_TIME, + &metrics::CONTEXT, + &[], + ) + .await +} + +#[inline] +pub async fn encrypt_optional( + inner: Option>, + key: &[u8], +) -> CustomResult>>, errors::CryptoError> +where + Secret: Send, + S: masking::Strategy, + crypto::Encryptable>: TypeEncryption, +{ + inner.async_map(|f| encrypt(f, key)).await.transpose() +} + +#[inline] +pub async fn decrypt>( + inner: Option, + key: &[u8], +) -> CustomResult>>, errors::CryptoError> +where + crypto::Encryptable>: TypeEncryption, +{ + record_operation_time( + inner.async_map(|item| crypto::Encryptable::decrypt(item, key, crypto::GcmAes256)), + &metrics::DECRYPTION_TIME, + &metrics::CONTEXT, + &[], + ) + .await + .transpose() +} + +pub(crate) mod metrics { + use router_env::{global_meter, histogram_metric, metrics_context, once_cell}; + + metrics_context!(CONTEXT); + global_meter!(GLOBAL_METER, "ROUTER_API"); + + // Encryption and Decryption metrics + histogram_metric!(ENCRYPTION_TIME, GLOBAL_METER); + histogram_metric!(DECRYPTION_TIME, GLOBAL_METER); +} diff --git a/crates/router/src/compatibility/stripe/payment_intents.rs b/crates/router/src/compatibility/stripe/payment_intents.rs index b8ef4137f9d3..79b6b0fc0085 100644 --- a/crates/router/src/compatibility/stripe/payment_intents.rs +++ b/crates/router/src/compatibility/stripe/payment_intents.rs @@ -497,7 +497,9 @@ pub async fn payment_intent_list( state.into_inner(), &req, payload, - |state, auth, req, _| payments::list_payments(state, auth.merchant_account, req), + |state, auth, req, _| { + payments::list_payments(state, auth.merchant_account, auth.key_store, req) + }, &auth::ApiKeyAuth, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/core/blocklist/utils.rs b/crates/router/src/core/blocklist/utils.rs index bc8724da8235..22b8469ea290 100644 --- a/crates/router/src/core/blocklist/utils.rs +++ b/crates/router/src/core/blocklist/utils.rs @@ -303,6 +303,7 @@ async fn delete_card_bin_blocklist_entry( pub async fn validate_data_for_blocklist( state: &AppState, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, payment_data: &mut PaymentData, ) -> CustomResult where @@ -407,6 +408,7 @@ where merchant_decision: Some(MerchantDecision::Rejected.to_string()), updated_by: merchant_account.storage_scheme.to_string(), }, + key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/cards_info.rs b/crates/router/src/core/cards_info.rs index 4352e1808c73..663ab250cfd4 100644 --- a/crates/router/src/core/cards_info.rs +++ b/crates/router/src/core/cards_info.rs @@ -23,6 +23,7 @@ fn verify_iin_length(card_iin: &str) -> Result<(), errors::ApiErrorResponse> { pub async fn retrieve_card_info( state: routes::AppState, merchant_account: domain::MerchantAccount, + key_store: domain::MerchantKeyStore, request: api_models::cards_info::CardsInfoRequest, ) -> RouterResponse { let db = state.store.as_ref(); @@ -31,6 +32,7 @@ pub async fn retrieve_card_info( helpers::verify_payment_intent_time_and_client_secret( db, &merchant_account, + &key_store, request.client_secret, ) .await?; diff --git a/crates/router/src/core/disputes.rs b/crates/router/src/core/disputes.rs index f608100c08a7..da1987979e04 100644 --- a/crates/router/src/core/disputes.rs +++ b/crates/router/src/core/disputes.rs @@ -91,6 +91,7 @@ pub async fn accept_dispute( .find_payment_intent_by_payment_id_merchant_id( &dispute.payment_id, &merchant_account.merchant_id, + &key_store, merchant_account.storage_scheme, ) .await @@ -204,6 +205,7 @@ pub async fn submit_evidence( .find_payment_intent_by_payment_id_merchant_id( &dispute.payment_id, &merchant_account.merchant_id, + &key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/files/helpers.rs b/crates/router/src/core/files/helpers.rs index 0c6a88d8270c..3c19ff8103e4 100644 --- a/crates/router/src/core/files/helpers.rs +++ b/crates/router/src/core/files/helpers.rs @@ -264,6 +264,7 @@ pub async fn upload_and_get_provider_provider_file_id_profile_id( .find_payment_intent_by_payment_id_merchant_id( &dispute.payment_id, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index dddcf581296f..954fdb5447a4 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -417,6 +417,7 @@ where .to_update_tracker()? .update_tracker( &*state.store, + &key_store, frm_data.clone(), payment_data, None, @@ -491,6 +492,7 @@ where .to_update_tracker()? .update_tracker( &*state.store, + &key_store, frm_data.to_owned(), payment_data, None, @@ -514,7 +516,7 @@ where merchant_account, frm_configs, &mut frm_suggestion, - key_store, + key_store.clone(), payment_data, customer, should_continue_capture, @@ -525,6 +527,7 @@ where .to_update_tracker()? .update_tracker( &*state.store, + &key_store, frm_data.to_owned(), payment_data, frm_suggestion, @@ -653,6 +656,7 @@ pub async fn frm_fulfillment_core( .find_payment_intent_by_payment_id_merchant_id( &req.payment_id.clone(), &merchant_account.merchant_id, + &key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/fraud_check/operation.rs b/crates/router/src/core/fraud_check/operation.rs index a9b95cdf3b5e..5ae3ad1a83f8 100644 --- a/crates/router/src/core/fraud_check/operation.rs +++ b/crates/router/src/core/fraud_check/operation.rs @@ -102,6 +102,7 @@ pub trait UpdateTracker: Send { async fn update_tracker<'b>( &'b self, db: &dyn StorageInterface, + key_store: &domain::MerchantKeyStore, frm_data: D, payment_data: &mut payments::PaymentData, _frm_suggestion: Option, diff --git a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs index 6a310aa131dd..af731ec3ca22 100644 --- a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs +++ b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs @@ -330,6 +330,7 @@ impl UpdateTracker for FraudCheckPost { async fn update_tracker<'b>( &'b self, db: &dyn StorageInterface, + key_store: &domain::MerchantKeyStore, mut frm_data: FrmData, payment_data: &mut payments::PaymentData, frm_suggestion: Option, @@ -520,6 +521,7 @@ impl UpdateTracker for FraudCheckPost { merchant_decision, updated_by: frm_data.merchant_account.storage_scheme.to_string(), }, + key_store, frm_data.merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs b/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs index ae316e7a1108..964e33d9b5c9 100644 --- a/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs +++ b/crates/router/src/core/fraud_check/operation/fraud_check_pre.rs @@ -219,6 +219,7 @@ impl UpdateTracker for FraudCheckPre { async fn update_tracker<'b>( &'b self, db: &dyn StorageInterface, + _key_store: &domain::MerchantKeyStore, mut frm_data: FrmData, payment_data: &mut payments::PaymentData, _frm_suggestion: Option, diff --git a/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs index 839f55dea2db..79bf41a6c915 100644 --- a/crates/router/src/core/mandate.rs +++ b/crates/router/src/core/mandate.rs @@ -78,9 +78,13 @@ pub async fn revoke_mandate( common_enums::MandateStatus::Active | common_enums::MandateStatus::Inactive | common_enums::MandateStatus::Pending => { - let profile_id = - helpers::get_profile_id_for_mandate(&state, &merchant_account, mandate.clone()) - .await?; + let profile_id = helpers::get_profile_id_for_mandate( + &state, + &merchant_account, + &key_store, + mandate.clone(), + ) + .await?; let merchant_connector_account = payment_helper::get_merchant_connector_account( &state, diff --git a/crates/router/src/core/mandate/helpers.rs b/crates/router/src/core/mandate/helpers.rs index 4e9d07b7f828..375c879097fa 100644 --- a/crates/router/src/core/mandate/helpers.rs +++ b/crates/router/src/core/mandate/helpers.rs @@ -14,6 +14,7 @@ use crate::{ pub async fn get_profile_id_for_mandate( state: &AppState, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, mandate: Mandate, ) -> CustomResult { let profile_id = if let Some(ref payment_id) = mandate.original_payment_id { @@ -22,6 +23,7 @@ pub async fn get_profile_id_for_mandate( .find_payment_intent_by_payment_id_merchant_id( payment_id, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/payment_link.rs b/crates/router/src/core/payment_link.rs index 9b8fd3cbe0ef..89c044be738e 100644 --- a/crates/router/src/core/payment_link.rs +++ b/crates/router/src/core/payment_link.rs @@ -49,6 +49,7 @@ pub async fn retrieve_payment_link( pub async fn initiate_payment_link_flow( state: AppState, merchant_account: domain::MerchantAccount, + key_store: domain::MerchantKeyStore, merchant_id: String, payment_id: String, ) -> RouterResponse { @@ -57,6 +58,7 @@ pub async fn initiate_payment_link_flow( .find_payment_intent_by_payment_id_merchant_id( &payment_id, &merchant_id, + &key_store, merchant_account.storage_scheme, ) .await @@ -503,6 +505,7 @@ fn check_payment_link_invalid_conditions( pub async fn get_payment_link_status( state: AppState, merchant_account: domain::MerchantAccount, + key_store: domain::MerchantKeyStore, merchant_id: String, payment_id: String, ) -> RouterResponse { @@ -511,6 +514,7 @@ pub async fn get_payment_link_status( .find_payment_intent_by_payment_id_merchant_id( &payment_id, &merchant_id, + &key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 66a695b2b0c5..360c3d2924a9 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -1096,7 +1096,7 @@ pub async fn add_card_to_locker( errors::VaultError, > { metrics::STORED_TO_LOCKER.add(&metrics::CONTEXT, 1, &[]); - let add_card_to_hs_resp = request::record_operation_time( + let add_card_to_hs_resp = common_utils::metrics::utils::record_operation_time( async { add_card_hs( state, @@ -1121,6 +1121,7 @@ pub async fn add_card_to_locker( }) }, &metrics::CARD_ADD_TIME, + &metrics::CONTEXT, &[router_env::opentelemetry::KeyValue::new("locker", "rust")], ) .await?; @@ -1137,7 +1138,7 @@ pub async fn get_card_from_locker( ) -> errors::RouterResult { metrics::GET_FROM_LOCKER.add(&metrics::CONTEXT, 1, &[]); - let get_card_from_rs_locker_resp = request::record_operation_time( + let get_card_from_rs_locker_resp = common_utils::metrics::utils::record_operation_time( async { get_card_from_hs_locker( state, @@ -1162,6 +1163,7 @@ pub async fn get_card_from_locker( }) }, &metrics::CARD_GET_TIME, + &metrics::CONTEXT, &[router_env::opentelemetry::KeyValue::new("locker", "rust")], ) .await?; @@ -1178,7 +1180,7 @@ pub async fn delete_card_from_locker( ) -> errors::RouterResult { metrics::DELETE_FROM_LOCKER.add(&metrics::CONTEXT, 1, &[]); - request::record_operation_time( + common_utils::metrics::utils::record_operation_time( async move { delete_card_from_hs_locker(state, customer_id, merchant_id, card_reference) .await @@ -1188,6 +1190,7 @@ pub async fn delete_card_from_locker( }) }, &metrics::CARD_DELETE_TIME, + &metrics::CONTEXT, &[], ) .await @@ -1750,6 +1753,7 @@ pub async fn list_payment_methods( helpers::verify_payment_intent_time_and_client_secret( db, &merchant_account, + &key_store, req.client_secret.clone(), ) .await? @@ -2582,6 +2586,7 @@ pub async fn list_payment_methods( Box::pin(call_surcharge_decision_management( state, &merchant_account, + &key_store, &business_profile, payment_attempt, payment_intent, @@ -2662,6 +2667,7 @@ async fn validate_payment_method_and_client_secret( pub async fn call_surcharge_decision_management( state: routes::AppState, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, business_profile: &BusinessProfile, payment_attempt: &storage::PaymentAttempt, payment_intent: storage::PaymentIntent, @@ -2700,6 +2706,7 @@ pub async fn call_surcharge_decision_management( surcharge_applicable: true, updated_by: merchant_account.storage_scheme.to_string(), }, + key_store, merchant_account.storage_scheme, ) .await @@ -2712,6 +2719,7 @@ pub async fn call_surcharge_decision_management( pub async fn call_surcharge_decision_management_for_saved_card( state: &routes::AppState, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, business_profile: &BusinessProfile, payment_attempt: &storage::PaymentAttempt, payment_intent: storage::PaymentIntent, @@ -2747,6 +2755,7 @@ pub async fn call_surcharge_decision_management_for_saved_card( surcharge_applicable: true, updated_by: merchant_account.storage_scheme.to_string(), }, + key_store, merchant_account.storage_scheme, ) .await @@ -3338,6 +3347,7 @@ pub async fn do_list_customer_pm_fetch_customer_if_not_passed( helpers::verify_payment_intent_time_and_client_secret( db, &merchant_account, + &key_store, cloned_secret, ) .await?; @@ -3673,6 +3683,7 @@ pub async fn list_customer_payment_method( call_surcharge_decision_management_for_saved_card( state, &merchant_account, + &key_store, &business_profile, &payment_attempt, payment_intent, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 7bc0b532239e..6db1f22c6339 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -330,6 +330,7 @@ where &validate_result.payment_id, payment_data, router_data, + &key_store, merchant_account.storage_scheme, ) .await? @@ -434,6 +435,7 @@ where &validate_result.payment_id, payment_data, router_data, + &key_store, merchant_account.storage_scheme, ) .await? @@ -1161,6 +1163,7 @@ impl PaymentRedirectFlow for PaymentAuthenticateCompleteAuthorize { .find_payment_intent_by_payment_id_merchant_id( &payment_id, &merchant_id, + &merchant_key_store, merchant_account.storage_scheme, ) .await @@ -1440,7 +1443,7 @@ where *payment_data = pd; // Validating the blocklist guard and generate the fingerprint - blocklist_guard(state, merchant_account, operation, payment_data).await?; + blocklist_guard(state, merchant_account, key_store, operation, payment_data).await?; let updated_customer = call_create_connector_customer_if_required( state, @@ -1615,6 +1618,7 @@ where async fn blocklist_guard( state: &AppState, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, operation: &BoxedOperation<'_, F, ApiRequest>, payment_data: &mut PaymentData, ) -> CustomResult @@ -1643,7 +1647,7 @@ where if blocklist_guard_enabled { Ok(operation .to_domain()? - .guard_payment_against_blocklist(state, merchant_account, payment_data) + .guard_payment_against_blocklist(state, merchant_account, key_store, payment_data) .await?) } else { Ok(false) @@ -2610,16 +2614,22 @@ pub fn is_operation_complete_authorize(operation: &Op) -> bool { pub async fn list_payments( state: AppState, merchant: domain::MerchantAccount, + key_store: domain::MerchantKeyStore, constraints: api::PaymentListConstraints, ) -> RouterResponse { use hyperswitch_domain_models::errors::StorageError; helpers::validate_payment_list_request(&constraints)?; let merchant_id = &merchant.merchant_id; let db = state.store.as_ref(); - let payment_intents = - helpers::filter_by_constraints(db, &constraints, merchant_id, merchant.storage_scheme) - .await - .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; + let payment_intents = helpers::filter_by_constraints( + db, + &constraints, + merchant_id, + &key_store, + merchant.storage_scheme, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; let collected_futures = payment_intents.into_iter().map(|pi| { async { @@ -2676,6 +2686,7 @@ pub async fn list_payments( pub async fn apply_filters_on_payments( state: AppState, merchant: domain::MerchantAccount, + merchant_key_store: domain::MerchantKeyStore, constraints: api::PaymentListFilterConstraints, ) -> RouterResponse { let limit = &constraints.limit; @@ -2685,6 +2696,7 @@ pub async fn apply_filters_on_payments( .get_filtered_payment_intents_attempt( &merchant.merchant_id, &constraints.clone().into(), + &merchant_key_store, merchant.storage_scheme, ) .await @@ -2729,6 +2741,7 @@ pub async fn apply_filters_on_payments( pub async fn get_filters_for_payments( state: AppState, merchant: domain::MerchantAccount, + merchant_key_store: domain::MerchantKeyStore, time_range: api::TimeRange, ) -> RouterResponse { let db = state.store.as_ref(); @@ -2736,6 +2749,7 @@ pub async fn get_filters_for_payments( .filter_payment_intents_by_time_range_constraints( &merchant.merchant_id, &time_range, + &merchant_key_store, merchant.storage_scheme, ) .await @@ -3777,7 +3791,12 @@ pub async fn payment_external_authentication( let storage_scheme = merchant_account.storage_scheme; let payment_id = req.payment_id; let payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + &key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; let attempt_id = payment_intent.active_attempt.get_id().clone(); diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 0bc8697eed8b..fe3fae08671a 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -603,6 +603,7 @@ pub async fn get_token_for_recurring_mandate( db.find_payment_intent_by_payment_id_merchant_id( payment_id, &mandate.merchant_id, + &merchant_key_store, merchant_account.storage_scheme, ) .await @@ -2411,12 +2412,14 @@ pub(super) async fn filter_by_constraints( db: &dyn StorageInterface, constraints: &api::PaymentListConstraints, merchant_id: &str, + key_store: &domain::MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult, errors::DataStorageError> { let result = db .filter_payment_intent_by_constraints( merchant_id, &constraints.clone().into(), + key_store, storage_scheme, ) .await?; @@ -2832,6 +2835,7 @@ pub(crate) fn validate_pm_or_token_given( pub async fn verify_payment_intent_time_and_client_secret( db: &dyn StorageInterface, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, client_secret: Option, ) -> error_stack::Result, errors::ApiErrorResponse> { client_secret @@ -2842,6 +2846,7 @@ pub async fn verify_payment_intent_time_and_client_secret( .find_payment_intent_by_payment_id_merchant_id( &payment_id, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await @@ -3588,6 +3593,7 @@ impl AttemptType { fetched_payment_intent: PaymentIntent, fetched_payment_attempt: PaymentAttempt, db: &dyn StorageInterface, + key_store: &domain::MerchantKeyStore, storage_scheme: storage::enums::MerchantStorageScheme, ) -> RouterResult<(PaymentIntent, PaymentAttempt)> { match self { @@ -3629,6 +3635,7 @@ impl AttemptType { attempt_count: new_attempt_count, updated_by: storage_scheme.to_string(), }, + key_store, storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 35fc2897ea48..36e192116c5d 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -183,6 +183,7 @@ pub trait Domain: Send + Sync { &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -226,6 +227,7 @@ pub trait PostUpdateTracker: Send { payment_id: &api::PaymentIdType, payment_data: D, response: types::RouterData, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult where @@ -322,6 +324,7 @@ where &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -394,6 +397,7 @@ where &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -467,6 +471,7 @@ where &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -529,6 +534,7 @@ where &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index 52325db753a6..0a4b80026171 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -52,7 +52,12 @@ impl GetTracker, api::PaymentsCaptureRequest> .change_context(errors::ApiErrorResponse::PaymentNotFound)?; payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; @@ -200,7 +205,7 @@ impl UpdateTracker, api::PaymentsCaptureRequest> for _customer: Option, storage_scheme: storage_enums::MerchantStorageScheme, _updated_customer: Option, - _merchant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, frm_suggestion: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<( @@ -224,6 +229,7 @@ impl UpdateTracker, api::PaymentsCaptureRequest> for .update_payment_intent( payment_data.payment_intent, intent_status_update, + key_store, storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index 64114fc40e65..dc6c8e26dd5c 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -50,7 +50,12 @@ impl GetTracker, api::PaymentsCancelRequest> .change_context(errors::ApiErrorResponse::PaymentNotFound)?; let payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; @@ -213,7 +218,7 @@ impl UpdateTracker, api::PaymentsCancelRequest> for _customer: Option, storage_scheme: enums::MerchantStorageScheme, _updated_customer: Option, - _mechant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<( @@ -242,6 +247,7 @@ impl UpdateTracker, api::PaymentsCancelRequest> for .update_payment_intent( payment_data.payment_intent, payment_intent_update, + key_store, storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index ec86d1d17245..1d127830e11e 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -52,7 +52,12 @@ impl GetTracker, api::PaymentsCaptu .change_context(errors::ApiErrorResponse::PaymentNotFound)?; payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index 49fe8ce20114..07d3350de616 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -52,7 +52,12 @@ impl GetTracker, api::PaymentsRequest> for Co .change_context(errors::ApiErrorResponse::PaymentNotFound)?; payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; payment_intent.setup_future_usage = request @@ -418,6 +423,7 @@ impl Domain for CompleteAuthorize { &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -435,7 +441,7 @@ impl UpdateTracker, api::PaymentsRequest> for Comple _customer: Option, storage_scheme: storage_enums::MerchantStorageScheme, _updated_customer: Option, - _merchant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<(BoxedOperation<'b, F, api::PaymentsRequest>, PaymentData)> @@ -450,7 +456,12 @@ impl UpdateTracker, api::PaymentsRequest> for Comple let payment_intent = payment_data.payment_intent.clone(); let updated_payment_intent = db - .update_payment_intent(payment_intent, payment_intent_update, storage_scheme) + .update_payment_intent( + payment_intent, + payment_intent_update, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index edda62d79f7c..f27a7f3355b2 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -73,6 +73,7 @@ impl GetTracker, api::PaymentsRequest> for Pa .find_payment_intent_by_payment_id_merchant_id( &payment_id, m_merchant_id.as_str(), + key_store, storage_scheme, ) .await @@ -303,6 +304,7 @@ impl GetTracker, api::PaymentsRequest> for Pa payment_intent, payment_attempt, &*state.store, + key_store, storage_scheme, ) .await?; @@ -859,9 +861,16 @@ impl Domain for PaymentConfirm { &'a self, state: &AppState, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, payment_data: &mut PaymentData, ) -> CustomResult { - blocklist_utils::validate_data_for_blocklist(state, merchant_account, payment_data).await + blocklist_utils::validate_data_for_blocklist( + state, + merchant_account, + key_store, + payment_data, + ) + .await } #[instrument(skip_all)] @@ -1217,6 +1226,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let m_db = state.clone().store; let m_storage_scheme = storage_scheme.to_string(); let session_expiry = m_payment_data_payment_intent.session_expiry; + let m_key_store = key_store.clone(); let payment_intent_fut = tokio::spawn( async move { @@ -1245,6 +1255,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen request_external_three_ds_authentication: None, frm_metadata: m_frm_metadata, }, + &m_key_store, storage_scheme, ) .map(|x| x.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)) diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index f77760fa46cc..20d927d4a249 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -281,7 +281,7 @@ impl GetTracker, api::PaymentsRequest> for Pa .await?; payment_intent = db - .insert_payment_intent(payment_intent_new, storage_scheme) + .insert_payment_intent(payment_intent_new, merchant_key_store, storage_scheme) .await .to_duplicate_response(errors::ApiErrorResponse::DuplicatePayment { payment_id: payment_id.clone(), @@ -545,6 +545,7 @@ impl Domain for PaymentCreate { &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -562,7 +563,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen _customer: Option, storage_scheme: enums::MerchantStorageScheme, _updated_customer: Option, - _merchant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<(BoxedOperation<'b, F, api::PaymentsRequest>, PaymentData)> @@ -639,6 +640,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen billing_address_id: None, updated_by: storage_scheme.to_string(), }, + key_store, storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index 60061d655c1c..206027874fea 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -47,7 +47,12 @@ impl GetTracker, PaymentsCancelRequest> for P .change_context(errors::ApiErrorResponse::PaymentNotFound)?; let payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; @@ -197,7 +202,7 @@ impl UpdateTracker, PaymentsCancelRequest> for Payme _customer: Option, storage_scheme: enums::MerchantStorageScheme, _updated_customer: Option, - _mechant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _should_decline_transaction: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<(BoxedOperation<'b, F, PaymentsCancelRequest>, PaymentData)> @@ -231,6 +236,7 @@ impl UpdateTracker, PaymentsCancelRequest> for Payme .update_payment_intent( payment_data.payment_intent, intent_status_update, + key_store, storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 3b5bd9fd43ba..82ec05d4820e 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -59,6 +59,7 @@ impl PostUpdateTracker, types::PaymentsAuthor types::PaymentsAuthorizeData, types::PaymentsResponseData, >, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -73,6 +74,7 @@ impl PostUpdateTracker, types::PaymentsAuthor payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await?; @@ -245,6 +247,7 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu types::PaymentsIncrementalAuthorizationData, types::PaymentsResponseData, >, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -305,6 +308,7 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu .update_payment_intent( payment_data.payment_intent.clone(), payment_intent_update, + key_store, storage_scheme, ) .await @@ -372,6 +376,7 @@ impl PostUpdateTracker, types::PaymentsSyncData> for payment_id: &api::PaymentIdType, payment_data: PaymentData, router_data: types::RouterData, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -382,6 +387,7 @@ impl PostUpdateTracker, types::PaymentsSyncData> for payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await @@ -422,6 +428,7 @@ impl PostUpdateTracker, types::PaymentsSessionData> payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -432,6 +439,7 @@ impl PostUpdateTracker, types::PaymentsSessionData> payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await?; @@ -450,6 +458,7 @@ impl PostUpdateTracker, types::PaymentsCaptureData> payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -460,6 +469,7 @@ impl PostUpdateTracker, types::PaymentsCaptureData> payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await?; @@ -476,7 +486,7 @@ impl PostUpdateTracker, types::PaymentsCancelData> f payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, - + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -487,6 +497,7 @@ impl PostUpdateTracker, types::PaymentsCancelData> f payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await?; @@ -505,7 +516,7 @@ impl PostUpdateTracker, types::PaymentsApproveData> payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, - + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -516,6 +527,7 @@ impl PostUpdateTracker, types::PaymentsApproveData> payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await?; @@ -532,7 +544,7 @@ impl PostUpdateTracker, types::PaymentsRejectData> f payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, - + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -543,6 +555,7 @@ impl PostUpdateTracker, types::PaymentsRejectData> f payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await?; @@ -565,7 +578,7 @@ impl PostUpdateTracker, types::SetupMandateRequestDa types::SetupMandateRequestData, types::PaymentsResponseData, >, - + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -581,6 +594,7 @@ impl PostUpdateTracker, types::SetupMandateRequestDa payment_id, payment_data, router_data, + key_store, storage_scheme, )) .await?; @@ -662,6 +676,7 @@ impl PostUpdateTracker, types::CompleteAuthorizeData payment_id: &api::PaymentIdType, payment_data: PaymentData, response: types::RouterData, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> where @@ -672,6 +687,7 @@ impl PostUpdateTracker, types::CompleteAuthorizeData payment_id, payment_data, response, + key_store, storage_scheme, )) .await @@ -708,6 +724,7 @@ async fn payment_response_update_tracker( _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult> { // Update additional payment data with the payment method response that we received from connector @@ -1133,6 +1150,7 @@ async fn payment_response_update_tracker( }; let m_db = state.clone().store; + let m_key_store = key_store.clone(); let m_payment_data_payment_intent = payment_data.payment_intent.clone(); let m_payment_intent_update = payment_intent_update.clone(); let payment_intent_fut = tokio::spawn( @@ -1140,6 +1158,7 @@ async fn payment_response_update_tracker( m_db.update_payment_intent( m_payment_data_payment_intent, m_payment_intent_update, + &m_key_store, storage_scheme, ) .map(|x| x.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)) diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 2aa01cd587fa..8000a58d6436 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -52,7 +52,12 @@ impl GetTracker, api::PaymentsSessionRequest> let storage_scheme = merchant_account.storage_scheme; let mut payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; @@ -224,7 +229,7 @@ impl UpdateTracker, api::PaymentsSessionRequest> for _customer: Option, storage_scheme: storage_enums::MerchantStorageScheme, _updated_customer: Option, - _mechant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<( @@ -244,6 +249,7 @@ impl UpdateTracker, api::PaymentsSessionRequest> for metadata, updated_by: storage_scheme.to_string(), }, + key_store, storage_scheme, ) .await @@ -460,6 +466,7 @@ where &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> errors::CustomResult { Ok(false) diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index e5567e5b4748..8da0fdafbd14 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -50,7 +50,12 @@ impl GetTracker, api::PaymentsStartRequest> f .change_context(errors::ApiErrorResponse::PaymentNotFound)?; payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; @@ -337,6 +342,7 @@ where &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 0bedd70b921e..4c2136aab6c8 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -133,6 +133,7 @@ impl Domain for PaymentStatus { &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -219,7 +220,7 @@ async fn get_tracker_for_sync< >( payment_id: &api::PaymentIdType, merchant_account: &domain::MerchantAccount, - mechant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, db: &dyn StorageInterface, request: &api::PaymentsRetrieveRequest, operation: Op, @@ -231,6 +232,7 @@ async fn get_tracker_for_sync< db, payment_id, &merchant_account.merchant_id, + key_store, storage_scheme, ) .await?; @@ -245,7 +247,7 @@ async fn get_tracker_for_sync< let shipping_address = helpers::get_address_by_id( db, payment_intent.shipping_address_id.clone(), - mechant_key_store, + key_store, &payment_intent.payment_id.clone(), &merchant_account.merchant_id, merchant_account.storage_scheme, @@ -254,7 +256,7 @@ async fn get_tracker_for_sync< let billing_address = helpers::get_address_by_id( db, payment_intent.billing_address_id.clone(), - mechant_key_store, + key_store, &payment_intent.payment_id.clone(), &merchant_account.merchant_id, merchant_account.storage_scheme, @@ -264,7 +266,7 @@ async fn get_tracker_for_sync< let payment_method_billing = helpers::get_address_by_id( db, payment_attempt.payment_method_billing_address_id.clone(), - mechant_key_store, + key_store, &payment_intent.payment_id.clone(), &merchant_account.merchant_id, merchant_account.storage_scheme, @@ -514,11 +516,11 @@ impl ValidateRequest for Payme } } -#[inline] pub async fn get_payment_intent_payment_attempt( db: &dyn StorageInterface, payment_id: &api::PaymentIdType, merchant_id: &str, + key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult<(storage::PaymentIntent, storage::PaymentAttempt)> { let get_pi_pa = || async { @@ -526,7 +528,12 @@ pub async fn get_payment_intent_payment_attempt( match payment_id { api_models::payments::PaymentIdType::PaymentIntentId(ref id) => { pi = db - .find_payment_intent_by_payment_id_merchant_id(id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + id, + merchant_id, + key_store, + storage_scheme, + ) .await?; pa = db .find_payment_attempt_by_payment_id_merchant_id_attempt_id( @@ -549,6 +556,7 @@ pub async fn get_payment_intent_payment_attempt( .find_payment_intent_by_payment_id_merchant_id( pa.payment_id.as_str(), merchant_id, + key_store, storage_scheme, ) .await?; @@ -561,6 +569,7 @@ pub async fn get_payment_intent_payment_attempt( .find_payment_intent_by_payment_id_merchant_id( pa.payment_id.as_str(), merchant_id, + key_store, storage_scheme, ) .await?; @@ -578,6 +587,7 @@ pub async fn get_payment_intent_payment_attempt( .find_payment_intent_by_payment_id_merchant_id( pa.payment_id.as_str(), merchant_id, + key_store, storage_scheme, ) .await?; diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index e44dc0c1f2c1..ef6fde0cd53b 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -56,7 +56,12 @@ impl GetTracker, api::PaymentsRequest> for Pa let db = &*state.store; payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; @@ -548,6 +553,7 @@ impl Domain for PaymentUpdate { &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut PaymentData, ) -> CustomResult { Ok(false) @@ -565,7 +571,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen customer: Option, storage_scheme: storage_enums::MerchantStorageScheme, _updated_customer: Option, - _key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<(BoxedOperation<'b, F, api::PaymentsRequest>, PaymentData)> @@ -721,6 +727,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen .request_external_three_ds_authentication, frm_metadata, }, + key_store, storage_scheme, ) .await diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index 56665d65a32d..19b301a3b8ea 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -45,7 +45,7 @@ impl payment_id: &api::PaymentIdType, request: &PaymentsIncrementalAuthorizationRequest, merchant_account: &domain::MerchantAccount, - _key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, _payment_confirm_source: Option, ) -> RouterResult> @@ -58,7 +58,12 @@ impl .change_context(errors::ApiErrorResponse::PaymentNotFound)?; let payment_intent = db - .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + &payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; @@ -180,7 +185,7 @@ impl UpdateTracker, PaymentsIncrementalAut _customer: Option, storage_scheme: enums::MerchantStorageScheme, _updated_customer: Option, - _mechant_key_store: &domain::MerchantKeyStore, + key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, _header_payload: api::HeaderPayload, ) -> RouterResult<( @@ -238,6 +243,7 @@ impl UpdateTracker, PaymentsIncrementalAut storage::PaymentIntentUpdate::AuthorizationCountUpdate { authorization_count: new_authorization_count, }, + key_store, storage_scheme, ) .await @@ -336,6 +342,7 @@ impl Domain &'a self, _state: &AppState, _merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, _payment_data: &mut payments::PaymentData, ) -> CustomResult { Ok(false) diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 3bafd7774099..09f1b24afdf6 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -299,6 +299,7 @@ where state, connector.connector_name.to_string(), payment_data, + key_store, merchant_account.storage_scheme, router_data, is_step_up, @@ -329,6 +330,7 @@ pub async fn modify_trackers( state: &routes::AppState, connector: String, payment_data: &mut payments::PaymentData, + key_store: &domain::MerchantKeyStore, storage_scheme: storage_enums::MerchantStorageScheme, router_data: types::RouterData, is_step_up: bool, @@ -462,6 +464,7 @@ where attempt_count: new_attempt_count, updated_by: storage_scheme.to_string(), }, + key_store, storage_scheme, ) .await diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index f184e166e22d..c7c8f6b15882 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -101,6 +101,7 @@ pub async fn create_link_token( let payment_intent = oss_helpers::verify_payment_intent_time_and_client_secret( &*state.store, &merchant_account, + &key_store, payload.client_secret, ) .await?; @@ -283,6 +284,7 @@ async fn store_bank_details_in_payment_methods( .find_payment_intent_by_payment_id_merchant_id( &payload.payment_id, &merchant_account.merchant_id, + &key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index d2d2db71ef36..2c057b27c8ee 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -56,6 +56,7 @@ pub async fn refund_create_core( .find_payment_intent_by_payment_id_merchant_id( &req.payment_id, merchant_id, + &key_store, merchant_account.storage_scheme, ) .await @@ -362,6 +363,7 @@ pub async fn refund_retrieve_core( .find_payment_intent_by_payment_id_merchant_id( payment_id, merchant_id, + &key_store, merchant_account.storage_scheme, ) .await @@ -1120,6 +1122,7 @@ pub async fn trigger_refund_execute_workflow( .find_payment_intent_by_payment_id_merchant_id( &payment_attempt.payment_id, &refund.merchant_id, + &key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 0d3bec40f40b..9ee0c2e6032b 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1315,11 +1315,12 @@ impl PaymentIntentInterface for KafkaStore { &self, this: storage::PaymentIntent, payment_intent: storage::PaymentIntentUpdate, + key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> CustomResult { let intent = self .diesel_store - .update_payment_intent(this.clone(), payment_intent, storage_scheme) + .update_payment_intent(this.clone(), payment_intent, key_store, storage_scheme) .await?; if let Err(er) = self @@ -1336,12 +1337,13 @@ impl PaymentIntentInterface for KafkaStore { async fn insert_payment_intent( &self, new: storage::PaymentIntent, + key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> CustomResult { logger::debug!("Inserting PaymentIntent Via KafkaStore"); let intent = self .diesel_store - .insert_payment_intent(new, storage_scheme) + .insert_payment_intent(new, key_store, storage_scheme) .await?; if let Err(er) = self @@ -1359,10 +1361,16 @@ impl PaymentIntentInterface for KafkaStore { &self, payment_id: &str, merchant_id: &str, + key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> CustomResult { self.diesel_store - .find_payment_intent_by_payment_id_merchant_id(payment_id, merchant_id, storage_scheme) + .find_payment_intent_by_payment_id_merchant_id( + payment_id, + merchant_id, + key_store, + storage_scheme, + ) .await } @@ -1371,10 +1379,11 @@ impl PaymentIntentInterface for KafkaStore { &self, merchant_id: &str, filters: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints, + key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> CustomResult, errors::DataStorageError> { self.diesel_store - .filter_payment_intent_by_constraints(merchant_id, filters, storage_scheme) + .filter_payment_intent_by_constraints(merchant_id, filters, key_store, storage_scheme) .await } @@ -1383,12 +1392,14 @@ impl PaymentIntentInterface for KafkaStore { &self, merchant_id: &str, time_range: &api_models::payments::TimeRange, + key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> CustomResult, errors::DataStorageError> { self.diesel_store .filter_payment_intents_by_time_range_constraints( merchant_id, time_range, + key_store, storage_scheme, ) .await @@ -1399,6 +1410,7 @@ impl PaymentIntentInterface for KafkaStore { &self, merchant_id: &str, constraints: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints, + key_store: &domain::MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> CustomResult< Vec<( @@ -1408,7 +1420,12 @@ impl PaymentIntentInterface for KafkaStore { errors::DataStorageError, > { self.diesel_store - .get_filtered_payment_intents_attempt(merchant_id, constraints, storage_scheme) + .get_filtered_payment_intents_attempt( + merchant_id, + constraints, + key_store, + storage_scheme, + ) .await } diff --git a/crates/router/src/routes/cards_info.rs b/crates/router/src/routes/cards_info.rs index ca59e072a900..889b6e0ec401 100644 --- a/crates/router/src/routes/cards_info.rs +++ b/crates/router/src/routes/cards_info.rs @@ -46,7 +46,9 @@ pub async fn card_iin_info( state, &req, payload, - |state, auth, req, _| cards_info::retrieve_card_info(state, auth.merchant_account, req), + |state, auth, req, _| { + cards_info::retrieve_card_info(state, auth.merchant_account, auth.key_store, req) + }, &*auth, api_locking::LockAction::NotApplicable, )) diff --git a/crates/router/src/routes/metrics.rs b/crates/router/src/routes/metrics.rs index 1123be1a8748..3e48472c72b7 100644 --- a/crates/router/src/routes/metrics.rs +++ b/crates/router/src/routes/metrics.rs @@ -88,10 +88,6 @@ histogram_metric!(CARD_ADD_TIME, GLOBAL_METER); histogram_metric!(CARD_GET_TIME, GLOBAL_METER); histogram_metric!(CARD_DELETE_TIME, GLOBAL_METER); -// Encryption and Decryption metrics -histogram_metric!(ENCRYPTION_TIME, GLOBAL_METER); -histogram_metric!(DECRYPTION_TIME, GLOBAL_METER); - // Apple Pay Flow Metrics counter_metric!(APPLE_PAY_MANUAL_FLOW, GLOBAL_METER); counter_metric!(APPLE_PAY_SIMPLIFIED_FLOW, GLOBAL_METER); diff --git a/crates/router/src/routes/metrics/request.rs b/crates/router/src/routes/metrics/request.rs index ef53ad83f2cb..69e0afacf969 100644 --- a/crates/router/src/routes/metrics/request.rs +++ b/crates/router/src/routes/metrics/request.rs @@ -21,20 +21,6 @@ where result } -#[inline] -pub async fn record_operation_time( - future: F, - metric: &once_cell::sync::Lazy>, - key_value: &[opentelemetry::KeyValue], -) -> R -where - F: futures::Future, -{ - let (result, time) = metric_utils::time_future(future).await; - metric.record(&super::CONTEXT, time.as_secs_f64(), key_value); - result -} - pub fn add_attributes>( key: &'static str, value: T, diff --git a/crates/router/src/routes/payment_link.rs b/crates/router/src/routes/payment_link.rs index f375a18ab614..fed182f03a81 100644 --- a/crates/router/src/routes/payment_link.rs +++ b/crates/router/src/routes/payment_link.rs @@ -71,6 +71,7 @@ pub async fn initiate_payment_link( initiate_payment_link_flow( state, auth.merchant_account, + auth.key_store, payload.merchant_id.clone(), payload.payment_id.clone(), ) @@ -144,6 +145,7 @@ pub async fn payment_link_status( get_payment_link_status( state, auth.merchant_account, + auth.key_store, payload.merchant_id.clone(), payload.payment_id.clone(), ) diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index ab6b0f450db1..6a1bb57a5893 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -954,7 +954,9 @@ pub async fn payments_list( state, &req, payload, - |state, auth, req, _| payments::list_payments(state, auth.merchant_account, req), + |state, auth, req, _| { + payments::list_payments(state, auth.merchant_account, auth.key_store, req) + }, auth::auth_type( &auth::ApiKeyAuth, &auth::JWTAuth(Permission::PaymentRead), @@ -979,7 +981,7 @@ pub async fn payments_list_by_filter( &req, payload, |state, auth: auth::AuthenticationData, req, _| { - payments::apply_filters_on_payments(state, auth.merchant_account, req) + payments::apply_filters_on_payments(state, auth.merchant_account, auth.key_store, req) }, &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, @@ -1001,7 +1003,7 @@ pub async fn get_filters_for_payments( &req, payload, |state, auth: auth::AuthenticationData, req, _| { - payments::get_filters_for_payments(state, auth.merchant_account, req) + payments::get_filters_for_payments(state, auth.merchant_account, auth.key_store, req) }, &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 5f69a9d40339..7e58649a1e75 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -46,8 +46,7 @@ use crate::{ logger, routes::{ app::{AppStateInfo, ReqState}, - metrics::{self, request as metrics_request}, - AppState, + metrics, AppState, }, types::{ self, @@ -712,9 +711,10 @@ pub async fn send_request( .attach_printable("Unable to send request to connector") }; - let response = metrics_request::record_operation_time( + let response = common_utils::metrics::utils::record_operation_time( send_request, &metrics::EXTERNAL_REQUEST_TIME, + &metrics::CONTEXT, &[metrics_tag.clone()], ) .await; @@ -739,9 +739,10 @@ pub async fn send_request( logger::info!( "Retrying request due to connection closed before message could complete" ); - metrics_request::record_operation_time( + common_utils::metrics::utils::record_operation_time( cloned_request, &metrics::EXTERNAL_REQUEST_TIME, + &metrics::CONTEXT, &[metrics_tag], ) .await diff --git a/crates/router/src/types/domain/merchant_key_store.rs b/crates/router/src/types/domain/merchant_key_store.rs index bf5e90399957..d32e686acaf8 100644 --- a/crates/router/src/types/domain/merchant_key_store.rs +++ b/crates/router/src/types/domain/merchant_key_store.rs @@ -1,59 +1 @@ -use common_utils::{ - crypto::{Encryptable, GcmAes256}, - custom_serde, date_time, -}; -use error_stack::ResultExt; -use masking::{PeekInterface, Secret}; -use time::PrimitiveDateTime; - -use crate::{ - errors::{CustomResult, ValidationError}, - types::domain::types::TypeEncryption, -}; - -#[derive(Clone, Debug, serde::Serialize)] -pub struct MerchantKeyStore { - pub merchant_id: String, - pub key: Encryptable>>, - #[serde(with = "custom_serde::iso8601")] - pub created_at: PrimitiveDateTime, -} - -#[async_trait::async_trait] -impl super::behaviour::Conversion for MerchantKeyStore { - type DstType = diesel_models::merchant_key_store::MerchantKeyStore; - type NewDstType = diesel_models::merchant_key_store::MerchantKeyStoreNew; - async fn convert(self) -> CustomResult { - Ok(diesel_models::merchant_key_store::MerchantKeyStore { - key: self.key.into(), - merchant_id: self.merchant_id, - created_at: self.created_at, - }) - } - - async fn convert_back( - item: Self::DstType, - key: &Secret>, - ) -> CustomResult - where - Self: Sized, - { - Ok(Self { - key: Encryptable::decrypt(item.key, key.peek(), GcmAes256) - .await - .change_context(ValidationError::InvalidValue { - message: "Failed while decrypting customer data".to_string(), - })?, - merchant_id: item.merchant_id, - created_at: item.created_at, - }) - } - - async fn construct_new(self) -> CustomResult { - Ok(diesel_models::merchant_key_store::MerchantKeyStoreNew { - merchant_id: self.merchant_id, - key: self.key.into(), - created_at: date_time::now(), - }) - } -} +pub use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore; diff --git a/crates/router/src/types/domain/types.rs b/crates/router/src/types/domain/types.rs index 0ef4e8579d36..fe3cec186da6 100644 --- a/crates/router/src/types/domain/types.rs +++ b/crates/router/src/types/domain/types.rs @@ -1,225 +1,229 @@ -use async_trait::async_trait; -use common_utils::{ - crypto, - errors::{self, CustomResult}, - ext_traits::AsyncExt, +pub use hyperswitch_domain_models::type_encryption::{ + decrypt, encrypt, encrypt_optional, AsyncLift, Lift, TypeEncryption, }; -use diesel_models::encryption::Encryption; -use error_stack::ResultExt; -use masking::{PeekInterface, Secret}; -use router_env::{instrument, tracing}; - -use crate::routes::metrics::{request, DECRYPTION_TIME, ENCRYPTION_TIME}; - -#[async_trait] -pub trait TypeEncryption< - T, - V: crypto::EncodeMessage + crypto::DecodeMessage, - S: masking::Strategy, ->: Sized -{ - async fn encrypt( - masked_data: Secret, - key: &[u8], - crypt_algo: V, - ) -> CustomResult; - - async fn decrypt( - encrypted_data: Encryption, - key: &[u8], - crypt_algo: V, - ) -> CustomResult; -} - -#[async_trait] -impl< - V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, - S: masking::Strategy + Send, - > TypeEncryption for crypto::Encryptable> -{ - #[instrument(skip_all)] - async fn encrypt( - masked_data: Secret, - key: &[u8], - crypt_algo: V, - ) -> CustomResult { - let encrypted_data = crypt_algo.encode_message(key, masked_data.peek().as_bytes())?; - - Ok(Self::new(masked_data, encrypted_data.into())) - } - - #[instrument(skip_all)] - async fn decrypt( - encrypted_data: Encryption, - key: &[u8], - crypt_algo: V, - ) -> CustomResult { - let encrypted = encrypted_data.into_inner(); - let data = crypt_algo.decode_message(key, encrypted.clone())?; - - let value: String = std::str::from_utf8(&data) - .change_context(errors::CryptoError::DecodingFailed)? - .to_string(); - - Ok(Self::new(value.into(), encrypted)) - } -} - -#[async_trait] -impl< - V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, - S: masking::Strategy + Send, - > TypeEncryption - for crypto::Encryptable> -{ - #[instrument(skip_all)] - async fn encrypt( - masked_data: Secret, - key: &[u8], - crypt_algo: V, - ) -> CustomResult { - let data = serde_json::to_vec(&masked_data.peek()) - .change_context(errors::CryptoError::DecodingFailed)?; - let encrypted_data = crypt_algo.encode_message(key, &data)?; - - Ok(Self::new(masked_data, encrypted_data.into())) - } - - #[instrument(skip_all)] - async fn decrypt( - encrypted_data: Encryption, - key: &[u8], - crypt_algo: V, - ) -> CustomResult { - let encrypted = encrypted_data.into_inner(); - let data = crypt_algo.decode_message(key, encrypted.clone())?; - - let value: serde_json::Value = - serde_json::from_slice(&data).change_context(errors::CryptoError::DecodingFailed)?; - - Ok(Self::new(value.into(), encrypted)) - } -} - -#[async_trait] -impl< - V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, - S: masking::Strategy> + Send, - > TypeEncryption, V, S> for crypto::Encryptable, S>> -{ - #[instrument(skip_all)] - async fn encrypt( - masked_data: Secret, S>, - key: &[u8], - crypt_algo: V, - ) -> CustomResult { - let encrypted_data = crypt_algo.encode_message(key, masked_data.peek())?; - - Ok(Self::new(masked_data, encrypted_data.into())) - } - - #[instrument(skip_all)] - async fn decrypt( - encrypted_data: Encryption, - key: &[u8], - crypt_algo: V, - ) -> CustomResult { - let encrypted = encrypted_data.into_inner(); - let data = crypt_algo.decode_message(key, encrypted.clone())?; - - Ok(Self::new(data.into(), encrypted)) - } -} - -pub trait Lift { - type SelfWrapper; - type OtherWrapper; - - fn lift(self, func: Func) -> Self::OtherWrapper - where - Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper; -} - -impl Lift for Option { - type SelfWrapper = Option; - type OtherWrapper = CustomResult, E>; - - fn lift(self, func: Func) -> Self::OtherWrapper - where - Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper, - { - func(self) - } -} - -#[async_trait] -pub trait AsyncLift { - type SelfWrapper; - type OtherWrapper; - - async fn async_lift(self, func: Func) -> Self::OtherWrapper - where - Func: Fn(Self::SelfWrapper) -> F + Send + Sync, - F: futures::Future> + Send; -} - -#[async_trait] -impl + Lift = V> + Send> AsyncLift for V { - type SelfWrapper = >::SelfWrapper; - type OtherWrapper = >::OtherWrapper; - - async fn async_lift(self, func: Func) -> Self::OtherWrapper - where - Func: Fn(Self::SelfWrapper) -> F + Send + Sync, - F: futures::Future> + Send, - { - func(self).await - } -} - -#[inline] -pub async fn encrypt( - inner: Secret, - key: &[u8], -) -> CustomResult>, errors::CryptoError> -where - S: masking::Strategy, - crypto::Encryptable>: TypeEncryption, -{ - request::record_operation_time( - crypto::Encryptable::encrypt(inner, key, crypto::GcmAes256), - &ENCRYPTION_TIME, - &[], - ) - .await -} - -#[inline] -pub async fn encrypt_optional( - inner: Option>, - key: &[u8], -) -> CustomResult>>, errors::CryptoError> -where - Secret: Send, - S: masking::Strategy, - crypto::Encryptable>: TypeEncryption, -{ - inner.async_map(|f| encrypt(f, key)).await.transpose() -} - -#[inline] -pub async fn decrypt>( - inner: Option, - key: &[u8], -) -> CustomResult>>, errors::CryptoError> -where - crypto::Encryptable>: TypeEncryption, -{ - request::record_operation_time( - inner.async_map(|item| crypto::Encryptable::decrypt(item, key, crypto::GcmAes256)), - &DECRYPTION_TIME, - &[], - ) - .await - .transpose() -} + +// use async_trait::async_trait; +// use common_utils::{ +// crypto, +// errors::{self, CustomResult}, +// ext_traits::AsyncExt, +// }; +// use diesel_models::encryption::Encryption; +// use error_stack::ResultExt; +// use masking::{PeekInterface, Secret}; +// use router_env::{instrument, tracing}; + +// use crate::routes::metrics::{request, DECRYPTION_TIME, ENCRYPTION_TIME}; + +// #[async_trait] +// pub trait TypeEncryption< +// T, +// V: crypto::EncodeMessage + crypto::DecodeMessage, +// S: masking::Strategy, +// >: Sized +// { +// async fn encrypt( +// masked_data: Secret, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult; + +// async fn decrypt( +// encrypted_data: Encryption, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult; +// } + +// #[async_trait] +// impl< +// V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, +// S: masking::Strategy + Send, +// > TypeEncryption for crypto::Encryptable> +// { +// #[instrument(skip_all)] +// async fn encrypt( +// masked_data: Secret, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult { +// let encrypted_data = crypt_algo.encode_message(key, masked_data.peek().as_bytes())?; + +// Ok(Self::new(masked_data, encrypted_data.into())) +// } + +// #[instrument(skip_all)] +// async fn decrypt( +// encrypted_data: Encryption, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult { +// let encrypted = encrypted_data.into_inner(); +// let data = crypt_algo.decode_message(key, encrypted.clone())?; + +// let value: String = std::str::from_utf8(&data) +// .change_context(errors::CryptoError::DecodingFailed)? +// .to_string(); + +// Ok(Self::new(value.into(), encrypted)) +// } +// } + +// #[async_trait] +// impl< +// V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, +// S: masking::Strategy + Send, +// > TypeEncryption +// for crypto::Encryptable> +// { +// #[instrument(skip_all)] +// async fn encrypt( +// masked_data: Secret, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult { +// let data = serde_json::to_vec(&masked_data.peek()) +// .change_context(errors::CryptoError::DecodingFailed)?; +// let encrypted_data = crypt_algo.encode_message(key, &data)?; + +// Ok(Self::new(masked_data, encrypted_data.into())) +// } + +// #[instrument(skip_all)] +// async fn decrypt( +// encrypted_data: Encryption, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult { +// let encrypted = encrypted_data.into_inner(); +// let data = crypt_algo.decode_message(key, encrypted.clone())?; + +// let value: serde_json::Value = +// serde_json::from_slice(&data).change_context(errors::CryptoError::DecodingFailed)?; + +// Ok(Self::new(value.into(), encrypted)) +// } +// } + +// #[async_trait] +// impl< +// V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, +// S: masking::Strategy> + Send, +// > TypeEncryption, V, S> for crypto::Encryptable, S>> +// { +// #[instrument(skip_all)] +// async fn encrypt( +// masked_data: Secret, S>, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult { +// let encrypted_data = crypt_algo.encode_message(key, masked_data.peek())?; + +// Ok(Self::new(masked_data, encrypted_data.into())) +// } + +// #[instrument(skip_all)] +// async fn decrypt( +// encrypted_data: Encryption, +// key: &[u8], +// crypt_algo: V, +// ) -> CustomResult { +// let encrypted = encrypted_data.into_inner(); +// let data = crypt_algo.decode_message(key, encrypted.clone())?; + +// Ok(Self::new(data.into(), encrypted)) +// } +// } + +// pub trait Lift { +// type SelfWrapper; +// type OtherWrapper; + +// fn lift(self, func: Func) -> Self::OtherWrapper +// where +// Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper; +// } + +// impl Lift for Option { +// type SelfWrapper = Option; +// type OtherWrapper = CustomResult, E>; + +// fn lift(self, func: Func) -> Self::OtherWrapper +// where +// Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper, +// { +// func(self) +// } +// } + +// #[async_trait] +// pub trait AsyncLift { +// type SelfWrapper; +// type OtherWrapper; + +// async fn async_lift(self, func: Func) -> Self::OtherWrapper +// where +// Func: Fn(Self::SelfWrapper) -> F + Send + Sync, +// F: futures::Future> + Send; +// } + +// #[async_trait] +// impl + Lift = V> + Send> AsyncLift for V { +// type SelfWrapper = >::SelfWrapper; +// type OtherWrapper = >::OtherWrapper; + +// async fn async_lift(self, func: Func) -> Self::OtherWrapper +// where +// Func: Fn(Self::SelfWrapper) -> F + Send + Sync, +// F: futures::Future> + Send, +// { +// func(self).await +// } +// } + +// #[inline] +// pub async fn encrypt( +// inner: Secret, +// key: &[u8], +// ) -> CustomResult>, errors::CryptoError> +// where +// S: masking::Strategy, +// crypto::Encryptable>: TypeEncryption, +// { +// request::record_operation_time( +// crypto::Encryptable::encrypt(inner, key, crypto::GcmAes256), +// &ENCRYPTION_TIME, +// &[], +// ) +// .await +// } + +// #[inline] +// pub async fn encrypt_optional( +// inner: Option>, +// key: &[u8], +// ) -> CustomResult>>, errors::CryptoError> +// where +// Secret: Send, +// S: masking::Strategy, +// crypto::Encryptable>: TypeEncryption, +// { +// inner.async_map(|f| encrypt(f, key)).await.transpose() +// } + +// #[inline] +// pub async fn decrypt>( +// inner: Option, +// key: &[u8], +// ) -> CustomResult>>, errors::CryptoError> +// where +// crypto::Encryptable>: TypeEncryption, +// { +// request::record_operation_time( +// inner.async_map(|item| crypto::Encryptable::decrypt(item, key, crypto::GcmAes256)), +// &DECRYPTION_TIME, +// &[], +// ) +// .await +// .transpose() +// } diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs index da6cac195ca2..0c698eba1122 100644 --- a/crates/router/src/utils.rs +++ b/crates/router/src/utils.rs @@ -196,12 +196,14 @@ pub async fn find_payment_intent_from_payment_id_type( db: &dyn StorageInterface, payment_id_type: payments::PaymentIdType, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, ) -> CustomResult { match payment_id_type { payments::PaymentIdType::PaymentIntentId(payment_id) => db .find_payment_intent_by_payment_id_merchant_id( &payment_id, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await @@ -218,6 +220,7 @@ pub async fn find_payment_intent_from_payment_id_type( db.find_payment_intent_by_payment_id_merchant_id( &attempt.payment_id, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await @@ -235,6 +238,7 @@ pub async fn find_payment_intent_from_payment_id_type( db.find_payment_intent_by_payment_id_merchant_id( &attempt.payment_id, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await @@ -250,6 +254,7 @@ pub async fn find_payment_intent_from_refund_id_type( db: &dyn StorageInterface, refund_id_type: webhooks::RefundIdType, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, connector_name: &str, ) -> CustomResult { let refund = match refund_id_type { @@ -282,6 +287,7 @@ pub async fn find_payment_intent_from_refund_id_type( db.find_payment_intent_by_payment_id_merchant_id( &attempt.payment_id, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await @@ -292,6 +298,7 @@ pub async fn find_payment_intent_from_mandate_id_type( db: &dyn StorageInterface, mandate_id_type: webhooks::MandateIdType, merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, ) -> CustomResult { let mandate = match mandate_id_type { webhooks::MandateIdType::MandateId(mandate_id) => db @@ -317,6 +324,7 @@ pub async fn find_payment_intent_from_mandate_id_type( .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("original_payment_id not present in mandate record")?, &merchant_account.merchant_id, + key_store, merchant_account.storage_scheme, ) .await @@ -438,8 +446,13 @@ pub async fn get_mca_from_object_reference_id( get_mca_from_payment_intent( db, merchant_account, - find_payment_intent_from_payment_id_type(db, payment_id_type, merchant_account) - .await?, + find_payment_intent_from_payment_id_type( + db, + payment_id_type, + merchant_account, + key_store, + ) + .await?, key_store, connector_name, ) @@ -453,6 +466,7 @@ pub async fn get_mca_from_object_reference_id( db, refund_id_type, merchant_account, + key_store, connector_name, ) .await?, @@ -465,8 +479,13 @@ pub async fn get_mca_from_object_reference_id( get_mca_from_payment_intent( db, merchant_account, - find_payment_intent_from_mandate_id_type(db, mandate_id_type, merchant_account) - .await?, + find_payment_intent_from_mandate_id_type( + db, + mandate_id_type, + merchant_account, + key_store, + ) + .await?, key_store, connector_name, ) diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs index 14f372789ed3..e56db4ceda3f 100644 --- a/crates/router/src/workflows/payment_sync.rs +++ b/crates/router/src/workflows/payment_sync.rs @@ -148,6 +148,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { .update_payment_intent( payment_data.payment_intent, payment_intent_update, + &key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/storage_impl/src/mock_db/payment_intent.rs b/crates/storage_impl/src/mock_db/payment_intent.rs index 6aa0121340e0..b4daa61206bc 100644 --- a/crates/storage_impl/src/mock_db/payment_intent.rs +++ b/crates/storage_impl/src/mock_db/payment_intent.rs @@ -2,6 +2,7 @@ use common_utils::errors::CustomResult; use diesel_models::enums as storage_enums; use hyperswitch_domain_models::{ errors::StorageError, + merchant_key_store::MerchantKeyStore, payments::{ payment_attempt::PaymentAttempt, payment_intent::{PaymentIntentInterface, PaymentIntentUpdate}, @@ -19,6 +20,7 @@ impl PaymentIntentInterface for MockDb { &self, _merchant_id: &str, _filters: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints, + _key_store: &MerchantKeyStore, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult, StorageError> { // [#172]: Implement function for `MockDb` @@ -29,6 +31,7 @@ impl PaymentIntentInterface for MockDb { &self, _merchant_id: &str, _time_range: &api_models::payments::TimeRange, + _key_store: &MerchantKeyStore, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult, StorageError> { // [#172]: Implement function for `MockDb` @@ -49,6 +52,7 @@ impl PaymentIntentInterface for MockDb { &self, _merchant_id: &str, _constraints: &hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints, + _key_store: &MerchantKeyStore, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result, StorageError> { // [#172]: Implement function for `MockDb` @@ -59,6 +63,7 @@ impl PaymentIntentInterface for MockDb { async fn insert_payment_intent( &self, new: PaymentIntent, + _key_store: &MerchantKeyStore, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { let mut payment_intents = self.payment_intents.lock().await; @@ -72,6 +77,7 @@ impl PaymentIntentInterface for MockDb { &self, this: PaymentIntent, update: PaymentIntentUpdate, + _key_store: &MerchantKeyStore, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { let mut payment_intents = self.payment_intents.lock().await; @@ -93,6 +99,7 @@ impl PaymentIntentInterface for MockDb { &self, payment_id: &str, merchant_id: &str, + _key_store: &MerchantKeyStore, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { let payment_intents = self.payment_intents.lock().await; diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index e1cb5af00359..008baa61111f 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -4,7 +4,7 @@ use api_models::payments::AmountFilter; use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl}; #[cfg(feature = "olap")] use common_utils::errors::ReportSwitchExt; -use common_utils::ext_traits::Encode; +use common_utils::ext_traits::{AsyncExt, Encode}; #[cfg(feature = "olap")] use diesel::{associations::HasTable, ExpressionMethods, JoinOnDsl, QueryDsl}; use diesel_models::{ @@ -50,11 +50,14 @@ use crate::{ DataModelExt, DatabaseStore, KVRouterStore, }; +use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore; + #[async_trait::async_trait] impl PaymentIntentInterface for KVRouterStore { async fn insert_payment_intent( &self, payment_intent: PaymentIntent, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let merchant_id = payment_intent.merchant_id.clone(); @@ -69,7 +72,7 @@ impl PaymentIntentInterface for KVRouterStore { match storage_scheme { MerchantStorageScheme::PostgresOnly => { self.router_store - .insert_payment_intent(payment_intent, storage_scheme) + .insert_payment_intent(payment_intent, merchant_key_store, storage_scheme) .await } @@ -123,6 +126,7 @@ impl PaymentIntentInterface for KVRouterStore { &self, this: PaymentIntent, payment_intent_update: PaymentIntentUpdate, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let merchant_id = this.merchant_id.clone(); @@ -141,14 +145,22 @@ impl PaymentIntentInterface for KVRouterStore { match storage_scheme { MerchantStorageScheme::PostgresOnly => { self.router_store - .update_payment_intent(this, payment_intent_update, storage_scheme) + .update_payment_intent( + this, + payment_intent_update, + merchant_key_store, + storage_scheme, + ) .await } MerchantStorageScheme::RedisKv => { let key_str = key.to_string(); - let diesel_intent_update = payment_intent_update.to_storage_model(); - let origin_diesel_intent = this.to_storage_model(); + let diesel_intent_update = DieselPaymentIntentUpdate::from(payment_intent_update); + let origin_diesel_intent = this + .convert() + .await + .change_context(StorageError::EncryptionError)?; let diesel_intent = diesel_intent_update .clone() @@ -180,7 +192,12 @@ impl PaymentIntentInterface for KVRouterStore { .try_into_hset() .change_context(StorageError::KVError)?; - Ok(PaymentIntent::from_storage_model(diesel_intent)) + let payment_intent = + PaymentIntent::convert_back(diesel_intent, merchant_key_store.key.get_inner()) + .await + .change_context(StorageError::DecryptionError)?; + + Ok(payment_intent) } } } @@ -190,6 +207,7 @@ impl PaymentIntentInterface for KVRouterStore { &self, payment_id: &str, merchant_id: &str, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let database_call = || async { @@ -203,7 +221,7 @@ impl PaymentIntentInterface for KVRouterStore { }; let storage_scheme = decide_storage_scheme::<_, DieselPaymentIntent>(self, storage_scheme, Op::Find).await; - match storage_scheme { + let diesel_payment_intent = match storage_scheme { MerchantStorageScheme::PostgresOnly => database_call().await, MerchantStorageScheme::RedisKv => { @@ -226,8 +244,11 @@ impl PaymentIntentInterface for KVRouterStore { )) .await } - } - .map(PaymentIntent::from_storage_model) + }?; + + PaymentIntent::convert_back(diesel_payment_intent, merchant_key_store.key.get_inner()) + .await + .change_context(StorageError::DecryptionError) } async fn get_active_payment_attempt( @@ -262,10 +283,16 @@ impl PaymentIntentInterface for KVRouterStore { &self, merchant_id: &str, filters: &PaymentIntentFetchConstraints, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { self.router_store - .filter_payment_intent_by_constraints(merchant_id, filters, storage_scheme) + .filter_payment_intent_by_constraints( + merchant_id, + filters, + merchant_key_store, + storage_scheme, + ) .await } @@ -274,12 +301,14 @@ impl PaymentIntentInterface for KVRouterStore { &self, merchant_id: &str, time_range: &api_models::payments::TimeRange, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { self.router_store .filter_payment_intents_by_time_range_constraints( merchant_id, time_range, + merchant_key_store, storage_scheme, ) .await @@ -290,10 +319,16 @@ impl PaymentIntentInterface for KVRouterStore { &self, merchant_id: &str, filters: &PaymentIntentFetchConstraints, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { self.router_store - .get_filtered_payment_intents_attempt(merchant_id, filters, storage_scheme) + .get_filtered_payment_intents_attempt( + merchant_id, + filters, + merchant_key_store, + storage_scheme, + ) .await } @@ -320,10 +355,11 @@ impl PaymentIntentInterface for crate::RouterStore { async fn insert_payment_intent( &self, payment_intent: PaymentIntent, + merchant_key_store: &MerchantKeyStore, _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let conn = pg_connection_write(self).await?; - payment_intent + let diesel_payment_intent = payment_intent .construct_new() .await .change_context(StorageError::EncryptionError)? @@ -332,8 +368,11 @@ impl PaymentIntentInterface for crate::RouterStore { .map_err(|er| { let new_err = diesel_error_to_data_error(er.current_context()); er.change_context(new_err) - }) - .map(PaymentIntent::from_storage_model) + })?; + + PaymentIntent::convert_back(diesel_payment_intent, merchant_key_store.key.get_inner()) + .await + .change_context(StorageError::DecryptionError) } #[instrument(skip_all)] @@ -341,17 +380,26 @@ impl PaymentIntentInterface for crate::RouterStore { &self, this: PaymentIntent, payment_intent: PaymentIntentUpdate, + merchant_key_store: &MerchantKeyStore, _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let conn = pg_connection_write(self).await?; - this.to_storage_model() - .update(&conn, payment_intent.to_storage_model()) + let diesel_payment_intent_update = DieselPaymentIntentUpdate::from(payment_intent); + + let diesel_payment_intent = this + .convert() + .await + .change_context(StorageError::EncryptionError)? + .update(&conn, diesel_payment_intent_update) .await .map_err(|er| { let new_err = diesel_error_to_data_error(er.current_context()); er.change_context(new_err) - }) - .map(PaymentIntent::from_storage_model) + })?; + + PaymentIntent::convert_back(diesel_payment_intent, merchant_key_store.key.get_inner()) + .await + .change_context(StorageError::DecryptionError) } #[instrument(skip_all)] @@ -359,16 +407,26 @@ impl PaymentIntentInterface for crate::RouterStore { &self, payment_id: &str, merchant_id: &str, + merchant_key_store: &MerchantKeyStore, _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result { let conn = pg_connection_read(self).await?; + DieselPaymentIntent::find_by_payment_id_merchant_id(&conn, payment_id, merchant_id) .await - .map(PaymentIntent::from_storage_model) .map_err(|er| { let new_err = diesel_error_to_data_error(er.current_context()); er.change_context(new_err) }) + .async_and_then(|diesel_payment_intent| async { + PaymentIntent::convert_back( + diesel_payment_intent, + merchant_key_store.key.get_inner(), + ) + .await + .change_context(StorageError::DecryptionError) + }) + .await } #[instrument(skip_all)] @@ -405,6 +463,7 @@ impl PaymentIntentInterface for crate::RouterStore { &self, merchant_id: &str, filters: &PaymentIntentFetchConstraints, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { use common_utils::errors::ReportSwitchExt; @@ -443,6 +502,7 @@ impl PaymentIntentInterface for crate::RouterStore { .find_payment_intent_by_payment_id_merchant_id( starting_after_id, merchant_id, + merchant_key_store, storage_scheme, ) .await? @@ -460,6 +520,7 @@ impl PaymentIntentInterface for crate::RouterStore { .find_payment_intent_by_payment_id_merchant_id( ending_before_id, merchant_id, + merchant_key_store, storage_scheme, ) .await? @@ -519,12 +580,18 @@ impl PaymentIntentInterface for crate::RouterStore { &self, merchant_id: &str, time_range: &api_models::payments::TimeRange, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { // TODO: Remove this redundant function let payment_filters = (*time_range).into(); - self.filter_payment_intent_by_constraints(merchant_id, &payment_filters, storage_scheme) - .await + self.filter_payment_intent_by_constraints( + merchant_id, + &payment_filters, + merchant_key_store, + storage_scheme, + ) + .await } #[cfg(feature = "olap")] @@ -533,6 +600,7 @@ impl PaymentIntentInterface for crate::RouterStore { &self, merchant_id: &str, constraints: &PaymentIntentFetchConstraints, + merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { let conn = connection::pg_connection_read(self).await.switch()?; @@ -571,6 +639,7 @@ impl PaymentIntentInterface for crate::RouterStore { .find_payment_intent_by_payment_id_merchant_id( starting_after_id, merchant_id, + merchant_key_store, storage_scheme, ) .await? @@ -588,6 +657,7 @@ impl PaymentIntentInterface for crate::RouterStore { .find_payment_intent_by_payment_id_merchant_id( ending_before_id, merchant_id, + merchant_key_store, storage_scheme, ) .await? From 7abbf36298af62eea31a34055dc2fd2a6711cf37 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Sun, 9 Jun 2024 13:46:41 +0530 Subject: [PATCH 04/12] refactor: remove datamodel trait for pi --- .../src/payments/payment_attempt.rs | 2 +- .../src/payments/payment_intent.rs | 28 +- .../router/src/core/payment_methods/cards.rs | 1 + crates/router/src/core/payments/helpers.rs | 2 +- crates/router/src/core/user/sample_data.rs | 31 +- crates/router/src/db/kafka_store.rs | 8 +- crates/router/src/db/user/sample_data.rs | 46 +- crates/router/src/utils/user/sample_data.rs | 12 +- .../src/mock_db/payment_intent.rs | 25 +- .../src/payments/payment_attempt.rs | 13 +- .../src/payments/payment_intent.rs | 422 ++---------------- 11 files changed, 139 insertions(+), 451 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 52872efc1971..c36e29bfe680 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -525,7 +525,7 @@ impl behaviour::Conversion for PaymentIntent { where Self: Sized, { - Ok(PaymentIntent { + Ok(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, status: storage_model.status, diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index a7350c5fa28b..b2e8e4fb14ce 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -459,7 +459,7 @@ impl From for DieselPaymentIntentUpdate { return_url, updated_by, incremental_authorization_allowed, - } => DieselPaymentIntentUpdate::ResponseUpdate { + } => Self::ResponseUpdate { status, amount_captured, fingerprint_id, @@ -470,7 +470,7 @@ impl From for DieselPaymentIntentUpdate { PaymentIntentUpdate::MetadataUpdate { metadata, updated_by, - } => DieselPaymentIntentUpdate::MetadataUpdate { + } => Self::MetadataUpdate { metadata, updated_by, }, @@ -481,7 +481,7 @@ impl From for DieselPaymentIntentUpdate { shipping_address_id, billing_address_id, updated_by, - } => DieselPaymentIntentUpdate::ReturnUrlUpdate { + } => Self::ReturnUrlUpdate { return_url, status, customer_id, @@ -494,7 +494,7 @@ impl From for DieselPaymentIntentUpdate { shipping_address_id, billing_address_id, updated_by, - } => DieselPaymentIntentUpdate::MerchantStatusUpdate { + } => Self::MerchantStatusUpdate { status, shipping_address_id, billing_address_id, @@ -504,7 +504,7 @@ impl From for DieselPaymentIntentUpdate { status, updated_by, incremental_authorization_allowed, - } => DieselPaymentIntentUpdate::PGStatusUpdate { + } => Self::PGStatusUpdate { status, updated_by, incremental_authorization_allowed, @@ -531,7 +531,7 @@ impl From for DieselPaymentIntentUpdate { session_expiry, request_external_three_ds_authentication, frm_metadata, - } => DieselPaymentIntentUpdate::Update { + } => Self::Update { amount, currency, setup_future_usage, @@ -558,7 +558,7 @@ impl From for DieselPaymentIntentUpdate { active_attempt_id, attempt_count, updated_by, - } => DieselPaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { + } => Self::PaymentAttemptAndAttemptCountUpdate { active_attempt_id, attempt_count, updated_by, @@ -568,7 +568,7 @@ impl From for DieselPaymentIntentUpdate { active_attempt_id, attempt_count, updated_by, - } => DieselPaymentIntentUpdate::StatusAndAttemptUpdate { + } => Self::StatusAndAttemptUpdate { status, active_attempt_id, attempt_count, @@ -578,7 +578,7 @@ impl From for DieselPaymentIntentUpdate { status, merchant_decision, updated_by, - } => DieselPaymentIntentUpdate::ApproveUpdate { + } => Self::ApproveUpdate { status, merchant_decision, updated_by, @@ -587,7 +587,7 @@ impl From for DieselPaymentIntentUpdate { status, merchant_decision, updated_by, - } => DieselPaymentIntentUpdate::RejectUpdate { + } => Self::RejectUpdate { status, merchant_decision, updated_by, @@ -595,21 +595,21 @@ impl From for DieselPaymentIntentUpdate { PaymentIntentUpdate::SurchargeApplicableUpdate { surcharge_applicable, updated_by, - } => DieselPaymentIntentUpdate::SurchargeApplicableUpdate { + } => Self::SurchargeApplicableUpdate { surcharge_applicable: Some(surcharge_applicable), updated_by, }, PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => { - DieselPaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } + Self::IncrementalAuthorizationAmountUpdate { amount } } PaymentIntentUpdate::AuthorizationCountUpdate { authorization_count, - } => DieselPaymentIntentUpdate::AuthorizationCountUpdate { + } => Self::AuthorizationCountUpdate { authorization_count, }, PaymentIntentUpdate::CompleteAuthorizeUpdate { shipping_address_id, - } => DieselPaymentIntentUpdate::CompleteAuthorizeUpdate { + } => Self::CompleteAuthorizeUpdate { shipping_address_id, }, } diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 360c3d2924a9..b43e5606df45 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2664,6 +2664,7 @@ async fn validate_payment_method_and_client_secret( Ok(()) } +#[allow(clippy::too_many_arguments)] pub async fn call_surcharge_decision_management( state: routes::AppState, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index fe3fae08671a..7468c7e960c3 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -603,7 +603,7 @@ pub async fn get_token_for_recurring_mandate( db.find_payment_intent_by_payment_id_merchant_id( payment_id, &mandate.merchant_id, - &merchant_key_store, + merchant_key_store, merchant_account.storage_scheme, ) .await diff --git a/crates/router/src/core/user/sample_data.rs b/crates/router/src/core/user/sample_data.rs index e1bde652305f..5b5556576001 100644 --- a/crates/router/src/core/user/sample_data.rs +++ b/crates/router/src/core/user/sample_data.rs @@ -1,12 +1,13 @@ use api_models::user::sample_data::SampleDataRequest; use common_utils::errors::ReportSwitchExt; use diesel_models::{user::sample_data::PaymentAttemptBatchNew, RefundNew}; -use hyperswitch_domain_models::payments::payment_intent::PaymentIntentNew; +use error_stack::ResultExt; +use hyperswitch_domain_models::payments::PaymentIntent; pub type SampleDataApiResponse = SampleDataResult>; use crate::{ - core::errors::sample_data::SampleDataResult, + core::errors::sample_data::{SampleDataError, SampleDataResult}, routes::{app::ReqState, AppState}, services::{authentication::UserFromToken, ApplicationResponse}, utils::user::sample_data::generate_sample_data, @@ -21,8 +22,18 @@ pub async fn generate_sample_data_for_user( let sample_data = generate_sample_data(&state, req, user_from_token.merchant_id.as_str()).await?; + let key_store = state + .store + .get_merchant_key_store_by_merchant_id( + &user_from_token.merchant_id, + &state.store.get_master_key().to_vec().into(), + ) + .await + .change_context(SampleDataError::InternalServerError) + .attach_printable("Not able to fetch merchant key store")?; // If not able to fetch merchant key store for any reason, this should be an internal server error + let (payment_intents, payment_attempts, refunds): ( - Vec, + Vec, Vec, Vec, ) = sample_data.into_iter().fold( @@ -39,7 +50,7 @@ pub async fn generate_sample_data_for_user( state .store - .insert_payment_intents_batch_for_sample_data(payment_intents) + .insert_payment_intents_batch_for_sample_data(payment_intents, &key_store) .await .switch()?; state @@ -64,9 +75,19 @@ pub async fn delete_sample_data_for_user( ) -> SampleDataApiResponse<()> { let merchant_id_del = user_from_token.merchant_id.as_str(); + let key_store = state + .store + .get_merchant_key_store_by_merchant_id( + &user_from_token.merchant_id, + &state.store.get_master_key().to_vec().into(), + ) + .await + .change_context(SampleDataError::InternalServerError) + .attach_printable("Not able to fetch merchant key store")?; // If not able to fetch merchant key store for any reason, this should be an internal server error + state .store - .delete_payment_intents_for_sample_data(merchant_id_del) + .delete_payment_intents_for_sample_data(merchant_id_del, &key_store) .await .switch()?; state diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 9ee0c2e6032b..1531b69a3e01 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -2540,14 +2540,15 @@ impl DashboardMetadataInterface for KafkaStore { impl BatchSampleDataInterface for KafkaStore { async fn insert_payment_intents_batch_for_sample_data( &self, - batch: Vec, + batch: Vec, + key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore, ) -> CustomResult< Vec, hyperswitch_domain_models::errors::StorageError, > { let payment_intents_list = self .diesel_store - .insert_payment_intents_batch_for_sample_data(batch) + .insert_payment_intents_batch_for_sample_data(batch, key_store) .await?; for payment_intent in payment_intents_list.iter() { @@ -2602,13 +2603,14 @@ impl BatchSampleDataInterface for KafkaStore { async fn delete_payment_intents_for_sample_data( &self, merchant_id: &str, + key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore, ) -> CustomResult< Vec, hyperswitch_domain_models::errors::StorageError, > { let payment_intents_list = self .diesel_store - .delete_payment_intents_for_sample_data(merchant_id) + .delete_payment_intents_for_sample_data(merchant_id, key_store) .await?; for payment_intent in payment_intents_list.iter() { diff --git a/crates/router/src/db/user/sample_data.rs b/crates/router/src/db/user/sample_data.rs index f7926021afd0..5a23666c7b10 100644 --- a/crates/router/src/db/user/sample_data.rs +++ b/crates/router/src/db/user/sample_data.rs @@ -5,9 +5,12 @@ use diesel_models::{ user::sample_data::PaymentAttemptBatchNew, }; use error_stack::{Report, ResultExt}; +use futures::{future::try_join_all, FutureExt}; use hyperswitch_domain_models::{ + behaviour::Conversion, errors::StorageError, - payments::{payment_attempt::PaymentAttempt, payment_intent::PaymentIntentNew, PaymentIntent}, + merchant_key_store::MerchantKeyStore, + payments::{payment_attempt::PaymentAttempt, PaymentIntent}, }; use storage_impl::DataModelExt; @@ -17,7 +20,8 @@ use crate::{connection::pg_connection_write, core::errors::CustomResult, service pub trait BatchSampleDataInterface { async fn insert_payment_intents_batch_for_sample_data( &self, - batch: Vec, + batch: Vec, + key_store: &MerchantKeyStore, ) -> CustomResult, StorageError>; async fn insert_payment_attempts_batch_for_sample_data( @@ -33,6 +37,7 @@ pub trait BatchSampleDataInterface { async fn delete_payment_intents_for_sample_data( &self, merchant_id: &str, + key_store: &MerchantKeyStore, ) -> CustomResult, StorageError>; async fn delete_payment_attempts_for_sample_data( @@ -50,20 +55,30 @@ pub trait BatchSampleDataInterface { impl BatchSampleDataInterface for Store { async fn insert_payment_intents_batch_for_sample_data( &self, - batch: Vec, + batch: Vec, + key_store: &MerchantKeyStore, ) -> CustomResult, StorageError> { let conn = pg_connection_write(self) .await .change_context(StorageError::DatabaseConnectionError)?; - let new_intents = batch.into_iter().map(|i| i.to_storage_model()).collect(); + let new_intents = try_join_all(batch.into_iter().map(|payment_intent| async { + payment_intent + .construct_new() + .await + .change_context(StorageError::EncryptionError) + })) + .await?; + sample_data_queries::insert_payment_intents(&conn, new_intents) .await .map_err(diesel_error_to_data_error) .map(|v| { - v.into_iter() - .map(PaymentIntent::from_storage_model) - .collect() - }) + try_join_all(v.into_iter().map(|payment_intent| { + PaymentIntent::convert_back(payment_intent, key_store.key.get_inner()) + })) + .map(|join_result| join_result.change_context(StorageError::DecryptionError)) + })? + .await } async fn insert_payment_attempts_batch_for_sample_data( @@ -97,6 +112,7 @@ impl BatchSampleDataInterface for Store { async fn delete_payment_intents_for_sample_data( &self, merchant_id: &str, + key_store: &MerchantKeyStore, ) -> CustomResult, StorageError> { let conn = pg_connection_write(self) .await @@ -105,10 +121,12 @@ impl BatchSampleDataInterface for Store { .await .map_err(diesel_error_to_data_error) .map(|v| { - v.into_iter() - .map(PaymentIntent::from_storage_model) - .collect() - }) + try_join_all(v.into_iter().map(|payment_intent| { + PaymentIntent::convert_back(payment_intent, key_store.key.get_inner()) + })) + .map(|join_result| join_result.change_context(StorageError::DecryptionError)) + })? + .await } async fn delete_payment_attempts_for_sample_data( @@ -144,7 +162,8 @@ impl BatchSampleDataInterface for Store { impl BatchSampleDataInterface for storage_impl::MockDb { async fn insert_payment_intents_batch_for_sample_data( &self, - _batch: Vec, + _batch: Vec, + _key_store: &MerchantKeyStore, ) -> CustomResult, StorageError> { Err(StorageError::MockDbError)? } @@ -166,6 +185,7 @@ impl BatchSampleDataInterface for storage_impl::MockDb { async fn delete_payment_intents_for_sample_data( &self, _merchant_id: &str, + _key_store: &MerchantKeyStore, ) -> CustomResult, StorageError> { Err(StorageError::MockDbError)? } diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index ea690af35aeb..2bb40bae54ff 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -5,7 +5,7 @@ use api_models::{ use common_utils::{id_type, types::MinorUnit}; use diesel_models::{user::sample_data::PaymentAttemptBatchNew, RefundNew}; use error_stack::ResultExt; -use hyperswitch_domain_models::payments::payment_intent::PaymentIntentNew; +use hyperswitch_domain_models::payments::PaymentIntent; use rand::{prelude::SliceRandom, thread_rng, Rng}; use time::OffsetDateTime; @@ -20,7 +20,7 @@ pub async fn generate_sample_data( state: &AppState, req: SampleDataRequest, merchant_id: &str, -) -> SampleDataResult)>> { +) -> SampleDataResult)>> { let merchant_id = merchant_id.to_string(); let sample_data_size: usize = req.record.unwrap_or(100); @@ -101,7 +101,7 @@ pub async fn generate_sample_data( let mut rng = thread_rng(); random_array.shuffle(&mut rng); - let mut res: Vec<(PaymentIntentNew, PaymentAttemptBatchNew, Option)> = Vec::new(); + let mut res: Vec<(PaymentIntent, PaymentAttemptBatchNew, Option)> = Vec::new(); let start_time = req .start_time .unwrap_or(common_utils::date_time::now() - time::Duration::days(7)) @@ -172,7 +172,7 @@ pub async fn generate_sample_data( let is_failed_payment = (random_array.get(num - 1).unwrap_or(&0) % failure_after_attempts) == 0; - let payment_intent = PaymentIntentNew { + let payment_intent = PaymentIntent { payment_id: payment_id.clone(), merchant_id: merchant_id.clone(), status: match is_failed_payment { @@ -186,8 +186,8 @@ pub async fn generate_sample_data( .unwrap_or(&common_enums::Currency::USD), ), description: Some("This is a sample payment".to_string()), - created_at: Some(created_at), - modified_at: Some(modified_at), + created_at, + modified_at, last_synced: Some(last_synced), client_secret: Some(client_secret), business_country: business_country_default, diff --git a/crates/storage_impl/src/mock_db/payment_intent.rs b/crates/storage_impl/src/mock_db/payment_intent.rs index b4daa61206bc..bf3ce0baaab0 100644 --- a/crates/storage_impl/src/mock_db/payment_intent.rs +++ b/crates/storage_impl/src/mock_db/payment_intent.rs @@ -1,6 +1,8 @@ use common_utils::errors::CustomResult; use diesel_models::enums as storage_enums; +use error_stack::ResultExt; use hyperswitch_domain_models::{ + behaviour::Conversion, errors::StorageError, merchant_key_store::MerchantKeyStore, payments::{ @@ -11,7 +13,6 @@ use hyperswitch_domain_models::{ }; use super::MockDb; -use crate::DataModelExt; #[async_trait::async_trait] impl PaymentIntentInterface for MockDb { @@ -77,7 +78,7 @@ impl PaymentIntentInterface for MockDb { &self, this: PaymentIntent, update: PaymentIntentUpdate, - _key_store: &MerchantKeyStore, + key_store: &MerchantKeyStore, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { let mut payment_intents = self.payment_intents.lock().await; @@ -85,11 +86,21 @@ impl PaymentIntentInterface for MockDb { .iter_mut() .find(|item| item.payment_id == this.payment_id && item.merchant_id == this.merchant_id) .unwrap(); - *payment_intent = PaymentIntent::from_storage_model( - update - .to_storage_model() - .apply_changeset(this.to_storage_model()), - ); + + let diesel_payment_intent_update = diesel_models::PaymentIntentUpdate::from(update); + let diesel_payment_intent = payment_intent + .clone() + .convert() + .await + .change_context(StorageError::EncryptionError)?; + + *payment_intent = PaymentIntent::convert_back( + diesel_payment_intent_update.apply_changeset(diesel_payment_intent), + key_store.key.get_inner(), + ) + .await + .change_context(StorageError::DecryptionError)?; + Ok(payment_intent.clone()) } diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index e5e3a487f508..70cb60f521cc 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -14,6 +14,7 @@ use diesel_models::{ }; use error_stack::ResultExt; use hyperswitch_domain_models::{ + behaviour::Conversion, errors, mandates::{MandateAmountData, MandateDataType, MandateDetails}, payments::{ @@ -192,11 +193,13 @@ impl PaymentAttemptInterface for RouterStore { _storage_scheme: MerchantStorageScheme, ) -> CustomResult { let conn = pg_connection_read(self).await?; - let intents = pi - .iter() - .cloned() - .map(|pi| pi.to_storage_model()) - .collect::>(); + let intents = futures::future::try_join_all(pi.iter().cloned().map(|pi| async { + pi.convert() + .await + .change_context(errors::StorageError::EncryptionError) + })) + .await?; + DieselPaymentAttempt::get_filters_for_payments(&conn, intents.as_slice(), merchant_id) .await .map_err(|er| { diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index 008baa61111f..25dd90131cb9 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -12,8 +12,7 @@ use diesel_models::{ kv, payment_attempt::PaymentAttempt as DieselPaymentAttempt, payment_intent::{ - PaymentIntent as DieselPaymentIntent, PaymentIntentNew as DieselPaymentIntentNew, - PaymentIntentUpdate as DieselPaymentIntentUpdate, + PaymentIntent as DieselPaymentIntent, PaymentIntentUpdate as DieselPaymentIntentUpdate, }, }; #[cfg(feature = "olap")] @@ -30,7 +29,7 @@ use hyperswitch_domain_models::{ errors::StorageError, payments::{ payment_attempt::PaymentAttempt, - payment_intent::{PaymentIntentInterface, PaymentIntentNew, PaymentIntentUpdate}, + payment_intent::{PaymentIntentInterface, PaymentIntentUpdate}, PaymentIntent, }, RemoteStorageObject, @@ -467,6 +466,7 @@ impl PaymentIntentInterface for crate::RouterStore { storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { use common_utils::errors::ReportSwitchExt; + use futures::{future::try_join_all, FutureExt}; let conn = connection::pg_connection_read(self).await.switch()?; let conn = async_bb8_diesel::Connection::as_async_conn(&conn); @@ -560,18 +560,21 @@ impl PaymentIntentInterface for crate::RouterStore { ) .await .map(|payment_intents| { - payment_intents - .into_iter() - .map(PaymentIntent::from_storage_model) - .collect::>() + try_join_all(payment_intents.into_iter().map(|diesel_payment_intent| { + PaymentIntent::convert_back( + diesel_payment_intent, + merchant_key_store.key.get_inner(), + ) + })) + .map(|join_result| join_result.change_context(StorageError::DecryptionError)) }) .map_err(|er| { StorageError::DatabaseError( error_stack::report!(diesel_models::errors::DatabaseError::from(er)) .attach_printable("Error filtering payment records"), ) - .into() - }) + })? + .await } #[cfg(feature = "olap")] @@ -603,6 +606,8 @@ impl PaymentIntentInterface for crate::RouterStore { merchant_key_store: &MerchantKeyStore, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { + use futures::{future::try_join_all, FutureExt}; + let conn = connection::pg_connection_read(self).await.switch()?; let conn = async_bb8_diesel::Connection::as_async_conn(&conn); let mut query = DieselPaymentIntent::table() @@ -741,23 +746,24 @@ impl PaymentIntentInterface for crate::RouterStore { .get_results_async::<(DieselPaymentIntent, DieselPaymentAttempt)>(conn) .await .map(|results| { - results - .into_iter() - .map(|(pi, pa)| { - ( - PaymentIntent::from_storage_model(pi), - PaymentAttempt::from_storage_model(pa), - ) - }) - .collect() + try_join_all(results.into_iter().map(|(pi, pa)| { + PaymentIntent::convert_back(pi, merchant_key_store.key.get_inner()).map( + |payment_intent| { + payment_intent.map(|payment_intent| { + (payment_intent, PaymentAttempt::from_storage_model(pa)) + }) + }, + ) + })) + .map(|join_result| join_result.change_context(StorageError::DecryptionError)) }) .map_err(|er| { StorageError::DatabaseError( error_stack::report!(diesel_models::errors::DatabaseError::from(er)) .attach_printable("Error filtering payment records"), ) - .into() - }) + })? + .await } #[cfg(feature = "olap")] @@ -842,379 +848,3 @@ impl PaymentIntentInterface for crate::RouterStore { }) } } - -impl DataModelExt for PaymentIntentNew { - type StorageModel = DieselPaymentIntentNew; - - fn to_storage_model(self) -> Self::StorageModel { - DieselPaymentIntentNew { - payment_id: self.payment_id, - merchant_id: self.merchant_id, - status: self.status, - amount: self.amount, - currency: self.currency, - amount_captured: self.amount_captured, - customer_id: self.customer_id, - description: self.description, - return_url: self.return_url, - metadata: self.metadata, - frm_metadata: self.frm_metadata, - connector_id: self.connector_id, - shipping_address_id: self.shipping_address_id, - billing_address_id: self.billing_address_id, - statement_descriptor_name: self.statement_descriptor_name, - statement_descriptor_suffix: self.statement_descriptor_suffix, - created_at: self.created_at, - modified_at: self.modified_at, - last_synced: self.last_synced, - setup_future_usage: self.setup_future_usage, - off_session: self.off_session, - client_secret: self.client_secret, - active_attempt_id: self.active_attempt.get_id(), - business_country: self.business_country, - business_label: self.business_label, - order_details: self.order_details, - allowed_payment_method_types: self.allowed_payment_method_types, - connector_metadata: self.connector_metadata, - feature_metadata: self.feature_metadata, - attempt_count: self.attempt_count, - profile_id: self.profile_id, - merchant_decision: self.merchant_decision, - payment_link_id: self.payment_link_id, - payment_confirm_source: self.payment_confirm_source, - updated_by: self.updated_by, - surcharge_applicable: self.surcharge_applicable, - request_incremental_authorization: self.request_incremental_authorization, - incremental_authorization_allowed: self.incremental_authorization_allowed, - authorization_count: self.authorization_count, - fingerprint_id: self.fingerprint_id, - session_expiry: self.session_expiry, - request_external_three_ds_authentication: self.request_external_three_ds_authentication, - charges: self.charges, - } - } - - fn from_storage_model(storage_model: Self::StorageModel) -> Self { - Self { - payment_id: storage_model.payment_id, - merchant_id: storage_model.merchant_id, - status: storage_model.status, - amount: storage_model.amount, - currency: storage_model.currency, - amount_captured: storage_model.amount_captured, - customer_id: storage_model.customer_id, - description: storage_model.description, - return_url: storage_model.return_url, - metadata: storage_model.metadata, - frm_metadata: storage_model.frm_metadata, - connector_id: storage_model.connector_id, - shipping_address_id: storage_model.shipping_address_id, - billing_address_id: storage_model.billing_address_id, - statement_descriptor_name: storage_model.statement_descriptor_name, - statement_descriptor_suffix: storage_model.statement_descriptor_suffix, - created_at: storage_model.created_at, - modified_at: storage_model.modified_at, - last_synced: storage_model.last_synced, - setup_future_usage: storage_model.setup_future_usage, - off_session: storage_model.off_session, - client_secret: storage_model.client_secret, - active_attempt: RemoteStorageObject::ForeignID(storage_model.active_attempt_id), - business_country: storage_model.business_country, - business_label: storage_model.business_label, - order_details: storage_model.order_details, - allowed_payment_method_types: storage_model.allowed_payment_method_types, - connector_metadata: storage_model.connector_metadata, - feature_metadata: storage_model.feature_metadata, - attempt_count: storage_model.attempt_count, - profile_id: storage_model.profile_id, - merchant_decision: storage_model.merchant_decision, - payment_link_id: storage_model.payment_link_id, - payment_confirm_source: storage_model.payment_confirm_source, - updated_by: storage_model.updated_by, - surcharge_applicable: storage_model.surcharge_applicable, - request_incremental_authorization: storage_model.request_incremental_authorization, - incremental_authorization_allowed: storage_model.incremental_authorization_allowed, - authorization_count: storage_model.authorization_count, - fingerprint_id: storage_model.fingerprint_id, - session_expiry: storage_model.session_expiry, - request_external_three_ds_authentication: storage_model - .request_external_three_ds_authentication, - charges: storage_model.charges, - } - } -} - -impl DataModelExt for PaymentIntent { - type StorageModel = DieselPaymentIntent; - - fn to_storage_model(self) -> Self::StorageModel { - DieselPaymentIntent { - payment_id: self.payment_id, - merchant_id: self.merchant_id, - status: self.status, - amount: self.amount, - currency: self.currency, - amount_captured: self.amount_captured, - customer_id: self.customer_id, - description: self.description, - return_url: self.return_url, - metadata: self.metadata, - connector_id: self.connector_id, - shipping_address_id: self.shipping_address_id, - billing_address_id: self.billing_address_id, - statement_descriptor_name: self.statement_descriptor_name, - statement_descriptor_suffix: self.statement_descriptor_suffix, - created_at: self.created_at, - modified_at: self.modified_at, - last_synced: self.last_synced, - setup_future_usage: self.setup_future_usage, - off_session: self.off_session, - client_secret: self.client_secret, - active_attempt_id: self.active_attempt.get_id(), - business_country: self.business_country, - business_label: self.business_label, - order_details: self.order_details, - allowed_payment_method_types: self.allowed_payment_method_types, - connector_metadata: self.connector_metadata, - feature_metadata: self.feature_metadata, - attempt_count: self.attempt_count, - profile_id: self.profile_id, - merchant_decision: self.merchant_decision, - payment_link_id: self.payment_link_id, - payment_confirm_source: self.payment_confirm_source, - updated_by: self.updated_by, - surcharge_applicable: self.surcharge_applicable, - request_incremental_authorization: self.request_incremental_authorization, - incremental_authorization_allowed: self.incremental_authorization_allowed, - authorization_count: self.authorization_count, - fingerprint_id: self.fingerprint_id, - session_expiry: self.session_expiry, - request_external_three_ds_authentication: self.request_external_three_ds_authentication, - charges: self.charges, - frm_metadata: self.frm_metadata, - } - } - - fn from_storage_model(storage_model: Self::StorageModel) -> Self { - Self { - payment_id: storage_model.payment_id, - merchant_id: storage_model.merchant_id, - status: storage_model.status, - amount: storage_model.amount, - currency: storage_model.currency, - amount_captured: storage_model.amount_captured, - customer_id: storage_model.customer_id, - description: storage_model.description, - return_url: storage_model.return_url, - metadata: storage_model.metadata, - connector_id: storage_model.connector_id, - shipping_address_id: storage_model.shipping_address_id, - billing_address_id: storage_model.billing_address_id, - statement_descriptor_name: storage_model.statement_descriptor_name, - statement_descriptor_suffix: storage_model.statement_descriptor_suffix, - created_at: storage_model.created_at, - modified_at: storage_model.modified_at, - last_synced: storage_model.last_synced, - setup_future_usage: storage_model.setup_future_usage, - off_session: storage_model.off_session, - client_secret: storage_model.client_secret, - active_attempt: RemoteStorageObject::ForeignID(storage_model.active_attempt_id), - business_country: storage_model.business_country, - business_label: storage_model.business_label, - order_details: storage_model.order_details, - allowed_payment_method_types: storage_model.allowed_payment_method_types, - connector_metadata: storage_model.connector_metadata, - feature_metadata: storage_model.feature_metadata, - attempt_count: storage_model.attempt_count, - profile_id: storage_model.profile_id, - merchant_decision: storage_model.merchant_decision, - payment_link_id: storage_model.payment_link_id, - payment_confirm_source: storage_model.payment_confirm_source, - updated_by: storage_model.updated_by, - surcharge_applicable: storage_model.surcharge_applicable, - request_incremental_authorization: storage_model.request_incremental_authorization, - incremental_authorization_allowed: storage_model.incremental_authorization_allowed, - authorization_count: storage_model.authorization_count, - fingerprint_id: storage_model.fingerprint_id, - session_expiry: storage_model.session_expiry, - request_external_three_ds_authentication: storage_model - .request_external_three_ds_authentication, - charges: storage_model.charges, - frm_metadata: storage_model.frm_metadata, - } - } -} - -impl DataModelExt for PaymentIntentUpdate { - type StorageModel = DieselPaymentIntentUpdate; - - fn to_storage_model(self) -> Self::StorageModel { - match self { - Self::ResponseUpdate { - status, - amount_captured, - fingerprint_id, - return_url, - updated_by, - incremental_authorization_allowed, - } => DieselPaymentIntentUpdate::ResponseUpdate { - status, - amount_captured, - fingerprint_id, - return_url, - updated_by, - incremental_authorization_allowed, - }, - Self::MetadataUpdate { - metadata, - updated_by, - } => DieselPaymentIntentUpdate::MetadataUpdate { - metadata, - updated_by, - }, - Self::ReturnUrlUpdate { - return_url, - status, - customer_id, - shipping_address_id, - billing_address_id, - updated_by, - } => DieselPaymentIntentUpdate::ReturnUrlUpdate { - return_url, - status, - customer_id, - shipping_address_id, - billing_address_id, - updated_by, - }, - Self::MerchantStatusUpdate { - status, - shipping_address_id, - billing_address_id, - updated_by, - } => DieselPaymentIntentUpdate::MerchantStatusUpdate { - status, - shipping_address_id, - billing_address_id, - updated_by, - }, - Self::PGStatusUpdate { - status, - updated_by, - incremental_authorization_allowed, - } => DieselPaymentIntentUpdate::PGStatusUpdate { - status, - updated_by, - incremental_authorization_allowed, - }, - Self::Update { - amount, - currency, - setup_future_usage, - status, - customer_id, - shipping_address_id, - billing_address_id, - return_url, - business_country, - business_label, - description, - statement_descriptor_name, - statement_descriptor_suffix, - order_details, - metadata, - payment_confirm_source, - updated_by, - fingerprint_id, - session_expiry, - request_external_three_ds_authentication, - frm_metadata, - } => DieselPaymentIntentUpdate::Update { - amount, - currency, - setup_future_usage, - status, - customer_id, - shipping_address_id, - billing_address_id, - return_url, - business_country, - business_label, - description, - statement_descriptor_name, - statement_descriptor_suffix, - order_details, - metadata, - payment_confirm_source, - updated_by, - fingerprint_id, - session_expiry, - request_external_three_ds_authentication, - frm_metadata, - }, - Self::PaymentAttemptAndAttemptCountUpdate { - active_attempt_id, - attempt_count, - updated_by, - } => DieselPaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { - active_attempt_id, - attempt_count, - updated_by, - }, - Self::StatusAndAttemptUpdate { - status, - active_attempt_id, - attempt_count, - updated_by, - } => DieselPaymentIntentUpdate::StatusAndAttemptUpdate { - status, - active_attempt_id, - attempt_count, - updated_by, - }, - Self::ApproveUpdate { - status, - merchant_decision, - updated_by, - } => DieselPaymentIntentUpdate::ApproveUpdate { - status, - merchant_decision, - updated_by, - }, - Self::RejectUpdate { - status, - merchant_decision, - updated_by, - } => DieselPaymentIntentUpdate::RejectUpdate { - status, - merchant_decision, - updated_by, - }, - Self::SurchargeApplicableUpdate { - surcharge_applicable, - updated_by, - } => DieselPaymentIntentUpdate::SurchargeApplicableUpdate { - surcharge_applicable: Some(surcharge_applicable), - updated_by, - }, - Self::IncrementalAuthorizationAmountUpdate { amount } => { - DieselPaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } - } - Self::AuthorizationCountUpdate { - authorization_count, - } => DieselPaymentIntentUpdate::AuthorizationCountUpdate { - authorization_count, - }, - Self::CompleteAuthorizeUpdate { - shipping_address_id, - } => DieselPaymentIntentUpdate::CompleteAuthorizeUpdate { - shipping_address_id, - }, - } - } - - #[allow(clippy::todo)] - fn from_storage_model(_storage_model: Self::StorageModel) -> Self { - todo!("Reverse map should no longer be needed") - } -} From 42da49bb8045db728f1184da78713dbb7c67bfe2 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 10 Jun 2024 05:05:41 +0000 Subject: [PATCH 05/12] chore: run formatter --- crates/common_utils/src/metrics/utils.rs | 3 ++- .../hyperswitch_domain_models/src/payments/payment_intent.rs | 3 +-- crates/storage_impl/src/payments/payment_intent.rs | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/common_utils/src/metrics/utils.rs b/crates/common_utils/src/metrics/utils.rs index 9a40339bb49b..05237afbc02d 100644 --- a/crates/common_utils/src/metrics/utils.rs +++ b/crates/common_utils/src/metrics/utils.rs @@ -1,8 +1,9 @@ //! metric utility functions -use router_env::opentelemetry; use std::time; +use router_env::opentelemetry; + /// Record the time taken by the future to execute #[inline] pub async fn time_future(future: F) -> (R, time::Duration) diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index b2e8e4fb14ce..2c99360d4f94 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -1,4 +1,3 @@ -use crate::merchant_key_store::MerchantKeyStore; use common_enums as storage_enums; use common_utils::{ consts::{PAYMENTS_LIST_MAX_LIMIT_V1, PAYMENTS_LIST_MAX_LIMIT_V2}, @@ -9,7 +8,7 @@ use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use super::{payment_attempt::PaymentAttempt, PaymentIntent}; -use crate::{errors, RemoteStorageObject}; +use crate::{errors, merchant_key_store::MerchantKeyStore, RemoteStorageObject}; #[async_trait::async_trait] pub trait PaymentIntentInterface { async fn update_payment_intent( diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index 25dd90131cb9..62854cb261a2 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -23,10 +23,10 @@ use diesel_models::{ use error_stack::ResultExt; #[cfg(feature = "olap")] use hyperswitch_domain_models::payments::payment_intent::PaymentIntentFetchConstraints; - use hyperswitch_domain_models::{ behaviour::Conversion, errors::StorageError, + merchant_key_store::MerchantKeyStore, payments::{ payment_attempt::PaymentAttempt, payment_intent::{PaymentIntentInterface, PaymentIntentUpdate}, @@ -49,8 +49,6 @@ use crate::{ DataModelExt, DatabaseStore, KVRouterStore, }; -use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore; - #[async_trait::async_trait] impl PaymentIntentInterface for KVRouterStore { async fn insert_payment_intent( From 7a16a8014f87d74426b049b266fb2b7591b50d99 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 10 Jun 2024 10:52:40 +0530 Subject: [PATCH 06/12] chore: cargo clippy --- crates/router/src/core/user/sample_data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/core/user/sample_data.rs b/crates/router/src/core/user/sample_data.rs index a28f95290e71..e1ccb3b03355 100644 --- a/crates/router/src/core/user/sample_data.rs +++ b/crates/router/src/core/user/sample_data.rs @@ -8,7 +8,7 @@ pub type SampleDataApiResponse = SampleDataResult>; use crate::{ core::errors::sample_data::{SampleDataError, SampleDataResult}, - routes::{app::ReqState, AppState}, + routes::{app::ReqState, SessionState}, services::{authentication::UserFromToken, ApplicationResponse}, utils::user::sample_data::generate_sample_data, }; From 1cb24859f4f450ea7a41f9b85aaba684bf8d4cd1 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 10 Jun 2024 11:27:14 +0530 Subject: [PATCH 07/12] chore: cargo clippy --- .../down.sql | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql index 899b595105fa..9766ed42d019 100644 --- a/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql +++ b/migrations/2024-06-03-090859_make_id_as_optional_for_payments/down.sql @@ -1,16 +1,18 @@ -- This file should undo anything in `up.sql` ALTER TABLE payment_attempt ALTER COLUMN id -SET NOT NULL: -ALTER TABLE payment_attempt DROP payment_attempt_pkey; +SET NOT NULL; + +ALTER TABLE payment_attempt DROP CONSTRAINT payment_attempt_pkey; ALTER TABLE payment_attempt ADD PRIMARY KEY (id); ALTER TABLE payment_intent ALTER COLUMN id -SET NOT NULL: -ALTER TABLE payment_intent DROP payment_intent_pkey; +SET NOT NULL; + +ALTER TABLE payment_intent DROP CONSTRAINT payment_intent_pkey; ALTER TABLE payment_intent ADD PRIMARY KEY (id); From b049676ab474660ce86c75279ed9713eb8e0e996 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 11 Jun 2024 15:40:56 +0530 Subject: [PATCH 08/12] chore: address PR comments --- crates/common_utils/Cargo.toml | 7 +- crates/common_utils/src/lib.rs | 1 + crates/common_utils/src/metrics/utils.rs | 2 +- crates/hyperswitch_domain_models/Cargo.toml | 2 +- crates/router/Cargo.toml | 6 +- crates/router/src/types/domain/types.rs | 226 -------------------- 6 files changed, 10 insertions(+), 234 deletions(-) diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index 365bc9436629..b1dd413148c2 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -8,9 +8,10 @@ readme = "README.md" license.workspace = true [features] -signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio"] +signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env"] async_ext = ["dep:async-trait"] -logs = [] +logs = ["dep:router_env"] +metrics = ["dep:router_env"] [dependencies] async-trait = { version = "0.1.79", optional = true } @@ -47,7 +48,7 @@ rust_decimal = "1.35" rusty-money = { git = "https://github.com/varunsrin/rusty_money", rev = "bbc0150742a0fff905225ff11ee09388e9babdcc", features = ["iso", "crypto"] } common_enums = { version = "0.1.0", path = "../common_enums" } masking = { version = "0.1.0", path = "../masking" } -router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"] } +router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"], optional = true } [target.'cfg(not(target_os = "windows"))'.dependencies] signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"], optional = true } diff --git a/crates/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs index b3df36faf721..ee0a474bcde0 100644 --- a/crates/common_utils/src/lib.rs +++ b/crates/common_utils/src/lib.rs @@ -30,6 +30,7 @@ pub mod static_cache; pub mod types; pub mod validation; +#[cfg(feature = "metrics")] pub mod metrics; /// Date-time utilities. diff --git a/crates/common_utils/src/metrics/utils.rs b/crates/common_utils/src/metrics/utils.rs index 05237afbc02d..71244ecc4fe4 100644 --- a/crates/common_utils/src/metrics/utils.rs +++ b/crates/common_utils/src/metrics/utils.rs @@ -16,7 +16,7 @@ where (result, time_spent) } -/// Record the time taken by the operation for the given context +/// Record the time taken (in seconds) by the operation for the given context #[inline] pub async fn record_operation_time( future: F, diff --git a/crates/hyperswitch_domain_models/Cargo.toml b/crates/hyperswitch_domain_models/Cargo.toml index a64770f3eeaa..0bbf0fe9bc2e 100644 --- a/crates/hyperswitch_domain_models/Cargo.toml +++ b/crates/hyperswitch_domain_models/Cargo.toml @@ -16,7 +16,7 @@ payouts = ["api_models/payouts"] # First party deps api_models = { version = "0.1.0", path = "../api_models", features = ["errors"] } common_enums = { version = "0.1.0", path = "../common_enums" } -common_utils = { version = "0.1.0", path = "../common_utils", features = ["async_ext"] } +common_utils = { version = "0.1.0", path = "../common_utils", features = ["async_ext", "metrics"] } masking = { version = "0.1.0", path = "../masking" } diesel_models = { version = "0.1.0", path = "../diesel_models", features = ["kv_store"] } cards = { version = "0.1.0", path = "../cards" } diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index c8eff1153029..871eed868937 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -71,7 +71,7 @@ qrcode = "0.14.0" rand = "0.8.5" rand_chacha = "0.3.1" regex = "1.10.4" -reqwest = { version = "0.11.27", features = ["json", "native-tls","__rustls", "gzip", "multipart"] } +reqwest = { version = "0.11.27", features = ["json", "native-tls", "__rustls", "gzip", "multipart"] } ring = "0.17.8" roxmltree = "0.19.0" rust_decimal = { version = "1.35.0", features = ["serde-with-float", "serde-with-str"] } @@ -102,7 +102,7 @@ api_models = { version = "0.1.0", path = "../api_models", features = ["errors"] analytics = { version = "0.1.0", path = "../analytics", optional = true } cards = { version = "0.1.0", path = "../cards" } common_enums = { version = "0.1.0", path = "../common_enums" } -common_utils = { version = "0.1.0", path = "../common_utils", features = ["signals", "async_ext", "logs"] } +common_utils = { version = "0.1.0", path = "../common_utils", features = ["signals", "async_ext", "logs", "metrics"] } hyperswitch_constraint_graph = { version = "0.1.0", path = "../hyperswitch_constraint_graph" } currency_conversion = { version = "0.1.0", path = "../currency_conversion" } hyperswitch_domain_models = { version = "0.1.0", path = "../hyperswitch_domain_models", default-features = false } @@ -126,7 +126,7 @@ isocountry = "0.3.2" iso_currency = "0.4.4" actix-http = "3.6.0" events = { version = "0.1.0", path = "../events" } -totp-rs = { version = "5.5.1", features = ["gen_secret", "otpauth"]} +totp-rs = { version = "5.5.1", features = ["gen_secret", "otpauth"] } serde_repr = "0.1.19" unidecode = "0.3.0" diff --git a/crates/router/src/types/domain/types.rs b/crates/router/src/types/domain/types.rs index fe3cec186da6..176b88b3f5bc 100644 --- a/crates/router/src/types/domain/types.rs +++ b/crates/router/src/types/domain/types.rs @@ -1,229 +1,3 @@ pub use hyperswitch_domain_models::type_encryption::{ decrypt, encrypt, encrypt_optional, AsyncLift, Lift, TypeEncryption, }; - -// use async_trait::async_trait; -// use common_utils::{ -// crypto, -// errors::{self, CustomResult}, -// ext_traits::AsyncExt, -// }; -// use diesel_models::encryption::Encryption; -// use error_stack::ResultExt; -// use masking::{PeekInterface, Secret}; -// use router_env::{instrument, tracing}; - -// use crate::routes::metrics::{request, DECRYPTION_TIME, ENCRYPTION_TIME}; - -// #[async_trait] -// pub trait TypeEncryption< -// T, -// V: crypto::EncodeMessage + crypto::DecodeMessage, -// S: masking::Strategy, -// >: Sized -// { -// async fn encrypt( -// masked_data: Secret, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult; - -// async fn decrypt( -// encrypted_data: Encryption, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult; -// } - -// #[async_trait] -// impl< -// V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, -// S: masking::Strategy + Send, -// > TypeEncryption for crypto::Encryptable> -// { -// #[instrument(skip_all)] -// async fn encrypt( -// masked_data: Secret, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult { -// let encrypted_data = crypt_algo.encode_message(key, masked_data.peek().as_bytes())?; - -// Ok(Self::new(masked_data, encrypted_data.into())) -// } - -// #[instrument(skip_all)] -// async fn decrypt( -// encrypted_data: Encryption, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult { -// let encrypted = encrypted_data.into_inner(); -// let data = crypt_algo.decode_message(key, encrypted.clone())?; - -// let value: String = std::str::from_utf8(&data) -// .change_context(errors::CryptoError::DecodingFailed)? -// .to_string(); - -// Ok(Self::new(value.into(), encrypted)) -// } -// } - -// #[async_trait] -// impl< -// V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, -// S: masking::Strategy + Send, -// > TypeEncryption -// for crypto::Encryptable> -// { -// #[instrument(skip_all)] -// async fn encrypt( -// masked_data: Secret, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult { -// let data = serde_json::to_vec(&masked_data.peek()) -// .change_context(errors::CryptoError::DecodingFailed)?; -// let encrypted_data = crypt_algo.encode_message(key, &data)?; - -// Ok(Self::new(masked_data, encrypted_data.into())) -// } - -// #[instrument(skip_all)] -// async fn decrypt( -// encrypted_data: Encryption, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult { -// let encrypted = encrypted_data.into_inner(); -// let data = crypt_algo.decode_message(key, encrypted.clone())?; - -// let value: serde_json::Value = -// serde_json::from_slice(&data).change_context(errors::CryptoError::DecodingFailed)?; - -// Ok(Self::new(value.into(), encrypted)) -// } -// } - -// #[async_trait] -// impl< -// V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static, -// S: masking::Strategy> + Send, -// > TypeEncryption, V, S> for crypto::Encryptable, S>> -// { -// #[instrument(skip_all)] -// async fn encrypt( -// masked_data: Secret, S>, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult { -// let encrypted_data = crypt_algo.encode_message(key, masked_data.peek())?; - -// Ok(Self::new(masked_data, encrypted_data.into())) -// } - -// #[instrument(skip_all)] -// async fn decrypt( -// encrypted_data: Encryption, -// key: &[u8], -// crypt_algo: V, -// ) -> CustomResult { -// let encrypted = encrypted_data.into_inner(); -// let data = crypt_algo.decode_message(key, encrypted.clone())?; - -// Ok(Self::new(data.into(), encrypted)) -// } -// } - -// pub trait Lift { -// type SelfWrapper; -// type OtherWrapper; - -// fn lift(self, func: Func) -> Self::OtherWrapper -// where -// Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper; -// } - -// impl Lift for Option { -// type SelfWrapper = Option; -// type OtherWrapper = CustomResult, E>; - -// fn lift(self, func: Func) -> Self::OtherWrapper -// where -// Func: Fn(Self::SelfWrapper) -> Self::OtherWrapper, -// { -// func(self) -// } -// } - -// #[async_trait] -// pub trait AsyncLift { -// type SelfWrapper; -// type OtherWrapper; - -// async fn async_lift(self, func: Func) -> Self::OtherWrapper -// where -// Func: Fn(Self::SelfWrapper) -> F + Send + Sync, -// F: futures::Future> + Send; -// } - -// #[async_trait] -// impl + Lift = V> + Send> AsyncLift for V { -// type SelfWrapper = >::SelfWrapper; -// type OtherWrapper = >::OtherWrapper; - -// async fn async_lift(self, func: Func) -> Self::OtherWrapper -// where -// Func: Fn(Self::SelfWrapper) -> F + Send + Sync, -// F: futures::Future> + Send, -// { -// func(self).await -// } -// } - -// #[inline] -// pub async fn encrypt( -// inner: Secret, -// key: &[u8], -// ) -> CustomResult>, errors::CryptoError> -// where -// S: masking::Strategy, -// crypto::Encryptable>: TypeEncryption, -// { -// request::record_operation_time( -// crypto::Encryptable::encrypt(inner, key, crypto::GcmAes256), -// &ENCRYPTION_TIME, -// &[], -// ) -// .await -// } - -// #[inline] -// pub async fn encrypt_optional( -// inner: Option>, -// key: &[u8], -// ) -> CustomResult>>, errors::CryptoError> -// where -// Secret: Send, -// S: masking::Strategy, -// crypto::Encryptable>: TypeEncryption, -// { -// inner.async_map(|f| encrypt(f, key)).await.transpose() -// } - -// #[inline] -// pub async fn decrypt>( -// inner: Option, -// key: &[u8], -// ) -> CustomResult>>, errors::CryptoError> -// where -// crypto::Encryptable>: TypeEncryption, -// { -// request::record_operation_time( -// inner.async_map(|item| crypto::Encryptable::decrypt(item, key, crypto::GcmAes256)), -// &DECRYPTION_TIME, -// &[], -// ) -// .await -// .transpose() -// } From bc0b61594f297f5218ac871a4e1baed5ae4fbe09 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Fri, 14 Jun 2024 19:18:57 +0530 Subject: [PATCH 09/12] chore: address PR comments --- crates/common_utils/Cargo.toml | 8 ++++---- crates/router/src/types/domain.rs | 9 +++++++-- crates/router/src/types/domain/behaviour.rs | 1 - crates/router/src/types/domain/merchant_key_store.rs | 1 - 4 files changed, 11 insertions(+), 8 deletions(-) delete mode 100644 crates/router/src/types/domain/behaviour.rs delete mode 100644 crates/router/src/types/domain/merchant_key_store.rs diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index b1dd413148c2..a76e05508676 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -11,14 +11,14 @@ license.workspace = true signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env"] async_ext = ["dep:async-trait"] logs = ["dep:router_env"] -metrics = ["dep:router_env"] +metrics = ["dep:router_env", "dep:futures"] [dependencies] async-trait = { version = "0.1.79", optional = true } bytes = "1.6.0" diesel = "2.1.5" error-stack = "0.4.1" -futures = { version = "0.3.30" } +futures = { version = "0.3.30", optional = true } hex = "0.4.3" http = "0.2.12" md5 = "0.7.0" @@ -30,7 +30,9 @@ rand = "0.8.5" regex = "1.10.4" reqwest = { version = "0.11.27", features = ["json", "native-tls", "gzip", "multipart"] } ring = { version = "0.17.8", features = ["std", "wasm32_unknown_unknown_js"] } +rust_decimal = "1.35" rustc-hash = "1.1.0" +semver = { version = "1.0.22", features = ["serde"] } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" serde_urlencoded = "0.7.1" @@ -39,12 +41,10 @@ strum = { version = "0.26.2", features = ["derive"] } thiserror = "1.0.58" time = { version = "0.3.35", features = ["serde", "serde-well-known", "std"] } tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread"], optional = true } -semver = { version = "1.0.22", features = ["serde"] } utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order"] } uuid = { version = "1.8.0", features = ["v7"] } # First party crates -rust_decimal = "1.35" rusty-money = { git = "https://github.com/varunsrin/rusty_money", rev = "bbc0150742a0fff905225ff11ee09388e9babdcc", features = ["iso", "crypto"] } common_enums = { version = "0.1.0", path = "../common_enums" } masking = { version = "0.1.0", path = "../masking" } diff --git a/crates/router/src/types/domain.rs b/crates/router/src/types/domain.rs index d18ae0d0190c..be93f30bfbed 100644 --- a/crates/router/src/types/domain.rs +++ b/crates/router/src/types/domain.rs @@ -1,10 +1,15 @@ mod address; -pub mod behaviour; +pub mod behaviour { + pub use hyperswitch_domain_models::behaviour::{Conversion, ReverseConversion}; +} + mod customer; mod event; mod merchant_account; mod merchant_connector_account; -mod merchant_key_store; +mod merchant_key_store { + pub use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore; +} pub mod payments; pub mod types; #[cfg(feature = "olap")] diff --git a/crates/router/src/types/domain/behaviour.rs b/crates/router/src/types/domain/behaviour.rs deleted file mode 100644 index 87ab7feab9c9..000000000000 --- a/crates/router/src/types/domain/behaviour.rs +++ /dev/null @@ -1 +0,0 @@ -pub use hyperswitch_domain_models::behaviour::{Conversion, ReverseConversion}; diff --git a/crates/router/src/types/domain/merchant_key_store.rs b/crates/router/src/types/domain/merchant_key_store.rs deleted file mode 100644 index d32e686acaf8..000000000000 --- a/crates/router/src/types/domain/merchant_key_store.rs +++ /dev/null @@ -1 +0,0 @@ -pub use hyperswitch_domain_models::merchant_key_store::MerchantKeyStore; From ba1734922226a93b6701730130cbd420f369bd0d Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 18 Jun 2024 12:29:42 +0530 Subject: [PATCH 10/12] chore: cargo clippy --- crates/common_utils/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index a76e05508676..eb20292c5801 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [features] signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env"] -async_ext = ["dep:async-trait"] +async_ext = ["dep:async-trait", "dep:futures"] logs = ["dep:router_env"] metrics = ["dep:router_env", "dep:futures"] From f2fa237f3b25931b260b0e00a76d02f611dd6821 Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 18 Jun 2024 12:40:50 +0530 Subject: [PATCH 11/12] chore: cargo clippy --- crates/common_utils/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index eb20292c5801..58a881db5905 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -8,7 +8,7 @@ readme = "README.md" license.workspace = true [features] -signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env"] +signals = ["dep:signal-hook-tokio", "dep:signal-hook", "dep:tokio", "dep:router_env", "dep:futures"] async_ext = ["dep:async-trait", "dep:futures"] logs = ["dep:router_env"] metrics = ["dep:router_env", "dep:futures"] From daf923130d52350f63b568f791e2d98c1fe860fa Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Wed, 19 Jun 2024 11:26:14 +0530 Subject: [PATCH 12/12] chore: cargo clippy --- crates/router/src/core/payment_methods/cards.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index bf1d52ca522b..3e23b2429450 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -62,12 +62,7 @@ use crate::{ }, db, logger, pii::prelude::*, - routes::{ - self, - app::SessionStateInfo, - metrics::{self, request}, - payment_methods::ParentPaymentMethodToken, - }, + routes::{self, app::SessionStateInfo, metrics, payment_methods::ParentPaymentMethodToken}, services, types::{ api::{self, routing as routing_types, PaymentMethodCreateExt},