use std::{
convert::TryFrom,
fmt::{self, Debug},
hash::{Hash, Hasher},
};
use serde_json::{Map, Value};
use libcryptsetup_rs::SafeMemHandle;
use crate::stratis::{ErrorEnum, StratisError, StratisResult};
pub struct SizedKeyMemory {
mem: SafeMemHandle,
size: usize,
}
impl SizedKeyMemory {
pub fn new(mem: SafeMemHandle, size: usize) -> SizedKeyMemory {
SizedKeyMemory { mem, size }
}
}
unsafe impl Send for SizedKeyMemory {}
impl Debug for SizedKeyMemory {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.as_ref())
}
}
impl AsRef<[u8]> for SizedKeyMemory {
fn as_ref(&self) -> &[u8] {
&self.mem.as_ref()[..self.size]
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct EncryptionInfo {
pub key_description: Option<KeyDescription>,
pub clevis_info: Option<(String, Value)>,
}
impl EncryptionInfo {
pub fn is_encrypted(&self) -> bool {
self.key_description.is_some() || self.clevis_info.is_some()
}
}
impl Default for EncryptionInfo {
fn default() -> Self {
EncryptionInfo {
key_description: None,
clevis_info: None,
}
}
}
impl fmt::Display for EncryptionInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let key_desc_str = if let Some(ref kd) = self.key_description {
format!("key description: \"{}\"", kd.as_application_str())
} else {
"no key description".to_string()
};
if let Some((pin, config)) = &self.clevis_info {
write!(
f,
"{}, clevis pin: \"{}\", clevis configuration: \"{}\"",
key_desc_str, pin, config
)
} else {
write!(f, "{}, no Clevis information", key_desc_str)
}
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for EncryptionInfo {
fn hash<H: Hasher>(&self, state: &mut H) {
self.key_description.hash(state);
self.clevis_info.as_ref().map(|(pin, _)| pin).hash(state);
}
}
impl<'a> Into<Value> for &'a EncryptionInfo {
fn into(self) -> Value {
let mut json = Map::new();
if let Some(ref kd) = self.key_description {
json.insert(
"key_description".to_string(),
Value::from(kd.as_application_str()),
);
}
if let Some(ref info) = self.clevis_info {
json.insert("clevis_pin".to_string(), Value::from(info.0.to_owned()));
json.insert("clevis_config".to_string(), info.1.clone());
}
Value::from(json)
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub struct KeyDescription(String);
impl KeyDescription {
pub fn as_application_str(&self) -> &str {
&self.0
}
}
impl TryFrom<String> for KeyDescription {
type Error = StratisError;
fn try_from(s: String) -> StratisResult<KeyDescription> {
if s.contains(';') {
Err(StratisError::Engine(
ErrorEnum::Invalid,
format!("Key description {} contains a ';'", s),
))
} else {
Ok(KeyDescription(s))
}
}
}
impl<'a> TryFrom<&'a String> for KeyDescription {
type Error = StratisError;
fn try_from(s: &String) -> StratisResult<KeyDescription> {
KeyDescription::try_from(s.to_owned())
}
}