Skip to main content
Glama
string.rs4.36 kB
use std::{ borrow::Cow, fmt, ops::Deref, str::FromStr, }; use serde::{ Deserialize, Serialize, }; /// A display/debug redacting [`String`]. /// /// The [`SensitiveString`] type is wrapper around the standard `String` type, except that it will /// not emit its value in its [`std::fmt::Display`] and [`std::fmt::Debug`] implementations. This /// should be suitable to use when handling passwords, credentials, tokens, etc. as any /// logging/tracing/debugging should redact it actual value and prevent accidental leaking of /// sensitive data. /// /// When serialized, the value is preserved for internal use (config loading, DB connections). /// Redaction for HTTP endpoints is handled by a custom serializer at the boundary. #[derive(Clone, Default, Deserialize, Serialize, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct SensitiveString(String); impl Deref for SensitiveString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } impl fmt::Debug for SensitiveString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("...") } } impl fmt::Display for SensitiveString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("...") } } impl From<String> for SensitiveString { /// Converts a `String` into a [`SensitiveString`]. fn from(value: String) -> Self { Self(value) } } impl From<&String> for SensitiveString { /// Converts a `&String` into a [`SensitiveString`]. /// /// This clones `value` and returns the clone. fn from(value: &String) -> Self { Self(value.clone()) } } impl From<&mut str> for SensitiveString { /// Converts a `&mut str` into a [`SensitiveString`]. /// /// The result is allocated on the heap. fn from(value: &mut str) -> Self { Self(value.to_owned()) } } impl From<&str> for SensitiveString { /// Converts a `&str` into a [`String`]. /// /// The result is allocated on the heap. fn from(value: &str) -> Self { Self(value.to_owned()) } } impl From<Box<str>> for SensitiveString { /// Converts the given boxed `str` slice to a [`SensitiveString`]. /// /// It is notable that the `str` slice is owned. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use si_std::SensitiveString; /// let s1: String = String::from("hello world"); /// let s2: Box<str> = s1.into_boxed_str(); /// let s3: SensitiveString = SensitiveString::from(s2); /// /// assert_eq!("hello world", *s3); /// ``` fn from(value: Box<str>) -> Self { Self(value.into_string()) } } impl<'a> From<Cow<'a, str>> for SensitiveString { /// Converts a clone-on-write string to an owned instance of [`SensitiveString`]. /// /// This extracts the owned string, and clones the string if it is not already owned. /// /// # Examples /// /// ``` /// # use si_std::SensitiveString; /// use std::borrow::Cow; /// // If the string is not owned /// let cow: Cow<str> = Cow::Borrowed("eggplant"); /// // It will allocate on the heap and copy the string. /// let owned: SensitiveString = SensitiveString::from(cow); /// assert_eq!(&owned[..], "eggplant"); /// ``` fn from(value: Cow<'a, str>) -> Self { Self(value.into_owned()) } } impl From<SensitiveString> for String { /// Converts a [`SensitiveString`] into a `String.` fn from(value: SensitiveString) -> Self { value.0 } } impl FromStr for SensitiveString { type Err = std::convert::Infallible; fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Self::from(s)) } } #[cfg(test)] mod tests { use super::*; #[test] fn serialize() { let s = SensitiveString::from("secret"); // This will be a JSON string, meaning it includes quotes let serialized = serde_json::to_string(&s).expect("failed to serialize"); assert_eq!(r#""secret""#, serialized); } #[test] fn deserialize() { // This will be a JSON string, meaning it includes quotes let raw = r#""secret""#; let s: SensitiveString = serde_json::from_str(raw).expect("failed to deserialize"); assert_eq!("secret", s.deref()); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server