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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
//! This defines data types related to the configuration for sensitive
//! information handling.
use tracing::error;
use serde::{Deserialize, Serialize};
use utilities::crypto::error::CryptoError;
use zeroize::{Zeroize, ZeroizeOnDrop};
/// The [`SensitiveInfoConfig`] type is used to configure how we handle
/// sensitive information (cryptographic keys, passwords, etc.) when using
/// `Display` and `Debug`.
#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)]
pub struct SensitiveInfoConfig {
/// A boolean indicating whether sensitive information should be redacted.
/// If set to true, the sensitive information will be redacted (hidden
/// or masked).
/// If set to false, the sensitive information will not
/// be redacted.
redact_sensitive_info: bool,
}
/// Conversion from `Vec<u8>` to [`SensitiveInfoConfig`]
impl TryFrom<Vec<u8>> for SensitiveInfoConfig {
type Error = CryptoError;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
let config: SensitiveInfoConfig =
bincode::deserialize(&bytes).map_err(|_| CryptoError::ConversionError)?;
Ok(config)
}
}
/// Conversion from [`SensitiveInfoConfig`] to `Vec<u8>`
impl TryFrom<SensitiveInfoConfig> for Vec<u8> {
type Error = CryptoError;
fn try_from(config: SensitiveInfoConfig) -> Result<Self, Self::Error> {
let encoded: Vec<u8> =
bincode::serialize(&config).map_err(|_| CryptoError::ConversionError)?;
Ok(encoded)
}
}
impl SensitiveInfoConfig {
/// Tis is the label used to redact sensitive information in the library
/// output
const REDACTED_INFO_LABEL: &'static str = "***REDACTED***";
/// Constructor for [`SensitiveInfoConfig`] type.
/// The default is to redact sensitive information in the output.
// pub fn new() -> Self {
// Self {redact_sensitive_info: true}
// }
/// Constructs a new instance of the type [`SensitiveInfoConfig`]
///
/// # Arguments
///
/// * `redact_sensitive_info` - A boolean indicating whether to redact
/// sensitive information.
/// - When set to true, any sensitive
/// information handled by instances using
/// this configuration will be redacted
/// (hidden or masked).
/// - When set to false, the sensitive
/// information will not be redacted.
///
/// # Returns
///
/// * Returns a new instance of [`SensitiveInfoConfig`], initialized with
/// the provided `redact_sensitive_info` flag.
///
/// # Example
///
/// ```rust
/// use lock_keeper::infrastructure::sensitive_info::SensitiveInfoConfig;
/// let redact_sensitive_info = true;
/// let config = SensitiveInfoConfig::new(redact_sensitive_info);
/// ```
pub fn new(redact_sensitive_info: bool) -> Self {
Self {
redact_sensitive_info,
}
}
/// Returns a label that is used in place of sensitive information.
pub fn redacted_label(self) -> String {
SensitiveInfoConfig::REDACTED_INFO_LABEL.to_string()
}
/// Redact sensitive information.
pub fn redact(&mut self) {
self.redact_sensitive_info = true;
}
/// Unredact sensitive information.
pub fn unredact(&mut self) {
self.redact_sensitive_info = false;
}
/// Returns the status of the sensitive information redaction.
pub fn is_redacted(&self) -> bool {
self.redact_sensitive_info
}
}
/// Checks if sensitive information is properly redacted in Debug and Display
/// outputs.
///
/// This function takes a generic `sensitive_info` object and a `config` object
/// which provides the redaction configuration.
///
/// The `sensitive_info` object should implement the `Debug` and `Display`
/// traits so that it can be properly formatted for output.
///
/// The function checks if the redaction is correctly applied based on the
/// configuration and the build type (Release or Debug).
///
/// # Arguments
///
/// * `sensitive_info` - A reference to an object of any type that implements
/// `Debug` and `Display`.
/// * `config` - A reference to a [`SensitiveInfoConfig`] object which provides
/// the redaction configuration.
///
/// # Returns
///
/// * `Ok(())` - If the sensitive information is correctly redacted in both
/// Debug and Display outputs.
/// * `Err(CryptoError::SensitiveInfoCheckFailed)` - If the sensitive
/// information is not correctly redacted.
///
/// # Panics
///
/// This function does not panic. However, the caller should handle the [`Err`]
/// result appropriately.
pub fn sensitive_info_check<T: std::fmt::Debug + std::fmt::Display>(
sensitive_info: &T,
config: &SensitiveInfoConfig,
) -> Result<(), CryptoError> {
// create formatted strings for Debug and Display traits
let debug_format_sensitive_info = format!("{:?}", sensitive_info);
let display_format_sensitive_info = format!("{}", sensitive_info);
// should_be_redacted...
// if this is a Release build OR if the redacted config flag is set to true
let should_be_redacted = !cfg!(debug_assertions) || (config.is_redacted());
// check if output contains the redacted tag
let is_debug_redacted = debug_format_sensitive_info.contains(&config.clone().redacted_label());
let is_display_redacted =
display_format_sensitive_info.contains(&config.clone().redacted_label());
// check if the redacted tag is applied correctly for Debug and Display traits.
if is_debug_redacted != should_be_redacted {
error!(
"Unexpected debug output: {}",
if should_be_redacted {
"Found UN-REDACTED info!!!"
} else {
"Found REDACTED info."
}
);
return Err(CryptoError::SensitiveInfoCheckFailed);
}
if is_display_redacted != should_be_redacted {
error!(
"Unexpected display output: {}",
if should_be_redacted {
"Found UN-REDACTED info!!!"
} else {
"Found REDACTED info."
}
);
return Err(CryptoError::SensitiveInfoCheckFailed);
}
Ok(())
}