redact_crypto/
storage.rs

1//! The storage module covers all aspects of CRUD operations on Redact data-types.
2//! It allows for retrieving data entries stored in a Redact database. These data entries
3//! can be either unencrypted bytes, encrypted bytes, or a reference pointing to another entry.
4//!
5//! Read operations allow for retrieval of data based on type information and the data's path.
6//!
7
8pub mod gcs;
9pub mod mongodb;
10pub mod redact;
11pub mod selfstore;
12
13use crate::{CryptoError, Entry, StorableType};
14use ::mongodb::bson::Document;
15use async_trait::async_trait;
16use serde::{Deserialize, Serialize};
17
18pub trait HasIndex {
19    type Index;
20
21    fn get_index() -> Option<Self::Index>;
22}
23
24#[derive(Serialize, Deserialize, Debug, Clone)]
25pub enum TypeStorer {
26    Indexed(IndexedTypeStorer),
27    NonIndexed(NonIndexedTypeStorer),
28}
29
30#[async_trait]
31impl Storer for TypeStorer {
32    async fn get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError> {
33        match self {
34            TypeStorer::NonIndexed(ts) => ts.get(path).await,
35            TypeStorer::Indexed(ts) => ts.get(path).await,
36        }
37    }
38
39    async fn create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError> {
40        match self {
41            TypeStorer::NonIndexed(ts) => ts.create(value).await,
42            TypeStorer::Indexed(ts) => ts.create(value).await,
43        }
44    }
45}
46
47#[derive(Serialize, Deserialize, Debug, Clone)]
48pub enum IndexedTypeStorer {
49    Redact(redact::RedactStorer),
50    Mongo(mongodb::MongoStorer),
51    Mock(tests::MockIndexedStorer),
52}
53
54#[derive(Serialize, Deserialize, Debug, Clone)]
55pub enum NonIndexedTypeStorer {
56    SelfStore(selfstore::SelfStorer),
57    GoogleCloud(gcs::GoogleCloudStorer),
58    Mock(tests::MockStorer),
59}
60
61impl From<IndexedTypeStorer> for TypeStorer {
62    fn from(its: IndexedTypeStorer) -> Self {
63        TypeStorer::Indexed(its)
64    }
65}
66
67impl From<NonIndexedTypeStorer> for TypeStorer {
68    fn from(nits: NonIndexedTypeStorer) -> Self {
69        TypeStorer::NonIndexed(nits)
70    }
71}
72
73#[async_trait]
74impl IndexedStorer for IndexedTypeStorer {
75    async fn get_indexed<T: StorableType>(
76        &self,
77        path: &str,
78        index: &Option<Document>,
79    ) -> Result<Entry<T>, CryptoError> {
80        match self {
81            IndexedTypeStorer::Redact(rs) => rs.get_indexed(path, index).await,
82            IndexedTypeStorer::Mongo(ms) => ms.get_indexed(path, index).await,
83            IndexedTypeStorer::Mock(ms) => ms.get_indexed(path, index).await,
84        }
85    }
86
87    async fn list<T: StorableType>(
88        &self,
89        path: &str,
90        skip: u64,
91        page_size: i64,
92    ) -> Result<Vec<Entry<T>>, CryptoError> {
93        match self {
94            IndexedTypeStorer::Redact(rs) => rs.list(path, skip, page_size).await,
95            IndexedTypeStorer::Mongo(ms) => ms.list(path, skip, page_size).await,
96            IndexedTypeStorer::Mock(ms) => ms.list(path, skip, page_size).await,
97        }
98    }
99
100    async fn list_indexed<T: StorableType>(
101        &self,
102        path: &str,
103        skip: u64,
104        page_size: i64,
105        index: &Option<Document>,
106    ) -> Result<Vec<Entry<T>>, CryptoError> {
107        match self {
108            IndexedTypeStorer::Redact(rs) => rs.list_indexed(path, skip, page_size, index).await,
109            IndexedTypeStorer::Mongo(ms) => ms.list_indexed(path, skip, page_size, index).await,
110            IndexedTypeStorer::Mock(ms) => ms.list_indexed(path, skip, page_size, index).await,
111        }
112    }
113}
114
115#[async_trait]
116impl Storer for IndexedTypeStorer {
117    async fn get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError> {
118        match self {
119            IndexedTypeStorer::Redact(rs) => rs.get(path).await,
120            IndexedTypeStorer::Mongo(ms) => ms.get(path).await,
121            IndexedTypeStorer::Mock(ms) => ms.get(path).await,
122        }
123    }
124
125    async fn create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError> {
126        match self {
127            IndexedTypeStorer::Redact(rs) => rs.create(value).await,
128            IndexedTypeStorer::Mongo(ms) => ms.create(value).await,
129            IndexedTypeStorer::Mock(ms) => ms.create(value).await,
130        }
131    }
132}
133
134#[async_trait]
135impl Storer for NonIndexedTypeStorer {
136    async fn get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError> {
137        match self {
138            NonIndexedTypeStorer::GoogleCloud(gcs) => gcs.get(path).await,
139            NonIndexedTypeStorer::Mock(ms) => ms.get(path).await,
140            NonIndexedTypeStorer::SelfStore(ss) => ss.get(path).await,
141        }
142    }
143
144    async fn create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError> {
145        match self {
146            NonIndexedTypeStorer::GoogleCloud(gcs) => gcs.create(value).await,
147            NonIndexedTypeStorer::Mock(ms) => ms.create(value).await,
148            NonIndexedTypeStorer::SelfStore(ss) => ss.create(value).await,
149        }
150    }
151}
152
153/// The operations a storer of `Key` structs must be able to fulfill.
154#[async_trait]
155pub trait IndexedStorer: Send + Sync + Storer {
156    /// Like get, but doesn't enforce IntoIndex and allows providing a custom index doc
157    async fn get_indexed<T: StorableType>(
158        &self,
159        path: &str,
160        index: &Option<Document>,
161    ) -> Result<Entry<T>, CryptoError>;
162
163    /// Fetches a list of all the stored keys.
164    async fn list<T: StorableType>(
165        &self,
166        path: &str,
167        skip: u64,
168        page_size: i64,
169    ) -> Result<Vec<Entry<T>>, CryptoError> {
170        self.list_indexed::<T>(path, skip, page_size, &T::get_index())
171            .await
172    }
173
174    /// Like list, but doesn't enforce IntoIndex and allows providing a custom index doc
175    async fn list_indexed<T: StorableType>(
176        &self,
177        path: &str,
178        skip: u64,
179        page_size: i64,
180        index: &Option<Document>,
181    ) -> Result<Vec<Entry<T>>, CryptoError>;
182}
183
184/// The operations a storer of `Key` structs must be able to fulfill.
185#[async_trait]
186pub trait Storer: Send + Sync + Into<TypeStorer> + Clone {
187    /// Fetches the instance of the `Key` with the given name.
188    async fn get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError>;
189
190    /// Adds the given `Key` struct to the backing store.
191    async fn create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError>;
192}
193
194pub mod tests {
195    use super::IndexedStorer as IndexedStorerTrait;
196    use super::Storer as StorerTrait;
197    use crate::storage::NonIndexedTypeStorer;
198    use crate::{CryptoError, Entry, IndexedTypeStorer, StorableType, TypeStorer};
199    use async_trait::async_trait;
200    use mockall::predicate::*;
201    use mockall::*;
202    use mongodb::bson::Document;
203    use serde::{Deserialize, Serialize};
204
205    mock! {
206    pub IndexedStorer {
207        pub fn private_deserialize() -> Self;
208        pub fn private_serialize(&self) -> MockIndexedStorer;
209    pub fn private_get_indexed<T: StorableType>(&self, path: &str, index: &Option<Document>) -> Result<Entry<T>, CryptoError>;
210    pub fn private_list_indexed<T: StorableType>(&self, path: &str, skip: u64, page_size: i64, index: &Option<Document>) -> Result<Vec<Entry<T>>, CryptoError>;
211    pub fn private_get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError>;
212    pub fn private_list<T: StorableType>(&self, path: &str, skip: u64, page_size: i64) -> Result<Vec<Entry<T>>, CryptoError>;
213    pub fn private_create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError>;
214    }
215    }
216
217    mock! {
218    pub Storer {
219        pub fn private_deserialize() -> Self;
220        pub fn private_serialize(&self) -> MockIndexedStorer;
221    pub fn private_get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError>;
222    pub fn private_create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError>;
223    }
224    }
225
226    impl core::fmt::Debug for MockIndexedStorer {
227        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228            f.debug_struct("MockStorer").finish()
229        }
230    }
231
232    impl Clone for MockIndexedStorer {
233        fn clone(&self) -> Self {
234            unimplemented!()
235        }
236    }
237
238    impl core::fmt::Debug for MockStorer {
239        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240            f.debug_struct("MockIndexedStorer").finish()
241        }
242    }
243
244    impl Clone for MockStorer {
245        fn clone(&self) -> Self {
246            unimplemented!()
247        }
248    }
249
250    #[async_trait]
251    impl IndexedStorerTrait for MockIndexedStorer {
252        async fn get_indexed<T: StorableType>(
253            &self,
254            path: &str,
255            index: &Option<Document>,
256        ) -> Result<Entry<T>, CryptoError> {
257            self.private_get_indexed(path, index)
258        }
259        async fn list<T: StorableType>(
260            &self,
261            path: &str,
262            skip: u64,
263            page_size: i64,
264        ) -> Result<Vec<Entry<T>>, CryptoError> {
265            self.private_list(path, skip, page_size)
266        }
267        async fn list_indexed<T: StorableType>(
268            &self,
269            path: &str,
270            skip: u64,
271            page_size: i64,
272            index: &Option<Document>,
273        ) -> Result<Vec<Entry<T>>, CryptoError> {
274            self.private_list_indexed(path, skip, page_size, index)
275        }
276    }
277
278    #[async_trait]
279    impl StorerTrait for MockIndexedStorer {
280        async fn get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError> {
281            self.private_get(path)
282        }
283        async fn create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError> {
284            self.private_create(value)
285        }
286    }
287
288    #[async_trait]
289    impl StorerTrait for MockStorer {
290        async fn get<T: StorableType>(&self, path: &str) -> Result<Entry<T>, CryptoError> {
291            self.private_get(path)
292        }
293        async fn create<T: StorableType>(&self, value: Entry<T>) -> Result<Entry<T>, CryptoError> {
294            self.private_create(value)
295        }
296    }
297
298    impl Serialize for MockStorer {
299        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
300        where
301            S: serde::Serializer,
302        {
303            self.private_serialize().serialize(serializer)
304        }
305    }
306
307    impl<'de> Deserialize<'de> for MockStorer {
308        fn deserialize<D>(_: D) -> Result<Self, D::Error>
309        where
310            D: serde::Deserializer<'de>,
311        {
312            Ok(MockStorer::private_deserialize())
313        }
314    }
315
316    impl Serialize for MockIndexedStorer {
317        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
318        where
319            S: serde::Serializer,
320        {
321            self.private_serialize().serialize(serializer)
322        }
323    }
324
325    impl<'de> Deserialize<'de> for MockIndexedStorer {
326        fn deserialize<D>(_: D) -> Result<Self, D::Error>
327        where
328            D: serde::Deserializer<'de>,
329        {
330            Ok(MockIndexedStorer::private_deserialize())
331        }
332    }
333
334    impl From<MockIndexedStorer> for TypeStorer {
335        fn from(mis: MockIndexedStorer) -> Self {
336            TypeStorer::Indexed(IndexedTypeStorer::Mock(mis))
337        }
338    }
339
340    impl From<MockStorer> for TypeStorer {
341        fn from(mis: MockStorer) -> Self {
342            TypeStorer::NonIndexed(NonIndexedTypeStorer::Mock(mis))
343        }
344    }
345}