mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
feat(router): restricted customer update in payments-confirm and payments-update call via clientAuth (#1659)
Co-authored-by: Sahkal Poddar <sahkal.poddar@juspay.in> Co-authored-by: Arun Raj M <jarnura47@gmail.com>
This commit is contained in:
@ -49,6 +49,7 @@ pub async fn payments_operation_core<F, Req, Op, FData>(
|
||||
operation: Op,
|
||||
req: Req,
|
||||
call_connector_action: CallConnectorAction,
|
||||
auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(PaymentData<F>, Req, Option<domain::Customer>)>
|
||||
where
|
||||
F: Send + Clone + Sync,
|
||||
@ -70,7 +71,6 @@ where
|
||||
let operation: BoxedOperation<'_, F, Req> = Box::new(operation);
|
||||
|
||||
tracing::Span::current().record("merchant_id", merchant_account.merchant_id.as_str());
|
||||
|
||||
let (operation, validate_result) = operation
|
||||
.to_validate_request()?
|
||||
.validate_request(&req, &merchant_account)?;
|
||||
@ -85,6 +85,7 @@ where
|
||||
validate_result.mandate_type.to_owned(),
|
||||
&merchant_account,
|
||||
&key_store,
|
||||
auth_flow,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -246,6 +247,7 @@ where
|
||||
operation.clone(),
|
||||
req,
|
||||
call_connector_action,
|
||||
auth_flow,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@ -2550,3 +2550,28 @@ pub async fn get_additional_payment_data(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_customer_access(
|
||||
payment_intent: &storage::PaymentIntent,
|
||||
auth_flow: services::AuthFlow,
|
||||
request: &api::PaymentsRequest,
|
||||
) -> Result<(), errors::ApiErrorResponse> {
|
||||
if auth_flow == services::AuthFlow::Client && request.customer_id.is_some() {
|
||||
let is_not_same_customer = request
|
||||
.clone()
|
||||
.customer_id
|
||||
.and_then(|customer| {
|
||||
payment_intent
|
||||
.clone()
|
||||
.customer_id
|
||||
.map(|payment_customer| payment_customer != customer)
|
||||
})
|
||||
.unwrap_or(false);
|
||||
if is_not_same_customer {
|
||||
Err(errors::ApiErrorResponse::GenericUnauthorized {
|
||||
message: "Unauthorised access to update customer".to_string(),
|
||||
})?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ use crate::{
|
||||
core::errors::{self, CustomResult, RouterResult},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
self, api, domain,
|
||||
storage::{self, enums},
|
||||
@ -94,6 +95,7 @@ pub trait GetTracker<F, D, R>: Send {
|
||||
mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
mechant_key_store: &domain::MerchantKeyStore,
|
||||
auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(BoxedOperation<'a, F, R>, D, Option<CustomerDetails>)>;
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
api::{self, PaymentIdTypeExt},
|
||||
domain,
|
||||
@ -37,6 +38,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
|
||||
_mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsCancelRequest>,
|
||||
PaymentData<F>,
|
||||
|
||||
@ -13,6 +13,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
api::{self, PaymentIdTypeExt},
|
||||
domain,
|
||||
@ -38,6 +39,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
|
||||
_mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsCaptureRequest>,
|
||||
payments::PaymentData<F>,
|
||||
|
||||
@ -14,6 +14,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
self,
|
||||
api::{self, PaymentIdTypeExt},
|
||||
@ -39,6 +40,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
|
||||
mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||
PaymentData<F>,
|
||||
|
||||
@ -15,6 +15,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
self,
|
||||
api::{self, PaymentIdTypeExt},
|
||||
@ -28,7 +29,6 @@ use crate::{
|
||||
#[derive(Debug, Clone, Copy, PaymentOperation)]
|
||||
#[operation(ops = "all", flow = "authorize")]
|
||||
pub struct PaymentConfirm;
|
||||
|
||||
#[async_trait]
|
||||
impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for PaymentConfirm {
|
||||
#[instrument(skip_all)]
|
||||
@ -40,6 +40,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||
PaymentData<F>,
|
||||
@ -59,6 +60,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
|
||||
|
||||
helpers::validate_customer_access(&payment_intent, auth_flow, request)?;
|
||||
|
||||
helpers::validate_payment_status_against_not_allowed_statuses(
|
||||
&payment_intent.status,
|
||||
&[
|
||||
@ -499,7 +502,6 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentConfir
|
||||
operations::ValidateResult<'a>,
|
||||
)> {
|
||||
helpers::validate_customer_details_in_request(request)?;
|
||||
|
||||
let given_payment_id = match &request.payment_id {
|
||||
Some(id_type) => Some(
|
||||
id_type
|
||||
|
||||
@ -46,6 +46,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
merchant_key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||
PaymentData<F>,
|
||||
|
||||
@ -16,6 +16,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
self,
|
||||
api::{self, enums as api_enums, PaymentIdTypeExt},
|
||||
@ -71,6 +72,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::VerifyRequest> for Paym
|
||||
_mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
_mechant_key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::VerifyRequest>,
|
||||
PaymentData<F>,
|
||||
|
||||
@ -15,6 +15,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
api::{self, PaymentIdTypeExt},
|
||||
domain,
|
||||
@ -40,6 +41,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
|
||||
_mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsSessionRequest>,
|
||||
PaymentData<F>,
|
||||
|
||||
@ -13,6 +13,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
api::{self, PaymentIdTypeExt},
|
||||
domain,
|
||||
@ -36,6 +37,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
||||
_mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
mechant_key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsStartRequest>,
|
||||
PaymentData<F>,
|
||||
|
||||
@ -14,6 +14,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
api, domain,
|
||||
storage::{self, enums},
|
||||
@ -163,6 +164,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRetrieveRequest
|
||||
_mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
_auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsRetrieveRequest>,
|
||||
PaymentData<F>,
|
||||
|
||||
@ -15,6 +15,7 @@ use crate::{
|
||||
},
|
||||
db::StorageInterface,
|
||||
routes::AppState,
|
||||
services,
|
||||
types::{
|
||||
api::{self, PaymentIdTypeExt},
|
||||
domain,
|
||||
@ -39,6 +40,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
mandate_type: Option<api::MandateTransactionType>,
|
||||
merchant_account: &domain::MerchantAccount,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(
|
||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||
PaymentData<F>,
|
||||
@ -63,6 +65,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
||||
.setup_future_usage
|
||||
.or(payment_intent.setup_future_usage);
|
||||
|
||||
helpers::validate_customer_access(&payment_intent, auth_flow, request)?;
|
||||
|
||||
helpers::validate_card_data(request.payment_method_data.clone())?;
|
||||
|
||||
helpers::validate_payment_status_against_not_allowed_statuses(
|
||||
@ -548,7 +552,6 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentUpdate
|
||||
operations::ValidateResult<'a>,
|
||||
)> {
|
||||
helpers::validate_customer_details_in_request(request)?;
|
||||
|
||||
let given_payment_id = match &request.payment_id {
|
||||
Some(id_type) => Some(
|
||||
id_type
|
||||
|
||||
@ -7,6 +7,7 @@ use crate::{
|
||||
errors,
|
||||
routes::AppState,
|
||||
scheduler::{consumer, process_data, utils},
|
||||
services,
|
||||
types::{
|
||||
api,
|
||||
storage::{self, enums, ProcessTrackerExt},
|
||||
@ -54,6 +55,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
|
||||
operations::PaymentStatus,
|
||||
tracking_data.clone(),
|
||||
payment_flows::CallConnectorAction::Trigger,
|
||||
services::AuthFlow::Client,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user