use std::collections::HashMap;
use crate::error::HexvaultError;
use crate::keys::PartitionKey;
use crate::stack::{self, Layer, LayerContext};
pub type CellId = String;
pub struct Payload {
pub data: Vec<u8>,
pub sealed_at: Layer,
}
pub struct Cell {
id: CellId,
payloads: HashMap<String, Payload>,
}
impl Cell {
pub fn new(id: CellId) -> Self {
Self {
id,
payloads: HashMap::new(),
}
}
pub fn id(&self) -> &str {
&self.id
}
pub fn store(
&mut self,
partition_key: &PartitionKey,
key: &str,
text: &[u8],
layer: Layer,
context: &LayerContext,
) -> Result<(), HexvaultError> {
let sealed = stack::seal(partition_key, &self.id, layer, context, text)?;
self.payloads.insert(
key.to_string(),
Payload {
data: sealed,
sealed_at: layer,
},
);
Ok(())
}
pub fn retrieve(
&self,
partition_key: &PartitionKey,
key: &str,
context: &LayerContext,
) -> Result<Vec<u8>, HexvaultError> {
let payload = self
.payloads
.get(key)
.ok_or_else(|| HexvaultError::CellNotFound(key.to_string()))?;
stack::peel(
partition_key,
&self.id,
payload.sealed_at,
context,
&payload.data,
)
}
pub fn remove(&mut self, key: &str) {
self.payloads.remove(key);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cell_isolation() {
use crate::keys::MasterKey;
let master = MasterKey::from_bytes([1u8; 32]);
let partition = crate::keys::derive_partition_key(&master, "p1").unwrap();
let mut cell_a = Cell::new("cell-a".to_string());
let mut cell_b = Cell::new("cell-b".to_string());
let context = LayerContext::default();
cell_a
.store(&partition, "secret", b"hello a", Layer::AtRest, &context)
.unwrap();
cell_b
.store(&partition, "secret", b"hello b", Layer::AtRest, &context)
.unwrap();
assert_eq!(
cell_a.retrieve(&partition, "secret", &context).unwrap(),
b"hello a"
);
assert_eq!(
cell_b.retrieve(&partition, "secret", &context).unwrap(),
b"hello b"
);
let sealed_a = cell_a.payloads.get("secret").unwrap();
assert!(stack::peel(
&partition,
"cell-b",
sealed_a.sealed_at,
&context,
&sealed_a.data
)
.is_err());
}
}