#![no_std]
#![forbid(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
#![doc(html_root_url = "https://docs.rs/secrecy/0.6.0")]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
mod boxed;
#[cfg(feature = "bytes")]
mod bytes;
#[cfg(feature = "alloc")]
mod string;
#[cfg(feature = "alloc")]
mod vec;
#[cfg(feature = "alloc")]
pub use self::{boxed::SecretBox, string::SecretString, vec::SecretVec};
#[cfg(feature = "bytes")]
pub use self::bytes::SecretBytesMut;
use core::fmt::{self, Debug};
#[cfg(feature = "serde")]
use serde::{de, ser, Deserialize, Serialize};
use zeroize::Zeroize;
pub struct Secret<S>
where
S: Zeroize,
{
inner_secret: S,
}
impl<S> Secret<S>
where
S: Zeroize,
{
pub fn new(secret: S) -> Self {
Secret {
inner_secret: secret,
}
}
}
impl<S> ExposeSecret<S> for Secret<S>
where
S: Zeroize,
{
fn expose_secret(&self) -> &S {
&self.inner_secret
}
}
impl<S> Clone for Secret<S>
where
S: CloneableSecret,
{
fn clone(&self) -> Self {
Secret {
inner_secret: self.inner_secret.clone(),
}
}
}
impl<S> Debug for Secret<S>
where
S: Zeroize + DebugSecret,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Secret({})", S::debug_secret())
}
}
impl<S> Drop for Secret<S>
where
S: Zeroize,
{
fn drop(&mut self) {
self.inner_secret.zeroize();
}
}
pub trait CloneableSecret: Clone + Zeroize {}
macro_rules! impl_cloneable_secret_for_array {
($($size:expr),+) => {
$(
impl<T: Clone + Zeroize> CloneableSecret for [T; $size] {}
)+
};
}
impl_cloneable_secret_for_array!(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
);
pub trait ExposeSecret<S> {
fn expose_secret(&self) -> &S;
}
pub trait DebugSecret {
fn debug_secret() -> &'static str {
"[REDACTED]"
}
}
macro_rules! impl_debug_secret_for_array {
($($size:expr),+) => {
$(
impl<T: Debug> DebugSecret for [T; $size] {}
)+
};
}
impl_debug_secret_for_array!(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
);
#[cfg(feature = "serde")]
pub trait SerializableSecret: Serialize {}
#[cfg(feature = "serde")]
impl<'de, T> Deserialize<'de> for Secret<T>
where
T: Zeroize + Clone + DebugSecret + de::DeserializeOwned + Sized,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
T::deserialize(deserializer).map(Secret::new)
}
}
#[cfg(feature = "serde")]
impl<T> Serialize for Secret<T>
where
T: Zeroize + DebugSecret + Serialize + Sized,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
self.expose_secret().serialize(serializer)
}
}