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