use super::join;
use azure_core::http::headers::{AsHeaders, HeaderName, HeaderValue};
use serde::Serialize;
#[cfg(test)]
use std::collections::HashMap;
use std::{
convert::Infallible,
fmt,
iter::{once, Once},
};
pub const SANITIZE_BODY_ID: &str = "AZSDK3430";
pub const SANITIZE_BODY_ETAG: &str = "AZSDK3490";
pub const SANITIZE_BODY_NAME: &str = "AZSDK3493";
pub const DEFAULT_SANITIZERS_TO_REMOVE: &[&str; 2] = &[
SANITIZE_BODY_ID, SANITIZE_BODY_ETAG, ];
pub const DEFAULT_SANITIZED_VALUE: &str = "Sanitized";
pub trait Sanitizer: AsHeaders + fmt::Debug + Serialize {}
macro_rules! impl_sanitizer {
($name:ident) => {
impl Sanitizer for $name {}
impl AsHeaders for $name {
type Error = Infallible;
type Iter = Once<(HeaderName, HeaderValue)>;
fn as_headers(&self) -> Result<Self::Iter, Self::Error> {
Ok(once((
super::ABSTRACTION_IDENTIFIER,
HeaderValue::from_static(stringify!($name)),
)))
}
}
};
($($name:ident),+ $(,)?) => {
$(impl_sanitizer!($name);)*
};
}
#[derive(Clone, Debug, Default, Serialize)]
pub struct ApplyCondition {
#[serde(rename = "UriRegex")]
pub uri_regex: String,
}
impl_sanitizer!(BodyKeySanitizer, BodyRegexSanitizer, BodyStringSanitizer);
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BodyKeySanitizer {
pub json_path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regex: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group_for_replace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
#[test]
fn test_body_key_sanitizer_as_headers() {
let sut = BodyKeySanitizer {
json_path: String::from("$.values"),
..Default::default()
};
let actual = sut.as_headers().expect("expect headers");
let expected: HashMap<HeaderName, HeaderValue> = HashMap::from_iter(vec![(
"x-abstraction-identifier".into(),
"BodyKeySanitizer".into(),
)]);
assert!(actual.eq(expected.into_iter()));
}
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BodyRegexSanitizer {
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regex: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group_for_replace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
#[test]
fn test_body_regex_sanitizer_as_headers() {
let sut = BodyRegexSanitizer::default();
let actual = sut.as_headers().expect("expect headers");
let expected: HashMap<HeaderName, HeaderValue> = HashMap::from_iter(vec![(
"x-abstraction-identifier".into(),
"BodyRegexSanitizer".into(),
)]);
assert!(actual.eq(expected.into_iter()));
}
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BodyStringSanitizer {
pub target: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
impl_sanitizer!(GeneralRegexSanitizer, GeneralStringSanitizer);
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GeneralRegexSanitizer {
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regex: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group_for_replace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GeneralStringSanitizer {
pub target: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
impl_sanitizer!(HeaderRegexSanitizer, HeaderStringSanitizer);
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct HeaderRegexSanitizer {
pub key: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regex: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group_for_replace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct HeaderStringSanitizer {
pub key: String,
pub target: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
impl_sanitizer!(OAuthResponseSanitizer);
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct OAuthResponseSanitizer;
#[derive(Clone, Copy, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum RegexEntryValues {
Body,
Header,
Uri,
}
impl_sanitizer!(RegexEntrySanitizer);
#[derive(Clone, Debug, Serialize)]
pub struct RegexEntrySanitizer {
pub target: RegexEntryValues,
pub regex: String,
}
impl_sanitizer!(RemoveHeaderSanitizer);
#[derive(Clone, Debug, Serialize)]
pub struct RemoveHeaderSanitizer {
#[serde(serialize_with = "join")]
pub headers_for_removal: Vec<&'static str>,
}
impl_sanitizer!(
UriRegexSanitizer,
UriStringSanitizer,
UriSubscriptionIdSanitizer,
);
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UriRegexSanitizer {
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub regex: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub group_for_replace: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UriStringSanitizer {
pub target: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<ApplyCondition>,
}
#[derive(Clone, Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UriSubscriptionIdSanitizer {
pub value: Option<String>,
pub condition: Option<ApplyCondition>,
}