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