#![cfg(feature = "encryption")]
use std::sync::Arc;
use armdb::armour::Db;
use armdb::{CollectionMeta, Config, NoHook, RapiraCodec, TtlHook, TxConfig, TypedMap};
use armour_core::GetType;
use rapira::Rapira;
type Id = [u8; 8];
fn id(n: u64) -> Id {
n.to_be_bytes()
}
#[derive(Clone, Debug, PartialEq, Eq, GetType, Rapira)]
struct Secret {
text: String,
}
impl CollectionMeta for Secret {
type SelfId = Id;
const NAME: &'static str = "secrets";
}
const DATA_KEY: [u8; 32] = [0x11; 32];
fn open_secrets(db: &Arc<Db>) -> Arc<TypedMap<Id, Secret, RapiraCodec, TtlHook<Secret, NoHook>>> {
let mut cfg = Config::test();
cfg.encryption_key = Some(DATA_KEY);
db.open_typed_map::<Secret, RapiraCodec, _>(cfg, NoHook, &[])
.unwrap()
}
#[test]
fn tx_encrypted_collection_requires_an_encrypted_log() {
let dir = tempfile::tempdir().unwrap();
let db = Arc::new(Db::open_with_tx_config(dir.path(), TxConfig::default()).unwrap());
let secrets = open_secrets(&db);
let err = db
.tx()
.put(
&secrets,
&id(1),
&Secret {
text: "hello".into(),
},
)
.unwrap()
.commit()
.unwrap_err();
assert!(matches!(err, armdb::DbError::Config(_)), "{err}");
assert!(secrets.get(&id(1)).is_none(), "nothing was written");
}
const LOG_KEY: [u8; 32] = [0x22; 32];
#[test]
fn the_builder_carries_the_log_key_into_the_transaction_log() {
let dir = tempfile::tempdir().unwrap();
let db = Arc::new(
Db::builder(dir.path())
.for_tests()
.tx_config(TxConfig {
log_encryption_key: Some(LOG_KEY),
..TxConfig::default()
})
.open()
.unwrap(),
);
let secrets = open_secrets(&db);
db.tx()
.put(
&secrets,
&id(2),
&Secret {
text: "world".into(),
},
)
.unwrap()
.commit()
.expect("an encrypted participant commits once the log has a key");
assert_eq!(
secrets.get(&id(2)).map(|s| s.text.clone()),
Some("world".to_string())
);
}