diff --git a/secrecy/src/lib.rs b/secrecy/src/lib.rs index 2f1866fd..74105deb 100644 --- a/secrecy/src/lib.rs +++ b/secrecy/src/lib.rs @@ -38,6 +38,7 @@ extern crate alloc; use alloc::{boxed::Box, string::String, vec::Vec}; use core::convert::Infallible; +use core::mem; use core::str::FromStr; use core::{ any, @@ -207,6 +208,28 @@ where } } +impl TryFrom> for SecretBox<[S; N]> +where + S: Zeroize, + [S]: Zeroize, +{ + type Error = SecretSlice; + + fn try_from(mut value: SecretSlice) -> Result { + let mut temp: Box<[S]> = Box::new([]); + mem::swap(&mut temp, &mut value.inner_secret); + + match TryInto::>::try_into(temp) { + Ok(inner_secret) => Ok(SecretBox { inner_secret }), + Err(mut old) => { + // Put the secret back + mem::swap(&mut old, &mut value.inner_secret); + Err(value) + } + } + } +} + /// Secret string type. /// /// This is a type alias for [`SecretBox`] which supports some helpful trait impls. @@ -337,7 +360,8 @@ where #[cfg(test)] mod tests { - use crate::{ExposeSecret, SecretString}; + use crate::{ExposeSecret, SecretBox, SecretSlice, SecretString}; + use alloc::boxed::Box; use core::str::FromStr; #[test] @@ -345,4 +369,21 @@ mod tests { let secret = SecretString::from_str("test").unwrap(); assert_eq!(secret.expose_secret(), "test"); } + + #[test] + fn secret_slice_to_array() { + let secret = SecretSlice::new(Box::new([5, 6, 7, 8, 9u8])); + assert_eq!(secret.expose_secret(), &[5, 6, 7, 8, 9]); + + // Failure when the slice is a different size from the array. + let res = TryInto::>::try_into(secret); + assert!(res.is_err()); + // We get the original secret back + let secret = res.unwrap_err(); + assert_eq!(secret.expose_secret(), &[5, 6, 7, 8, 9]); + + // Success when the array is the same size as the slice + let secret_array: SecretBox<[u8; 5]> = secret.try_into().unwrap(); + assert_eq!(secret_array.expose_secret(), &[5, 6, 7, 8, 9]); + } }