mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 12:15:40 +08:00
fix(webhooks): mask custom outgoing webhook headers in profile response (#6798)
Co-authored-by: Chikke Srujan <chikke.srujan@Chikke-Srujan-N7WRTY72X7.local> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -11,7 +11,7 @@ use common_utils::{
|
|||||||
use common_utils::{crypto::OptionalEncryptableName, ext_traits::ValueExt};
|
use common_utils::{crypto::OptionalEncryptableName, ext_traits::ValueExt};
|
||||||
#[cfg(feature = "v2")]
|
#[cfg(feature = "v2")]
|
||||||
use masking::ExposeInterface;
|
use masking::ExposeInterface;
|
||||||
use masking::Secret;
|
use masking::{PeekInterface, Secret};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url;
|
use url;
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
@ -2198,7 +2198,7 @@ pub struct ProfileResponse {
|
|||||||
|
|
||||||
/// These key-value pairs are sent as additional custom headers in the outgoing webhook request.
|
/// These key-value pairs are sent as additional custom headers in the outgoing webhook request.
|
||||||
#[schema(value_type = Option<Object>, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)]
|
#[schema(value_type = Option<Object>, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)]
|
||||||
pub outgoing_webhook_custom_http_headers: Option<HashMap<String, Secret<String>>>,
|
pub outgoing_webhook_custom_http_headers: Option<MaskedHeaders>,
|
||||||
|
|
||||||
/// Merchant Connector id to be stored for tax_calculator connector
|
/// Merchant Connector id to be stored for tax_calculator connector
|
||||||
#[schema(value_type = Option<String>)]
|
#[schema(value_type = Option<String>)]
|
||||||
@ -2317,7 +2317,7 @@ pub struct ProfileResponse {
|
|||||||
|
|
||||||
/// These key-value pairs are sent as additional custom headers in the outgoing webhook request.
|
/// These key-value pairs are sent as additional custom headers in the outgoing webhook request.
|
||||||
#[schema(value_type = Option<Object>, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)]
|
#[schema(value_type = Option<Object>, example = r#"{ "key1": "value-1", "key2": "value-2" }"#)]
|
||||||
pub outgoing_webhook_custom_http_headers: Option<HashMap<String, Secret<String>>>,
|
pub outgoing_webhook_custom_http_headers: Option<MaskedHeaders>,
|
||||||
|
|
||||||
/// Will be used to determine the time till which your payment will be active once the payment session starts
|
/// Will be used to determine the time till which your payment will be active once the payment session starts
|
||||||
#[schema(value_type = Option<u32>, example = 900)]
|
#[schema(value_type = Option<u32>, example = 900)]
|
||||||
@ -2616,6 +2616,43 @@ pub struct BusinessPayoutLinkConfig {
|
|||||||
pub payout_test_mode: Option<bool>,
|
pub payout_test_mode: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, serde::Serialize)]
|
||||||
|
pub struct MaskedHeaders(HashMap<String, String>);
|
||||||
|
|
||||||
|
impl MaskedHeaders {
|
||||||
|
fn mask_value(value: &str) -> String {
|
||||||
|
let value_len = value.len();
|
||||||
|
|
||||||
|
let masked_value = if value_len <= 4 {
|
||||||
|
"*".repeat(value_len)
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
.char_indices()
|
||||||
|
.map(|(index, ch)| {
|
||||||
|
if index < 2 || index >= value_len - 2 {
|
||||||
|
// Show the first two and last two characters, mask the rest with '*'
|
||||||
|
ch
|
||||||
|
} else {
|
||||||
|
// Mask the remaining characters
|
||||||
|
'*'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<String>()
|
||||||
|
};
|
||||||
|
|
||||||
|
masked_value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_headers(headers: HashMap<String, Secret<String>>) -> Self {
|
||||||
|
let masked_headers = headers
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, value)| (key, Self::mask_value(value.peek())))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Self(masked_headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
|
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
|
||||||
pub struct BusinessGenericLinkConfig {
|
pub struct BusinessGenericLinkConfig {
|
||||||
/// Custom domain name to be used for hosting the link
|
/// Custom domain name to be used for hosting the link
|
||||||
|
|||||||
@ -4,12 +4,12 @@ use std::collections::HashMap;
|
|||||||
pub use api_models::admin;
|
pub use api_models::admin;
|
||||||
pub use api_models::{
|
pub use api_models::{
|
||||||
admin::{
|
admin::{
|
||||||
MerchantAccountCreate, MerchantAccountDeleteResponse, MerchantAccountResponse,
|
MaskedHeaders, MerchantAccountCreate, MerchantAccountDeleteResponse,
|
||||||
MerchantAccountUpdate, MerchantConnectorCreate, MerchantConnectorDeleteResponse,
|
MerchantAccountResponse, MerchantAccountUpdate, MerchantConnectorCreate,
|
||||||
MerchantConnectorDetails, MerchantConnectorDetailsWrap, MerchantConnectorId,
|
MerchantConnectorDeleteResponse, MerchantConnectorDetails, MerchantConnectorDetailsWrap,
|
||||||
MerchantConnectorResponse, MerchantDetails, MerchantId, PaymentMethodsEnabled,
|
MerchantConnectorId, MerchantConnectorResponse, MerchantDetails, MerchantId,
|
||||||
ProfileCreate, ProfileResponse, ProfileUpdate, ToggleAllKVRequest, ToggleAllKVResponse,
|
PaymentMethodsEnabled, ProfileCreate, ProfileResponse, ProfileUpdate, ToggleAllKVRequest,
|
||||||
ToggleKVRequest, ToggleKVResponse, WebhookDetails,
|
ToggleAllKVResponse, ToggleKVRequest, ToggleKVResponse, WebhookDetails,
|
||||||
},
|
},
|
||||||
organization::{
|
organization::{
|
||||||
OrganizationCreateRequest, OrganizationId, OrganizationResponse, OrganizationUpdateRequest,
|
OrganizationCreateRequest, OrganizationId, OrganizationResponse, OrganizationUpdateRequest,
|
||||||
@ -131,6 +131,8 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
.transpose()?;
|
.transpose()?;
|
||||||
|
let masked_outgoing_webhook_custom_http_headers =
|
||||||
|
outgoing_webhook_custom_http_headers.map(MaskedHeaders::from_headers);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
merchant_id: item.merchant_id,
|
merchant_id: item.merchant_id,
|
||||||
@ -168,7 +170,7 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
|
|||||||
always_collect_shipping_details_from_wallet_connector: item
|
always_collect_shipping_details_from_wallet_connector: item
|
||||||
.always_collect_shipping_details_from_wallet_connector,
|
.always_collect_shipping_details_from_wallet_connector,
|
||||||
is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
|
is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
|
||||||
outgoing_webhook_custom_http_headers,
|
outgoing_webhook_custom_http_headers: masked_outgoing_webhook_custom_http_headers,
|
||||||
tax_connector_id: item.tax_connector_id,
|
tax_connector_id: item.tax_connector_id,
|
||||||
is_tax_connector_enabled: item.is_tax_connector_enabled,
|
is_tax_connector_enabled: item.is_tax_connector_enabled,
|
||||||
is_network_tokenization_enabled: item.is_network_tokenization_enabled,
|
is_network_tokenization_enabled: item.is_network_tokenization_enabled,
|
||||||
@ -204,6 +206,8 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
|
|||||||
.map(admin::OrderFulfillmentTime::try_new)
|
.map(admin::OrderFulfillmentTime::try_new)
|
||||||
.transpose()
|
.transpose()
|
||||||
.change_context(errors::ParsingError::IntegerOverflow)?;
|
.change_context(errors::ParsingError::IntegerOverflow)?;
|
||||||
|
let masked_outgoing_webhook_custom_http_headers =
|
||||||
|
outgoing_webhook_custom_http_headers.map(MaskedHeaders::from_headers);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
merchant_id: item.merchant_id,
|
merchant_id: item.merchant_id,
|
||||||
@ -236,7 +240,7 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
|
|||||||
always_collect_billing_details_from_wallet_connector: item
|
always_collect_billing_details_from_wallet_connector: item
|
||||||
.always_collect_billing_details_from_wallet_connector,
|
.always_collect_billing_details_from_wallet_connector,
|
||||||
is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
|
is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
|
||||||
outgoing_webhook_custom_http_headers,
|
outgoing_webhook_custom_http_headers: masked_outgoing_webhook_custom_http_headers,
|
||||||
order_fulfillment_time,
|
order_fulfillment_time,
|
||||||
order_fulfillment_time_origin: item.order_fulfillment_time_origin,
|
order_fulfillment_time_origin: item.order_fulfillment_time_origin,
|
||||||
should_collect_cvv_during_payment: item.should_collect_cvv_during_payment,
|
should_collect_cvv_during_payment: item.should_collect_cvv_during_payment,
|
||||||
|
|||||||
Reference in New Issue
Block a user