diff --git a/connector-template/mod.rs b/connector-template/mod.rs index 8282f7d169..926a481973 100644 --- a/connector-template/mod.rs +++ b/connector-template/mod.rs @@ -421,21 +421,21 @@ impl impl api::IncomingWebhook for {{project-name | downcase | pascal_case}} { fn get_webhook_object_reference_id( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/api_models/src/webhooks.rs b/crates/api_models/src/webhooks.rs index eb116eba31..d3ae9ea0d6 100644 --- a/crates/api_models/src/webhooks.rs +++ b/crates/api_models/src/webhooks.rs @@ -9,12 +9,14 @@ use crate::{enums as api_enums, payments}; pub enum IncomingWebhookEvent { PaymentIntentFailure, PaymentIntentSuccess, + EndpointVerification, } pub enum WebhookFlow { Payment, Refund, Subscription, + ReturnResponse, } impl From for WebhookFlow { @@ -22,10 +24,17 @@ impl From for WebhookFlow { match evt { IncomingWebhookEvent::PaymentIntentFailure => Self::Payment, IncomingWebhookEvent::PaymentIntentSuccess => Self::Payment, + IncomingWebhookEvent::EndpointVerification => Self::ReturnResponse, } } } +pub struct IncomingWebhookRequestDetails<'a> { + pub method: actix_web::http::Method, + pub headers: &'a actix_web::http::header::HeaderMap, + pub body: &'a [u8], +} + pub type MerchantWebhookConfig = std::collections::HashSet; pub struct IncomingWebhookDetails { diff --git a/crates/router/src/connector/aci.rs b/crates/router/src/connector/aci.rs index b1ebb50a26..648464c4c8 100644 --- a/crates/router/src/connector/aci.rs +++ b/crates/router/src/connector/aci.rs @@ -530,21 +530,21 @@ impl services::ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index f126a75f43..a7762862f2 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -656,18 +656,16 @@ fn get_webhook_object_from_body( impl api::IncomingWebhook for Adyen { fn get_webhook_source_verification_algorithm( &self, - _headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::HmacSha256)) } fn get_webhook_source_verification_signature( &self, - _headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { - let notif_item = get_webhook_object_from_body(body) + let notif_item = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let base64_signature = notif_item.additional_data.hmac_signature; @@ -682,12 +680,11 @@ impl api::IncomingWebhook for Adyen { fn get_webhook_source_verification_message( &self, - _headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, _merchant_id: &str, _secret: &[u8], ) -> CustomResult, errors::ConnectorError> { - let notif = get_webhook_object_from_body(body) + let notif = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let message = format!( @@ -721,9 +718,9 @@ impl api::IncomingWebhook for Adyen { fn get_webhook_object_reference_id( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let notif = get_webhook_object_from_body(body) + let notif = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; Ok(notif.psp_reference) @@ -731,9 +728,9 @@ impl api::IncomingWebhook for Adyen { fn get_webhook_event_type( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let notif = get_webhook_object_from_body(body) + let notif = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; Ok(match notif.event_code.as_str() { @@ -744,9 +741,9 @@ impl api::IncomingWebhook for Adyen { fn get_webhook_resource_object( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let notif = get_webhook_object_from_body(body) + let notif = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; let response: adyen::AdyenResponse = notif.into(); @@ -760,6 +757,7 @@ impl api::IncomingWebhook for Adyen { fn get_webhook_api_response( &self, + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(services::api::ApplicationResponse::TextPlain( diff --git a/crates/router/src/connector/applepay.rs b/crates/router/src/connector/applepay.rs index 3687c3b782..791507fb57 100644 --- a/crates/router/src/connector/applepay.rs +++ b/crates/router/src/connector/applepay.rs @@ -242,21 +242,21 @@ impl services::ConnectorRedirectResponse for Applepay {} impl api::IncomingWebhook for Applepay { fn get_webhook_object_reference_id( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/authorizedotnet.rs b/crates/router/src/connector/authorizedotnet.rs index 5542af0da5..5a1b561362 100644 --- a/crates/router/src/connector/authorizedotnet.rs +++ b/crates/router/src/connector/authorizedotnet.rs @@ -572,21 +572,21 @@ impl services::ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/braintree.rs b/crates/router/src/connector/braintree.rs index a757fea17b..e3f2435888 100644 --- a/crates/router/src/connector/braintree.rs +++ b/crates/router/src/connector/braintree.rs @@ -688,21 +688,21 @@ impl services::ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into()) } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into()) } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("braintree".to_string()).into()) } diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs index 49be6ce113..ea4c4697c9 100644 --- a/crates/router/src/connector/checkout.rs +++ b/crates/router/src/connector/checkout.rs @@ -734,21 +734,21 @@ impl services::ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/cybersource.rs b/crates/router/src/connector/cybersource.rs index a932a3fe82..998ccdc363 100644 --- a/crates/router/src/connector/cybersource.rs +++ b/crates/router/src/connector/cybersource.rs @@ -696,21 +696,21 @@ impl ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("cybersource".to_string()).into()) } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("cybersource".to_string()).into()) } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("cybersource".to_string()).into()) } diff --git a/crates/router/src/connector/fiserv.rs b/crates/router/src/connector/fiserv.rs index 0e241cefd9..a1ca56b04a 100644 --- a/crates/router/src/connector/fiserv.rs +++ b/crates/router/src/connector/fiserv.rs @@ -416,21 +416,21 @@ impl services::ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("fiserv".to_string()).into()) } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("fiserv".to_string()).into()) } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::NotImplemented("fiserv".to_string()).into()) } diff --git a/crates/router/src/connector/globalpay.rs b/crates/router/src/connector/globalpay.rs index 25b5a0fb06..580dd3fccc 100644 --- a/crates/router/src/connector/globalpay.rs +++ b/crates/router/src/connector/globalpay.rs @@ -693,21 +693,21 @@ impl ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/klarna.rs b/crates/router/src/connector/klarna.rs index aab27644cf..38e576cffd 100644 --- a/crates/router/src/connector/klarna.rs +++ b/crates/router/src/connector/klarna.rs @@ -360,21 +360,21 @@ impl services::ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/payu.rs b/crates/router/src/connector/payu.rs index 2354679918..3972f9c62b 100644 --- a/crates/router/src/connector/payu.rs +++ b/crates/router/src/connector/payu.rs @@ -684,21 +684,21 @@ impl ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/rapyd.rs b/crates/router/src/connector/rapyd.rs index ec6687913e..8c0c47409e 100644 --- a/crates/router/src/connector/rapyd.rs +++ b/crates/router/src/connector/rapyd.rs @@ -666,18 +666,16 @@ impl services::ConnectorIntegration, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::HmacSha256)) } fn get_webhook_source_verification_signature( &self, - headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { - let base64_signature = conn_utils::get_header_key_value("signature", headers)?; + let base64_signature = conn_utils::get_header_key_value("signature", request.headers)?; let signature = consts::BASE64_ENGINE_URL_SAFE .decode(base64_signature.as_bytes()) .into_report() @@ -701,16 +699,15 @@ impl api::IncomingWebhook for Rapyd { fn get_webhook_source_verification_message( &self, - headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, merchant_id: &str, secret: &[u8], ) -> CustomResult, errors::ConnectorError> { - let host = conn_utils::get_header_key_value("host", headers)?; + let host = conn_utils::get_header_key_value("host", request.headers)?; let connector = self.id(); let url_path = format!("https://{host}/webhooks/{merchant_id}/{connector}"); - let salt = conn_utils::get_header_key_value("salt", headers)?; - let timestamp = conn_utils::get_header_key_value("timestamp", headers)?; + let salt = conn_utils::get_header_key_value("salt", request.headers)?; + let timestamp = conn_utils::get_header_key_value("timestamp", request.headers)?; let stringify_auth = String::from_utf8(secret.to_vec()) .into_report() .change_context(errors::ConnectorError::WebhookSourceVerificationFailed) @@ -720,7 +717,7 @@ impl api::IncomingWebhook for Rapyd { .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let access_key = auth.access_key; let secret_key = auth.secret_key; - let body_string = String::from_utf8(body.to_vec()) + let body_string = String::from_utf8(request.body.to_vec()) .into_report() .change_context(errors::ConnectorError::WebhookSourceVerificationFailed) .attach_printable("Could not convert body to UTF-8")?; @@ -732,19 +729,18 @@ impl api::IncomingWebhook for Rapyd { async fn verify_webhook_source( &self, db: &dyn StorageInterface, - headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, merchant_id: &str, ) -> CustomResult { let signature = self - .get_webhook_source_verification_signature(headers, body) + .get_webhook_source_verification_signature(request) .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let secret = self .get_webhook_source_verification_merchant_secret(db, merchant_id) .await .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let message = self - .get_webhook_source_verification_message(headers, body, merchant_id, &secret) + .get_webhook_source_verification_message(request, merchant_id, &secret) .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let stringify_auth = String::from_utf8(secret.to_vec()) @@ -763,11 +759,13 @@ impl api::IncomingWebhook for Rapyd { fn get_webhook_object_reference_id( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let webhook: transformers::RapydIncomingWebhook = body + let webhook: transformers::RapydIncomingWebhook = request + .body .parse_struct("RapydIncomingWebhook") .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; + Ok(match webhook.data { transformers::WebhookData::PaymentData(payment_data) => payment_data.id, transformers::WebhookData::RefundData(refund_data) => refund_data.id, @@ -776,19 +774,22 @@ impl api::IncomingWebhook for Rapyd { fn get_webhook_event_type( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let webhook: transformers::RapydIncomingWebhook = body + let webhook: transformers::RapydIncomingWebhook = request + .body .parse_struct("RapydIncomingWebhook") .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; + webhook.webhook_type.try_into() } fn get_webhook_resource_object( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let webhook: transformers::RapydIncomingWebhook = body + let webhook: transformers::RapydIncomingWebhook = request + .body .parse_struct("RapydIncomingWebhook") .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; let response = match webhook.data { diff --git a/crates/router/src/connector/shift4.rs b/crates/router/src/connector/shift4.rs index 470eeb2502..cc515d3d8e 100644 --- a/crates/router/src/connector/shift4.rs +++ b/crates/router/src/connector/shift4.rs @@ -499,9 +499,10 @@ impl ConnectorIntegration, ) -> CustomResult { - let details: shift4::Shift4WebhookObjectId = body + let details: shift4::Shift4WebhookObjectId = request + .body .parse_struct("Shift4WebhookObjectId") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; @@ -510,9 +511,10 @@ impl api::IncomingWebhook for Shift4 { fn get_webhook_event_type( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: shift4::Shift4WebhookObjectEventType = body + let details: shift4::Shift4WebhookObjectEventType = request + .body .parse_struct("Shift4WebhookObjectEventType") .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; Ok(match details.event_type { @@ -524,9 +526,10 @@ impl api::IncomingWebhook for Shift4 { fn get_webhook_resource_object( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: shift4::Shift4WebhookObjectResource = body + let details: shift4::Shift4WebhookObjectResource = request + .body .parse_struct("Shift4WebhookObjectResource") .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?; Ok(details.data) diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index 15959b945e..8e54d50fc4 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -880,18 +880,16 @@ fn get_signature_elements_from_header( impl api::IncomingWebhook for Stripe { fn get_webhook_source_verification_algorithm( &self, - _headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::HmacSha256)) } fn get_webhook_source_verification_signature( &self, - headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { - let mut security_header_kvs = get_signature_elements_from_header(headers)?; + let mut security_header_kvs = get_signature_elements_from_header(request.headers)?; let signature = security_header_kvs .remove("v1") @@ -905,12 +903,11 @@ impl api::IncomingWebhook for Stripe { fn get_webhook_source_verification_message( &self, - headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, _merchant_id: &str, _secret: &[u8], ) -> CustomResult, errors::ConnectorError> { - let mut security_header_kvs = get_signature_elements_from_header(headers)?; + let mut security_header_kvs = get_signature_elements_from_header(request.headers)?; let timestamp = security_header_kvs .remove("t") @@ -920,7 +917,7 @@ impl api::IncomingWebhook for Stripe { Ok(format!( "{}.{}", String::from_utf8_lossy(×tamp), - String::from_utf8_lossy(body) + String::from_utf8_lossy(request.body) ) .into_bytes()) } @@ -941,9 +938,10 @@ impl api::IncomingWebhook for Stripe { fn get_webhook_object_reference_id( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: stripe::StripeWebhookObjectId = body + let details: stripe::StripeWebhookObjectId = request + .body .parse_struct("StripeWebhookObjectId") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; @@ -952,9 +950,10 @@ impl api::IncomingWebhook for Stripe { fn get_webhook_event_type( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: stripe::StripeWebhookObjectEventType = body + let details: stripe::StripeWebhookObjectEventType = request + .body .parse_struct("StripeWebhookObjectEventType") .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; @@ -967,9 +966,10 @@ impl api::IncomingWebhook for Stripe { fn get_webhook_resource_object( &self, - body: &[u8], + request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: stripe::StripeWebhookObjectResource = body + let details: stripe::StripeWebhookObjectResource = request + .body .parse_struct("StripeWebhookObjectResource") .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?; diff --git a/crates/router/src/connector/worldline.rs b/crates/router/src/connector/worldline.rs index 7d6f214e96..d086205cd5 100644 --- a/crates/router/src/connector/worldline.rs +++ b/crates/router/src/connector/worldline.rs @@ -655,21 +655,21 @@ impl ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/connector/worldpay.rs b/crates/router/src/connector/worldpay.rs index bd53b9fd78..ff41f8b1b8 100644 --- a/crates/router/src/connector/worldpay.rs +++ b/crates/router/src/connector/worldpay.rs @@ -594,21 +594,21 @@ impl ConnectorIntegration, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_event_type( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(errors::ConnectorError::WebhooksNotImplemented).into_report() } diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs index bb059356eb..7be7781bd0 100644 --- a/crates/router/src/core/webhooks.rs +++ b/crates/router/src/core/webhooks.rs @@ -211,11 +211,16 @@ pub async fn webhooks_core( let connector = connector.connector; + let mut request_details = api::IncomingWebhookRequestDetails { + method: req.method().clone(), + headers: req.headers(), + body: &body, + }; + let source_verified = connector .verify_webhook_source( &*state.store, - req.headers(), - &body, + &request_details, &merchant_account.merchant_id, ) .await @@ -225,16 +230,17 @@ pub async fn webhooks_core( let decoded_body = connector .decode_webhook_body( &*state.store, - req.headers(), - &body, + &request_details, &merchant_account.merchant_id, ) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("There was an error in incoming webhook body decoding")?; + request_details.body = &decoded_body; + let event_type = connector - .get_webhook_event_type(&decoded_body) + .get_webhook_event_type(&request_details) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Could not find event type in incoming webhook body")?; @@ -248,12 +254,12 @@ pub async fn webhooks_core( if process_webhook_further { let object_ref_id = connector - .get_webhook_object_reference_id(&decoded_body) + .get_webhook_object_reference_id(&request_details) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Could not find object reference id in incoming webhook body")?; let event_object = connector - .get_webhook_resource_object(&decoded_body) + .get_webhook_resource_object(&request_details) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Could not find resource object in incoming webhook body")?; @@ -277,6 +283,9 @@ pub async fn webhooks_core( .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Incoming webhook flow for payments failed")?, + + api::WebhookFlow::ReturnResponse => {} + _ => Err(errors::ApiErrorResponse::InternalServerError) .into_report() .attach_printable("Unsupported Flow Type received in incoming webhooks")?, @@ -284,7 +293,7 @@ pub async fn webhooks_core( } let response = connector - .get_webhook_api_response() + .get_webhook_api_response(&request_details) .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Could not get incoming webhook api response from connector")?; diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 968d69e69d..f3bdbaf32e 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -315,7 +315,8 @@ impl Webhooks { .app_data(web::Data::new(config)) .service( web::resource("/{merchant_id}/{connector}") - .route(web::post().to(receive_incoming_webhook)), + .route(web::post().to(receive_incoming_webhook)) + .route(web::get().to(receive_incoming_webhook)), ) } } diff --git a/crates/router/src/types/api/webhooks.rs b/crates/router/src/types/api/webhooks.rs index 36a9f87624..2340c30964 100644 --- a/crates/router/src/types/api/webhooks.rs +++ b/crates/router/src/types/api/webhooks.rs @@ -1,6 +1,6 @@ pub use api_models::webhooks::{ - IncomingWebhookDetails, IncomingWebhookEvent, MerchantWebhookConfig, OutgoingWebhook, - OutgoingWebhookContent, WebhookFlow, + IncomingWebhookDetails, IncomingWebhookEvent, IncomingWebhookRequestDetails, + MerchantWebhookConfig, OutgoingWebhook, OutgoingWebhookContent, WebhookFlow, }; use error_stack::ResultExt; @@ -16,8 +16,7 @@ use crate::{ pub trait IncomingWebhook: ConnectorCommon + Sync { fn get_webhook_body_decoding_algorithm( &self, - _headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::NoAlgorithm)) } @@ -32,23 +31,21 @@ pub trait IncomingWebhook: ConnectorCommon + Sync { fn get_webhook_body_decoding_message( &self, - _headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { - Ok(body.to_vec()) + Ok(request.body.to_vec()) } async fn decode_webhook_body( &self, db: &dyn StorageInterface, - headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &IncomingWebhookRequestDetails<'_>, merchant_id: &str, ) -> CustomResult, errors::ConnectorError> { - let algorithm = self.get_webhook_body_decoding_algorithm(headers, body)?; + let algorithm = self.get_webhook_body_decoding_algorithm(request)?; let message = self - .get_webhook_body_decoding_message(headers, body) + .get_webhook_body_decoding_message(request) .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; let secret = self .get_webhook_body_decoding_merchant_secret(db, merchant_id) @@ -62,8 +59,7 @@ pub trait IncomingWebhook: ConnectorCommon + Sync { fn get_webhook_source_verification_algorithm( &self, - _headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::NoAlgorithm)) } @@ -78,16 +74,14 @@ pub trait IncomingWebhook: ConnectorCommon + Sync { fn get_webhook_source_verification_signature( &self, - _headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Vec::new()) } fn get_webhook_source_verification_message( &self, - _headers: &actix_web::http::header::HeaderMap, - _body: &[u8], + _request: &IncomingWebhookRequestDetails<'_>, _merchant_id: &str, _secret: &[u8], ) -> CustomResult, errors::ConnectorError> { @@ -97,23 +91,22 @@ pub trait IncomingWebhook: ConnectorCommon + Sync { async fn verify_webhook_source( &self, db: &dyn StorageInterface, - headers: &actix_web::http::header::HeaderMap, - body: &[u8], + request: &IncomingWebhookRequestDetails<'_>, merchant_id: &str, ) -> CustomResult { let algorithm = self - .get_webhook_source_verification_algorithm(headers, body) + .get_webhook_source_verification_algorithm(request) .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let signature = self - .get_webhook_source_verification_signature(headers, body) + .get_webhook_source_verification_signature(request) .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let secret = self .get_webhook_source_verification_merchant_secret(db, merchant_id) .await .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; let message = self - .get_webhook_source_verification_message(headers, body, merchant_id, &secret) + .get_webhook_source_verification_message(request, merchant_id, &secret) .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?; algorithm @@ -123,21 +116,22 @@ pub trait IncomingWebhook: ConnectorCommon + Sync { fn get_webhook_object_reference_id( &self, - _body: &[u8], + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult; fn get_webhook_event_type( &self, - _body: &[u8], + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult; fn get_webhook_resource_object( &self, - _body: &[u8], + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult; fn get_webhook_api_response( &self, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(services::api::ApplicationResponse::StatusOk)