1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
//! Common record representation inside of vaults.
//!
//! A record is a collection of data stored in a vault. It's
//! structured into a publicly known, unencrypted header and
//! a securely saved, encrypted body.
//!
//! While the `lockchain-server` never has access to the body data,
//! the header is stored and cached for make search requests faster.
//!
//! **No secret information should ever be stored in the header**
use chrono::{DateTime, Local};
use serde::{Serialize, Deserialize};
use std::collections::BTreeMap;
use crate::traits::{AutoEncoder, Body};
/// An enum that wraps around all possible data types to store
/// as the value of a vault record.
///
/// This doesn't include metadata attached to a field, just the
/// data representation itself (i.e. text, number or sub data-tree)
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub enum Payload {
/// A simple (variable) text
Text(String),
/// A boolean (true, false)
Boolean(bool),
/// A 64bit, signed number
Number(i64),
/// A tree of String names, mapped to payloads
BTreeMap(BTreeMap<String, Payload>),
/// A list of various payloads
List(Vec<Payload>),
}
/// The public header of a record
///
/// A header consists of always-available fields that
/// are hard-defined in the lockchain file format as well
/// as custom fields that can be declared by each application
/// specifically.
///
/// You should never rely on the presence of custom fields as
/// older version of the software might not support them or
/// know about them!
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Header {
/// The name of this record
pub name: String,
/// The primary category the record is in
pub category: String,
/// A collection of custom tags
pub tags: Vec<String>,
/// Custom fields to query by. **Do not store secure data in fields!
pub fields: BTreeMap<String, Payload>,
/// Timestamp when the record was created
pub date_created: DateTime<Local>,
/// Timestamp when the record was last updated
pub date_updated: DateTime<Local>,
}
/// Represents a whole record in memory
///
/// The body field can be `None` if it hasn't been cached
/// yet. Calling `body()` will either resolve the data from disk
/// or still return `None` if the current setting doesn't support
/// body loading (such as the `lockchain-server` which has no
/// cryptocraphy subsystem)
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Record<T: Body> {
pub header: Header,
#[serde(bound(deserialize = "T: Body"))]
pub body: Option<T>,
}
impl<T: Body> Record<T> {
/// Create a new Record, generically for a backend in question
pub fn new(name: &str, category: &str, tags: Vec<&str>) -> Self {
Record {
header: Header {
name: name.to_owned(),
category: category.to_owned(),
tags: tags.into_iter().map(|s| s.to_owned()).collect(),
fields: BTreeMap::new(),
date_created: Local::now(),
date_updated: Local::now(),
},
body: None,
}
}
/// Attempt to set a key to a certain value
pub fn add_data(&mut self, key: &str, value: Payload) -> Option<()> {
(self.body.as_mut()?).set_field(key, value);
Some(())
}
/// Attempt to read out the value of a certain key
pub fn get_data(&self, key: &str) -> Option<&Payload> {
(self.body.as_ref()?).get_field(key)
}
}
impl<T: Body> AutoEncoder for Record<T> {}
#[derive(Serialize, Deserialize)]
pub struct EncryptedBody {
pub data: String,
}
impl Body for EncryptedBody {
fn get_field(&self, _: &str) -> Option<&Payload> {
None
}
fn set_field(&mut self, _: &str, _: Payload) -> Option<()> {
None
}
fn flatten(&mut self) -> Option<()> {
None
}
}
|