secure_gate/encoding/extensions/
base64.rs

1use ::base64 as base64_crate;
2
3use base64_crate::engine::general_purpose::URL_SAFE_NO_PAD;
4
5use base64_crate::Engine;
6
7// ========================================
8// Consuming (into_) methods on RNG types
9// ========================================
10
11#[cfg(feature = "rand")]
12impl crate::DynamicRandom {
13    /// Consume self and return the random bytes as a validated base64 string.
14    ///
15    /// The raw bytes are zeroized immediately after encoding.
16    pub fn into_base64(self) -> crate::encoding::base64::Base64String {
17        let encoded = URL_SAFE_NO_PAD.encode(self.expose_secret());
18        crate::encoding::base64::Base64String::new_unchecked(encoded)
19    }
20}
21
22#[cfg(feature = "rand")]
23impl<const N: usize> crate::FixedRandom<N> {
24    /// Consume self and return the random bytes as a validated base64 string.
25    ///
26    /// The raw bytes are zeroized immediately after encoding.
27    pub fn into_base64(self) -> crate::encoding::base64::Base64String {
28        let encoded = URL_SAFE_NO_PAD.encode(self.expose_secret());
29        crate::encoding::base64::Base64String::new_unchecked(encoded)
30    }
31}
32
33// ========================================
34// Borrowing (to_) methods on RNG types
35// ========================================
36
37#[cfg(feature = "rand")]
38impl<const N: usize> crate::FixedRandom<N> {
39    /// Borrow and encode the random bytes as a validated base64 string (allocates).
40    ///
41    /// The original secret remains intact and usable.
42    pub fn to_base64(&self) -> crate::encoding::base64::Base64String {
43        let encoded = URL_SAFE_NO_PAD.encode(self.expose_secret());
44        crate::encoding::base64::Base64String::new_unchecked(encoded)
45    }
46}
47
48#[cfg(feature = "rand")]
49impl crate::DynamicRandom {
50    /// Borrow and encode the random bytes as a validated base64 string (allocates).
51    ///
52    /// The original secret remains intact and usable.
53    pub fn to_base64(&self) -> crate::encoding::base64::Base64String {
54        let encoded = URL_SAFE_NO_PAD.encode(self.expose_secret());
55        crate::encoding::base64::Base64String::new_unchecked(encoded)
56    }
57}
58
59// ========================================
60// View types and their implementations
61// ========================================
62
63/// View struct for exposed base64 strings, allowing decoding without direct access.
64pub struct Base64StringView<'a>(pub(crate) &'a String);
65
66impl<'a> Base64StringView<'a> {
67    /// Decode the validated base64 string into raw bytes (allocates).
68    pub fn to_bytes(&self) -> Vec<u8> {
69        URL_SAFE_NO_PAD
70            .decode(self.0.as_str())
71            .expect("Base64String is always valid")
72    }
73}
74
75impl<'a> core::ops::Deref for Base64StringView<'a> {
76    type Target = str;
77    fn deref(&self) -> &Self::Target {
78        self.0.as_str()
79    }
80}
81
82impl<'a> core::fmt::Debug for Base64StringView<'a> {
83    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84        f.write_str("[REDACTED]")
85    }
86}
87
88impl<'a> core::fmt::Display for Base64StringView<'a> {
89    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
90        f.write_str(self.0)
91    }
92}
93
94impl<'a> core::cmp::PartialEq<&str> for Base64StringView<'a> {
95    fn eq(&self, other: &&str) -> bool {
96        self.0 == *other
97    }
98}
99
100// ========================================
101// expose_secret → view implementations
102// ========================================
103
104impl crate::encoding::base64::Base64String {
105    pub fn expose_secret(&self) -> Base64StringView<'_> {
106        Base64StringView(self.0.expose_secret())
107    }
108}
109
110// ========================================
111// Consuming decode (into_bytes) for secure zeroization
112// ========================================
113
114impl crate::encoding::base64::Base64String {
115    /// Decode the validated base64 string into raw bytes, consuming and zeroizing the wrapper.
116    pub fn into_bytes(self) -> Vec<u8> {
117        URL_SAFE_NO_PAD
118            .decode(self.expose_secret().0.as_str())
119            .expect("Base64String is always valid")
120    }
121}