1use crate::vault::{
5 crypto_box::{BoxProvider, Decrypt, Encrypt, Key},
6 types::{
7 transactions::{DataTransaction, RevocationTransaction, SealedBlob, SealedTransaction},
8 utils::{BlobId, ChainId, RecordHint, RecordId, VaultId},
9 },
10};
11
12use runtime::memories::buffer::Buffer;
13use serde::{Deserialize, Serialize};
14use std::{collections::HashMap, convert::Infallible, fmt::Debug};
15use thiserror::Error as DeriveError;
16use zeroize::Zeroizing;
17
18use super::{crypto_box::DecryptError, types::transactions::Transaction};
19
20#[derive(DeriveError, Debug)]
21pub enum VaultError<TProvErr: Debug, TProcErr: Debug = Infallible> {
22 #[error("vault `{0:?}` does not exist")]
23 VaultNotFound(VaultId),
24
25 #[error("record error: `{0:?}`")]
26 Record(#[from] RecordError<TProvErr>),
27
28 #[error("procedure error `{0:?}`")]
29 Procedure(TProcErr),
30
31 #[error("Lock is poisoned")]
32 LockPoisoned,
33}
34
35#[derive(DeriveError, Debug)]
36pub enum RecordError<TProvErr: Debug> {
37 #[error("provider error: `{0:?}`")]
38 Provider(TProvErr),
39
40 #[error("decrypted content does not match expected format: {0}")]
41 CorruptedContent(String),
42
43 #[error("invalid key provided")]
44 InvalidKey,
45
46 #[error("no record with `{0:?}`")]
47 RecordNotFound(ChainId),
48
49 #[error("lock is poisoned")]
50 LockPoisoned,
51}
52
53#[derive(Deserialize, Serialize, Clone, Default)]
55pub struct DbView<P: BoxProvider> {
56 pub vaults: HashMap<VaultId, Vault<P>>,
58}
59
60#[derive(Deserialize, Serialize, Clone)]
62pub struct Vault<P: BoxProvider> {
63 key: Key<P>,
64 entries: HashMap<ChainId, Record>,
65}
66
67#[derive(Deserialize, Serialize, Clone)]
69pub struct Record {
70 id: ChainId,
72 data: SealedTransaction,
74 revoke: Option<SealedTransaction>,
76 blob: SealedBlob,
78}
79
80impl<P: BoxProvider> DbView<P> {
81 pub fn new() -> DbView<P> {
83 let vaults = HashMap::new();
84
85 Self { vaults }
86 }
87
88 pub fn init_vault(&mut self, key: &Key<P>, vid: VaultId) {
90 self.vaults.entry(vid).or_insert_with(|| Vault::init_vault(key));
91 }
92
93 pub fn write(
95 &mut self,
96 key: &Key<P>,
97 vid: VaultId,
98 rid: RecordId,
99 data: &[u8],
100 record_hint: RecordHint,
101 ) -> Result<(), RecordError<P::Error>> {
102 if !self.vaults.contains_key(&vid) {
103 self.init_vault(key, vid);
104 }
105
106 let vault = self.vaults.get_mut(&vid).expect("Vault was initiated");
107 vault.add_or_update_record(key, rid.0, data, record_hint)
108 }
109
110 pub fn list_hints_and_ids(&self, key: &Key<P>, vid: VaultId) -> Vec<(RecordId, RecordHint)> {
112 if let Some(vault) = self.vaults.get(&vid) {
113 vault.list_hints_and_ids(key)
114 } else {
115 vec![]
116 }
117 }
118
119 pub fn contains_vault(&self, vid: &VaultId) -> bool {
121 self.vaults.contains_key(vid)
122 }
123
124 pub fn contains_record(&self, vid: VaultId, rid: RecordId) -> bool {
126 if let Some(vault) = self.vaults.get(&vid) {
127 vault.contains_record(rid)
128 } else {
129 false
130 }
131 }
132
133 pub fn get_blob_id(&self, key: &Key<P>, vid: VaultId, rid: RecordId) -> Result<BlobId, VaultError<P::Error>> {
136 let vault = self.vaults.get(&vid).ok_or(VaultError::VaultNotFound(vid))?;
137 let blob_id = vault.get_blob_id(key, rid.0)?;
138 Ok(blob_id)
139 }
140
141 fn get_buffers<E, const N: usize>(
143 &self,
144 ids: [(Key<P>, VaultId, RecordId); N],
145 ) -> Result<[Buffer<u8>; N], VaultError<P::Error, E>>
146 where
147 E: Debug,
148 {
149 let mut buffers: Vec<Buffer<u8>> = Vec::with_capacity(N);
150
151 for (key, vid, rid) in ids {
152 let vault = self.vaults.get(&vid).ok_or(VaultError::VaultNotFound(vid))?;
153 let guard = vault.get_guard(&key, rid.0).map_err(VaultError::Record)?;
154
155 buffers.push(guard);
156 }
157
158 let buffers: [Buffer<u8>; N] = <[_; N]>::try_from(buffers).expect("buffers did not have exactly len N");
159
160 Ok(buffers)
161 }
162
163 pub fn get_guard<T, E, F>(
165 &self,
166 key: &Key<P>,
167 vid: VaultId,
168 rid: RecordId,
169 f: F,
170 ) -> Result<T, VaultError<P::Error, E>>
171 where
172 F: FnOnce(Buffer<u8>) -> Result<T, E>,
173 E: Debug,
174 {
175 let vault = self.vaults.get(&vid).ok_or(VaultError::VaultNotFound(vid))?;
176 let guard = vault.get_guard(key, rid.0).map_err(VaultError::Record)?;
177 f(guard).map_err(VaultError::Procedure)
178 }
179
180 pub fn get_guards<T, E, F, const N: usize>(
181 &self,
182 ids: [(Key<P>, VaultId, RecordId); N],
183 f: F,
184 ) -> Result<T, VaultError<P::Error, E>>
185 where
186 F: FnOnce([Buffer<u8>; N]) -> Result<T, E>,
187 E: Debug,
188 {
189 let buffers: [Buffer<u8>; N] = self.get_buffers(ids)?;
190 f(buffers).map_err(VaultError::Procedure)
191 }
192
193 pub fn exec_procedure<T, E, F, const N: usize>(
196 &mut self,
197 sources: [(Key<P>, VaultId, RecordId); N],
198 target_key: &Key<P>,
199 target_vid: VaultId,
200 target_rid: RecordId,
201 hint: RecordHint,
202 f: F,
203 ) -> Result<T, VaultError<P::Error, E>>
204 where
205 F: FnOnce([Buffer<u8>; N]) -> Result<(Zeroizing<Vec<u8>>, T), E>,
206 E: Debug,
207 {
208 let buffers: [Buffer<u8>; N] = self.get_buffers(sources)?;
209
210 let (data, result) = f(buffers).map_err(VaultError::Procedure)?;
211
212 self.write(target_key, target_vid, target_rid, &data, hint)
213 .map_err(VaultError::Record)?;
214
215 Ok(result)
216 }
217
218 pub fn revoke_record(&mut self, key: &Key<P>, vid: VaultId, rid: RecordId) -> Result<(), RecordError<P::Error>> {
220 if let Some(vault) = self.vaults.get_mut(&vid) {
221 vault.revoke(key, rid.0)?;
222 }
223 Ok(())
224 }
225
226 pub fn garbage_collect_vault(&mut self, key: &Key<P>, vid: VaultId) {
228 if let Some(vault) = self.vaults.get_mut(&vid) {
229 if &vault.key == key {
230 vault.garbage_collect();
231 }
232 }
233 }
234
235 pub fn clear(&mut self) {
237 self.vaults.clear();
238 }
239
240 pub fn list_vaults(&self) -> Vec<VaultId> {
242 self.vaults.keys().cloned().collect()
243 }
244
245 pub fn list_records(&self, vid: &VaultId) -> Vec<RecordId> {
247 self.vaults
248 .get(vid)
249 .map(|v| v.entries.keys().map(|&c| c.into()).collect())
250 .unwrap_or_default()
251 }
252
253 pub fn list_records_with_blob_id(
255 &self,
256 key: &Key<P>,
257 vid: VaultId,
258 ) -> Result<Vec<(RecordId, BlobId)>, VaultError<P::Error>> {
259 self.vaults
260 .get(&vid)
261 .ok_or(VaultError::VaultNotFound(vid))
262 .and_then(|v| v.list_entries(key).map_err(|e| e.into()))
263 }
264
265 pub fn export_all(&self) -> HashMap<VaultId, Vec<(RecordId, Record)>> {
267 self.vaults
268 .iter()
269 .map(|(vid, vault)| {
270 let entries = vault.entries.iter().map(|(&id, r)| (id.into(), r.clone())).collect();
271 (*vid, entries)
272 })
273 .collect()
274 }
275
276 pub fn export_records<I>(&self, vid: VaultId, records: I) -> Result<Vec<(RecordId, Record)>, VaultError<P::Error>>
281 where
282 I: IntoIterator<Item = RecordId>,
283 {
284 let vault = self.vaults.get(&vid).ok_or(VaultError::VaultNotFound(vid))?;
285 let list = records
286 .into_iter()
287 .filter_map(|rid| vault.export_record(&rid).map(|r| (rid, r)))
288 .collect();
289 Ok(list)
290 }
291
292 pub fn import_records(
295 &mut self,
296 old_key: &Key<P>,
297 new_key: &Key<P>,
298 vid: VaultId,
299 mut records: Vec<(RecordId, Record)>,
300 ) -> Result<(), RecordError<P::Error>> {
301 if !self.vaults.contains_key(&vid) {
302 self.init_vault(new_key, vid);
303 }
304 for (rid, record) in &mut records {
305 record
306 .update_meta(old_key, (*rid).into(), new_key, (*rid).into())
307 .unwrap();
308 }
309 let vault = self.vaults.get_mut(&vid).expect("Vault was initiated.");
310 vault.extend(new_key, records.into_iter().map(|(rid, r)| (rid.0, r)))
311 }
312}
313
314impl<P: BoxProvider> Vault<P> {
315 pub fn init_vault(key: &Key<P>) -> Vault<P> {
317 let entries = HashMap::new();
318
319 Self {
320 entries,
321 key: key.clone(),
322 }
323 }
324
325 pub fn add_or_update_record(
328 &mut self,
329 key: &Key<P>,
330 id: ChainId,
331 data: &[u8],
332 record_hint: RecordHint,
333 ) -> Result<(), RecordError<P::Error>> {
334 self.check_key(key)?;
335 let blob_id = BlobId::random::<P>().map_err(RecordError::Provider)?;
336 if let Some(entry) = self.entries.get_mut(&id) {
337 entry.update_data(key, id, data, blob_id)?
339 } else {
340 let entry = Record::new(key, id, blob_id, data, record_hint).map_err(RecordError::Provider)?;
341 self.entries.insert(id, entry);
342 }
343
344 Ok(())
345 }
346
347 pub fn extend<I>(&mut self, key: &Key<P>, entries: I) -> Result<(), RecordError<P::Error>>
350 where
351 I: IntoIterator<Item = (ChainId, Record)>,
352 {
353 self.check_key(key)?;
354 self.entries.extend(entries.into_iter());
355 Ok(())
356 }
357
358 pub fn export_record(&self, rid: &RecordId) -> Option<Record> {
361 self.entries.get(&rid.0).cloned()
362 }
363
364 pub(crate) fn list_hints_and_ids(&self, key: &Key<P>) -> Vec<(RecordId, RecordHint)> {
366 let mut buf: Vec<(RecordId, RecordHint)> = Vec::new();
367
368 if key == &self.key {
369 buf = self
370 .entries
371 .values()
372 .filter_map(|entry| entry.get_hint_and_id(key).ok())
373 .collect();
374 }
375
376 buf
377 }
378
379 fn list_entries(&self, key: &Key<P>) -> Result<Vec<(RecordId, BlobId)>, RecordError<P::Error>> {
381 let mut buf = Vec::new();
382 for (&id, record) in self.entries.iter() {
383 let blob_id = record.get_blob_id(key, id)?;
384 buf.push((id.into(), blob_id))
385 }
386 Ok(buf)
387 }
388
389 fn contains_record(&self, rid: RecordId) -> bool {
391 self.entries.values().any(|entry| entry.check_id(rid))
392 }
393
394 pub fn revoke(&mut self, key: &Key<P>, id: ChainId) -> Result<(), RecordError<P::Error>> {
396 self.check_key(key)?;
397 if let Some(entry) = self.entries.get_mut(&id) {
398 entry.revoke(key, id)?;
399 }
400 Ok(())
401 }
402
403 pub fn get_guard(&self, key: &Key<P>, id: ChainId) -> Result<Buffer<u8>, RecordError<P::Error>> {
405 self.check_key(key)?;
406 let entry = self.entries.get(&id).ok_or(RecordError::RecordNotFound(id))?;
407 entry.get_blob(key, id)
408 }
409
410 pub fn garbage_collect(&mut self) {
412 let garbage: Vec<ChainId> = self
414 .entries
415 .iter()
416 .filter(|(_, entry)| entry.revoke.is_some())
417 .map(|(c, _)| *c)
418 .collect();
419
420 garbage.iter().for_each(|c| {
422 self.entries.remove(c);
423 });
424 }
425
426 pub fn get_blob_id(&self, key: &Key<P>, id: ChainId) -> Result<BlobId, RecordError<P::Error>> {
428 self.check_key(key)?;
429 self.entries
430 .get(&id)
431 .ok_or(RecordError::RecordNotFound(id))
432 .and_then(|r| r.get_blob_id(key, id))
433 }
434
435 fn check_key(&self, key: &Key<P>) -> Result<(), RecordError<P::Error>> {
436 if key == &self.key {
437 Ok(())
438 } else {
439 Err(RecordError::InvalidKey)
440 }
441 }
442}
443
444impl Record {
445 pub fn new<P: BoxProvider>(
447 key: &Key<P>,
448 id: ChainId,
449 blob: BlobId,
450 data: &[u8],
451 hint: RecordHint,
452 ) -> Result<Record, P::Error> {
453 let len = data.len() as u64;
454 let dtx = DataTransaction::new(id, len, blob, hint);
455
456 let blob: SealedBlob = data.encrypt(key, blob)?;
457 let data = dtx.encrypt(key, id)?;
458
459 Ok(Record {
460 id,
461 data,
462 blob,
463 revoke: None,
464 })
465 }
466
467 fn get_transaction<P: BoxProvider>(&self, key: &Key<P>) -> Result<Transaction, RecordError<P::Error>> {
468 if self.revoke.is_none() {
470 self.data.decrypt(key, self.id).map_err(|err| match err {
472 DecryptError::Invalid => {
473 RecordError::CorruptedContent("Could not convert bytes into transaction structure".into())
474 }
475 DecryptError::Provider(e) => RecordError::Provider(e),
476 })
477 } else {
478 Err(RecordError::RecordNotFound(self.id))
479 }
480 }
481
482 fn get_hint_and_id<P: BoxProvider>(&self, key: &Key<P>) -> Result<(RecordId, RecordHint), RecordError<P::Error>> {
484 let tx = self.get_transaction(key)?;
485 let tx = tx.typed::<DataTransaction>().ok_or_else(|| {
486 RecordError::CorruptedContent("Could not type decrypted transaction as data-transaction".into())
487 })?;
488 let hint = tx.record_hint;
489 Ok((self.id.into(), hint))
490 }
491
492 fn check_id(&self, rid: RecordId) -> bool {
495 if self.revoke.is_none() {
496 rid.0 == self.id
497 } else {
498 false
499 }
500 }
501
502 fn get_blob<P: BoxProvider>(&self, key: &Key<P>, id: ChainId) -> Result<Buffer<u8>, RecordError<P::Error>> {
504 if self.id != id {
506 return Err(RecordError::RecordNotFound(id));
507 }
508
509 let tx = self.get_transaction(key)?;
510 let tx = tx.typed::<DataTransaction>().ok_or_else(|| {
511 RecordError::CorruptedContent("Could not type decrypted transaction as data-transaction".into())
512 })?;
513
514 let blob = SealedBlob::from(self.blob.as_ref())
515 .decrypt(key, tx.blob)
516 .expect("Unable to decrypt blob");
517
518 let guarded = Buffer::alloc(&blob, tx.len.u64() as usize);
519
520 Ok(guarded)
530 }
531
532 fn get_blob_id<P: BoxProvider>(&self, key: &Key<P>, id: ChainId) -> Result<BlobId, RecordError<P::Error>> {
534 if self.id != id {
536 return Err(RecordError::RecordNotFound(id));
537 }
538 let tx = self.get_transaction(key)?;
539 let tx = tx.typed::<DataTransaction>().ok_or_else(|| {
540 RecordError::CorruptedContent("Could not type decrypted transaction as data-transaction".into())
541 })?;
542 Ok(tx.blob)
543 }
544
545 fn update_data<P: BoxProvider>(
547 &mut self,
548 key: &Key<P>,
549 id: ChainId,
550 new_data: &[u8],
551 new_blob: BlobId,
552 ) -> Result<(), RecordError<P::Error>> {
553 if self.id != id {
555 return Err(RecordError::RecordNotFound(id));
556 }
557
558 let tx = self.get_transaction(key)?;
559 let tx = tx.typed::<DataTransaction>().ok_or_else(|| {
560 RecordError::CorruptedContent("Could not type decrypted transaction as data-transaction".into())
561 })?;
562
563 let blob: SealedBlob = new_data.encrypt(key, new_blob).map_err(RecordError::Provider)?;
565
566 let dtx = DataTransaction::new(tx.id, new_data.len() as u64, new_blob, tx.record_hint);
568 let data = dtx.encrypt(key, tx.id).map_err(RecordError::Provider)?;
569
570 self.blob = blob;
571 self.data = data;
572
573 Ok(())
574 }
575
576 pub fn update_meta<P: BoxProvider>(
578 &mut self,
579 old_key: &Key<P>,
580 old_id: ChainId,
581 new_key: &Key<P>,
582 new_id: ChainId,
583 ) -> Result<(), RecordError<P::Error>> {
584 if self.id != old_id {
586 return Err(RecordError::RecordNotFound(old_id));
587 }
588
589 let tx = self.get_transaction(old_key)?;
590 let typed_tx = tx.typed::<DataTransaction>().ok_or_else(|| {
591 RecordError::CorruptedContent("Could not type decrypted transaction as data-transaction".into())
592 })?;
593
594 let updated_blob = SealedBlob::from(self.blob.as_ref())
596 .decrypt(old_key, typed_tx.blob)
597 .map_err(|e| match e {
598 DecryptError::Provider(e) => RecordError::Provider(e),
599 DecryptError::Invalid => unreachable!("Vec<u8>: TryFrom<Vec<u8>> is infallible."),
600 })?
601 .encrypt(new_key, typed_tx.blob)
602 .map_err(RecordError::Provider)?;
603
604 let updated_data = DataTransaction::new(new_id, typed_tx.len, typed_tx.blob, typed_tx.record_hint)
606 .encrypt(new_key, new_id)
607 .map_err(RecordError::Provider)?;
608
609 self.blob = updated_blob;
610 self.data = updated_data;
611 self.id = new_id;
612
613 Ok(())
614 }
615
616 fn revoke<P: BoxProvider>(&mut self, key: &Key<P>, id: ChainId) -> Result<(), RecordError<P::Error>> {
618 if self.id != id {
620 return Err(RecordError::RecordNotFound(id));
621 }
622
623 if self.revoke.is_none() {
625 let revoke = RevocationTransaction::new(self.id)
626 .encrypt(key, self.id)
627 .map_err(RecordError::Provider)?;
628 self.revoke = Some(revoke);
629 }
630
631 Ok(())
632 }
633}