Skip to content

Commit

Permalink
feat(payment_methods_v2): Added Ephemeral auth for v2 (#6813)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
Sarthak1799 and hyperswitch-bot[bot] authored Dec 22, 2024
1 parent 7540b74 commit 24401bc
Show file tree
Hide file tree
Showing 23 changed files with 688 additions and 126 deletions.
15 changes: 1 addition & 14 deletions api-reference-v2/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -13870,16 +13870,11 @@
"PaymentMethodIntentConfirm": {
"type": "object",
"required": [
"client_secret",
"payment_method_data",
"payment_method_type",
"payment_method_subtype"
],
"properties": {
"client_secret": {
"type": "string",
"description": "For SDK based calls, client_secret would be required"
},
"customer_id": {
"type": "string",
"description": "The unique identifier of the customer.",
Expand Down Expand Up @@ -14165,7 +14160,7 @@
"example": "2024-02-24T11:04:09.922Z",
"nullable": true
},
"client_secret": {
"ephemeral_key": {
"type": "string",
"description": "For Client based calls",
"nullable": true
Expand Down Expand Up @@ -14314,14 +14309,6 @@
"properties": {
"payment_method_data": {
"$ref": "#/components/schemas/PaymentMethodUpdateData"
},
"client_secret": {
"type": "string",
"description": "This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK",
"example": "secret_k2uj3he2893eiu2d",
"nullable": true,
"maxLength": 30,
"minLength": 30
}
},
"additionalProperties": false
Expand Down
43 changes: 43 additions & 0 deletions crates/api_models/src/ephemeral_key.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use common_utils::id_type;
#[cfg(feature = "v2")]
use masking::Secret;
use serde;
use utoipa::ToSchema;

#[cfg(feature = "v1")]
/// Information required to create an ephemeral key.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct EphemeralKeyCreateRequest {
Expand All @@ -15,12 +18,52 @@ pub struct EphemeralKeyCreateRequest {
pub customer_id: id_type::CustomerId,
}

#[cfg(feature = "v2")]
/// Information required to create an ephemeral key.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct EphemeralKeyCreateRequest {
/// Customer ID for which an ephemeral key must be created
#[schema(
min_length = 32,
max_length = 64,
value_type = String,
example = "12345_cus_01926c58bc6e77c09e809964e72af8c8"
)]
pub customer_id: id_type::GlobalCustomerId,
}

#[cfg(feature = "v2")]
/// ephemeral_key for the customer_id mentioned
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq, ToSchema)]
pub struct EphemeralKeyResponse {
/// Ephemeral key id
#[schema(value_type = String, max_length = 32, min_length = 1)]
pub id: id_type::EphemeralKeyId,
/// customer_id to which this ephemeral key belongs to
#[schema(value_type = String, max_length = 64, min_length = 32, example = "12345_cus_01926c58bc6e77c09e809964e72af8c8")]
pub customer_id: id_type::GlobalCustomerId,
/// time at which this ephemeral key was created
pub created_at: time::PrimitiveDateTime,
/// time at which this ephemeral key would expire
pub expires: time::PrimitiveDateTime,
#[schema(value_type=String)]
/// ephemeral key
pub secret: Secret<String>,
}

impl common_utils::events::ApiEventMetric for EphemeralKeyCreateRequest {
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
Some(common_utils::events::ApiEventsType::Miscellaneous)
}
}

#[cfg(feature = "v2")]
impl common_utils::events::ApiEventMetric for EphemeralKeyResponse {
fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
Some(common_utils::events::ApiEventsType::Miscellaneous)
}
}

/// ephemeral_key for the customer_id mentioned
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq, ToSchema)]
pub struct EphemeralKeyCreateResponse {
Expand Down
14 changes: 2 additions & 12 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,6 @@ pub struct PaymentMethodIntentCreate {
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct PaymentMethodIntentConfirm {
/// For SDK based calls, client_secret would be required
pub client_secret: String,

/// The unique identifier of the customer.
#[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
pub customer_id: Option<id_type::CustomerId>,
Expand Down Expand Up @@ -211,9 +208,6 @@ pub struct PaymentMethodIntentConfirmInternal {
#[schema(value_type = PaymentMethodType,example = "credit")]
pub payment_method_subtype: api_enums::PaymentMethodType,

/// For SDK based calls, client_secret would be required
pub client_secret: String,

/// The unique identifier of the customer.
#[schema(value_type = Option<String>, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
pub customer_id: Option<id_type::CustomerId>,
Expand All @@ -226,7 +220,6 @@ pub struct PaymentMethodIntentConfirmInternal {
impl From<PaymentMethodIntentConfirmInternal> for PaymentMethodIntentConfirm {
fn from(item: PaymentMethodIntentConfirmInternal) -> Self {
Self {
client_secret: item.client_secret,
payment_method_type: item.payment_method_type,
payment_method_subtype: item.payment_method_subtype,
customer_id: item.customer_id,
Expand Down Expand Up @@ -408,10 +401,6 @@ pub struct PaymentMethodUpdate {
pub struct PaymentMethodUpdate {
/// payment method data to be passed
pub payment_method_data: PaymentMethodUpdateData,

/// This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK
#[schema(max_length = 30, min_length = 30, example = "secret_k2uj3he2893eiu2d")]
pub client_secret: Option<String>,
}

#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
Expand Down Expand Up @@ -826,7 +815,8 @@ pub struct PaymentMethodResponse {
pub last_used_at: Option<time::PrimitiveDateTime>,

/// For Client based calls
pub client_secret: Option<String>,
#[schema(value_type=Option<String>)]
pub ephemeral_key: Option<masking::Secret<String>>,

pub payment_method_data: Option<PaymentMethodResponseData>,
}
Expand Down
3 changes: 3 additions & 0 deletions crates/common_utils/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ pub enum ApiEventsType {
poll_id: String,
},
Analytics,
EphemeralKey {
key_id: id_type::EphemeralKeyId,
},
}

impl ApiEventMetric for serde_json::Value {}
Expand Down
2 changes: 2 additions & 0 deletions crates/common_utils/src/id_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod api_key;
mod customer;
mod ephemeral_key;
#[cfg(feature = "v2")]
mod global_id;
mod merchant;
Expand Down Expand Up @@ -38,6 +39,7 @@ pub use self::global_id::{
pub use self::{
api_key::ApiKeyId,
customer::CustomerId,
ephemeral_key::EphemeralKeyId,
merchant::MerchantId,
merchant_connector_account::MerchantConnectorAccountId,
organization::OrganizationId,
Expand Down
31 changes: 31 additions & 0 deletions crates/common_utils/src/id_type/ephemeral_key.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
crate::id_type!(
EphemeralKeyId,
"A type for key_id that can be used for Ephemeral key IDs"
);
crate::impl_id_type_methods!(EphemeralKeyId, "key_id");

// This is to display the `EphemeralKeyId` as EphemeralKeyId(abcd)
crate::impl_debug_id_type!(EphemeralKeyId);
crate::impl_try_from_cow_str_id_type!(EphemeralKeyId, "key_id");

crate::impl_generate_id_id_type!(EphemeralKeyId, "eki");
crate::impl_serializable_secret_id_type!(EphemeralKeyId);
crate::impl_queryable_id_type!(EphemeralKeyId);
crate::impl_to_sql_from_sql_id_type!(EphemeralKeyId);

impl crate::events::ApiEventMetric for EphemeralKeyId {
fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
Some(crate::events::ApiEventsType::EphemeralKey {
key_id: self.clone(),
})
}
}

crate::impl_default_id_type!(EphemeralKeyId, "key");

impl EphemeralKeyId {
/// Generate a key for redis
pub fn generate_redis_key(&self) -> String {
format!("epkey_{}", self.get_string_repr())
}
}
48 changes: 48 additions & 0 deletions crates/diesel_models/src/ephemeral_key.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
#[cfg(feature = "v2")]
use masking::{PeekInterface, Secret};
#[cfg(feature = "v2")]
pub struct EphemeralKeyTypeNew {
pub id: common_utils::id_type::EphemeralKeyId,
pub merchant_id: common_utils::id_type::MerchantId,
pub customer_id: common_utils::id_type::GlobalCustomerId,
pub secret: Secret<String>,
pub resource_type: ResourceType,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct EphemeralKeyType {
pub id: common_utils::id_type::EphemeralKeyId,
pub merchant_id: common_utils::id_type::MerchantId,
pub customer_id: common_utils::id_type::GlobalCustomerId,
pub resource_type: ResourceType,
pub created_at: time::PrimitiveDateTime,
pub expires: time::PrimitiveDateTime,
pub secret: Secret<String>,
}

#[cfg(feature = "v2")]
impl EphemeralKeyType {
pub fn generate_secret_key(&self) -> String {
format!("epkey_{}", self.secret.peek())
}
}

pub struct EphemeralKeyNew {
pub id: String,
pub merchant_id: common_utils::id_type::MerchantId,
Expand All @@ -20,3 +50,21 @@ impl common_utils::events::ApiEventMetric for EphemeralKey {
Some(common_utils::events::ApiEventsType::Miscellaneous)
}
}

#[derive(
Clone,
Copy,
Debug,
serde::Serialize,
serde::Deserialize,
strum::Display,
strum::EnumString,
PartialEq,
Eq,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ResourceType {
Payment,
PaymentMethod,
}
13 changes: 12 additions & 1 deletion crates/diesel_models/src/payment_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ pub enum PaymentMethodUpdate {
network_token_requestor_reference_id: Option<String>,
network_token_locker_id: Option<String>,
network_token_payment_method_data: Option<Encryption>,
locker_fingerprint_id: Option<String>,
},
ConnectorMandateDetailsUpdate {
connector_mandate_details: Option<PaymentsMandateReference>,
Expand Down Expand Up @@ -324,6 +325,7 @@ pub struct PaymentMethodUpdateInternal {
network_token_requestor_reference_id: Option<String>,
network_token_locker_id: Option<String>,
network_token_payment_method_data: Option<Encryption>,
locker_fingerprint_id: Option<String>,
}

#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
Expand All @@ -343,6 +345,7 @@ impl PaymentMethodUpdateInternal {
network_token_requestor_reference_id,
network_token_locker_id,
network_token_payment_method_data,
locker_fingerprint_id,
} = self;

PaymentMethod {
Expand All @@ -361,7 +364,7 @@ impl PaymentMethodUpdateInternal {
client_secret: source.client_secret,
payment_method_billing_address: source.payment_method_billing_address,
updated_by: updated_by.or(source.updated_by),
locker_fingerprint_id: source.locker_fingerprint_id,
locker_fingerprint_id: locker_fingerprint_id.or(source.locker_fingerprint_id),
payment_method_type_v2: payment_method_type_v2.or(source.payment_method_type_v2),
payment_method_subtype: payment_method_subtype.or(source.payment_method_subtype),
id: source.id,
Expand Down Expand Up @@ -710,6 +713,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_locker_id: None,
network_token_requestor_reference_id: None,
network_token_payment_method_data: None,
locker_fingerprint_id: None,
},
PaymentMethodUpdate::LastUsedUpdate { last_used_at } => Self {
payment_method_data: None,
Expand All @@ -725,6 +729,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_locker_id: None,
network_token_requestor_reference_id: None,
network_token_payment_method_data: None,
locker_fingerprint_id: None,
},
PaymentMethodUpdate::UpdatePaymentMethodDataAndLastUsed {
payment_method_data,
Expand All @@ -744,6 +749,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_locker_id: None,
network_token_requestor_reference_id: None,
network_token_payment_method_data: None,
locker_fingerprint_id: None,
},
PaymentMethodUpdate::NetworkTransactionIdAndStatusUpdate {
network_transaction_id,
Expand All @@ -762,6 +768,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_locker_id: None,
network_token_requestor_reference_id: None,
network_token_payment_method_data: None,
locker_fingerprint_id: None,
},
PaymentMethodUpdate::StatusUpdate { status } => Self {
payment_method_data: None,
Expand All @@ -777,6 +784,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_locker_id: None,
network_token_requestor_reference_id: None,
network_token_payment_method_data: None,
locker_fingerprint_id: None,
},
PaymentMethodUpdate::AdditionalDataUpdate {
payment_method_data,
Expand All @@ -787,6 +795,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_requestor_reference_id,
network_token_locker_id,
network_token_payment_method_data,
locker_fingerprint_id,
} => Self {
payment_method_data,
last_used_at: None,
Expand All @@ -801,6 +810,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_requestor_reference_id,
network_token_locker_id,
network_token_payment_method_data,
locker_fingerprint_id,
},
PaymentMethodUpdate::ConnectorMandateDetailsUpdate {
connector_mandate_details,
Expand All @@ -818,6 +828,7 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
network_token_locker_id: None,
network_token_requestor_reference_id: None,
network_token_payment_method_data: None,
locker_fingerprint_id: None,
},
}
}
Expand Down
5 changes: 4 additions & 1 deletion crates/hyperswitch_domain_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ pub mod payment_intent;

use common_enums as storage_enums;
#[cfg(feature = "v2")]
use diesel_models::types::{FeatureMetadata, OrderDetailsWithAmount};
use diesel_models::{
ephemeral_key,
types::{FeatureMetadata, OrderDetailsWithAmount},
};

use self::payment_attempt::PaymentAttempt;
#[cfg(feature = "v1")]
Expand Down
Loading

0 comments on commit 24401bc

Please sign in to comment.