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