Skip to content

Commit

Permalink
refactor(webhooks): check event type not supported before checking fo…
Browse files Browse the repository at this point in the history
…r profile_id (#3543)
  • Loading branch information
Narayanbhat166 authored Feb 15, 2024
1 parent 610a5a3 commit 2d4f6b3
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 56 deletions.
66 changes: 25 additions & 41 deletions crates/router/src/core/webhooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,16 +984,15 @@ pub async fn webhooks_core<W: types::OutgoingWebhookType, Ctx: PaymentMethodRetr
// Fetch the merchant connector account to get the webhooks source secret
// `webhooks source secret` is a secret shared between the merchant and connector
// This is used for source verification and webhooks integrity
let (merchant_connector_account, connector) = fetch_mca_and_connector(
let (merchant_connector_account, connector) = fetch_optional_mca_and_connector(
&state,
&merchant_account,
connector_name_or_mca_id,
&key_store,
&request_details,
)
.await?;

let connector_name = merchant_connector_account.clone().connector_name;
let connector_name = connector.connector_name.to_string();

let connector = connector.connector;

Expand Down Expand Up @@ -1090,6 +1089,20 @@ pub async fn webhooks_core<W: types::OutgoingWebhookType, Ctx: PaymentMethodRetr
})?;
let connectors_with_source_verification_call = &state.conf.webhook_source_verification_call;

let merchant_connector_account = match merchant_connector_account {
Some(merchant_connector_account) => merchant_connector_account,
None => {
helper_utils::get_mca_from_object_reference_id(
&*state.clone().store,
object_ref_id.clone(),
&merchant_account,
&connector_name,
&key_store,
)
.await?
}
};

let source_verified = if connectors_with_source_verification_call
.connectors_with_webhook_source_verification_call
.contains(&connector_enum)
Expand Down Expand Up @@ -1311,14 +1324,17 @@ pub async fn get_payment_id(
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
}

async fn fetch_mca_and_connector(
/// This function fetches the merchant connector account ( if the url used is /{merchant_connector_id})
/// if merchant connector id is not passed in the request, then this will return None for mca
async fn fetch_optional_mca_and_connector(
state: &AppState,
merchant_account: &domain::MerchantAccount,
connector_name_or_mca_id: &str,
key_store: &domain::MerchantKeyStore,
request_details: &api::IncomingWebhookRequestDetails<'_>,
) -> CustomResult<(domain::MerchantConnectorAccount, api::ConnectorData), errors::ApiErrorResponse>
{
) -> CustomResult<
(Option<domain::MerchantConnectorAccount>, api::ConnectorData),
errors::ApiErrorResponse,
> {
let db = &state.store;
if connector_name_or_mca_id.starts_with("mca_") {
let mca = db
Expand Down Expand Up @@ -1346,7 +1362,7 @@ async fn fetch_mca_and_connector(
})
.attach_printable("Failed construction of ConnectorData")?;

Ok((mca, connector))
Ok((Some(mca), connector))
} else {
// Merchant connector account is already being queried, it is safe to set connector id as None
let connector = api::ConnectorData::get_connector_by_name(
Expand All @@ -1360,38 +1376,6 @@ async fn fetch_mca_and_connector(
})
.attach_printable("Failed construction of ConnectorData")?;

let object_ref_id = connector
.connector
.get_webhook_object_reference_id(request_details)
.switch()
.attach_printable("Could not find object reference id in incoming webhook body")?;

let profile_id = helper_utils::get_profile_id_using_object_reference_id(
&*state.store,
object_ref_id,
merchant_account,
connector_name_or_mca_id,
)
.await
.change_context(errors::ApiErrorResponse::InvalidDataValue {
field_name: "object reference id",
})
.attach_printable("Could not find profile id from object reference id")?;

let mca = db
.find_merchant_connector_account_by_profile_id_connector_name(
&profile_id,
connector_name_or_mca_id,
key_store,
)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
id: format!(
"profile_id {profile_id} and connector name {connector_name_or_mca_id}"
),
})
.attach_printable("error while fetching merchant_connector_account from profile_id")?;

Ok((mca, connector))
Ok((None, connector))
}
}
79 changes: 64 additions & 15 deletions crates/router/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,14 +326,26 @@ pub async fn find_payment_intent_from_mandate_id_type(
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
}

pub async fn get_profile_id_using_object_reference_id(
pub async fn get_mca_from_object_reference_id(
db: &dyn StorageInterface,
object_reference_id: webhooks::ObjectReferenceId,
merchant_account: &domain::MerchantAccount,
connector_name: &str,
) -> CustomResult<String, errors::ApiErrorResponse> {
key_store: &domain::MerchantKeyStore,
) -> CustomResult<domain::MerchantConnectorAccount, errors::ApiErrorResponse> {
let merchant_id = merchant_account.merchant_id.clone();

match merchant_account.default_profile.as_ref() {
Some(profile_id) => Ok(profile_id.clone()),
Some(profile_id) => db
.find_merchant_connector_account_by_profile_id_connector_name(
profile_id,
connector_name,
key_store,
)
.await
.to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
id: format!("profile_id {profile_id} and connector_name {connector_name}"),
}),
_ => {
let payment_intent = match object_reference_id {
webhooks::ObjectReferenceId::PaymentId(payment_id_type) => {
Expand All @@ -355,19 +367,56 @@ pub async fn get_profile_id_using_object_reference_id(
}
};

let profile_id = utils::get_profile_id_from_business_details(
payment_intent.business_country,
payment_intent.business_label.as_ref(),
merchant_account,
payment_intent.profile_id.as_ref(),
db,
false,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("profile_id is not set in payment_intent")?;
let payment_attempt = db
.find_payment_attempt_by_attempt_id_merchant_id(
&payment_intent.active_attempt.get_id(),
&merchant_id,
merchant_account.storage_scheme,
)
.await
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

Ok(profile_id)
match payment_attempt.merchant_connector_id {
Some(merchant_connector_id) => db
.find_by_merchant_connector_account_merchant_id_merchant_connector_id(
&merchant_id,
&merchant_connector_id,
key_store,
)
.await
.to_not_found_response(
errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
id: merchant_connector_id,
},
),
None => {
let profile_id = utils::get_profile_id_from_business_details(
payment_intent.business_country,
payment_intent.business_label.as_ref(),
merchant_account,
payment_intent.profile_id.as_ref(),
db,
false,
)
.await
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("profile_id is not set in payment_intent")?;

db.find_merchant_connector_account_by_profile_id_connector_name(
&profile_id,
connector_name,
key_store,
)
.await
.to_not_found_response(
errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
id: format!(
"profile_id {profile_id} and connector_name {connector_name}"
),
},
)
}
}
}
}
}
Expand Down

0 comments on commit 2d4f6b3

Please sign in to comment.