mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 12:06:56 +08:00
feat(webhooks): Webhook source verification (#2069)
This commit is contained in:
committed by
GitHub
parent
f8410b5b2a
commit
8b22f38dd6
@ -641,6 +641,8 @@ pub struct MerchantConnectorCreate {
|
|||||||
pub struct MerchantConnectorWebhookDetails {
|
pub struct MerchantConnectorWebhookDetails {
|
||||||
#[schema(value_type = String, example = "12345678900987654321")]
|
#[schema(value_type = String, example = "12345678900987654321")]
|
||||||
pub merchant_secret: Secret<String>,
|
pub merchant_secret: Secret<String>,
|
||||||
|
#[schema(value_type = String, example = "12345678900987654321")]
|
||||||
|
pub additional_secret: Option<Secret<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Response of creating a new Merchant Connector for the merchant account."
|
/// Response of creating a new Merchant Connector for the merchant account."
|
||||||
|
|||||||
@ -2474,6 +2474,8 @@ pub struct ApplepaySessionTokenResponse {
|
|||||||
pub connector_reference_id: Option<String>,
|
pub connector_reference_id: Option<String>,
|
||||||
/// The public key id is to invoke third party sdk
|
/// The public key id is to invoke third party sdk
|
||||||
pub connector_sdk_public_key: Option<String>,
|
pub connector_sdk_public_key: Option<String>,
|
||||||
|
/// The connector merchant id
|
||||||
|
pub connector_merchant_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, serde::Serialize, Clone, ToSchema)]
|
#[derive(Debug, Eq, PartialEq, serde::Serialize, Clone, ToSchema)]
|
||||||
|
|||||||
@ -114,3 +114,8 @@ pub enum OutgoingWebhookContent {
|
|||||||
#[schema(value_type = DisputeResponse)]
|
#[schema(value_type = DisputeResponse)]
|
||||||
DisputeDetails(Box<disputes::DisputeResponse>),
|
DisputeDetails(Box<disputes::DisputeResponse>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ConnectorWebhookSecrets {
|
||||||
|
pub secret: Vec<u8>,
|
||||||
|
pub additional_secret: Option<masking::Secret<String>>,
|
||||||
|
}
|
||||||
|
|||||||
@ -1408,7 +1408,7 @@ impl api::IncomingWebhook for Adyen {
|
|||||||
let signature = self
|
let signature = self
|
||||||
.get_webhook_source_verification_signature(request)
|
.get_webhook_source_verification_signature(request)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
let secret = self
|
let connector_webhook_secrets = self
|
||||||
.get_webhook_source_verification_merchant_secret(
|
.get_webhook_source_verification_merchant_secret(
|
||||||
db,
|
db,
|
||||||
merchant_account,
|
merchant_account,
|
||||||
@ -1422,11 +1422,11 @@ impl api::IncomingWebhook for Adyen {
|
|||||||
.get_webhook_source_verification_message(
|
.get_webhook_source_verification_message(
|
||||||
request,
|
request,
|
||||||
&merchant_account.merchant_id,
|
&merchant_account.merchant_id,
|
||||||
&secret,
|
&connector_webhook_secrets.secret,
|
||||||
)
|
)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
|
|
||||||
let raw_key = hex::decode(secret)
|
let raw_key = hex::decode(connector_webhook_secrets.secret)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ConnectorError::WebhookSignatureNotFound)?;
|
.change_context(errors::ConnectorError::WebhookSignatureNotFound)?;
|
||||||
|
|
||||||
|
|||||||
@ -427,6 +427,7 @@ impl TryFrom<types::PaymentsSessionResponseRouterData<BluesnapWalletTokenRespons
|
|||||||
},
|
},
|
||||||
connector_reference_id: None,
|
connector_reference_id: None,
|
||||||
connector_sdk_public_key: None,
|
connector_sdk_public_key: None,
|
||||||
|
connector_merchant_id: None,
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -341,7 +341,7 @@ impl api::IncomingWebhook for Cashtocode {
|
|||||||
let signature = self
|
let signature = self
|
||||||
.get_webhook_source_verification_signature(request)
|
.get_webhook_source_verification_signature(request)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
let secret = self
|
let connector_webhook_secrets = self
|
||||||
.get_webhook_source_verification_merchant_secret(
|
.get_webhook_source_verification_merchant_secret(
|
||||||
db,
|
db,
|
||||||
merchant_account,
|
merchant_account,
|
||||||
@ -351,7 +351,7 @@ impl api::IncomingWebhook for Cashtocode {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
let secret_auth = String::from_utf8(secret.to_vec())
|
let secret_auth = String::from_utf8(connector_webhook_secrets.secret.to_vec())
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
||||||
.attach_printable("Could not convert secret to UTF-8")?;
|
.attach_printable("Could not convert secret to UTF-8")?;
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use crate::{
|
|||||||
configs::settings,
|
configs::settings,
|
||||||
connector::utils as connector_utils,
|
connector::utils as connector_utils,
|
||||||
core::errors::{self, CustomResult},
|
core::errors::{self, CustomResult},
|
||||||
headers,
|
db, headers,
|
||||||
services::{self, request, ConnectorIntegration, ConnectorValidation},
|
services::{self, request, ConnectorIntegration, ConnectorValidation},
|
||||||
types::{
|
types::{
|
||||||
self,
|
self,
|
||||||
@ -722,6 +722,62 @@ impl api::IncomingWebhook for Payme {
|
|||||||
.to_vec())
|
.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn verify_webhook_source(
|
||||||
|
&self,
|
||||||
|
db: &dyn db::StorageInterface,
|
||||||
|
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||||
|
merchant_account: &types::domain::MerchantAccount,
|
||||||
|
connector_label: &str,
|
||||||
|
key_store: &types::domain::MerchantKeyStore,
|
||||||
|
object_reference_id: api_models::webhooks::ObjectReferenceId,
|
||||||
|
) -> CustomResult<bool, errors::ConnectorError> {
|
||||||
|
let algorithm = self
|
||||||
|
.get_webhook_source_verification_algorithm(request)
|
||||||
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
|
|
||||||
|
let signature = self
|
||||||
|
.get_webhook_source_verification_signature(request)
|
||||||
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
|
|
||||||
|
let connector_webhook_secrets = self
|
||||||
|
.get_webhook_source_verification_merchant_secret(
|
||||||
|
db,
|
||||||
|
merchant_account,
|
||||||
|
connector_label,
|
||||||
|
key_store,
|
||||||
|
object_reference_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
|
let mut message = self
|
||||||
|
.get_webhook_source_verification_message(
|
||||||
|
request,
|
||||||
|
&merchant_account.merchant_id,
|
||||||
|
&connector_webhook_secrets.secret,
|
||||||
|
)
|
||||||
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
|
let mut message_to_verify = connector_webhook_secrets
|
||||||
|
.additional_secret
|
||||||
|
.ok_or(errors::ConnectorError::WebhookSourceVerificationFailed)
|
||||||
|
.into_report()
|
||||||
|
.attach_printable("Failed to get additional secrets")?
|
||||||
|
.expose()
|
||||||
|
.as_bytes()
|
||||||
|
.to_vec();
|
||||||
|
message_to_verify.append(&mut message);
|
||||||
|
|
||||||
|
let signature_to_verify = hex::decode(signature)
|
||||||
|
.into_report()
|
||||||
|
.change_context(errors::ConnectorError::WebhookResponseEncodingFailed)?;
|
||||||
|
algorithm
|
||||||
|
.verify_signature(
|
||||||
|
&connector_webhook_secrets.secret,
|
||||||
|
&signature_to_verify,
|
||||||
|
&message_to_verify,
|
||||||
|
)
|
||||||
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
||||||
|
}
|
||||||
|
|
||||||
fn get_webhook_object_reference_id(
|
fn get_webhook_object_reference_id(
|
||||||
&self,
|
&self,
|
||||||
request: &api::IncomingWebhookRequestDetails<'_>,
|
request: &api::IncomingWebhookRequestDetails<'_>,
|
||||||
|
|||||||
@ -290,7 +290,7 @@ impl TryFrom<&PaymentMethodData> for SalePaymentMethod {
|
|||||||
match item {
|
match item {
|
||||||
PaymentMethodData::Card(_) => Ok(Self::CreditCard),
|
PaymentMethodData::Card(_) => Ok(Self::CreditCard),
|
||||||
PaymentMethodData::Wallet(wallet_data) => match wallet_data {
|
PaymentMethodData::Wallet(wallet_data) => match wallet_data {
|
||||||
api_models::payments::WalletData::ApplePay(_) => Ok(Self::ApplePay),
|
api_models::payments::WalletData::ApplePayThirdPartySdk(_) => Ok(Self::ApplePay),
|
||||||
api_models::payments::WalletData::AliPayQr(_)
|
api_models::payments::WalletData::AliPayQr(_)
|
||||||
| api_models::payments::WalletData::AliPayRedirect(_)
|
| api_models::payments::WalletData::AliPayRedirect(_)
|
||||||
| api_models::payments::WalletData::AliPayHkRedirect(_)
|
| api_models::payments::WalletData::AliPayHkRedirect(_)
|
||||||
@ -299,7 +299,6 @@ impl TryFrom<&PaymentMethodData> for SalePaymentMethod {
|
|||||||
| api_models::payments::WalletData::GoPayRedirect(_)
|
| api_models::payments::WalletData::GoPayRedirect(_)
|
||||||
| api_models::payments::WalletData::GcashRedirect(_)
|
| api_models::payments::WalletData::GcashRedirect(_)
|
||||||
| api_models::payments::WalletData::ApplePayRedirect(_)
|
| api_models::payments::WalletData::ApplePayRedirect(_)
|
||||||
| api_models::payments::WalletData::ApplePayThirdPartySdk(_)
|
|
||||||
| api_models::payments::WalletData::DanaRedirect {}
|
| api_models::payments::WalletData::DanaRedirect {}
|
||||||
| api_models::payments::WalletData::GooglePay(_)
|
| api_models::payments::WalletData::GooglePay(_)
|
||||||
| api_models::payments::WalletData::GooglePayRedirect(_)
|
| api_models::payments::WalletData::GooglePayRedirect(_)
|
||||||
@ -315,6 +314,7 @@ impl TryFrom<&PaymentMethodData> for SalePaymentMethod {
|
|||||||
| api_models::payments::WalletData::WeChatPayRedirect(_)
|
| api_models::payments::WalletData::WeChatPayRedirect(_)
|
||||||
| api_models::payments::WalletData::WeChatPayQr(_)
|
| api_models::payments::WalletData::WeChatPayQr(_)
|
||||||
| api_models::payments::WalletData::CashappQr(_)
|
| api_models::payments::WalletData::CashappQr(_)
|
||||||
|
| api_models::payments::WalletData::ApplePay(_)
|
||||||
| api_models::payments::WalletData::SwishQr(_) => {
|
| api_models::payments::WalletData::SwishQr(_) => {
|
||||||
Err(errors::ConnectorError::NotSupported {
|
Err(errors::ConnectorError::NotSupported {
|
||||||
message: "Wallet".to_string(),
|
message: "Wallet".to_string(),
|
||||||
@ -401,6 +401,7 @@ impl<F>
|
|||||||
let amount = item.data.request.get_amount()?;
|
let amount = item.data.request.get_amount()?;
|
||||||
let amount_in_base_unit = utils::to_currency_base_unit(amount, currency_code)?;
|
let amount_in_base_unit = utils::to_currency_base_unit(amount, currency_code)?;
|
||||||
let pmd = item.data.request.payment_method_data.to_owned();
|
let pmd = item.data.request.payment_method_data.to_owned();
|
||||||
|
let payme_auth_type = PaymeAuthType::try_from(&item.data.connector_auth_type)?;
|
||||||
|
|
||||||
let session_token = match pmd {
|
let session_token = match pmd {
|
||||||
Some(PaymentMethodData::Wallet(
|
Some(PaymentMethodData::Wallet(
|
||||||
@ -427,11 +428,10 @@ impl<F>
|
|||||||
next_action: api_models::payments::NextActionCall::Sync,
|
next_action: api_models::payments::NextActionCall::Sync,
|
||||||
},
|
},
|
||||||
connector_reference_id: Some(item.response.payme_sale_id.to_owned()),
|
connector_reference_id: Some(item.response.payme_sale_id.to_owned()),
|
||||||
connector_sdk_public_key: Some(
|
connector_sdk_public_key: Some(payme_auth_type.payme_public_key.expose()),
|
||||||
PaymeAuthType::try_from(&item.data.connector_auth_type)?
|
connector_merchant_id: payme_auth_type
|
||||||
.payme_public_key
|
.payme_merchant_id
|
||||||
.expose(),
|
.map(|mid| mid.expose()),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
))),
|
))),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -513,6 +513,7 @@ pub struct PaymeAuthType {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(super) payme_public_key: Secret<String>,
|
pub(super) payme_public_key: Secret<String>,
|
||||||
pub(super) seller_payme_id: Secret<String>,
|
pub(super) seller_payme_id: Secret<String>,
|
||||||
|
pub(super) payme_merchant_id: Option<Secret<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&types::ConnectorAuthType> for PaymeAuthType {
|
impl TryFrom<&types::ConnectorAuthType> for PaymeAuthType {
|
||||||
@ -522,6 +523,16 @@ impl TryFrom<&types::ConnectorAuthType> for PaymeAuthType {
|
|||||||
types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
|
types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
|
||||||
seller_payme_id: api_key.to_owned(),
|
seller_payme_id: api_key.to_owned(),
|
||||||
payme_public_key: key1.to_owned(),
|
payme_public_key: key1.to_owned(),
|
||||||
|
payme_merchant_id: None,
|
||||||
|
}),
|
||||||
|
types::ConnectorAuthType::SignatureKey {
|
||||||
|
api_key,
|
||||||
|
key1,
|
||||||
|
api_secret,
|
||||||
|
} => Ok(Self {
|
||||||
|
seller_payme_id: api_key.to_owned(),
|
||||||
|
payme_public_key: key1.to_owned(),
|
||||||
|
payme_merchant_id: Some(api_secret.to_owned()),
|
||||||
}),
|
}),
|
||||||
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
|
_ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -772,7 +772,7 @@ impl api::IncomingWebhook for Rapyd {
|
|||||||
let signature = self
|
let signature = self
|
||||||
.get_webhook_source_verification_signature(request)
|
.get_webhook_source_verification_signature(request)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
let secret = self
|
let connector_webhook_secrets = self
|
||||||
.get_webhook_source_verification_merchant_secret(
|
.get_webhook_source_verification_merchant_secret(
|
||||||
db,
|
db,
|
||||||
merchant_account,
|
merchant_account,
|
||||||
@ -786,11 +786,11 @@ impl api::IncomingWebhook for Rapyd {
|
|||||||
.get_webhook_source_verification_message(
|
.get_webhook_source_verification_message(
|
||||||
request,
|
request,
|
||||||
&merchant_account.merchant_id,
|
&merchant_account.merchant_id,
|
||||||
&secret,
|
&connector_webhook_secrets.secret,
|
||||||
)
|
)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
|
|
||||||
let stringify_auth = String::from_utf8(secret.to_vec())
|
let stringify_auth = String::from_utf8(connector_webhook_secrets.secret.to_vec())
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
||||||
.attach_printable("Could not convert secret to UTF-8")?;
|
.attach_printable("Could not convert secret to UTF-8")?;
|
||||||
|
|||||||
@ -1068,6 +1068,7 @@ pub fn get_apple_pay_session<F, T>(
|
|||||||
},
|
},
|
||||||
connector_reference_id: None,
|
connector_reference_id: None,
|
||||||
connector_sdk_public_key: None,
|
connector_sdk_public_key: None,
|
||||||
|
connector_merchant_id: None,
|
||||||
},
|
},
|
||||||
))),
|
))),
|
||||||
connector_response_reference_id: None,
|
connector_response_reference_id: None,
|
||||||
|
|||||||
@ -573,7 +573,7 @@ impl api::IncomingWebhook for Zen {
|
|||||||
let algorithm = self.get_webhook_source_verification_algorithm(request)?;
|
let algorithm = self.get_webhook_source_verification_algorithm(request)?;
|
||||||
|
|
||||||
let signature = self.get_webhook_source_verification_signature(request)?;
|
let signature = self.get_webhook_source_verification_signature(request)?;
|
||||||
let mut secret = self
|
let mut connector_webhook_secrets = self
|
||||||
.get_webhook_source_verification_merchant_secret(
|
.get_webhook_source_verification_merchant_secret(
|
||||||
db,
|
db,
|
||||||
merchant_account,
|
merchant_account,
|
||||||
@ -585,11 +585,11 @@ impl api::IncomingWebhook for Zen {
|
|||||||
let mut message = self.get_webhook_source_verification_message(
|
let mut message = self.get_webhook_source_verification_message(
|
||||||
request,
|
request,
|
||||||
&merchant_account.merchant_id,
|
&merchant_account.merchant_id,
|
||||||
&secret,
|
&connector_webhook_secrets.secret,
|
||||||
)?;
|
)?;
|
||||||
message.append(&mut secret);
|
message.append(&mut connector_webhook_secrets.secret);
|
||||||
algorithm
|
algorithm
|
||||||
.verify_signature(&secret, &signature, &message)
|
.verify_signature(&connector_webhook_secrets.secret, &signature, &message)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -273,6 +273,7 @@ fn create_apple_pay_session_response(
|
|||||||
sdk_next_action: { payment_types::SdkNextAction { next_action } },
|
sdk_next_action: { payment_types::SdkNextAction { next_action } },
|
||||||
connector_reference_id: None,
|
connector_reference_id: None,
|
||||||
connector_sdk_public_key: None,
|
connector_sdk_public_key: None,
|
||||||
|
connector_merchant_id: None,
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -82,7 +82,7 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
|
|||||||
connector_name: &str,
|
connector_name: &str,
|
||||||
key_store: &domain::MerchantKeyStore,
|
key_store: &domain::MerchantKeyStore,
|
||||||
object_reference_id: ObjectReferenceId,
|
object_reference_id: ObjectReferenceId,
|
||||||
) -> CustomResult<Vec<u8>, errors::ConnectorError> {
|
) -> CustomResult<api_models::webhooks::ConnectorWebhookSecrets, errors::ConnectorError> {
|
||||||
let merchant_id = merchant_account.merchant_id.as_str();
|
let merchant_id = merchant_account.merchant_id.as_str();
|
||||||
let debug_suffix = format!(
|
let debug_suffix = format!(
|
||||||
"For merchant_id: {}, and connector_name: {}",
|
"For merchant_id: {}, and connector_name: {}",
|
||||||
@ -106,22 +106,34 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let merchant_secret = match merchant_connector_account_result {
|
let connector_webhook_secrets = match merchant_connector_account_result {
|
||||||
Ok(mca) => match mca.connector_webhook_details {
|
Ok(mca) => match mca.connector_webhook_details {
|
||||||
Some(merchant_connector_webhook_details) => merchant_connector_webhook_details
|
Some(merchant_connector_webhook_details) => {
|
||||||
|
let connector_webhook_details = merchant_connector_webhook_details
|
||||||
.parse_value::<MerchantConnectorWebhookDetails>(
|
.parse_value::<MerchantConnectorWebhookDetails>(
|
||||||
"MerchantConnectorWebhookDetails",
|
"MerchantConnectorWebhookDetails",
|
||||||
)
|
)
|
||||||
.change_context_lazy(|| errors::ConnectorError::WebhookSourceVerificationFailed)
|
.change_context_lazy(|| {
|
||||||
|
errors::ConnectorError::WebhookSourceVerificationFailed
|
||||||
|
})
|
||||||
.attach_printable_lazy(|| {
|
.attach_printable_lazy(|| {
|
||||||
format!(
|
format!(
|
||||||
"Deserializing MerchantConnectorWebhookDetails failed {}",
|
"Deserializing MerchantConnectorWebhookDetails failed {}",
|
||||||
debug_suffix
|
debug_suffix
|
||||||
)
|
)
|
||||||
})?
|
})?;
|
||||||
|
api_models::webhooks::ConnectorWebhookSecrets {
|
||||||
|
secret: connector_webhook_details
|
||||||
.merchant_secret
|
.merchant_secret
|
||||||
.expose(),
|
.expose()
|
||||||
None => default_secret,
|
.into_bytes(),
|
||||||
|
additional_secret: connector_webhook_details.additional_secret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => api_models::webhooks::ConnectorWebhookSecrets {
|
||||||
|
secret: default_secret.into_bytes(),
|
||||||
|
additional_secret: None,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
logger::error!(
|
logger::error!(
|
||||||
@ -129,7 +141,10 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
|
|||||||
debug_suffix
|
debug_suffix
|
||||||
);
|
);
|
||||||
logger::error!("DB error = {:?}", err);
|
logger::error!("DB error = {:?}", err);
|
||||||
default_secret
|
api_models::webhooks::ConnectorWebhookSecrets {
|
||||||
|
secret: default_secret.into_bytes(),
|
||||||
|
additional_secret: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -137,7 +152,7 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
|
|||||||
|
|
||||||
//If merchant has not set the secret for webhook source verification, "default_secret" is returned.
|
//If merchant has not set the secret for webhook source verification, "default_secret" is returned.
|
||||||
//So it will fail during verification step and goes to psync flow.
|
//So it will fail during verification step and goes to psync flow.
|
||||||
Ok(merchant_secret.into_bytes())
|
Ok(connector_webhook_secrets)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_webhook_source_verification_signature(
|
fn get_webhook_source_verification_signature(
|
||||||
@ -172,7 +187,7 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
|
|||||||
let signature = self
|
let signature = self
|
||||||
.get_webhook_source_verification_signature(request)
|
.get_webhook_source_verification_signature(request)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
let secret = self
|
let connector_webhook_secrets = self
|
||||||
.get_webhook_source_verification_merchant_secret(
|
.get_webhook_source_verification_merchant_secret(
|
||||||
db,
|
db,
|
||||||
merchant_account,
|
merchant_account,
|
||||||
@ -186,11 +201,11 @@ pub trait IncomingWebhook: ConnectorCommon + Sync {
|
|||||||
.get_webhook_source_verification_message(
|
.get_webhook_source_verification_message(
|
||||||
request,
|
request,
|
||||||
&merchant_account.merchant_id,
|
&merchant_account.merchant_id,
|
||||||
&secret,
|
&connector_webhook_secrets.secret,
|
||||||
)
|
)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;
|
||||||
algorithm
|
algorithm
|
||||||
.verify_signature(&secret, &signature, &message)
|
.verify_signature(&connector_webhook_secrets.secret, &signature, &message)
|
||||||
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
.change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2370,6 +2370,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The public key id is to invoke third party sdk",
|
"description": "The public key id is to invoke third party sdk",
|
||||||
"nullable": true
|
"nullable": true
|
||||||
|
},
|
||||||
|
"connector_merchant_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The connector merchant id",
|
||||||
|
"nullable": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -6815,12 +6820,17 @@
|
|||||||
"MerchantConnectorWebhookDetails": {
|
"MerchantConnectorWebhookDetails": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"merchant_secret"
|
"merchant_secret",
|
||||||
|
"additional_secret"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"merchant_secret": {
|
"merchant_secret": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "12345678900987654321"
|
"example": "12345678900987654321"
|
||||||
|
},
|
||||||
|
"additional_secret": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "12345678900987654321"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user