core_crypto_keystore/entities/
mod.rs1pub(crate) mod general;
2pub(crate) mod mls;
3
4pub use self::general::*;
5pub use self::mls::*;
6
7cfg_if::cfg_if! {
8 if #[cfg(feature = "proteus-keystore")] {
9 pub(crate) mod proteus;
10 pub use self::proteus::*;
11 }
12}
13
14mod platform {
15 cfg_if::cfg_if! {
16 if #[cfg(target_family = "wasm")] {
17 mod wasm;
18 pub use self::wasm::*;
19 } else {
20 mod generic;
21 pub use self::generic::*;
22 }
23 }
24}
25
26pub use self::platform::*;
27
28use crate::connection::DatabaseConnection;
29#[cfg(not(target_family = "wasm"))]
30use crate::sha256;
31use crate::{CryptoKeystoreError, CryptoKeystoreResult, MissingKeyErrorKind};
32#[cfg(target_family = "wasm")]
33use aes_gcm::Aes256Gcm;
34use serde::Deserialize;
35use serde::Serialize;
36
37#[derive(Debug, Clone, PartialEq, Eq, Default)]
38#[cfg_attr(target_family = "wasm", derive(serde::Serialize, serde::Deserialize))]
39#[repr(transparent)]
40pub struct StringEntityId<'a>(&'a [u8]);
41
42impl<'a> StringEntityId<'a> {
43 pub fn new(bytes: &'a [u8]) -> Self {
44 Self(bytes)
45 }
46
47 pub fn as_hex_string(&self) -> String {
48 hex::encode(self.0)
49 }
50
51 #[cfg(not(target_family = "wasm"))]
52 pub(crate) fn sha256(&self) -> String {
53 sha256(self.0)
54 }
55
56 pub fn to_bytes(&self) -> Vec<u8> {
57 self.0.into()
58 }
59
60 pub fn as_slice(&self) -> &[u8] {
61 self.0
62 }
63
64 pub fn try_as_str(&self) -> Result<&str, ::core::str::Utf8Error> {
65 std::str::from_utf8(self.0)
66 }
67}
68
69impl TryInto<String> for &StringEntityId<'_> {
70 type Error = CryptoKeystoreError;
71
72 fn try_into(self) -> CryptoKeystoreResult<String> {
73 Ok(String::from_utf8(self.0.into())?)
74 }
75}
76
77impl std::fmt::Display for StringEntityId<'_> {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 write!(f, "{}", self.as_hex_string())
80 }
81}
82
83impl<'a> From<&'a [u8]> for StringEntityId<'a> {
84 fn from(bytes: &'a [u8]) -> Self {
85 Self::new(bytes)
86 }
87}
88
89#[derive(Debug, Clone, Default)]
90pub struct EntityFindParams {
91 pub limit: Option<u32>,
92 pub offset: Option<u32>,
93 pub reverse: bool,
94}
95
96#[cfg(not(target_family = "wasm"))]
97impl EntityFindParams {
98 pub fn to_sql(&self) -> String {
99 use std::fmt::Write as _;
100 let mut query: String = "".into();
101 if let Some(offset) = self.offset {
102 let _ = write!(query, " OFFSET {offset}");
103 }
104 let _ = write!(query, " ORDER BY rowid");
105 if self.reverse {
106 let _ = write!(query, " DESC");
107 }
108 if let Some(limit) = self.limit {
109 let _ = write!(query, " LIMIT {limit}");
110 }
111
112 query
113 }
114}
115
116#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
117#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
118pub trait EntityBase:
119 'static + Send + Sized + Clone + PartialEq + Eq + std::fmt::Debug + Serialize + for<'de> Deserialize<'de>
120{
121 type ConnectionType: for<'a> DatabaseConnection<'a>;
122 type AutoGeneratedFields: Default;
123 const COLLECTION_NAME: &'static str;
126
127 fn to_missing_key_err_kind() -> MissingKeyErrorKind;
128
129 fn downcast<T: EntityBase>(&self) -> Option<&T> {
130 let as_dyn_any: &dyn std::any::Any = self;
131 as_dyn_any.downcast_ref()
132 }
133
134 fn to_transaction_entity(self) -> crate::transaction::dynamic_dispatch::Entity;
135}
136
137cfg_if::cfg_if! {
138 if #[cfg(target_family = "wasm")] {
139 const AES_GCM_256_NONCE_SIZE: usize = 12;
140
141 #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
142 struct Aad {
143 type_name: Vec<u8>,
144 id: Vec<u8>,
145 }
146
147 #[async_trait::async_trait(?Send)]
148 pub trait EntityTransactionExt: Entity<ConnectionType = crate::connection::KeystoreDatabaseConnection> {
149 async fn save<'a>(&'a self, tx: &crate::connection::storage::WasmStorageTransaction<'a>) -> CryptoKeystoreResult<()> {
150 tx.save(self.clone()).await
151 }
152 async fn pre_save<'a>(&'a mut self) -> CryptoKeystoreResult<Self::AutoGeneratedFields> {
153 Ok(Default::default())
154 }
155 async fn delete_fail_on_missing_id<'a>(tx: &crate::connection::storage::WasmStorageTransaction<'a>, id: StringEntityId<'a>) -> CryptoKeystoreResult<()> {
156 tx.delete(Self::COLLECTION_NAME, id.as_slice()).await
157 }
158
159 async fn delete<'a>(tx: &crate::connection::storage::WasmStorageTransaction<'a>, id: StringEntityId<'a>) -> CryptoKeystoreResult<()> {
160 match Self::delete_fail_on_missing_id(tx, id).await{
161 Ok(_) => Ok(()),
162 Err(CryptoKeystoreError::IdbError(idb::Error::DeleteFailed(_))) => Ok(()),
163 Err(e) => Err(e),
164 }
165 }
166 }
167
168 #[async_trait::async_trait(?Send)]
169 pub trait Entity: EntityBase + serde::Serialize + serde::de::DeserializeOwned {
170 fn id(&self) -> CryptoKeystoreResult<wasm_bindgen::JsValue> {
171 Ok(js_sys::Uint8Array::from(self.id_raw()).into())
172 }
173
174 fn id_raw(&self) -> &[u8];
175
176 fn merge_key(&self) -> Vec<u8> {
179 self.id_raw().into()
180 }
181
182 fn aad(&self) -> CryptoKeystoreResult<Vec<u8>> {
183 let aad = Aad {
184 type_name: Self::COLLECTION_NAME.as_bytes().to_vec(),
185 id: self.id_raw().into(),
186 };
187 serde_json::to_vec(&aad).map_err(Into::into)
188 }
189
190 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>>;
191 async fn find_one(conn: &mut Self::ConnectionType, id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>>;
192 async fn find_many(conn: &mut Self::ConnectionType, ids: &[StringEntityId]) -> CryptoKeystoreResult<Vec<Self>> {
193 let mut ret = Vec::with_capacity(ids.len());
195 for id in ids {
196 if let Some(entity) = Self::find_one(conn, id).await? {
197 ret.push(entity);
198 }
199 }
200 Ok(ret)
201 }
202 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize>;
203
204 fn encrypt(&mut self, cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()>;
212 fn encrypt_with_nonce_and_aad(cipher: &aes_gcm::Aes256Gcm, data: &[u8], nonce: &[u8], aad: &[u8]) -> CryptoKeystoreResult<Vec<u8>> {
213 use aes_gcm::aead::Aead as _;
214 let nonce = aes_gcm::Nonce::from_slice(nonce);
215 let msg = data;
216 let payload = aes_gcm::aead::Payload {
217 msg,
218 aad,
219 };
220
221 let mut encrypted = cipher.encrypt(nonce, payload).map_err(|_| CryptoKeystoreError::AesGcmError)?;
222 let mut message = Vec::with_capacity(nonce.len() + encrypted.len());
223 message.extend_from_slice(nonce);
224 message.append(&mut encrypted);
225 Ok(message)
226 }
227
228 fn encrypt_data(&self, cipher: &aes_gcm::Aes256Gcm, data: &[u8]) -> CryptoKeystoreResult<Vec<u8>> {
229 let nonce_bytes: [u8; AES_GCM_256_NONCE_SIZE] = rand::random();
230 Self::encrypt_with_nonce_and_aad(cipher, data, &nonce_bytes, &self.aad()?)
231 }
232
233 fn decrypt(&mut self, cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()>;
234 fn decrypt_data(&self, cipher: &aes_gcm::Aes256Gcm, data: &[u8]) -> CryptoKeystoreResult<Vec<u8>> {
235 use aes_gcm::aead::Aead as _;
236
237 if data.is_empty() {
238 return Err(CryptoKeystoreError::MissingKeyInStore(Self::to_missing_key_err_kind()));
239 }
240 if data.len() < AES_GCM_256_NONCE_SIZE {
241 return Err(CryptoKeystoreError::AesGcmError);
242 }
243
244 let nonce_bytes = &data[..AES_GCM_256_NONCE_SIZE];
245 let nonce = aes_gcm::Nonce::from_slice(nonce_bytes);
246 let msg = &data[AES_GCM_256_NONCE_SIZE..];
247 let aad = &self.aad()?;
248 let payload = aes_gcm::aead::Payload {
249 msg,
250 aad,
251 };
252 let cleartext = cipher.decrypt(nonce, payload).map_err(|_| CryptoKeystoreError::AesGcmError)?;
253 Ok(cleartext)
254 }
255 }
256
257 #[async_trait::async_trait(?Send)]
258 impl<T: UniqueEntity + serde::Serialize + serde::de::DeserializeOwned> Entity for T {
259 fn id_raw(&self) -> &[u8] {
260 &Self::ID
261 }
262
263 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
264 <Self as UniqueEntity>::find_all(conn, params).await
265 }
266
267 async fn find_one(conn: &mut Self::ConnectionType, _id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>> {
268 <Self as UniqueEntity>::find_one(conn).await
269 }
270
271 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
272 <Self as UniqueEntity>::count(conn).await
273 }
274
275 fn encrypt(&mut self, cipher: &Aes256Gcm) -> CryptoKeystoreResult<()> {
276 self.set_content(self.encrypt_data(cipher, self.content())?);
277 Self::ConnectionType::check_buffer_size(self.content().len())?;
278 Ok(())
279 }
280
281 fn decrypt(&mut self, cipher: &Aes256Gcm) -> CryptoKeystoreResult<()> {
282 self.set_content(self.decrypt_data(cipher, self.content())?);
283 Self::ConnectionType::check_buffer_size(self.content().len())?;
284 Ok(())
285 }
286 }
287 } else {
288 #[async_trait::async_trait]
289 pub trait EntityTransactionExt: Entity {
290 async fn save(&self, tx: &crate::connection::TransactionWrapper<'_>) -> CryptoKeystoreResult<()>;
291 async fn pre_save<'a>(&'a mut self) -> CryptoKeystoreResult<Self::AutoGeneratedFields> {
292 Ok(Default::default())
293 }
294 async fn delete_fail_on_missing_id(
295 tx: &crate::connection::TransactionWrapper<'_>,
296 id: StringEntityId<'_>,
297 ) -> CryptoKeystoreResult<()>;
298
299 async fn delete(
300 tx: &crate::connection::TransactionWrapper<'_>,
301 id: StringEntityId<'_>,
302 ) -> CryptoKeystoreResult<()> {
303 match Self::delete_fail_on_missing_id(tx, id).await{
304 Ok(_) => Ok(()),
305 Err(CryptoKeystoreError::MissingKeyInStore(_)) => Ok(()),
306 Err(e) => Err(e),
307 }
308 }
309 }
310
311 #[async_trait::async_trait]
312 pub trait Entity: EntityBase {
313 fn id_raw(&self) -> &[u8];
314
315 fn merge_key(&self) -> Vec<u8> {
318 self.id_raw().into()
319 }
320
321 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>>;
322 async fn find_one(conn: &mut Self::ConnectionType, id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>>;
323 async fn find_many(conn: &mut Self::ConnectionType, ids: &[StringEntityId]) -> CryptoKeystoreResult<Vec<Self>> {
324 let mut ret = Vec::with_capacity(ids.len());
326 for id in ids {
327 if let Some(entity) = Self::find_one(conn, id).await? {
328 ret.push(entity);
329 }
330 }
331 Ok(ret)
332 }
333 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize>;
334 }
335
336 #[async_trait::async_trait]
337 impl<T: UniqueEntity> Entity for T {
338 fn id_raw(&self) -> &[u8] {
339 &[Self::ID as u8]
340 }
341
342 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
343 <Self as UniqueEntity>::find_all(conn, params).await
344 }
345
346 async fn find_one(conn: &mut Self::ConnectionType, _id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>> {
347 <Self as UniqueEntity>::find_one(conn).await
348 }
349
350 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
351 <Self as UniqueEntity>::count(conn).await
352 }
353 }
354
355 pub trait EntityIdStringExt: Entity {
356 fn id_hex(&self) -> String {
357 hex::encode(self.id_raw())
358 }
359
360 fn id_sha256(&self) -> String {
361 sha256(self.id_raw())
362 }
363
364 fn id_from_hex(id_hex: &str) -> CryptoKeystoreResult<Vec<u8>> {
365 hex::decode(id_hex).map_err(Into::into)
366 }
367 }
368
369 impl<T: Entity> EntityIdStringExt for T {}
370 }
371}