mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-30 01:27:31 +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,
|
operation: Op,
|
||||||
req: Req,
|
req: Req,
|
||||||
call_connector_action: CallConnectorAction,
|
call_connector_action: CallConnectorAction,
|
||||||
|
auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(PaymentData<F>, Req, Option<domain::Customer>)>
|
) -> RouterResult<(PaymentData<F>, Req, Option<domain::Customer>)>
|
||||||
where
|
where
|
||||||
F: Send + Clone + Sync,
|
F: Send + Clone + Sync,
|
||||||
@ -70,7 +71,6 @@ where
|
|||||||
let operation: BoxedOperation<'_, F, Req> = Box::new(operation);
|
let operation: BoxedOperation<'_, F, Req> = Box::new(operation);
|
||||||
|
|
||||||
tracing::Span::current().record("merchant_id", merchant_account.merchant_id.as_str());
|
tracing::Span::current().record("merchant_id", merchant_account.merchant_id.as_str());
|
||||||
|
|
||||||
let (operation, validate_result) = operation
|
let (operation, validate_result) = operation
|
||||||
.to_validate_request()?
|
.to_validate_request()?
|
||||||
.validate_request(&req, &merchant_account)?;
|
.validate_request(&req, &merchant_account)?;
|
||||||
@ -85,6 +85,7 @@ where
|
|||||||
validate_result.mandate_type.to_owned(),
|
validate_result.mandate_type.to_owned(),
|
||||||
&merchant_account,
|
&merchant_account,
|
||||||
&key_store,
|
&key_store,
|
||||||
|
auth_flow,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -246,6 +247,7 @@ where
|
|||||||
operation.clone(),
|
operation.clone(),
|
||||||
req,
|
req,
|
||||||
call_connector_action,
|
call_connector_action,
|
||||||
|
auth_flow,
|
||||||
)
|
)
|
||||||
.await?;
|
.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},
|
core::errors::{self, CustomResult, RouterResult},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
self, api, domain,
|
self, api, domain,
|
||||||
storage::{self, enums},
|
storage::{self, enums},
|
||||||
@ -94,6 +95,7 @@ pub trait GetTracker<F, D, R>: Send {
|
|||||||
mandate_type: Option<api::MandateTransactionType>,
|
mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
mechant_key_store: &domain::MerchantKeyStore,
|
mechant_key_store: &domain::MerchantKeyStore,
|
||||||
|
auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(BoxedOperation<'a, F, R>, D, Option<CustomerDetails>)>;
|
) -> RouterResult<(BoxedOperation<'a, F, R>, D, Option<CustomerDetails>)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
api::{self, PaymentIdTypeExt},
|
api::{self, PaymentIdTypeExt},
|
||||||
domain,
|
domain,
|
||||||
@ -37,6 +38,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
|
|||||||
_mandate_type: Option<api::MandateTransactionType>,
|
_mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsCancelRequest>,
|
BoxedOperation<'a, F, api::PaymentsCancelRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
api::{self, PaymentIdTypeExt},
|
api::{self, PaymentIdTypeExt},
|
||||||
domain,
|
domain,
|
||||||
@ -38,6 +39,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
|
|||||||
_mandate_type: Option<api::MandateTransactionType>,
|
_mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsCaptureRequest>,
|
BoxedOperation<'a, F, api::PaymentsCaptureRequest>,
|
||||||
payments::PaymentData<F>,
|
payments::PaymentData<F>,
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
self,
|
self,
|
||||||
api::{self, PaymentIdTypeExt},
|
api::{self, PaymentIdTypeExt},
|
||||||
@ -39,6 +40,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
|
|||||||
mandate_type: Option<api::MandateTransactionType>,
|
mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
self,
|
self,
|
||||||
api::{self, PaymentIdTypeExt},
|
api::{self, PaymentIdTypeExt},
|
||||||
@ -28,7 +29,6 @@ use crate::{
|
|||||||
#[derive(Debug, Clone, Copy, PaymentOperation)]
|
#[derive(Debug, Clone, Copy, PaymentOperation)]
|
||||||
#[operation(ops = "all", flow = "authorize")]
|
#[operation(ops = "all", flow = "authorize")]
|
||||||
pub struct PaymentConfirm;
|
pub struct PaymentConfirm;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for PaymentConfirm {
|
impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for PaymentConfirm {
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
@ -40,6 +40,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
mandate_type: Option<api::MandateTransactionType>,
|
mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
@ -59,6 +60,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
.await
|
.await
|
||||||
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
|
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
|
||||||
|
|
||||||
|
helpers::validate_customer_access(&payment_intent, auth_flow, request)?;
|
||||||
|
|
||||||
helpers::validate_payment_status_against_not_allowed_statuses(
|
helpers::validate_payment_status_against_not_allowed_statuses(
|
||||||
&payment_intent.status,
|
&payment_intent.status,
|
||||||
&[
|
&[
|
||||||
@ -499,7 +502,6 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentConfir
|
|||||||
operations::ValidateResult<'a>,
|
operations::ValidateResult<'a>,
|
||||||
)> {
|
)> {
|
||||||
helpers::validate_customer_details_in_request(request)?;
|
helpers::validate_customer_details_in_request(request)?;
|
||||||
|
|
||||||
let given_payment_id = match &request.payment_id {
|
let given_payment_id = match &request.payment_id {
|
||||||
Some(id_type) => Some(
|
Some(id_type) => Some(
|
||||||
id_type
|
id_type
|
||||||
|
|||||||
@ -46,6 +46,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
mandate_type: Option<api::MandateTransactionType>,
|
mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
merchant_key_store: &domain::MerchantKeyStore,
|
merchant_key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
self,
|
self,
|
||||||
api::{self, enums as api_enums, PaymentIdTypeExt},
|
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>,
|
_mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
_mechant_key_store: &domain::MerchantKeyStore,
|
_mechant_key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::VerifyRequest>,
|
BoxedOperation<'a, F, api::VerifyRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
api::{self, PaymentIdTypeExt},
|
api::{self, PaymentIdTypeExt},
|
||||||
domain,
|
domain,
|
||||||
@ -40,6 +41,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
|
|||||||
_mandate_type: Option<api::MandateTransactionType>,
|
_mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsSessionRequest>,
|
BoxedOperation<'a, F, api::PaymentsSessionRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
api::{self, PaymentIdTypeExt},
|
api::{self, PaymentIdTypeExt},
|
||||||
domain,
|
domain,
|
||||||
@ -36,6 +37,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
|
|||||||
_mandate_type: Option<api::MandateTransactionType>,
|
_mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
mechant_key_store: &domain::MerchantKeyStore,
|
mechant_key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsStartRequest>,
|
BoxedOperation<'a, F, api::PaymentsStartRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
|
|||||||
@ -14,6 +14,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
api, domain,
|
api, domain,
|
||||||
storage::{self, enums},
|
storage::{self, enums},
|
||||||
@ -163,6 +164,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRetrieveRequest
|
|||||||
_mandate_type: Option<api::MandateTransactionType>,
|
_mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
_auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsRetrieveRequest>,
|
BoxedOperation<'a, F, api::PaymentsRetrieveRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
db::StorageInterface,
|
db::StorageInterface,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
api::{self, PaymentIdTypeExt},
|
api::{self, PaymentIdTypeExt},
|
||||||
domain,
|
domain,
|
||||||
@ -39,6 +40,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
mandate_type: Option<api::MandateTransactionType>,
|
mandate_type: Option<api::MandateTransactionType>,
|
||||||
merchant_account: &domain::MerchantAccount,
|
merchant_account: &domain::MerchantAccount,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
|
auth_flow: services::AuthFlow,
|
||||||
) -> RouterResult<(
|
) -> RouterResult<(
|
||||||
BoxedOperation<'a, F, api::PaymentsRequest>,
|
BoxedOperation<'a, F, api::PaymentsRequest>,
|
||||||
PaymentData<F>,
|
PaymentData<F>,
|
||||||
@ -63,6 +65,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
|
|||||||
.setup_future_usage
|
.setup_future_usage
|
||||||
.or(payment_intent.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_card_data(request.payment_method_data.clone())?;
|
||||||
|
|
||||||
helpers::validate_payment_status_against_not_allowed_statuses(
|
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>,
|
operations::ValidateResult<'a>,
|
||||||
)> {
|
)> {
|
||||||
helpers::validate_customer_details_in_request(request)?;
|
helpers::validate_customer_details_in_request(request)?;
|
||||||
|
|
||||||
let given_payment_id = match &request.payment_id {
|
let given_payment_id = match &request.payment_id {
|
||||||
Some(id_type) => Some(
|
Some(id_type) => Some(
|
||||||
id_type
|
id_type
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use crate::{
|
|||||||
errors,
|
errors,
|
||||||
routes::AppState,
|
routes::AppState,
|
||||||
scheduler::{consumer, process_data, utils},
|
scheduler::{consumer, process_data, utils},
|
||||||
|
services,
|
||||||
types::{
|
types::{
|
||||||
api,
|
api,
|
||||||
storage::{self, enums, ProcessTrackerExt},
|
storage::{self, enums, ProcessTrackerExt},
|
||||||
@ -54,6 +55,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
|
|||||||
operations::PaymentStatus,
|
operations::PaymentStatus,
|
||||||
tracking_data.clone(),
|
tracking_data.clone(),
|
||||||
payment_flows::CallConnectorAction::Trigger,
|
payment_flows::CallConnectorAction::Trigger,
|
||||||
|
services::AuthFlow::Client,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user