1use crate::{
2 Algorithm, ByteAlgorithm, ByteSource, CryptoError, Data, DataBuilder, HasByteSource, HasIndex,
3 Key, KeyBuilder, Storer, ToPublicAsymmetricByteAlgorithm, ToSecretAsymmetricByteAlgorithm,
4 ToSymmetricByteAlgorithm, TypeStorer,
5};
6use async_recursion::async_recursion;
7use async_trait::async_trait;
8use mongodb::bson::Document;
9use once_cell::sync::OnceCell;
10use serde::{Deserialize, Serialize};
11use std::convert::TryFrom;
12
13pub type EntryPath = String;
14
15#[derive(Serialize, Deserialize, Debug)]
16#[serde(bound = "T: StorableType")]
17pub struct Entry<T> {
18 pub path: EntryPath,
19 pub builder: TypeBuilder,
20 pub value: State,
21 #[serde(skip)]
22 resolved_value: OnceCell<T>,
23}
24
25pub trait StorableType:
26 HasByteSource
27 + HasBuilder
28 + HasIndex<Index = Document>
29 + Unpin
30 + Send
31 + std::fmt::Debug
32 + 'static
33{
34}
35
36impl<T: ToSymmetricByteAlgorithm + StorableType> Entry<T> {
37 pub async fn to_symmetric_byte_algorithm(
38 self,
39 nonce: Option<<T as ToSymmetricByteAlgorithm>::Nonce>,
40 ) -> Result<ByteAlgorithm, CryptoError> {
41 let (key, entry_path, state) = self.take_resolve_all().await?;
42 key.to_byte_algorithm(nonce, |key| async move {
43 match state {
44 State::Referenced { path, storer } => key.to_ref_entry(path, storer),
45 State::Sealed { algorithm, .. } => key.to_sealed_entry(entry_path, algorithm).await,
46 State::Unsealed { .. } => key.to_unsealed_entry(entry_path),
47 }
48 })
49 .await
50 }
51}
52
53impl<T: ToSecretAsymmetricByteAlgorithm + StorableType> Entry<T> {
54 pub async fn to_secret_asymmetric_byte_algorithm(
55 self,
56 public_key: Option<Entry<<T as ToSecretAsymmetricByteAlgorithm>::PublicKey>>,
57 nonce: Option<<T as ToSecretAsymmetricByteAlgorithm>::Nonce>,
58 ) -> Result<ByteAlgorithm, CryptoError> {
59 let (secret_key, entry_path, state) = self.take_resolve_all().await?;
60 secret_key
61 .to_byte_algorithm(public_key, nonce, |key| async move {
62 match state {
63 State::Referenced { path, storer } => key.to_ref_entry(path, storer),
64 State::Sealed { algorithm, .. } => {
65 key.to_sealed_entry(entry_path, algorithm).await
66 }
67 State::Unsealed { .. } => key.to_unsealed_entry(entry_path),
68 }
69 })
70 .await
71 }
72}
73
74impl<T: ToPublicAsymmetricByteAlgorithm + StorableType> Entry<T> {
75 pub async fn to_public_asymmetric_byte_algorithm(
76 self,
77 secret_key: Entry<<T as ToPublicAsymmetricByteAlgorithm>::SecretKey>,
78 nonce: Option<<T as ToPublicAsymmetricByteAlgorithm>::Nonce>,
79 ) -> Result<ByteAlgorithm, CryptoError> {
80 let (public_key, entry_path, state) = self.take_resolve_all().await?;
81 public_key
82 .to_byte_algorithm(secret_key, nonce, |key| async move {
83 match state {
84 State::Referenced { path, storer } => key.to_ref_entry(path, storer),
85 State::Sealed { algorithm, .. } => {
86 key.to_sealed_entry(entry_path, algorithm).await
87 }
88 State::Unsealed { .. } => key.to_unsealed_entry(entry_path),
89 }
90 })
91 .await
92 }
93}
94
95impl<T: StorableType> Entry<T> {
96 pub fn cast<U: StorableType>(self) -> Result<Entry<U>, CryptoError> {
97 let builder =
98 <U as HasBuilder>::Builder::try_from(TypeBuilderContainer(self.builder))?.into();
99 Ok(Entry::new(self.path, builder, self.value))
100 }
101
102 pub fn new(path: EntryPath, builder: TypeBuilder, value: State) -> Self {
103 Entry {
104 path,
105 builder,
106 value,
107 resolved_value: OnceCell::new(),
108 }
109 }
110
111 #[async_recursion]
112 pub async fn dereference(self) -> Result<Entry<T>, CryptoError> {
113 match self.value {
114 State::Referenced {
115 ref path,
116 ref storer,
117 } => {
118 let entry = storer.get::<T>(path).await?;
119 Ok(entry.dereference().await?)
120 }
121 _ => Ok(self),
122 }
123 }
124
125 #[async_recursion]
126 pub async fn take_resolve(mut self) -> Result<T, CryptoError> {
127 match self.resolved_value.take() {
128 None => match self.value {
129 State::Referenced {
130 ref path,
131 ref storer,
132 } => {
133 let entry = storer.get::<T>(path).await?;
134 Ok(entry.take_resolve().await?)
135 }
136 State::Sealed {
137 ref ciphertext,
138 ref algorithm,
139 } => {
140 let builder =
141 <T as HasBuilder>::Builder::try_from(TypeBuilderContainer(self.builder))?;
142 let plaintext = algorithm.unseal(ciphertext).await?;
143 builder.build(Some(plaintext.get()?))
144 }
145 State::Unsealed { bytes, .. } => {
146 let builder =
147 <T as HasBuilder>::Builder::try_from(TypeBuilderContainer(self.builder))?;
148 builder.build(Some(bytes.get()?))
149 }
150 },
151 Some(value) => Ok(value),
152 }
153 }
154
155 #[async_recursion]
156 pub async fn take_resolve_all(mut self) -> Result<(T, EntryPath, State), CryptoError> {
157 match self.resolved_value.take() {
158 None => match self.value {
159 State::Referenced {
160 ref path,
161 ref storer,
162 } => {
163 let entry = storer.get::<T>(path).await?;
164 entry.take_resolve_all().await
165 }
166 State::Sealed {
167 ref ciphertext,
168 ref algorithm,
169 } => {
170 let builder =
171 <T as HasBuilder>::Builder::try_from(TypeBuilderContainer(self.builder))?;
172 let plaintext = algorithm.unseal(ciphertext).await?;
173 Ok((
174 builder.build(Some(plaintext.get()?))?,
175 self.path,
176 self.value,
177 ))
178 }
179 State::Unsealed { ref bytes, .. } => {
180 let builder =
181 <T as HasBuilder>::Builder::try_from(TypeBuilderContainer(self.builder))?;
182 Ok((builder.build(Some(bytes.get()?))?, self.path, self.value))
183 }
184 },
185 Some(value) => Ok((value, self.path, self.value)),
186 }
187 }
188
189 pub async fn resolve(&self) -> Result<&T, CryptoError> {
190 match self.resolved_value.get() {
191 None => match self.value {
192 State::Referenced {
193 ref path,
194 ref storer,
195 } => {
196 let entry = storer.get::<T>(path).await?;
197 let value = entry.take_resolve().await?;
198 Ok(self.resolved_value.get_or_init(|| value))
199 }
200 State::Sealed {
201 ref ciphertext,
202 ref algorithm,
203 } => {
204 let builder =
205 <T as HasBuilder>::Builder::try_from(TypeBuilderContainer(self.builder))?;
206 let plaintext = algorithm.unseal(ciphertext).await?;
207 self.resolved_value
208 .get_or_try_init(|| builder.build(Some(plaintext.get()?)))
209 }
210 State::Unsealed { ref bytes, .. } => {
211 let builder =
212 <T as HasBuilder>::Builder::try_from(TypeBuilderContainer(self.builder))?;
213 self.resolved_value
214 .get_or_try_init(|| builder.build(Some(bytes.get()?)))
215 }
216 },
217 Some(value) => Ok(value),
218 }
219 }
220}
221
222#[derive(Serialize, Deserialize, Debug)]
223#[serde(tag = "t", content = "c")]
224pub enum State {
225 Referenced {
226 path: EntryPath,
227 storer: TypeStorer,
228 },
229 Sealed {
230 ciphertext: ByteSource,
231 algorithm: ByteAlgorithm,
232 },
233 Unsealed {
234 bytes: ByteSource,
235 },
236}
237
238pub trait HasBuilder {
239 type Builder: Builder<Output = Self>;
240
241 fn builder(&self) -> Self::Builder;
242}
243
244pub trait Builder:
245 TryFrom<TypeBuilderContainer, Error = CryptoError> + Into<TypeBuilder> + Send
246{
247 type Output;
248
249 fn build(&self, bytes: Option<&[u8]>) -> Result<Self::Output, CryptoError>;
250}
251
252#[async_trait]
253pub trait ToEntry: StorableType + Sized {
254 fn to_ref_entry<S: Storer + Into<TypeStorer>>(
255 self,
256 path: EntryPath,
257 storer: S,
258 ) -> Result<Entry<Self>, CryptoError> {
259 Ok(Entry::new(
260 path.clone(),
261 self.builder().into(),
262 State::Referenced {
263 storer: storer.into(),
264 path,
265 },
266 ))
267 }
268
269 async fn to_sealed_entry(
270 self,
271 path: EntryPath,
272 algorithm: ByteAlgorithm,
273 ) -> Result<Entry<Self>, CryptoError> {
274 let byte_source = self.byte_source();
275 let ciphertext = algorithm.seal(&byte_source).await?;
276 Ok(Entry::new(
277 path,
278 self.builder().into(),
279 State::Sealed {
280 ciphertext,
281 algorithm,
282 },
283 ))
284 }
285
286 fn to_unsealed_entry(self, path: EntryPath) -> Result<Entry<Self>, CryptoError> {
287 Ok(Entry::new(
288 path,
289 self.builder().into(),
290 State::Unsealed {
291 bytes: self.byte_source(),
292 },
293 ))
294 }
295}
296
297impl<T: StorableType> ToEntry for T {}
298
299#[derive(Serialize, Deserialize, Copy, Clone)]
301pub struct TypeBuilderContainer(pub TypeBuilder);
302
303#[derive(Debug)]
304pub enum Type {
305 Key(Key),
306 Data(Data),
307}
308
309impl StorableType for Type {}
310
311impl HasIndex for Type {
312 type Index = Document;
313
314 fn get_index() -> Option<Self::Index> {
315 None
316 }
317}
318
319impl HasBuilder for Type {
320 type Builder = TypeBuilder;
321
322 fn builder(&self) -> Self::Builder {
323 match self {
324 Self::Key(kb) => TypeBuilder::Key(kb.builder()),
325 Self::Data(db) => TypeBuilder::Data(db.builder()),
326 }
327 }
328}
329
330impl HasByteSource for Type {
331 fn byte_source(&self) -> ByteSource {
332 match self {
333 Self::Key(kb) => kb.byte_source(),
334 Self::Data(db) => db.byte_source(),
335 }
336 }
337}
338
339#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
340#[serde(tag = "t", content = "c")]
341pub enum TypeBuilder {
342 Data(DataBuilder),
343 Key(KeyBuilder),
344}
345
346impl TryFrom<TypeBuilderContainer> for TypeBuilder {
347 type Error = CryptoError;
348
349 fn try_from(builder: TypeBuilderContainer) -> Result<Self, Self::Error> {
350 Ok(builder.0)
351 }
352}
353
354impl Builder for TypeBuilder {
355 type Output = Type;
356
357 fn build(&self, bytes: Option<&[u8]>) -> Result<Self::Output, CryptoError> {
358 match self {
359 Self::Key(k) => Ok(Type::Key(k.build(bytes)?)),
360 Self::Data(d) => Ok(Type::Data(d.build(bytes)?)),
361 }
362 }
363}
364
365#[cfg(test)]
366mod tests {
367 use super::{Type, TypeBuilder, TypeBuilderContainer};
368 use crate::{
369 BoolDataBuilder, Builder, Data, DataBuilder, HasBuilder, HasIndex, StringDataBuilder,
370 };
371 use std::convert::TryInto;
372
373 #[test]
374 fn test_type_to_index() {
375 assert_eq!(Type::get_index(), None);
376 }
377
378 #[test]
379 fn test_type_to_builder() {
380 let t = Type::Data(Data::String("hello, world!".to_owned()));
381 let tb = t.builder();
382 match tb {
383 TypeBuilder::Data(DataBuilder::String(_)) => (),
384 _ => panic!("Outputted builder should have been a StringDataBuilder"),
385 }
386 }
387
388 #[test]
389 fn test_typebuilder_build_valid() {
390 let tb = TypeBuilder::Data(DataBuilder::String(StringDataBuilder {}));
391 let t = tb.build(Some(b"hello, world!")).unwrap();
392 match t {
393 Type::Data(Data::String(s)) => assert_eq!(s, "hello, world!".to_owned()),
394 _ => panic!("Extracted type should have been a data string-type"),
395 }
396 }
397
398 #[test]
399 #[should_panic]
400 fn test_typebuilder_build_invalid() {
401 let tb = TypeBuilder::Data(DataBuilder::Bool(BoolDataBuilder {}));
402 tb.build(Some(b"not a bool")).unwrap();
403 }
404
405 #[test]
406 fn test_typebuilder_from_typebuildercontainer_valid() {
407 let tbc = TypeBuilderContainer(TypeBuilder::Data(DataBuilder::Bool(BoolDataBuilder {})));
408 let tb: TypeBuilder = tbc.try_into().unwrap();
409 let t = tb.build(Some(b"true")).unwrap();
410 match t {
411 Type::Data(Data::Bool(b)) => assert_eq!(b, true),
412 _ => panic!("Extracted data should have been a bool-type"),
413 }
414 }
415}