Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(router): [V2] Introduce V2Auth and use it for payment_methods_list_enabled #7038

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,541 changes: 218 additions & 1,323 deletions api-reference-v2/openapi_spec.json

Large diffs are not rendered by default.

33 changes: 23 additions & 10 deletions crates/api_models/src/ephemeral_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,30 @@ pub struct EphemeralKeyCreateRequest {
pub customer_id: id_type::CustomerId,
}

#[cfg(feature = "v2")]
#[derive(
Clone,
// Copy,
Debug,
serde::Serialize,
serde::Deserialize,
// strum::EnumString,
PartialEq,
Eq,
ToSchema,
)]
#[serde(rename_all = "snake_case")]
pub enum ResourceId {
#[schema(value_type = String)]
Customer(id_type::GlobalCustomerId),
}

#[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,
/// Resource ID for which an ephemeral key must be created
pub resource_id: ResourceId,
}

#[cfg(feature = "v2")]
Expand All @@ -40,8 +52,8 @@ pub struct EphemeralKeyResponse {
#[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,
#[schema(value_type = ResourceId)]
pub resource_id: ResourceId,
/// time at which this ephemeral key was created
pub created_at: time::PrimitiveDateTime,
/// time at which this ephemeral key would expire
Expand All @@ -64,6 +76,7 @@ impl common_utils::events::ApiEventMetric for EphemeralKeyResponse {
}
}

#[cfg(feature = "v1")]
/// ephemeral_key for the customer_id mentioned
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Eq, PartialEq, ToSchema)]
pub struct EphemeralKeyCreateResponse {
Expand Down
21 changes: 12 additions & 9 deletions crates/api_models/src/events/payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use super::{
not(feature = "payment_methods_v2")
))]
use crate::payment_methods::CustomerPaymentMethodsListResponse;
#[cfg(feature = "v1")]
use crate::payments::{PaymentListResponse, PaymentListResponseV2, PaymentsResponse};
#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
use crate::{events, payment_methods::CustomerPaymentMethodsListResponse};
use crate::{
Expand All @@ -23,15 +25,14 @@ use crate::{
payments::{
self, ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints,
PaymentListFilterConstraints, PaymentListFilters, PaymentListFiltersV2,
PaymentListResponse, PaymentListResponseV2, PaymentsAggregateResponse,
PaymentsApproveRequest, PaymentsCancelRequest, PaymentsCaptureRequest,
PaymentsCompleteAuthorizeRequest, PaymentsDynamicTaxCalculationRequest,
PaymentsDynamicTaxCalculationResponse, PaymentsExternalAuthenticationRequest,
PaymentsExternalAuthenticationResponse, PaymentsIncrementalAuthorizationRequest,
PaymentsManualUpdateRequest, PaymentsManualUpdateResponse,
PaymentsPostSessionTokensRequest, PaymentsPostSessionTokensResponse, PaymentsRejectRequest,
PaymentsResponse, PaymentsRetrieveRequest, PaymentsSessionResponse, PaymentsStartRequest,
RedirectionResponse,
PaymentsAggregateResponse, PaymentsApproveRequest, PaymentsCancelRequest,
PaymentsCaptureRequest, PaymentsCompleteAuthorizeRequest,
PaymentsDynamicTaxCalculationRequest, PaymentsDynamicTaxCalculationResponse,
PaymentsExternalAuthenticationRequest, PaymentsExternalAuthenticationResponse,
PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest,
PaymentsManualUpdateResponse, PaymentsPostSessionTokensRequest,
PaymentsPostSessionTokensResponse, PaymentsRejectRequest, PaymentsRetrieveRequest,
PaymentsSessionResponse, PaymentsStartRequest, RedirectionResponse,
},
};

Expand Down Expand Up @@ -355,12 +356,14 @@ impl ApiEventMetric for PaymentListConstraints {
}
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentListResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
}
}

#[cfg(feature = "v1")]
impl ApiEventMetric for PaymentListResponseV2 {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::ResourceListAPI)
Expand Down
6 changes: 5 additions & 1 deletion crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ use time::{Date, PrimitiveDateTime};
use url::Url;
use utoipa::ToSchema;

#[cfg(feature = "v1")]
use crate::ephemeral_key::EphemeralKeyCreateResponse;
#[cfg(feature = "v2")]
use crate::payment_methods;
use crate::{
admin::{self, MerchantConnectorInfo},
disputes, enums as api_enums,
ephemeral_key::EphemeralKeyCreateResponse,
mandates::RecurringDetails,
refunds,
};
Expand Down Expand Up @@ -4411,6 +4412,7 @@ pub struct ReceiverDetails {
amount_remaining: Option<i64>,
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema, router_derive::PolymorphicSchema)]
#[generate_schemas(PaymentsCreateResponseOpenApi)]
pub struct PaymentsResponse {
Expand Down Expand Up @@ -5101,6 +5103,7 @@ pub struct PaymentListConstraints {
pub created_gte: Option<PrimitiveDateTime>,
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, serde::Serialize, ToSchema)]
pub struct PaymentListResponse {
/// The number of payments included in the list
Expand All @@ -5127,6 +5130,7 @@ pub struct IncrementalAuthorizationResponse {
pub previously_authorized_amount: MinorUnit,
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, serde::Serialize)]
pub struct PaymentListResponseV2 {
/// The number of payments included in the list for given constraints
Expand Down
2 changes: 1 addition & 1 deletion crates/api_models/src/webhooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ pub enum OutgoingWebhookContent {
#[serde(tag = "type", content = "object", rename_all = "snake_case")]
#[cfg(feature = "v2")]
pub enum OutgoingWebhookContent {
#[schema(value_type = PaymentsResponse, title = "PaymentsResponse")]
#[schema(value_type = PaymentsRetrieveResponse, title = "PaymentsResponse")]
PaymentDetails(Box<payments::PaymentsRetrieveResponse>),
#[schema(value_type = RefundResponse, title = "RefundResponse")]
RefundDetails(Box<refunds::RefundResponse>),
Expand Down
27 changes: 8 additions & 19 deletions crates/diesel_models/src/ephemeral_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@ use masking::{PeekInterface, Secret};
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,
pub resource_id: ResourceId,
}

#[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 resource_id: ResourceId,
pub created_at: time::PrimitiveDateTime,
pub expires: time::PrimitiveDateTime,
pub secret: Secret<String>,
Expand Down Expand Up @@ -51,20 +49,11 @@ impl common_utils::events::ApiEventMetric for EphemeralKey {
}
}

#[derive(
Clone,
Copy,
Debug,
serde::Serialize,
serde::Deserialize,
strum::Display,
strum::EnumString,
PartialEq,
Eq,
)]
#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ResourceType {
Payment,
PaymentMethod,
pub enum ResourceId {
Payment(common_utils::id_type::GlobalPaymentId),
PaymentMethod(common_utils::id_type::GlobalPaymentMethodId),
Customer(common_utils::id_type::GlobalCustomerId),
}
6 changes: 2 additions & 4 deletions crates/openapi/src/openapi_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::customers::CustomerRequest,
api_models::customers::CustomerUpdateRequest,
api_models::customers::CustomerDeleteResponse,
api_models::ephemeral_key::ResourceId,
api_models::payment_methods::PaymentMethodCreate,
api_models::payment_methods::PaymentMethodIntentCreate,
api_models::payment_methods::PaymentMethodIntentConfirm,
Expand Down Expand Up @@ -358,8 +359,6 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payments::CardRedirectData,
api_models::payments::CardToken,
api_models::payments::CustomerAcceptance,
api_models::payments::PaymentsResponse,
api_models::payments::PaymentsCreateResponseOpenApi,
api_models::payments::PaymentRetrieveBody,
api_models::payments::PaymentsRetrieveRequest,
api_models::payments::PaymentsCaptureRequest,
Expand Down Expand Up @@ -423,7 +422,6 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::payments::SamsungPayTokenData,
api_models::payments::PaymentsCancelRequest,
api_models::payments::PaymentListConstraints,
api_models::payments::PaymentListResponse,
api_models::payments::CashappQr,
api_models::payments::BankTransferData,
api_models::payments::BankTransferNextStepsData,
Expand Down Expand Up @@ -493,7 +491,7 @@ Never share your secret api keys. Keep them guarded and secure.
api_models::mandates::MandateCardDetails,
api_models::mandates::RecurringDetails,
api_models::mandates::ProcessorPaymentToken,
api_models::ephemeral_key::EphemeralKeyCreateResponse,
api_models::ephemeral_key::EphemeralKeyResponse,
api_models::payments::CustomerDetails,
api_models::payments::GiftCardData,
api_models::payments::GiftCardDetails,
Expand Down
3 changes: 1 addition & 2 deletions crates/router/src/core/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1403,9 +1403,8 @@ pub async fn create_payment_method_for_intent(
let db = &*state.store;
let ephemeral_key = payment_helpers::create_ephemeral_key(
state,
customer_id,
merchant_id,
ephemeral_key::ResourceType::PaymentMethod,
diesel_models::ResourceId::PaymentMethod(payment_method_id.clone()),
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
Expand Down
85 changes: 47 additions & 38 deletions crates/router/src/core/payments/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3054,67 +3054,74 @@ pub async fn make_ephemeral_key(
#[cfg(feature = "v2")]
pub async fn make_ephemeral_key(
state: SessionState,
customer_id: id_type::GlobalCustomerId,
resource_id: api_models::ephemeral_key::ResourceId,
merchant_account: domain::MerchantAccount,
key_store: domain::MerchantKeyStore,
headers: &actix_web::http::header::HeaderMap,
) -> errors::RouterResponse<EphemeralKeyResponse> {
let db = &state.store;
let key_manager_state = &((&state).into());
db.find_customer_by_global_id(
key_manager_state,
&customer_id,
merchant_account.get_id(),
&key_store,
merchant_account.storage_scheme,
)
.await
.to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;

let resource_type = services::authentication::get_header_value_by_key(
headers::X_RESOURCE_TYPE.to_string(),
headers,
)?
.map(ephemeral_key::ResourceType::from_str)
.transpose()
.change_context(errors::ApiErrorResponse::InvalidRequestData {
message: format!("`{}` header is invalid", headers::X_RESOURCE_TYPE),
})?
.get_required_value("ResourceType")
.attach_printable("Failed to convert ResourceType from string")?;

let ephemeral_key = create_ephemeral_key(
&state,
&customer_id,
merchant_account.get_id(),
resource_type,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to create ephemeral key")?;

let response = EphemeralKeyResponse::foreign_from(ephemeral_key);
match &resource_id {
api_models::ephemeral_key::ResourceId::Customer(global_customer_id) => {
db.find_customer_by_global_id(
key_manager_state,
global_customer_id,
merchant_account.get_id(),
&key_store,
merchant_account.storage_scheme,
)
.await
.to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
}
}

// TODO: Supersede in V2Auth
// services::authentication::get_header_value_by_key(
// headers::X_RESOURCE_TYPE.to_string(),
// headers,
// )?
// .map(diesel_models::ResourceId::validate_enum_str)
// .transpose()
// .change_context(errors::ApiErrorResponse::InvalidRequestData {
// message: format!("`{}` header is invalid", headers::X_RESOURCE_TYPE),
// })?
// .get_required_value("ResourceType")
// .attach_printable("Failed to convert ResourceType from string")?;

let resource_id = match resource_id {
api_models::ephemeral_key::ResourceId::Customer(global_customer_id) => {
diesel_models::ResourceId::Customer(global_customer_id)
}
};

let ephemeral_key = create_ephemeral_key(&state, merchant_account.get_id(), resource_id)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Unable to create ephemeral key")?;

let response = EphemeralKeyResponse::foreign_try_from(ephemeral_key)
.attach_printable("Only customer is supported as resource_id in response")?;
Ok(services::ApplicationResponse::Json(response))
}

#[cfg(feature = "v2")]
pub async fn create_ephemeral_key(
state: &SessionState,
customer_id: &id_type::GlobalCustomerId,
merchant_id: &id_type::MerchantId,
resource_type: ephemeral_key::ResourceType,
resource_id: diesel_models::ephemeral_key::ResourceId,
) -> RouterResult<ephemeral_key::EphemeralKeyType> {
use common_utils::generate_time_ordered_id;

let store = &state.store;
let id = id_type::EphemeralKeyId::generate();
let secret = masking::Secret::new(generate_time_ordered_id("epk"));

let ephemeral_key = ephemeral_key::EphemeralKeyTypeNew {
id,
customer_id: customer_id.to_owned(),
merchant_id: merchant_id.to_owned(),
secret,
resource_type,
resource_id,
};
let ephemeral_key = store
.create_ephemeral_key(ephemeral_key, state.conf.eph_key.validity)
Expand Down Expand Up @@ -3157,10 +3164,12 @@ pub async fn delete_ephemeral_key(
})
.attach_printable("Unable to delete ephemeral key")?;

let response = EphemeralKeyResponse::foreign_from(ephemeral_key);
let response = EphemeralKeyResponse::foreign_try_from(ephemeral_key)
.attach_printable("Only customer is supported as resource_id in response")?;
Ok(services::ApplicationResponse::Json(response))
}

#[cfg(feature = "v1")]
pub fn make_pg_redirect_response(
payment_id: id_type::PaymentId,
response: &api::PaymentsResponse,
Expand Down
3 changes: 2 additions & 1 deletion crates/router/src/core/payments/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1714,7 +1714,7 @@ pub fn payments_to_payments_response<Op, F: Clone, D>(
_connector_http_status_code: Option<u16>,
_external_latency: Option<u128>,
_is_latency_header_enabled: Option<bool>,
) -> RouterResponse<api::PaymentsResponse>
) -> RouterResponse<api_models::payments::PaymentsRetrieveResponse>
where
Op: Debug,
D: OperationSessionGetters<F>,
Expand Down Expand Up @@ -2554,6 +2554,7 @@ impl ForeignFrom<(storage::PaymentIntent, storage::PaymentAttempt)> for api::Pay
}
}

#[cfg(feature = "v1")]
impl ForeignFrom<ephemeral_key::EphemeralKey> for api::ephemeral_key::EphemeralKeyCreateResponse {
fn foreign_from(from: ephemeral_key::EphemeralKey) -> Self {
Self {
Expand Down
1 change: 1 addition & 0 deletions crates/router/src/core/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1415,6 +1415,7 @@ pub fn get_external_authentication_request_poll_id(
payment_id.get_external_authentication_request_poll_id()
}

#[cfg(feature = "v1")]
pub fn get_html_redirect_response_for_external_authentication(
return_url_with_query_params: String,
payment_response: &api_models::payments::PaymentsResponse,
Expand Down
Loading
Loading