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: 'static + Send + Sized + Clone + PartialEq + Eq + std::fmt::Debug {
136 type ConnectionType: for<'a> DatabaseConnection<'a>;
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 let as_dyn_any: &dyn std::any::Any = self;
146 as_dyn_any.downcast_ref()
147 }
148
149 fn to_transaction_entity(self) -> crate::transaction::dynamic_dispatch::Entity;
150}
151
152cfg_if::cfg_if! {
153 if #[cfg(target_family = "wasm")] {
154 const AES_GCM_256_NONCE_SIZE: usize = 12;
155
156 #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
157 struct Aad {
158 type_name: Vec<u8>,
159 id: Vec<u8>,
160 }
161
162 #[async_trait::async_trait(?Send)]
163 pub trait EntityTransactionExt: Entity<ConnectionType = crate::connection::KeystoreDatabaseConnection> {
164 async fn save<'a>(&'a self, tx: &crate::connection::storage::WasmStorageTransaction<'a>) -> CryptoKeystoreResult<()> {
165 tx.save(self.clone()).await
166 }
167 async fn pre_save<'a>(&'a mut self) -> CryptoKeystoreResult<Self::AutoGeneratedFields> {
168 Ok(Default::default())
169 }
170 async fn delete_fail_on_missing_id<'a>(tx: &crate::connection::storage::WasmStorageTransaction<'a>, id: StringEntityId<'a>) -> CryptoKeystoreResult<()> {
171 tx.delete(Self::COLLECTION_NAME, id.as_slice()).await
172 }
173
174 async fn delete<'a>(tx: &crate::connection::storage::WasmStorageTransaction<'a>, id: StringEntityId<'a>) -> CryptoKeystoreResult<()> {
175 match Self::delete_fail_on_missing_id(tx, id).await{
176 Ok(_) => Ok(()),
177 Err(CryptoKeystoreError::IdbError(idb::Error::DeleteFailed(_))) => Ok(()),
178 Err(e) => Err(e),
179 }
180 }
181 }
182
183 #[async_trait::async_trait(?Send)]
184 pub trait Entity: EntityBase + serde::Serialize + serde::de::DeserializeOwned {
185 fn id(&self) -> CryptoKeystoreResult<wasm_bindgen::JsValue> {
186 Ok(js_sys::Uint8Array::from(self.id_raw()).into())
187 }
188
189 fn id_raw(&self) -> &[u8];
190
191 fn merge_key(&self) -> Vec<u8> {
194 self.id_raw().into()
195 }
196
197 fn aad(&self) -> CryptoKeystoreResult<Vec<u8>> {
198 let aad = Aad {
199 type_name: Self::COLLECTION_NAME.as_bytes().to_vec(),
200 id: self.id_raw().into(),
201 };
202 serde_json::to_vec(&aad).map_err(Into::into)
203 }
204
205 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>>;
206 async fn find_one(conn: &mut Self::ConnectionType, id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>>;
207 async fn find_many(conn: &mut Self::ConnectionType, ids: &[StringEntityId]) -> CryptoKeystoreResult<Vec<Self>> {
208 let mut ret = Vec::with_capacity(ids.len());
210 for id in ids {
211 if let Some(entity) = Self::find_one(conn, id).await? {
212 ret.push(entity);
213 }
214 }
215 Ok(ret)
216 }
217 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize>;
218
219 fn encrypt(&mut self, cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()>;
227 fn encrypt_with_nonce_and_aad(cipher: &aes_gcm::Aes256Gcm, data: &[u8], nonce: &[u8], aad: &[u8]) -> CryptoKeystoreResult<Vec<u8>> {
228 use aes_gcm::aead::Aead as _;
229 let nonce = aes_gcm::Nonce::from_slice(nonce);
230 let msg = data;
231 let payload = aes_gcm::aead::Payload {
232 msg,
233 aad,
234 };
235
236 let mut encrypted = cipher.encrypt(nonce, payload).map_err(|_| CryptoKeystoreError::AesGcmError)?;
237 let mut message = Vec::with_capacity(nonce.len() + encrypted.len());
238 message.extend_from_slice(nonce);
239 message.append(&mut encrypted);
240 Ok(message)
241 }
242
243 fn encrypt_data(&self, cipher: &aes_gcm::Aes256Gcm, data: &[u8]) -> CryptoKeystoreResult<Vec<u8>> {
244 let nonce_bytes: [u8; AES_GCM_256_NONCE_SIZE] = rand::random();
245 Self::encrypt_with_nonce_and_aad(cipher, data, &nonce_bytes, &self.aad()?)
246 }
247
248 fn decrypt(&mut self, cipher: &aes_gcm::Aes256Gcm) -> CryptoKeystoreResult<()>;
249 fn decrypt_data(&self, cipher: &aes_gcm::Aes256Gcm, data: &[u8]) -> CryptoKeystoreResult<Vec<u8>> {
250 use aes_gcm::aead::Aead as _;
251
252 if data.is_empty() {
253 return Err(CryptoKeystoreError::MissingKeyInStore(Self::to_missing_key_err_kind()));
254 }
255 if data.len() < AES_GCM_256_NONCE_SIZE {
256 return Err(CryptoKeystoreError::AesGcmError);
257 }
258
259 let nonce_bytes = &data[..AES_GCM_256_NONCE_SIZE];
260 let nonce = aes_gcm::Nonce::from_slice(nonce_bytes);
261 let msg = &data[AES_GCM_256_NONCE_SIZE..];
262 let aad = &self.aad()?;
263 let payload = aes_gcm::aead::Payload {
264 msg,
265 aad,
266 };
267 let cleartext = cipher.decrypt(nonce, payload).map_err(|_| CryptoKeystoreError::AesGcmError)?;
268 Ok(cleartext)
269 }
270 }
271
272 #[async_trait::async_trait(?Send)]
273 impl<T: UniqueEntity + serde::Serialize + serde::de::DeserializeOwned> Entity for T {
274 fn id_raw(&self) -> &[u8] {
275 &Self::ID
276 }
277
278 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
279 <Self as UniqueEntity>::find_all(conn, params).await
280 }
281
282 async fn find_one(conn: &mut Self::ConnectionType, _id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>> {
283 <Self as UniqueEntity>::find_one(conn).await
284 }
285
286 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
287 <Self as UniqueEntity>::count(conn).await
288 }
289
290 fn encrypt(&mut self, cipher: &Aes256Gcm) -> CryptoKeystoreResult<()> {
291 self.set_content(self.encrypt_data(cipher, self.content())?);
292 Self::ConnectionType::check_buffer_size(self.content().len())?;
293 Ok(())
294 }
295
296 fn decrypt(&mut self, cipher: &Aes256Gcm) -> CryptoKeystoreResult<()> {
297 self.set_content(self.decrypt_data(cipher, self.content())?);
298 Self::ConnectionType::check_buffer_size(self.content().len())?;
299 Ok(())
300 }
301 }
302 } else {
303 #[async_trait::async_trait]
304 pub trait EntityTransactionExt: Entity {
305 async fn save(&self, tx: &crate::connection::TransactionWrapper<'_>) -> CryptoKeystoreResult<()>;
306 async fn pre_save<'a>(&'a mut self) -> CryptoKeystoreResult<Self::AutoGeneratedFields> {
307 Ok(Default::default())
308 }
309 async fn delete_fail_on_missing_id(
310 tx: &crate::connection::TransactionWrapper<'_>,
311 id: StringEntityId<'_>,
312 ) -> CryptoKeystoreResult<()>;
313
314 async fn delete(
315 tx: &crate::connection::TransactionWrapper<'_>,
316 id: StringEntityId<'_>,
317 ) -> CryptoKeystoreResult<()> {
318 match Self::delete_fail_on_missing_id(tx, id).await{
319 Ok(_) => Ok(()),
320 Err(CryptoKeystoreError::MissingKeyInStore(_)) => Ok(()),
321 Err(e) => Err(e),
322 }
323 }
324 }
325
326 #[async_trait::async_trait]
327 pub trait Entity: EntityBase {
328 fn id_raw(&self) -> &[u8];
329
330 fn merge_key(&self) -> Vec<u8> {
333 self.id_raw().into()
334 }
335
336 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>>;
337 async fn find_one(conn: &mut Self::ConnectionType, id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>>;
338 async fn find_many(conn: &mut Self::ConnectionType, ids: &[StringEntityId]) -> CryptoKeystoreResult<Vec<Self>> {
339 let mut ret = Vec::with_capacity(ids.len());
341 for id in ids {
342 if let Some(entity) = Self::find_one(conn, id).await? {
343 ret.push(entity);
344 }
345 }
346 Ok(ret)
347 }
348 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize>;
349 }
350
351 #[async_trait::async_trait]
352 impl<T: UniqueEntity> Entity for T {
353 fn id_raw(&self) -> &[u8] {
354 &[Self::ID as u8]
355 }
356
357 async fn find_all(conn: &mut Self::ConnectionType, params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
358 <Self as UniqueEntity>::find_all(conn, params).await
359 }
360
361 async fn find_one(conn: &mut Self::ConnectionType, _id: &StringEntityId) -> CryptoKeystoreResult<Option<Self>> {
362 <Self as UniqueEntity>::find_one(conn).await
363 }
364
365 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
366 <Self as UniqueEntity>::count(conn).await
367 }
368 }
369
370 pub trait EntityIdStringExt: Entity {
371 fn id_hex(&self) -> String {
372 hex::encode(self.id_raw())
373 }
374
375 fn id_sha256(&self) -> String {
376 sha256(self.id_raw())
377 }
378
379 fn id_from_hex(id_hex: &str) -> CryptoKeystoreResult<Vec<u8>> {
380 hex::decode(id_hex).map_err(Into::into)
381 }
382 }
383
384 impl<T: Entity> EntityIdStringExt for T {}
385 }
386}