use std::fmt;
use std::ops::Deref;
use std::str::FromStr;
#[cfg(feature = "proptest")]
use proptest::prelude::{Arbitrary, BoxedStrategy, Strategy};
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SensitiveUrl(pub Url);
impl SensitiveUrl {
pub fn into_redacted(mut self) -> Url {
if self.0.password().is_some() {
self.0.set_password(Some("<redacted>")).unwrap();
}
self.0
}
pub fn to_string_unredacted(&self) -> String {
self.0.to_string()
}
}
impl fmt::Display for SensitiveUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.clone().into_redacted().fmt(f)
}
}
impl fmt::Debug for SensitiveUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.clone().into_redacted().fmt(f)
}
}
impl FromStr for SensitiveUrl {
type Err = url::ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(Url::from_str(s)?))
}
}
impl Deref for SensitiveUrl {
type Target = Url;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(feature = "proptest")]
impl Arbitrary for SensitiveUrl {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
proptest::sample::select(vec![
SensitiveUrl::from_str("http://user:pass@example.com").unwrap(),
SensitiveUrl::from_str("http://user@example.com").unwrap(),
SensitiveUrl::from_str("http://example.com").unwrap(),
])
.boxed()
}
}