extern crate alloc;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use core::convert::Infallible;
use core::str::FromStr;
use core::{any, fmt};
use zeroize::{Zeroize, ZeroizeOnDrop};
use super::{CloneableSecret, ExposeSecret, ExposeSecretMut};
#[cfg(feature = "serde-serialize")]
use super::SerializableSecret;
pub struct SecretBox<S: Zeroize + ?Sized> {
inner_secret: Box<S>,
}
impl<S: Zeroize + ?Sized> Zeroize for SecretBox<S> {
fn zeroize(&mut self) {
self.inner_secret.as_mut().zeroize();
}
}
impl<S: Zeroize + ?Sized> Drop for SecretBox<S> {
fn drop(&mut self) {
self.zeroize();
}
}
impl<S: Zeroize + ?Sized> ZeroizeOnDrop for SecretBox<S> {}
impl<S: Zeroize + ?Sized> From<Box<S>> for SecretBox<S> {
fn from(source: Box<S>) -> Self {
Self::new(source)
}
}
impl<S: Zeroize + ?Sized> SecretBox<S> {
pub fn new(boxed_secret: Box<S>) -> Self {
Self {
inner_secret: boxed_secret,
}
}
}
impl<S: Zeroize + Default> SecretBox<S> {
pub fn init_with_mut(ctr: impl FnOnce(&mut S)) -> Self {
let mut secret = Self::default();
ctr(secret.inner_secret.as_mut());
secret
}
}
impl<S: Zeroize + Clone> SecretBox<S> {
pub fn init_with(ctr: impl FnOnce() -> S) -> Self {
let mut data = ctr();
let secret = Self {
inner_secret: Box::new(data.clone()),
};
data.zeroize();
secret
}
pub fn try_init_with<E>(ctr: impl FnOnce() -> Result<S, E>) -> Result<Self, E> {
let mut data = ctr()?;
let secret = Self {
inner_secret: Box::new(data.clone()),
};
data.zeroize();
Ok(secret)
}
}
impl<S: Zeroize + Default> Default for SecretBox<S> {
fn default() -> Self {
Self {
inner_secret: Box::<S>::default(),
}
}
}
impl<S: Zeroize + ?Sized> fmt::Debug for SecretBox<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "SecretBox<{}>([REDACTED])", any::type_name::<S>())
}
}
impl<S: CloneableSecret> Clone for SecretBox<S> {
fn clone(&self) -> Self {
SecretBox {
inner_secret: self.inner_secret.clone(),
}
}
}
impl<S: Zeroize + ?Sized> ExposeSecret<S> for SecretBox<S> {
fn expose_secret(&self) -> &S {
self.inner_secret.as_ref()
}
}
impl<S: Zeroize + ?Sized> ExposeSecretMut<S> for SecretBox<S> {
fn expose_secret_mut(&mut self) -> &mut S {
self.inner_secret.as_mut()
}
}
pub type SecretString = SecretBox<str>;
impl From<String> for SecretString {
fn from(s: String) -> Self {
Self::from(s.into_boxed_str())
}
}
impl<'a> From<&'a str> for SecretString {
fn from(s: &'a str) -> Self {
Self::from(String::from(s))
}
}
impl FromStr for SecretString {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::from(s))
}
}
impl Clone for SecretString {
fn clone(&self) -> Self {
SecretBox {
inner_secret: self.inner_secret.clone(),
}
}
}
impl Default for SecretString {
fn default() -> Self {
String::default().into()
}
}
pub type SecretSlice<S> = SecretBox<[S]>;
impl<S> From<Vec<S>> for SecretSlice<S>
where
S: Zeroize,
[S]: Zeroize,
{
fn from(vec: Vec<S>) -> Self {
Self::from(vec.into_boxed_slice())
}
}
impl<S> Clone for SecretSlice<S>
where
S: CloneableSecret + Zeroize,
[S]: Zeroize,
{
fn clone(&self) -> Self {
SecretBox {
inner_secret: Vec::from(&*self.inner_secret).into_boxed_slice(),
}
}
}
impl<S> Default for SecretSlice<S>
where
S: Zeroize,
[S]: Zeroize,
{
fn default() -> Self {
Vec::<S>::new().into()
}
}
impl<S: Clone + Zeroize + 'static> From<SecretBox<S>> for crate::Dynamic<S> {
fn from(sb: SecretBox<S>) -> Self {
crate::Dynamic::new(sb.inner_secret.as_ref().clone())
}
}
impl From<crate::Dynamic<String>> for SecretBox<String> {
fn from(d: crate::Dynamic<String>) -> Self {
let val = <crate::Dynamic<String> as crate::RevealSecret>::expose_secret(&d).clone();
SecretBox::new(Box::new(val))
}
}
impl From<crate::Dynamic<String>> for SecretString {
fn from(d: crate::Dynamic<String>) -> Self {
let val = <crate::Dynamic<String> as crate::RevealSecret>::expose_secret(&d).clone();
SecretString::from(val)
}
}
impl<S: Clone + Zeroize + 'static> From<crate::Dynamic<Vec<S>>> for SecretBox<Vec<S>> {
fn from(d: crate::Dynamic<Vec<S>>) -> Self {
let val = <crate::Dynamic<Vec<S>> as crate::RevealSecret>::expose_secret(&d).clone();
SecretBox::new(Box::new(val))
}
}
impl From<SecretString> for crate::Dynamic<String> {
fn from(sb: SecretString) -> Self {
let val = String::from(sb.inner_secret.as_ref());
crate::Dynamic::new(val)
}
}
#[cfg(feature = "serde-deserialize")]
impl<'de, T> serde::Deserialize<'de> for SecretBox<T>
where
T: Zeroize + Clone + serde::de::DeserializeOwned + Sized,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Self::try_init_with(|| T::deserialize(deserializer))
}
}
#[cfg(feature = "serde-deserialize")]
impl<'de> serde::Deserialize<'de> for SecretString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
String::deserialize(deserializer).map(Into::into)
}
}
#[cfg(feature = "serde-serialize")]
impl<T> serde::Serialize for SecretBox<T>
where
T: Zeroize + SerializableSecret + serde::Serialize + Sized,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner_secret.as_ref().serialize(serializer)
}
}
#[deprecated(since = "0.8.0", note = "Use `SecretBox` instead (mirrors secrecy >=0.9)")]
pub type Secret<S> = SecretBox<S>;