mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 21:07:58 +08:00
refactor(storage): remove id from payment intent, attempt and remove datamodel ext from payment intent (#4923)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: Prajjwal Kumar <prajjwal.kumar@juspay.in>
This commit is contained in:
@ -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", "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"}
|
||||
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"
|
||||
|
||||
31
crates/hyperswitch_domain_models/src/behaviour.rs
Normal file
31
crates/hyperswitch_domain_models/src/behaviour.rs
Normal file
@ -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<Self::DstType, ValidationError>;
|
||||
|
||||
async fn convert_back(
|
||||
item: Self::DstType,
|
||||
key: &Secret<Vec<u8>>,
|
||||
) -> CustomResult<Self, ValidationError>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait ReverseConversion<SrcType: Conversion> {
|
||||
async fn convert(self, key: &Secret<Vec<u8>>) -> CustomResult<SrcType, ValidationError>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<T: Send, U: Conversion<DstType = T>> ReverseConversion<U> for T {
|
||||
async fn convert(self, key: &Secret<Vec<u8>>) -> CustomResult<U, ValidationError> {
|
||||
U::convert_back(self, key).await
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,10 @@ pub mod router_flow_types;
|
||||
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 {}
|
||||
|
||||
|
||||
57
crates/hyperswitch_domain_models/src/merchant_key_store.rs
Normal file
57
crates/hyperswitch_domain_models/src/merchant_key_store.rs
Normal file
@ -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<Secret<Vec<u8>>>,
|
||||
#[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<Self::DstType, ValidationError> {
|
||||
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<Vec<u8>>,
|
||||
) -> CustomResult<Self, ValidationError>
|
||||
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<Self::NewDstType, ValidationError> {
|
||||
Ok(diesel_models::merchant_key_store::MerchantKeyStoreNew {
|
||||
merchant_id: self.merchant_id,
|
||||
key: self.key.into(),
|
||||
created_at: date_time::now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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<Self::DstType, ValidationError> {
|
||||
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<Vec<u8>>,
|
||||
) -> CustomResult<Self, ValidationError>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(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,
|
||||
})
|
||||
}
|
||||
|
||||
async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,19 +8,21 @@ 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(
|
||||
&self,
|
||||
this: PaymentIntent,
|
||||
payment_intent: PaymentIntentUpdate,
|
||||
merchant_key_store: &MerchantKeyStore,
|
||||
storage_scheme: storage_enums::MerchantStorageScheme,
|
||||
) -> error_stack::Result<PaymentIntent, errors::StorageError>;
|
||||
|
||||
async fn insert_payment_intent(
|
||||
&self,
|
||||
new: PaymentIntentNew,
|
||||
new: PaymentIntent,
|
||||
merchant_key_store: &MerchantKeyStore,
|
||||
storage_scheme: storage_enums::MerchantStorageScheme,
|
||||
) -> error_stack::Result<PaymentIntent, errors::StorageError>;
|
||||
|
||||
@ -28,6 +30,7 @@ pub trait PaymentIntentInterface {
|
||||
&self,
|
||||
payment_id: &str,
|
||||
merchant_id: &str,
|
||||
merchant_key_store: &MerchantKeyStore,
|
||||
storage_scheme: storage_enums::MerchantStorageScheme,
|
||||
) -> error_stack::Result<PaymentIntent, errors::StorageError>;
|
||||
|
||||
@ -42,6 +45,7 @@ pub trait PaymentIntentInterface {
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
filters: &PaymentIntentFetchConstraints,
|
||||
merchant_key_store: &MerchantKeyStore,
|
||||
storage_scheme: storage_enums::MerchantStorageScheme,
|
||||
) -> error_stack::Result<Vec<PaymentIntent>, errors::StorageError>;
|
||||
|
||||
@ -50,6 +54,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<Vec<PaymentIntent>, errors::StorageError>;
|
||||
|
||||
@ -58,6 +63,7 @@ pub trait PaymentIntentInterface {
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
constraints: &PaymentIntentFetchConstraints,
|
||||
merchant_key_store: &MerchantKeyStore,
|
||||
storage_scheme: storage_enums::MerchantStorageScheme,
|
||||
) -> error_stack::Result<Vec<(PaymentIntent, PaymentAttempt)>, errors::StorageError>;
|
||||
|
||||
@ -440,6 +446,247 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
|
||||
}
|
||||
}
|
||||
|
||||
use diesel_models::PaymentIntentUpdate as DieselPaymentIntentUpdate;
|
||||
|
||||
impl From<PaymentIntentUpdate> for DieselPaymentIntentUpdate {
|
||||
fn from(value: PaymentIntentUpdate) -> Self {
|
||||
match value {
|
||||
PaymentIntentUpdate::ResponseUpdate {
|
||||
status,
|
||||
amount_captured,
|
||||
fingerprint_id,
|
||||
return_url,
|
||||
updated_by,
|
||||
incremental_authorization_allowed,
|
||||
} => Self::ResponseUpdate {
|
||||
status,
|
||||
amount_captured,
|
||||
fingerprint_id,
|
||||
return_url,
|
||||
updated_by,
|
||||
incremental_authorization_allowed,
|
||||
},
|
||||
PaymentIntentUpdate::MetadataUpdate {
|
||||
metadata,
|
||||
updated_by,
|
||||
} => Self::MetadataUpdate {
|
||||
metadata,
|
||||
updated_by,
|
||||
},
|
||||
PaymentIntentUpdate::ReturnUrlUpdate {
|
||||
return_url,
|
||||
status,
|
||||
customer_id,
|
||||
shipping_address_id,
|
||||
billing_address_id,
|
||||
updated_by,
|
||||
} => Self::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,
|
||||
} => Self::MerchantStatusUpdate {
|
||||
status,
|
||||
shipping_address_id,
|
||||
billing_address_id,
|
||||
updated_by,
|
||||
},
|
||||
PaymentIntentUpdate::PGStatusUpdate {
|
||||
status,
|
||||
updated_by,
|
||||
incremental_authorization_allowed,
|
||||
} => Self::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,
|
||||
} => 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,
|
||||
},
|
||||
PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate {
|
||||
active_attempt_id,
|
||||
attempt_count,
|
||||
updated_by,
|
||||
} => Self::PaymentAttemptAndAttemptCountUpdate {
|
||||
active_attempt_id,
|
||||
attempt_count,
|
||||
updated_by,
|
||||
},
|
||||
PaymentIntentUpdate::StatusAndAttemptUpdate {
|
||||
status,
|
||||
active_attempt_id,
|
||||
attempt_count,
|
||||
updated_by,
|
||||
} => Self::StatusAndAttemptUpdate {
|
||||
status,
|
||||
active_attempt_id,
|
||||
attempt_count,
|
||||
updated_by,
|
||||
},
|
||||
PaymentIntentUpdate::ApproveUpdate {
|
||||
status,
|
||||
merchant_decision,
|
||||
updated_by,
|
||||
} => Self::ApproveUpdate {
|
||||
status,
|
||||
merchant_decision,
|
||||
updated_by,
|
||||
},
|
||||
PaymentIntentUpdate::RejectUpdate {
|
||||
status,
|
||||
merchant_decision,
|
||||
updated_by,
|
||||
} => Self::RejectUpdate {
|
||||
status,
|
||||
merchant_decision,
|
||||
updated_by,
|
||||
},
|
||||
PaymentIntentUpdate::SurchargeApplicableUpdate {
|
||||
surcharge_applicable,
|
||||
updated_by,
|
||||
} => Self::SurchargeApplicableUpdate {
|
||||
surcharge_applicable: Some(surcharge_applicable),
|
||||
updated_by,
|
||||
},
|
||||
PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => {
|
||||
Self::IncrementalAuthorizationAmountUpdate { amount }
|
||||
}
|
||||
PaymentIntentUpdate::AuthorizationCountUpdate {
|
||||
authorization_count,
|
||||
} => Self::AuthorizationCountUpdate {
|
||||
authorization_count,
|
||||
},
|
||||
PaymentIntentUpdate::CompleteAuthorizeUpdate {
|
||||
shipping_address_id,
|
||||
} => Self::CompleteAuthorizeUpdate {
|
||||
shipping_address_id,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PaymentIntentUpdateInternal> 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<PaymentIntentListParams>),
|
||||
|
||||
237
crates/hyperswitch_domain_models/src/type_encryption.rs
Normal file
237
crates/hyperswitch_domain_models/src/type_encryption.rs
Normal file
@ -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<T>,
|
||||
>: Sized
|
||||
{
|
||||
async fn encrypt(
|
||||
masked_data: Secret<T, S>,
|
||||
key: &[u8],
|
||||
crypt_algo: V,
|
||||
) -> CustomResult<Self, errors::CryptoError>;
|
||||
|
||||
async fn decrypt(
|
||||
encrypted_data: Encryption,
|
||||
key: &[u8],
|
||||
crypt_algo: V,
|
||||
) -> CustomResult<Self, errors::CryptoError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<
|
||||
V: crypto::DecodeMessage + crypto::EncodeMessage + Send + 'static,
|
||||
S: masking::Strategy<String> + Send,
|
||||
> TypeEncryption<String, V, S> for crypto::Encryptable<Secret<String, S>>
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn encrypt(
|
||||
masked_data: Secret<String, S>,
|
||||
key: &[u8],
|
||||
crypt_algo: V,
|
||||
) -> CustomResult<Self, errors::CryptoError> {
|
||||
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<Self, errors::CryptoError> {
|
||||
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<serde_json::Value> + Send,
|
||||
> TypeEncryption<serde_json::Value, V, S>
|
||||
for crypto::Encryptable<Secret<serde_json::Value, S>>
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn encrypt(
|
||||
masked_data: Secret<serde_json::Value, S>,
|
||||
key: &[u8],
|
||||
crypt_algo: V,
|
||||
) -> CustomResult<Self, errors::CryptoError> {
|
||||
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<Self, errors::CryptoError> {
|
||||
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<Vec<u8>> + Send,
|
||||
> TypeEncryption<Vec<u8>, V, S> for crypto::Encryptable<Secret<Vec<u8>, S>>
|
||||
{
|
||||
#[instrument(skip_all)]
|
||||
async fn encrypt(
|
||||
masked_data: Secret<Vec<u8>, S>,
|
||||
key: &[u8],
|
||||
crypt_algo: V,
|
||||
) -> CustomResult<Self, errors::CryptoError> {
|
||||
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<Self, errors::CryptoError> {
|
||||
let encrypted = encrypted_data.into_inner();
|
||||
let data = crypt_algo.decode_message(key, encrypted.clone())?;
|
||||
|
||||
Ok(Self::new(data.into(), encrypted))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Lift<U> {
|
||||
type SelfWrapper<T>;
|
||||
type OtherWrapper<T, E>;
|
||||
|
||||
fn lift<Func, E, V>(self, func: Func) -> Self::OtherWrapper<V, E>
|
||||
where
|
||||
Func: Fn(Self::SelfWrapper<U>) -> Self::OtherWrapper<V, E>;
|
||||
}
|
||||
|
||||
impl<U> Lift<U> for Option<U> {
|
||||
type SelfWrapper<T> = Option<T>;
|
||||
type OtherWrapper<T, E> = CustomResult<Option<T>, E>;
|
||||
|
||||
fn lift<Func, E, V>(self, func: Func) -> Self::OtherWrapper<V, E>
|
||||
where
|
||||
Func: Fn(Self::SelfWrapper<U>) -> Self::OtherWrapper<V, E>,
|
||||
{
|
||||
func(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AsyncLift<U> {
|
||||
type SelfWrapper<T>;
|
||||
type OtherWrapper<T, E>;
|
||||
|
||||
async fn async_lift<Func, F, E, V>(self, func: Func) -> Self::OtherWrapper<V, E>
|
||||
where
|
||||
Func: Fn(Self::SelfWrapper<U>) -> F + Send + Sync,
|
||||
F: futures::Future<Output = Self::OtherWrapper<V, E>> + Send;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<U, V: Lift<U> + Lift<U, SelfWrapper<U> = V> + Send> AsyncLift<U> for V {
|
||||
type SelfWrapper<T> = <V as Lift<U>>::SelfWrapper<T>;
|
||||
type OtherWrapper<T, E> = <V as Lift<U>>::OtherWrapper<T, E>;
|
||||
|
||||
async fn async_lift<Func, F, E, W>(self, func: Func) -> Self::OtherWrapper<W, E>
|
||||
where
|
||||
Func: Fn(Self::SelfWrapper<U>) -> F + Send + Sync,
|
||||
F: futures::Future<Output = Self::OtherWrapper<W, E>> + Send,
|
||||
{
|
||||
func(self).await
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn encrypt<E: Clone, S>(
|
||||
inner: Secret<E, S>,
|
||||
key: &[u8],
|
||||
) -> CustomResult<crypto::Encryptable<Secret<E, S>>, errors::CryptoError>
|
||||
where
|
||||
S: masking::Strategy<E>,
|
||||
crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
|
||||
{
|
||||
record_operation_time(
|
||||
crypto::Encryptable::encrypt(inner, key, crypto::GcmAes256),
|
||||
&metrics::ENCRYPTION_TIME,
|
||||
&metrics::CONTEXT,
|
||||
&[],
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn encrypt_optional<E: Clone, S>(
|
||||
inner: Option<Secret<E, S>>,
|
||||
key: &[u8],
|
||||
) -> CustomResult<Option<crypto::Encryptable<Secret<E, S>>>, errors::CryptoError>
|
||||
where
|
||||
Secret<E, S>: Send,
|
||||
S: masking::Strategy<E>,
|
||||
crypto::Encryptable<Secret<E, S>>: TypeEncryption<E, crypto::GcmAes256, S>,
|
||||
{
|
||||
inner.async_map(|f| encrypt(f, key)).await.transpose()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn decrypt<T: Clone, S: masking::Strategy<T>>(
|
||||
inner: Option<Encryption>,
|
||||
key: &[u8],
|
||||
) -> CustomResult<Option<crypto::Encryptable<Secret<T, S>>>, errors::CryptoError>
|
||||
where
|
||||
crypto::Encryptable<Secret<T, S>>: TypeEncryption<T, crypto::GcmAes256, S>,
|
||||
{
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user