use crate::{
crypto::{attrs::flattened_protected_attributes::FlattenedAttrName, SealError},
encrypted_table::TableAttributes,
traits::TableAttribute,
};
use cipherstash_client::{
credentials::{service_credentials::ServiceToken, Credentials},
encryption::Encryption,
zerokms::EncryptedRecord,
};
use itertools::Itertools;
use super::FlattenedProtectedAttributes;
pub(crate) struct FlattenedEncryptedAttributes {
attrs: Vec<EncryptedRecord>,
}
impl FlattenedEncryptedAttributes {
pub(crate) fn with_capacity(capacity: usize) -> Self {
Self {
attrs: Vec::with_capacity(capacity),
}
}
pub(crate) fn is_empty(&self) -> bool {
self.attrs.is_empty()
}
pub(crate) fn len(&self) -> usize {
self.attrs.len()
}
pub(crate) async fn decrypt_all(
self,
cipher: &Encryption<impl Credentials<Token = ServiceToken>>,
) -> Result<FlattenedProtectedAttributes, SealError> {
let descriptors = self
.attrs
.iter()
.map(|record| record.descriptor.clone())
.collect_vec();
cipher
.decrypt(self.attrs.into_iter())
.await
.map(|records| records.into_iter().zip(descriptors.into_iter()).collect())
.map_err(SealError::from)
}
pub(crate) fn denormalize(self) -> Result<TableAttributes, SealError> {
self.attrs
.into_iter()
.map(|record| {
record
.to_vec()
.map(|data| (FlattenedAttrName::parse(&record.descriptor), data))
.map_err(|_| SealError::AssertionFailed("Decryption failed".to_string()))
})
.fold_ok(
Ok(TableAttributes::new()),
|acc, (flattened_attr_name, bytes)| {
let (name, subkey) = flattened_attr_name.into_parts();
if let Some(subkey) = subkey {
acc.and_then(|mut acc| acc.try_insert_map(name, subkey, bytes).map(|_| acc))
} else {
acc.map(|mut acc| {
acc.insert(name, bytes);
acc
})
}
},
)?
}
pub(crate) fn try_extend(
&mut self,
attributes: TableAttributes,
prefix: String,
) -> Result<(), SealError> {
for (name, value) in attributes.into_iter() {
match value {
TableAttribute::Map(map) => {
for (subkey, value) in map.into_iter() {
let attr_key = FlattenedAttrName::new(Some(prefix.clone()), name.clone())
.with_subkey(subkey);
let record = value.as_encrypted_record(&attr_key.descriptor())?;
self.attrs.push(record);
}
}
TableAttribute::Bytes(_) => {
let attr_key = FlattenedAttrName::new(Some(prefix.clone()), name);
let record = value.as_encrypted_record(&attr_key.descriptor())?;
self.attrs.push(record);
}
_ => {
Err(SealError::AssertionFailed(
"Unsupported attribute type".to_string(),
))?;
}
}
}
Ok(())
}
}
impl From<Vec<EncryptedRecord>> for FlattenedEncryptedAttributes {
fn from(attrs: Vec<EncryptedRecord>) -> Self {
Self { attrs }
}
}
impl FromIterator<EncryptedRecord> for FlattenedEncryptedAttributes {
fn from_iter<T: IntoIterator<Item = EncryptedRecord>>(iter: T) -> Self {
Self {
attrs: iter.into_iter().collect(),
}
}
}