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